Merge pull request #542 from gameblabla/mdec_fix
authorAutechre <libretro@gmail.com>
Sat, 21 Aug 2021 16:06:01 +0000 (18:06 +0200)
committerGitHub <noreply@github.com>
Sat, 21 Aug 2021 16:06:01 +0000 (18:06 +0200)
mdec.cpp: Dare to set MDEC_BIAS to 10

588 files changed:
.github/ISSUE_TEMPLATE/custom-issue-report.md [new file with mode: 0644]
.gitignore
.gitlab-ci.yml [new file with mode: 0644]
.gitmodules [deleted file]
.travis.yml
Makefile
Makefile.libretro
README.md
blackberry_qnx/.cproject [deleted file]
blackberry_qnx/.project [deleted file]
configure
debian_maemo/buildpkg [deleted file]
debian_maemo/changelog [deleted file]
debian_maemo/compat [deleted file]
debian_maemo/control [deleted file]
debian_maemo/copyright [deleted file]
debian_maemo/dirs [deleted file]
debian_maemo/docs [deleted file]
debian_maemo/files [deleted file]
debian_maemo/install [deleted file]
debian_maemo/rules [deleted file]
deps/libchdr/.gitrepo [new file with mode: 0644]
deps/libchdr/CMakeLists.txt [new file with mode: 0644]
deps/libchdr/LICENSE.txt [new file with mode: 0644]
deps/libchdr/README.md [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/CMakeLists.txt [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/LICENSE [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/7zTypes.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/Alloc.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/Bra.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/Compiler.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/CpuArch.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/Delta.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/LzFind.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/LzHash.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/Lzma86.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/LzmaDec.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/LzmaEnc.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/LzmaLib.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/Precomp.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/include/Sort.h [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/lzma-history.txt [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/lzma.txt [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/lzma.vcxproj [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/lzma.vcxproj.filters [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/Alloc.c [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/Bra86.c [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/BraIA64.c [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/CpuArch.c [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/Delta.c [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/LzFind.c [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/Lzma86Dec.c [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/LzmaDec.c [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/LzmaEnc.c [new file with mode: 0644]
deps/libchdr/deps/lzma-19.00/src/Sort.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/CMakeLists.txt [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/ChangeLog [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/FAQ [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/INDEX [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/Makefile [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/Makefile.in [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/README [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/adler32.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/compress.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/configure [new file with mode: 0755]
deps/libchdr/deps/zlib-1.2.11/crc32.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/crc32.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/deflate.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/deflate.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/doc/algorithm.txt [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/doc/rfc1950.txt [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/doc/rfc1951.txt [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/doc/rfc1952.txt [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/doc/txtvsbin.txt [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/gzclose.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/gzguts.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/gzlib.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/gzread.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/gzwrite.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/infback.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/inffast.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/inffast.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/inffixed.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/inflate.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/inflate.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/inftrees.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/inftrees.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/make_vms.com [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/treebuild.xml [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/trees.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/trees.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/uncompr.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zconf.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zconf.h.cmakein [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zconf.h.in [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zlib.3 [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zlib.3.pdf [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zlib.h [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zlib.map [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zlib.pc.cmakein [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zlib.pc.in [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zlib2ansi [new file with mode: 0755]
deps/libchdr/deps/zlib-1.2.11/zutil.c [new file with mode: 0644]
deps/libchdr/deps/zlib-1.2.11/zutil.h [new file with mode: 0644]
deps/libchdr/include/dr_libs/dr_flac.h [new file with mode: 0644]
deps/libchdr/include/libchdr/bitstream.h [new file with mode: 0644]
deps/libchdr/include/libchdr/cdrom.h [new file with mode: 0644]
deps/libchdr/include/libchdr/chd.h [new file with mode: 0644]
deps/libchdr/include/libchdr/chdconfig.h [new file with mode: 0644]
deps/libchdr/include/libchdr/coretypes.h [new file with mode: 0644]
deps/libchdr/include/libchdr/flac.h [new file with mode: 0644]
deps/libchdr/include/libchdr/huffman.h [new file with mode: 0644]
deps/libchdr/pkg-config.pc.in [new file with mode: 0644]
deps/libchdr/src/libchdr_bitstream.c [new file with mode: 0644]
deps/libchdr/src/libchdr_cdrom.c [new file with mode: 0644]
deps/libchdr/src/libchdr_chd.c [new file with mode: 0644]
deps/libchdr/src/libchdr_flac.c [new file with mode: 0644]
deps/libchdr/src/libchdr_huffman.c [new file with mode: 0644]
deps/libchdr/src/link.T [new file with mode: 0644]
deps/libchdr/tests/benchmark.c [new file with mode: 0644]
deps/libchdr/tests/build_tests.sh [new file with mode: 0755]
deps/lightning/.gitattributes [new file with mode: 0644]
deps/lightning/.gitignore [new file with mode: 0644]
deps/lightning/.gitrepo [new file with mode: 0644]
deps/lightning/AUTHORS [new file with mode: 0644]
deps/lightning/COPYING [new file with mode: 0644]
deps/lightning/COPYING.DOC [new file with mode: 0644]
deps/lightning/COPYING.LESSER [new file with mode: 0644]
deps/lightning/ChangeLog [new file with mode: 0644]
deps/lightning/Makefile.am [new file with mode: 0644]
deps/lightning/NEWS [new file with mode: 0644]
deps/lightning/README [new file with mode: 0644]
deps/lightning/THANKS [new file with mode: 0644]
deps/lightning/TODO [new file with mode: 0644]
deps/lightning/check/3to2.ok [new file with mode: 0644]
deps/lightning/check/3to2.tst [new file with mode: 0644]
deps/lightning/check/Makefile.am [new file with mode: 0644]
deps/lightning/check/add.ok [new file with mode: 0644]
deps/lightning/check/add.tst [new file with mode: 0644]
deps/lightning/check/align.ok [new file with mode: 0644]
deps/lightning/check/align.tst [new file with mode: 0644]
deps/lightning/check/all.tst [new file with mode: 0644]
deps/lightning/check/allocai.ok [new file with mode: 0644]
deps/lightning/check/allocai.tst [new file with mode: 0644]
deps/lightning/check/allocar.ok [new file with mode: 0644]
deps/lightning/check/allocar.tst [new file with mode: 0644]
deps/lightning/check/alu.inc [new file with mode: 0644]
deps/lightning/check/alu_add.ok [new file with mode: 0644]
deps/lightning/check/alu_add.tst [new file with mode: 0644]
deps/lightning/check/alu_and.ok [new file with mode: 0644]
deps/lightning/check/alu_and.tst [new file with mode: 0644]
deps/lightning/check/alu_com.ok [new file with mode: 0644]
deps/lightning/check/alu_com.tst [new file with mode: 0644]
deps/lightning/check/alu_div.ok [new file with mode: 0644]
deps/lightning/check/alu_div.tst [new file with mode: 0644]
deps/lightning/check/alu_lsh.ok [new file with mode: 0644]
deps/lightning/check/alu_lsh.tst [new file with mode: 0644]
deps/lightning/check/alu_mul.ok [new file with mode: 0644]
deps/lightning/check/alu_mul.tst [new file with mode: 0644]
deps/lightning/check/alu_neg.ok [new file with mode: 0644]
deps/lightning/check/alu_neg.tst [new file with mode: 0644]
deps/lightning/check/alu_or.ok [new file with mode: 0644]
deps/lightning/check/alu_or.tst [new file with mode: 0644]
deps/lightning/check/alu_rem.ok [new file with mode: 0644]
deps/lightning/check/alu_rem.tst [new file with mode: 0644]
deps/lightning/check/alu_rsb.ok [new file with mode: 0644]
deps/lightning/check/alu_rsb.tst [new file with mode: 0644]
deps/lightning/check/alu_rsh.ok [new file with mode: 0644]
deps/lightning/check/alu_rsh.tst [new file with mode: 0644]
deps/lightning/check/alu_sub.ok [new file with mode: 0644]
deps/lightning/check/alu_sub.tst [new file with mode: 0644]
deps/lightning/check/alu_xor.ok [new file with mode: 0644]
deps/lightning/check/alu_xor.tst [new file with mode: 0644]
deps/lightning/check/alux_add.ok [new file with mode: 0644]
deps/lightning/check/alux_add.tst [new file with mode: 0644]
deps/lightning/check/alux_sub.ok [new file with mode: 0644]
deps/lightning/check/alux_sub.tst [new file with mode: 0644]
deps/lightning/check/bp.ok [new file with mode: 0644]
deps/lightning/check/bp.tst [new file with mode: 0644]
deps/lightning/check/branch.ok [new file with mode: 0644]
deps/lightning/check/branch.tst [new file with mode: 0644]
deps/lightning/check/call.ok [new file with mode: 0644]
deps/lightning/check/call.tst [new file with mode: 0644]
deps/lightning/check/carg.c [new file with mode: 0644]
deps/lightning/check/carry.ok [new file with mode: 0644]
deps/lightning/check/carry.tst [new file with mode: 0644]
deps/lightning/check/ccall.c [new file with mode: 0644]
deps/lightning/check/check.arm.sh [new file with mode: 0755]
deps/lightning/check/check.arm.swf.sh [new file with mode: 0755]
deps/lightning/check/check.arm4.swf.sh [new file with mode: 0755]
deps/lightning/check/check.nodata.sh [new file with mode: 0755]
deps/lightning/check/check.sh [new file with mode: 0755]
deps/lightning/check/check.swf.sh [new file with mode: 0755]
deps/lightning/check/check.x87.nodata.sh [new file with mode: 0755]
deps/lightning/check/check.x87.sh [new file with mode: 0755]
deps/lightning/check/clobber.ok [new file with mode: 0644]
deps/lightning/check/clobber.tst [new file with mode: 0644]
deps/lightning/check/ctramp.c [new file with mode: 0644]
deps/lightning/check/cva_list.c [new file with mode: 0644]
deps/lightning/check/cvt.ok [new file with mode: 0644]
deps/lightning/check/cvt.tst [new file with mode: 0644]
deps/lightning/check/divi.ok [new file with mode: 0644]
deps/lightning/check/divi.tst [new file with mode: 0644]
deps/lightning/check/fib.ok [new file with mode: 0644]
deps/lightning/check/fib.tst [new file with mode: 0644]
deps/lightning/check/float.ok [new file with mode: 0644]
deps/lightning/check/float.tst [new file with mode: 0644]
deps/lightning/check/fop_abs.ok [new file with mode: 0644]
deps/lightning/check/fop_abs.tst [new file with mode: 0644]
deps/lightning/check/fop_sqrt.ok [new file with mode: 0644]
deps/lightning/check/fop_sqrt.tst [new file with mode: 0644]
deps/lightning/check/hton.ok [new file with mode: 0644]
deps/lightning/check/hton.tst [new file with mode: 0644]
deps/lightning/check/jmpr.ok [new file with mode: 0644]
deps/lightning/check/jmpr.tst [new file with mode: 0644]
deps/lightning/check/ldst.inc [new file with mode: 0644]
deps/lightning/check/ldsti.ok [new file with mode: 0644]
deps/lightning/check/ldsti.tst [new file with mode: 0644]
deps/lightning/check/ldstr-c.ok [new file with mode: 0644]
deps/lightning/check/ldstr-c.tst [new file with mode: 0644]
deps/lightning/check/ldstr.ok [new file with mode: 0644]
deps/lightning/check/ldstr.tst [new file with mode: 0644]
deps/lightning/check/ldstxi-c.ok [new file with mode: 0644]
deps/lightning/check/ldstxi-c.tst [new file with mode: 0644]
deps/lightning/check/ldstxi.ok [new file with mode: 0644]
deps/lightning/check/ldstxi.tst [new file with mode: 0644]
deps/lightning/check/ldstxr-c.ok [new file with mode: 0644]
deps/lightning/check/ldstxr-c.tst [new file with mode: 0644]
deps/lightning/check/ldstxr.ok [new file with mode: 0644]
deps/lightning/check/ldstxr.tst [new file with mode: 0644]
deps/lightning/check/lightning.c [new file with mode: 0644]
deps/lightning/check/nodata.c [new file with mode: 0644]
deps/lightning/check/put.ok [new file with mode: 0644]
deps/lightning/check/put.tst [new file with mode: 0644]
deps/lightning/check/qalu.inc [new file with mode: 0644]
deps/lightning/check/qalu_div.ok [new file with mode: 0644]
deps/lightning/check/qalu_div.tst [new file with mode: 0644]
deps/lightning/check/qalu_mul.ok [new file with mode: 0644]
deps/lightning/check/qalu_mul.tst [new file with mode: 0644]
deps/lightning/check/range.ok [new file with mode: 0644]
deps/lightning/check/range.tst [new file with mode: 0644]
deps/lightning/check/ranger.ok [new file with mode: 0644]
deps/lightning/check/ranger.tst [new file with mode: 0644]
deps/lightning/check/ret.ok [new file with mode: 0644]
deps/lightning/check/ret.tst [new file with mode: 0644]
deps/lightning/check/rpn.ok [new file with mode: 0644]
deps/lightning/check/rpn.tst [new file with mode: 0644]
deps/lightning/check/run-test [new file with mode: 0755]
deps/lightning/check/self.c [new file with mode: 0644]
deps/lightning/check/setcode.c [new file with mode: 0644]
deps/lightning/check/stack.ok [new file with mode: 0644]
deps/lightning/check/stack.tst [new file with mode: 0644]
deps/lightning/check/tramp.ok [new file with mode: 0644]
deps/lightning/check/tramp.tst [new file with mode: 0644]
deps/lightning/check/va_list.ok [new file with mode: 0644]
deps/lightning/check/va_list.tst [new file with mode: 0644]
deps/lightning/check/varargs.ok [new file with mode: 0644]
deps/lightning/check/varargs.tst [new file with mode: 0644]
deps/lightning/configure.ac [new file with mode: 0644]
deps/lightning/doc/.cvsignore [new file with mode: 0644]
deps/lightning/doc/.gitignore [new file with mode: 0644]
deps/lightning/doc/Makefile.am [new file with mode: 0644]
deps/lightning/doc/body.texi [new file with mode: 0644]
deps/lightning/doc/fact.c [new file with mode: 0644]
deps/lightning/doc/ifib.c [new file with mode: 0644]
deps/lightning/doc/incr.c [new file with mode: 0644]
deps/lightning/doc/lightning.texi [new file with mode: 0644]
deps/lightning/doc/printf.c [new file with mode: 0644]
deps/lightning/doc/rfib.c [new file with mode: 0644]
deps/lightning/doc/rpn.c [new file with mode: 0644]
deps/lightning/doc/version.texi [new file with mode: 0644]
deps/lightning/include/Makefile.am [new file with mode: 0644]
deps/lightning/include/lightning.h [new file with mode: 0644]
deps/lightning/include/lightning.h.in [new file with mode: 0644]
deps/lightning/include/lightning/Makefile.am [new file with mode: 0644]
deps/lightning/include/lightning/jit_aarch64.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_alpha.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_arm.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_hppa.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_ia64.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_mips.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_ppc.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_private.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_riscv.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_s390.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_sparc.h [new file with mode: 0644]
deps/lightning/include/lightning/jit_x86.h [new file with mode: 0644]
deps/lightning/lib/Makefile.am [new file with mode: 0644]
deps/lightning/lib/jit_aarch64-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_aarch64-fpu.c [new file with mode: 0644]
deps/lightning/lib/jit_aarch64-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_aarch64.c [new file with mode: 0644]
deps/lightning/lib/jit_alpha-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_alpha-fpu.c [new file with mode: 0644]
deps/lightning/lib/jit_alpha-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_alpha.c [new file with mode: 0644]
deps/lightning/lib/jit_arm-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_arm-swf.c [new file with mode: 0644]
deps/lightning/lib/jit_arm-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_arm-vfp.c [new file with mode: 0644]
deps/lightning/lib/jit_arm.c [new file with mode: 0644]
deps/lightning/lib/jit_disasm.c [new file with mode: 0644]
deps/lightning/lib/jit_hppa-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_hppa-fpu.c [new file with mode: 0644]
deps/lightning/lib/jit_hppa-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_hppa.c [new file with mode: 0644]
deps/lightning/lib/jit_ia64-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_ia64-fpu.c [new file with mode: 0644]
deps/lightning/lib/jit_ia64-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_ia64.c [new file with mode: 0644]
deps/lightning/lib/jit_memory.c [new file with mode: 0644]
deps/lightning/lib/jit_mips-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_mips-fpu.c [new file with mode: 0644]
deps/lightning/lib/jit_mips-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_mips.c [new file with mode: 0644]
deps/lightning/lib/jit_names.c [new file with mode: 0644]
deps/lightning/lib/jit_note.c [new file with mode: 0644]
deps/lightning/lib/jit_ppc-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_ppc-fpu.c [new file with mode: 0644]
deps/lightning/lib/jit_ppc-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_ppc.c [new file with mode: 0644]
deps/lightning/lib/jit_print.c [new file with mode: 0644]
deps/lightning/lib/jit_rewind.c [new file with mode: 0644]
deps/lightning/lib/jit_riscv-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_riscv-fpu.c [new file with mode: 0644]
deps/lightning/lib/jit_riscv-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_riscv.c [new file with mode: 0644]
deps/lightning/lib/jit_s390-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_s390-fpu.c [new file with mode: 0644]
deps/lightning/lib/jit_s390-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_s390.c [new file with mode: 0644]
deps/lightning/lib/jit_size.c [new file with mode: 0644]
deps/lightning/lib/jit_sparc-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_sparc-fpu.c [new file with mode: 0644]
deps/lightning/lib/jit_sparc-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_sparc.c [new file with mode: 0644]
deps/lightning/lib/jit_x86-cpu.c [new file with mode: 0644]
deps/lightning/lib/jit_x86-sse.c [new file with mode: 0644]
deps/lightning/lib/jit_x86-sz.c [new file with mode: 0644]
deps/lightning/lib/jit_x86-x87.c [new file with mode: 0644]
deps/lightning/lib/jit_x86.c [new file with mode: 0644]
deps/lightning/lib/lightning.c [new file with mode: 0644]
deps/lightning/lightning.pc.in [new file with mode: 0644]
deps/lightning/m4/.gitkeep [new file with mode: 0644]
deps/lightning/size.c [new file with mode: 0644]
deps/lightrec/.gitignore [new file with mode: 0644]
deps/lightrec/.gitrepo [new file with mode: 0644]
deps/lightrec/CMakeLists.txt [new file with mode: 0644]
deps/lightrec/COPYING [new file with mode: 0644]
deps/lightrec/README.md [new file with mode: 0644]
deps/lightrec/blockcache.c [new file with mode: 0644]
deps/lightrec/blockcache.h [new file with mode: 0644]
deps/lightrec/config.h [new file with mode: 0644]
deps/lightrec/config.h.cmakein [new file with mode: 0644]
deps/lightrec/debug.h [new file with mode: 0644]
deps/lightrec/disassembler.c [new file with mode: 0644]
deps/lightrec/disassembler.h [new file with mode: 0644]
deps/lightrec/emitter.c [new file with mode: 0644]
deps/lightrec/emitter.h [new file with mode: 0644]
deps/lightrec/interpreter.c [new file with mode: 0644]
deps/lightrec/interpreter.h [new file with mode: 0644]
deps/lightrec/lightrec-private.h [new file with mode: 0644]
deps/lightrec/lightrec.c [new file with mode: 0644]
deps/lightrec/lightrec.h [new file with mode: 0644]
deps/lightrec/memmanager.c [new file with mode: 0644]
deps/lightrec/memmanager.h [new file with mode: 0644]
deps/lightrec/optimizer.c [new file with mode: 0644]
deps/lightrec/optimizer.h [new file with mode: 0644]
deps/lightrec/reaper.c [new file with mode: 0644]
deps/lightrec/reaper.h [new file with mode: 0644]
deps/lightrec/recompiler.c [new file with mode: 0644]
deps/lightrec/recompiler.h [new file with mode: 0644]
deps/lightrec/regcache.c [new file with mode: 0644]
deps/lightrec/regcache.h [new file with mode: 0644]
deps/lightrec/slist.h [new file with mode: 0644]
deps/mman/.gitignore [new file with mode: 0644]
deps/mman/.gitrepo [new file with mode: 0644]
deps/mman/.vs/mman/v14/.suo [new file with mode: 0644]
deps/mman/CMakeLists.txt [new file with mode: 0644]
deps/mman/Makefile [new file with mode: 0644]
deps/mman/README.md [new file with mode: 0644]
deps/mman/UpgradeLog.htm [new file with mode: 0644]
deps/mman/configure [new file with mode: 0755]
deps/mman/mman-win32.pro [new file with mode: 0644]
deps/mman/mman.c [new file with mode: 0644]
deps/mman/mman.h [new file with mode: 0644]
deps/mman/mman.sln [new file with mode: 0644]
deps/mman/mman.vcxproj [new file with mode: 0644]
deps/mman/mman.vcxproj.filters [new file with mode: 0644]
deps/mman/mman.vcxproj.user [new file with mode: 0644]
deps/mman/test.c [new file with mode: 0644]
frontend/320240/caanoo.gpe [deleted file]
frontend/320240/haptic_s.cfg [deleted file]
frontend/320240/haptic_w.cfg [deleted file]
frontend/320240/pcsx26.png [deleted file]
frontend/320240/pcsx_rearmed.ini [deleted file]
frontend/320240/pcsxb.png [deleted file]
frontend/320240/pollux_set.c [deleted file]
frontend/320240/skin/background.png [deleted file]
frontend/320240/skin/font.png [deleted file]
frontend/320240/skin/readme.txt [deleted file]
frontend/320240/skin/selector.png [deleted file]
frontend/320240/skin/skin.txt [deleted file]
frontend/320240/ui_gp2x.h [deleted file]
frontend/3ds/3ds_utils.h [new file with mode: 0644]
frontend/3ds/pthread.h [new file with mode: 0644]
frontend/3ds/semaphore.h [new file with mode: 0644]
frontend/3ds/sys/mman.h [new file with mode: 0644]
frontend/3ds/utils.S [new file with mode: 0644]
frontend/3ds/zconf.h [new file with mode: 0644]
frontend/3ds/zlib.h [new file with mode: 0644]
frontend/blit320.h
frontend/cspace.c
frontend/cspace.h
frontend/in_tsbutton.h
frontend/libpicofe [deleted submodule]
frontend/libretro.c
frontend/libretro.h [deleted file]
frontend/libretro_core_options.h [new file with mode: 0644]
frontend/libretro_core_options_intl.h [new file with mode: 0644]
frontend/link.T [new file with mode: 0644]
frontend/main.c
frontend/menu.c
frontend/menu.h
frontend/nopic.h
frontend/pandora/pcsx.png [deleted file]
frontend/pandora/pcsx.pxml.templ [deleted file]
frontend/pandora/pcsx.sh [deleted file]
frontend/pandora/picorestore.c [deleted file]
frontend/pandora/skin/background.png [deleted file]
frontend/pandora/skin/font.png [deleted file]
frontend/pandora/skin/readme.txt [deleted file]
frontend/pandora/skin/selector.png [deleted file]
frontend/pandora/skin/skin.txt [deleted file]
frontend/pandora/ui_feat.h [deleted file]
frontend/pl_gun_ts.h
frontend/plat.h
frontend/plat_omap.h
frontend/plugin.c
frontend/plugin.h
frontend/plugin_lib.c
frontend/plugin_lib.h
frontend/switch/sys/mman.h [new file with mode: 0644]
frontend/switch/zconf.h [new file with mode: 0644]
frontend/switch/zlib.h [new file with mode: 0644]
frontend/vita/retro_inline.h [new file with mode: 0644]
frontend/vita/sys/mman.h [new file with mode: 0644]
frontend/warm [deleted submodule]
include/config.h
include/pcnt.h
include/psemu_plugin_defs.h
jni/Android.mk
jni/Application.mk
libpcsxcore/cdriso.c
libpcsxcore/cdrom.c
libpcsxcore/cdrom.h
libpcsxcore/debug.c
libpcsxcore/disr3000a.c
libpcsxcore/gpu.h
libpcsxcore/gte.c
libpcsxcore/gte.h
libpcsxcore/gte_arm.h
libpcsxcore/gte_divider.h
libpcsxcore/gte_neon.S
libpcsxcore/gte_neon.h
libpcsxcore/lightrec/plugin.c [new file with mode: 0644]
libpcsxcore/misc.c
libpcsxcore/new_dynarec/arm/assem_arm.c [moved from libpcsxcore/new_dynarec/assem_arm.c with 99% similarity]
libpcsxcore/new_dynarec/arm/assem_arm.h [moved from libpcsxcore/new_dynarec/assem_arm.h with 95% similarity]
libpcsxcore/new_dynarec/arm/linkage_arm.S [moved from libpcsxcore/new_dynarec/linkage_arm.S with 99% similarity]
libpcsxcore/new_dynarec/arm/linkage_offsets.h [moved from libpcsxcore/new_dynarec/linkage_offsets.h with 94% similarity]
libpcsxcore/new_dynarec/backends/psx/emu_if.c [moved from libpcsxcore/new_dynarec/emu_if.c with 98% similarity]
libpcsxcore/new_dynarec/backends/psx/emu_if.h [moved from libpcsxcore/new_dynarec/emu_if.h with 94% similarity]
libpcsxcore/new_dynarec/backends/psx/pcsxmem.c [moved from libpcsxcore/new_dynarec/pcsxmem.c with 99% similarity]
libpcsxcore/new_dynarec/backends/psx/pcsxmem.h [moved from libpcsxcore/new_dynarec/pcsxmem.h with 76% similarity]
libpcsxcore/new_dynarec/backends/psx/pcsxmem_inline.c [moved from libpcsxcore/new_dynarec/pcsxmem_inline.c with 100% similarity]
libpcsxcore/new_dynarec/new_dynarec.c
libpcsxcore/new_dynarec/new_dynarec.h
libpcsxcore/new_dynarec/new_dynarec_config.h
libpcsxcore/plugins.c
libpcsxcore/ppf.c
libpcsxcore/psxbios.c
libpcsxcore/psxcommon.h
libpcsxcore/psxcounters.c
libpcsxcore/psxhle.c
libpcsxcore/psxinterpreter.c
libpcsxcore/psxmem.c
libpcsxcore/psxmem.h
libpcsxcore/r3000a.c
libpcsxcore/sio.c
libpcsxcore/sio.h
libpcsxcore/sjisfont.h
libpcsxcore/socket.c
libpcsxcore/system.h
libretro-common/compat/compat_posix_string.c [new file with mode: 0644]
libretro-common/compat/compat_strcasestr.c [new file with mode: 0644]
libretro-common/compat/fopen_utf8.c [new file with mode: 0644]
libretro-common/encodings/compat_strl.c [new file with mode: 0644]
libretro-common/encodings/encoding_utf.c [new file with mode: 0644]
libretro-common/file/file_path.c [new file with mode: 0644]
libretro-common/include/boolean.h [new file with mode: 0644]
libretro-common/include/compat/fopen_utf8.h [new file with mode: 0644]
libretro-common/include/compat/posix_string.h [new file with mode: 0644]
libretro-common/include/compat/strcasestr.h [new file with mode: 0644]
libretro-common/include/compat/strl.h [new file with mode: 0644]
libretro-common/include/encodings/utf.h [new file with mode: 0644]
libretro-common/include/file/file_path.h [new file with mode: 0644]
libretro-common/include/libretro.h [new file with mode: 0644]
libretro-common/include/memmap.h [new file with mode: 0644]
libretro-common/include/retro_assert.h [new file with mode: 0644]
libretro-common/include/retro_common_api.h [new file with mode: 0644]
libretro-common/include/retro_environment.h [new file with mode: 0644]
libretro-common/include/retro_inline.h [new file with mode: 0644]
libretro-common/include/retro_miscellaneous.h [new file with mode: 0644]
libretro-common/include/streams/file_stream.h [new file with mode: 0644]
libretro-common/include/streams/file_stream_transforms.h [new file with mode: 0644]
libretro-common/include/string/stdstring.h [new file with mode: 0644]
libretro-common/include/time/rtime.h [new file with mode: 0644]
libretro-common/include/vfs/vfs.h [new file with mode: 0644]
libretro-common/include/vfs/vfs_implementation.h [new file with mode: 0644]
libretro-common/streams/file_stream.c [new file with mode: 0644]
libretro-common/streams/file_stream_transforms.c [new file with mode: 0644]
libretro-common/string/stdstring.c [new file with mode: 0644]
libretro-common/time/rtime.c [new file with mode: 0644]
libretro-common/vfs/vfs_implementation.c [new file with mode: 0644]
maemo/hildon.c [deleted file]
maemo/maemo_common.h [deleted file]
maemo/maemo_xkb.c [deleted file]
maemo/main.c [deleted file]
plugins/cdrcimg/cdrcimg.c
plugins/cdrcimg/cdrcimg.h
plugins/dfinput/externals.h
plugins/dfinput/main.c
plugins/dfinput/main.h
plugins/dfinput/pad.c
plugins/dfsound/adsr.h
plugins/dfsound/dma.h
plugins/dfsound/externals.h
plugins/dfsound/gauss_i.h
plugins/dfsound/out.c
plugins/dfsound/out.h
plugins/dfsound/registers.c
plugins/dfsound/registers.h
plugins/dfsound/spu.c
plugins/dfsound/spu.h
plugins/dfsound/spu_c64x.h
plugins/dfsound/spu_config.h
plugins/dfsound/stdafx.h
plugins/dfsound/xa.c
plugins/dfsound/xa.h
plugins/dfxvideo/gpulib_if.c
plugins/dfxvideo/soft.c
plugins/gpu-gles/gpulib_if.c
plugins/gpu_neon/psx_gpu/psx_gpu.h
plugins/gpu_neon/psx_gpu/psx_gpu_offsets.h
plugins/gpu_neon/psx_gpu/psx_gpu_parse.c
plugins/gpu_neon/psx_gpu_if.c
plugins/gpu_unai/Makefile
plugins/gpu_unai/README_senquack.txt [new file with mode: 0644]
plugins/gpu_unai/gpu.cpp
plugins/gpu_unai/gpu.h
plugins/gpu_unai/gpu_arm.S [moved from plugins/gpu_unai/gpu_arm.s with 97% similarity]
plugins/gpu_unai/gpu_arm.h
plugins/gpu_unai/gpu_blit.h
plugins/gpu_unai/gpu_command.h
plugins/gpu_unai/gpu_fixedpoint.h
plugins/gpu_unai/gpu_inner.h
plugins/gpu_unai/gpu_inner_blend.h
plugins/gpu_unai/gpu_inner_blend_arm.h [new file with mode: 0644]
plugins/gpu_unai/gpu_inner_blend_arm5.h [new file with mode: 0644]
plugins/gpu_unai/gpu_inner_blend_arm7.h [new file with mode: 0644]
plugins/gpu_unai/gpu_inner_light.h
plugins/gpu_unai/gpu_inner_light_arm.h [new file with mode: 0644]
plugins/gpu_unai/gpu_inner_quantization.h [new file with mode: 0644]
plugins/gpu_unai/gpu_raster_image.h
plugins/gpu_unai/gpu_raster_line.h
plugins/gpu_unai/gpu_raster_polygon.h
plugins/gpu_unai/gpu_raster_sprite.h
plugins/gpu_unai/gpu_unai.h [new file with mode: 0644]
plugins/gpu_unai/gpulib_if.cpp
plugins/gpu_unai/port.h
plugins/gpu_unai/profiler.h
plugins/gpulib/gpu.c
plugins/gpulib/gpu.h
plugins/gpulib/gpulib_thread_if.c [new file with mode: 0644]
plugins/gpulib/gpulib_thread_if.h [new file with mode: 0644]
plugins/gpulib/vout_pl.c
plugins/spunull/register.h

diff --git a/.github/ISSUE_TEMPLATE/custom-issue-report.md b/.github/ISSUE_TEMPLATE/custom-issue-report.md
new file mode 100644 (file)
index 0000000..d31f02b
--- /dev/null
@@ -0,0 +1,34 @@
+---
+name: custom-issue-report
+about: A brief template for bug/issue reports
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+#This tracker is for pcsx-rearmed-libretro issues *only*.
+
+If the issue also occurs in standalone PCSX-ReARMed, the upstream repo is probably a better place for it.
+
+## Description
+
+Please describe the issue. If this is a feature request, please add [feature request] to the title of the issue report.
+
+## Steps to reproduce
+
+How can we reproduce this issue? Please include all relevant steps, as well as any settings that you have changed from their default values, particularly including whether you are using the dynarec or interpreter CPU emulation.
+
+## When did the behavior start?
+
+If you can bisect the issue (that is, pinpoint the exact commit that caused the problem), please do. Someone has to do it, and having this already done greatly increases the likelihood that a developer will investigate and/or fix the problem. Barring that, please state the last time it worked properly (if ever).
+
+## Your device/OS/platform/architecture
+
+Such as Android, iOS, Windows 10, Linux, x86_64, a smart toaster, etc.
+
+## Logs (enable file logging and set log levels to DEBUG for core and frontend)
+
+## Screenshots (if needed for visual confirmation)
+
+## Others (save states and/or save files nearest to the affected area, compressed)
index 2500270..0106896 100644 (file)
@@ -11,3 +11,8 @@ frontend/revision.h
 tools
 .pcsx/
 obj/
+.vscode
+
+# Switch
+*.d
+.vscode/ipch/*
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644 (file)
index 0000000..bf05cac
--- /dev/null
@@ -0,0 +1,184 @@
+# DESCRIPTION: GitLab CI/CD for libRetro (NOT FOR GitLab-proper)
+
+##############################################################################
+################################# BOILERPLATE ################################
+##############################################################################
+
+# Core definitions
+.core-defs:
+  variables:
+    JNI_PATH: .
+    MAKEFILE: Makefile.libretro
+    CORENAME: pcsx_rearmed
+
+# Inclusion templates, required for the build to work
+include:
+  ################################## DESKTOPS ################################
+  # Windows 64-bit
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/windows-x64-mingw.yml'
+
+  # Windows 32-bit
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/windows-i686-mingw.yml'
+
+  # Linux 64-bit
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/linux-x64.yml'
+
+  # Linux 32-bit
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/linux-i686.yml'
+
+  # MacOS 64-bit
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/osx-x64.yml'
+
+  # MacOS ARM 64-bit
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/osx-arm64.yml'
+
+  ################################## CELLULAR ################################
+  # Android
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/android-jni.yml'
+
+  # iOS
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/ios-arm64.yml'
+
+  # iOS (armv7)
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/ios9.yml'
+    
+  ################################## CONSOLES ################################
+  # PlayStation Portable
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/psp-static.yml'
+  
+  # PlayStation Vita
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/vita-static.yml'
+    
+  # Nintendo 3DS
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/ctr-static.yml'
+    
+  # Nintendo Switch
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/libnx-static.yml'
+
+  # tvOS (AppleTV)
+  - project: 'libretro-infrastructure/ci-templates'
+    file: '/tvos-arm64.yml'
+    
+  #################################### MISC ##################################
+
+# Stages for building
+stages:
+  - build-prepare
+  - build-shared
+  - build-static
+
+##############################################################################
+#################################### STAGES ##################################
+##############################################################################
+#
+################################### DESKTOPS #################################
+# Windows 64-bit
+libretro-build-windows-x64:
+  extends:
+    - .libretro-windows-x64-mingw-make-default
+    - .core-defs
+
+# Windows 32-bit
+libretro-build-windows-i686:
+  extends:
+    - .libretro-windows-i686-mingw-make-default
+    - .core-defs
+
+# Linux 64-bit
+libretro-build-linux-x64:
+  extends:
+    - .libretro-linux-x64-make-default
+    - .core-defs
+    
+# Linux 32-bit
+libretro-build-linux-i686:
+  extends:
+    - .libretro-linux-i686-make-default
+    - .core-defs
+
+# MacOS 64-bit
+libretro-build-osx-x64:
+  extends:
+    - .libretro-osx-x64-make-default
+    - .core-defs
+
+# MacOS ARM 64-bit
+libretro-build-osx-arm64:
+  extends:
+    - .libretro-osx-arm64-make-default
+    - .core-defs
+
+################################### CELLULAR #################################
+# Android ARMv7a
+android-armeabi-v7a:
+  extends:
+    - .core-defs
+    - .libretro-android-jni-armeabi-v7a
+
+# Android ARMv8a
+android-arm64-v8a:
+  extends:
+    - .libretro-android-jni-arm64-v8a
+    - .core-defs
+
+# Android 64-bit x86
+android-x86_64:
+  extends:
+    - .libretro-android-jni-x86_64
+    - .core-defs
+
+# Android 32-bit x86
+android-x86:
+  extends:
+    - .libretro-android-jni-x86
+    - .core-defs
+
+# iOS
+libretro-build-ios-arm64:
+  extends:
+    - .libretro-ios-arm64-make-default
+    - .core-defs
+
+# iOS (armv7) [iOS 9 and up]
+libretro-build-ios9:
+  extends:
+    - .libretro-ios9-make-default
+    - .core-defs
+    
+# tvOS
+libretro-build-tvos-arm64:
+  extends:
+    - .libretro-tvos-arm64-make-default
+    - .core-defs
+    
+################################### CONSOLES #################################
+# PlayStation Vita
+libretro-build-vita:
+  extends:
+    - .libretro-vita-static-retroarch-master
+    - .core-defs
+    
+# Nintendo 3DS
+libretro-build-ctr:
+  extends:
+    - .libretro-ctr-static-retroarch-master
+    - .core-defs
+    
+# Nintendo Switch
+libretro-build-libnx-aarch64:
+  extends:
+    - .libretro-libnx-static-retroarch-master
+    - .core-defs
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644 (file)
index f93599e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[submodule "libpicofe"]
-       path = frontend/libpicofe
-       url = git://notaz.gp2x.de/~notaz/libpicofe.git
-[submodule "warm"]
-       path = frontend/warm
-       url = git://notaz.gp2x.de/~notaz/warm.git
index 7c4eafb..182b90d 100644 (file)
@@ -1,8 +1,33 @@
-language: cpp
-compiler:
-  - gcc
-  - clang
-before_install:
-  - sudo apt-get update -qq
-  - sudo apt-get install -y libsdl1.2-dev libasound2-dev libpng-dev libz-dev
-script: ./configure && make
+language: generic
+os: linux
+dist: trusty
+sudo: required
+addons:
+  apt:
+    packages:
+      - g++-7
+    sources:
+      - ubuntu-toolchain-r-test
+env:
+  global:
+    - CORE=pcsx_rearmed
+    - COMPILER_NAME=gcc CXX=g++-7 CC=gcc-7
+  matrix:
+    - PLATFORM=3ds
+    - PLATFORM=linux_x64
+before_script:
+  - pwd
+  - mkdir -p ~/bin
+  - ln -s /usr/bin/gcc-7 ~/bin/gcc
+  - ln -s /usr/bin/g++-7 ~/bin/g++
+  - ln -s /usr/bin/cpp-7 ~/bin/cpp
+  - export PATH=~/bin:$PATH
+  - ls -l ~/bin
+  - echo $PATH
+  - g++-7 --version
+  - g++ --version
+script:
+  - cd ~/
+  - git clone --depth=50 https://github.com/libretro/libretro-super
+  - cd libretro-super/travis
+  - ./build.sh
index 0a3b1fe..80d129e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,14 +2,23 @@
 
 # default stuff goes here, so that config can override
 TARGET ?= pcsx
-CFLAGS += -Wall -ggdb -Iinclude -ffast-math
-ifndef DEBUG
+CFLAGS += -Wall -Iinclude -ffast-math
+ifeq ($(DEBUG), 1)
+CFLAGS += -O0 -ggdb
+else
+ifeq ($(platform), $(filter $(platform), vita ctr))
+CFLAGS += -O3 -DNDEBUG
+else
 CFLAGS += -O2 -DNDEBUG
 endif
+endif
 CXXFLAGS += $(CFLAGS)
 #DRC_DBG = 1
 #PCNT = 1
 
+# Suppress minor warnings for dependencies
+deps/%: CFLAGS += -Wno-unused -Wno-unused-function
+
 all: config.mak target_ plugins_
 
 ifndef NO_CONFIG_MAK
@@ -39,13 +48,36 @@ CFLAGS += -DPCNT
 endif
 
 # core
-OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cheat.o libpcsxcore/debug.o \
-       libpcsxcore/decode_xa.o libpcsxcore/disr3000a.o libpcsxcore/mdec.o \
+OBJS += libpcsxcore/cdriso.o libpcsxcore/cdrom.o libpcsxcore/cheat.o \
+       libpcsxcore/decode_xa.o libpcsxcore/mdec.o \
        libpcsxcore/misc.o libpcsxcore/plugins.o libpcsxcore/ppf.o libpcsxcore/psxbios.o \
        libpcsxcore/psxcommon.o libpcsxcore/psxcounters.o libpcsxcore/psxdma.o libpcsxcore/psxhle.o \
        libpcsxcore/psxhw.o libpcsxcore/psxinterpreter.o libpcsxcore/psxmem.o libpcsxcore/r3000a.o \
-       libpcsxcore/sio.o libpcsxcore/socket.o libpcsxcore/spu.o
+       libpcsxcore/sio.o libpcsxcore/spu.o
 OBJS += libpcsxcore/gte.o libpcsxcore/gte_nf.o libpcsxcore/gte_divider.o
+
+ifeq ($(DEBUG), 1)
+OBJS += libpcsxcore/debug.o    libpcsxcore/socket.o libpcsxcore/disr3000a.o
+endif
+
+ifeq ($(WANT_ZLIB),1)
+CFLAGS += -Ideps/libchdr/deps/zlib-1.2.11
+OBJS += deps/libchdr/deps/zlib-1.2.11/adler32.o \
+        deps/libchdr/deps/zlib-1.2.11/compress.o \
+        deps/libchdr/deps/zlib-1.2.11/crc32.o \
+        deps/libchdr/deps/zlib-1.2.11/deflate.o \
+        deps/libchdr/deps/zlib-1.2.11/gzclose.o \
+        deps/libchdr/deps/zlib-1.2.11/gzlib.o \
+        deps/libchdr/deps/zlib-1.2.11/gzread.o \
+        deps/libchdr/deps/zlib-1.2.11/gzwrite.o \
+        deps/libchdr/deps/zlib-1.2.11/infback.o \
+        deps/libchdr/deps/zlib-1.2.11/inffast.o \
+        deps/libchdr/deps/zlib-1.2.11/inflate.o \
+        deps/libchdr/deps/zlib-1.2.11/inftrees.o \
+        deps/libchdr/deps/zlib-1.2.11/trees.o \
+        deps/libchdr/deps/zlib-1.2.11/uncompr.o \
+        deps/libchdr/deps/zlib-1.2.11/zutil.o
+endif
 ifeq "$(ARCH)" "arm"
 OBJS += libpcsxcore/gte_arm.o
 endif
@@ -55,22 +87,52 @@ endif
 libpcsxcore/psxbios.o: CFLAGS += -Wno-nonnull
 
 # dynarec
-ifeq "$(USE_DYNAREC)" "1"
-OBJS += libpcsxcore/new_dynarec/new_dynarec.o libpcsxcore/new_dynarec/linkage_arm.o
-OBJS += libpcsxcore/new_dynarec/pcsxmem.o
+ifeq "$(DYNAREC)" "lightrec"
+CFLAGS += -Ideps/lightning/include -Ideps/lightrec \
+                 -DLIGHTREC -DLIGHTREC_STATIC
+OBJS += libpcsxcore/lightrec/plugin.o
+OBJS += deps/lightning/lib/jit_disasm.o \
+               deps/lightning/lib/jit_memory.o \
+               deps/lightning/lib/jit_names.o \
+               deps/lightning/lib/jit_note.o \
+               deps/lightning/lib/jit_print.o \
+               deps/lightning/lib/jit_size.o \
+               deps/lightning/lib/lightning.o \
+               deps/lightrec/blockcache.o \
+               deps/lightrec/disassembler.o \
+               deps/lightrec/emitter.o \
+               deps/lightrec/interpreter.o \
+               deps/lightrec/lightrec.o \
+               deps/lightrec/memmanager.o \
+               deps/lightrec/optimizer.o \
+               deps/lightrec/regcache.o \
+               deps/lightrec/recompiler.o \
+               deps/lightrec/reaper.o
+ifeq ($(MMAP_WIN32),1)
+CFLAGS += -Ideps/mman
+OBJS += deps/mman/mman.o
+endif
+else ifeq "$(DYNAREC)" "ari64"
+CFLAGS += -DNEW_DYNAREC
+OBJS += libpcsxcore/new_dynarec/backends/psx/emu_if.o \
+               libpcsxcore/new_dynarec/new_dynarec.o \
+               libpcsxcore/new_dynarec/arm/linkage_arm.o \
+               libpcsxcore/new_dynarec/backends/psx/pcsxmem.o
+libpcsxcore/new_dynarec/new_dynarec.o: libpcsxcore/new_dynarec/arm/assem_arm.c \
+       libpcsxcore/new_dynarec/backends/psx/pcsxmem_inline.c
 else
-libpcsxcore/new_dynarec/emu_if.o: CFLAGS += -DDRC_DISABLE
+OBJS += libpcsxcore/new_dynarec/backends/psx/emu_if.o
+libpcsxcore/new_dynarec/backends/psx/emu_if.o: CFLAGS += -DDRC_DISABLE
 frontend/libretro.o: CFLAGS += -DDRC_DISABLE
 endif
-OBJS += libpcsxcore/new_dynarec/emu_if.o
-libpcsxcore/new_dynarec/new_dynarec.o: libpcsxcore/new_dynarec/assem_arm.c \
-       libpcsxcore/new_dynarec/pcsxmem_inline.c
 ifdef DRC_DBG
-libpcsxcore/new_dynarec/emu_if.o: CFLAGS += -D_FILE_OFFSET_BITS=64
+libpcsxcore/new_dynarec/backends/psx/emu_if.o: CFLAGS += -D_FILE_OFFSET_BITS=64
 CFLAGS += -DDRC_DBG
 endif
 ifeq "$(DRC_CACHE_BASE)" "1"
 libpcsxcore/new_dynarec/%.o: CFLAGS += -DBASE_ADDR_FIXED=1
+libpcsxcore/new_dynarec/backends/psx/%.o: CFLAGS += -DBASE_ADDR_FIXED=1
+libpcsxcore/new_dynarec/arm/%.o: CFLAGS += -DBASE_ADDR_FIXED=1
 endif
 
 # spu
@@ -111,21 +173,40 @@ endif
 # builtin gpu
 OBJS += plugins/gpulib/gpu.o plugins/gpulib/vout_pl.o
 ifeq "$(BUILTIN_GPU)" "neon"
-OBJS += plugins/gpu_neon/psx_gpu_if.o plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.o
+CFLAGS += -DGPU_NEON
+OBJS += plugins/gpu_neon/psx_gpu_if.o
+ifeq "$(HAVE_NEON)" "1"
+OBJS += plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.o
 plugins/gpu_neon/psx_gpu_if.o: CFLAGS += -DNEON_BUILD -DTEXTURE_CACHE_4BPP -DTEXTURE_CACHE_8BPP
+else
+plugins/gpu_neon/psx_gpu_if.o: CFLAGS += -DTEXTURE_CACHE_4BPP -DTEXTURE_CACHE_8BPP
+endif
 plugins/gpu_neon/psx_gpu_if.o: plugins/gpu_neon/psx_gpu/*.c
 endif
 ifeq "$(BUILTIN_GPU)" "peops"
+CFLAGS += -DGPU_PEOPS
 # note: code is not safe for strict-aliasing? (Castlevania problems)
 plugins/dfxvideo/gpulib_if.o: CFLAGS += -fno-strict-aliasing
 plugins/dfxvideo/gpulib_if.o: plugins/dfxvideo/prim.c plugins/dfxvideo/soft.c
 OBJS += plugins/dfxvideo/gpulib_if.o
+ifeq "$(THREAD_RENDERING)" "1"
+CFLAGS += -DTHREAD_RENDERING
+OBJS += plugins/gpulib/gpulib_thread_if.o
+endif
 endif
 ifeq "$(BUILTIN_GPU)" "unai"
+CFLAGS += -DGPU_UNAI
+CFLAGS += -DUSE_GPULIB=1
+#CFLAGS += -DINLINE="static __inline__"
+#CFLAGS += -Dasm="__asm__ __volatile__"
 OBJS += plugins/gpu_unai/gpulib_if.o
 ifeq "$(ARCH)" "arm"
 OBJS += plugins/gpu_unai/gpu_arm.o
 endif
+ifeq "$(THREAD_RENDERING)" "1"
+CFLAGS += -DTHREAD_RENDERING
+OBJS += plugins/gpulib/gpulib_thread_if.o
+endif
 plugins/gpu_unai/gpulib_if.o: CFLAGS += -DREARMED -O3 
 CC_LINK = $(CXX)
 endif
@@ -133,8 +214,34 @@ endif
 # cdrcimg
 OBJS += plugins/cdrcimg/cdrcimg.o
 
+# libchdr
+ifeq "$(HAVE_CHD)" "1"
+CFLAGS += -Ideps/libchdr/include
+CFLAGS += -Ideps/libchdr/include/libchdr
+OBJS += deps/libchdr/deps/lzma-19.00/src/Alloc.o
+OBJS += deps/libchdr/deps/lzma-19.00/src/Bra86.o
+OBJS += deps/libchdr/deps/lzma-19.00/src/BraIA64.o
+OBJS += deps/libchdr/deps/lzma-19.00/src/CpuArch.o
+OBJS += deps/libchdr/deps/lzma-19.00/src/Delta.o
+OBJS += deps/libchdr/deps/lzma-19.00/src/LzFind.o
+OBJS += deps/libchdr/deps/lzma-19.00/src/Lzma86Dec.o
+OBJS += deps/libchdr/deps/lzma-19.00/src/LzmaDec.o
+OBJS += deps/libchdr/deps/lzma-19.00/src/LzmaEnc.o
+OBJS += deps/libchdr/deps/lzma-19.00/src/Sort.o
+OBJS += deps/libchdr/src/libchdr_bitstream.o
+OBJS += deps/libchdr/src/libchdr_cdrom.o
+OBJS += deps/libchdr/src/libchdr_chd.o
+OBJS += deps/libchdr/src/libchdr_flac.o
+OBJS += deps/libchdr/src/libchdr_huffman.o
+CFLAGS += -Ideps/libchdr/deps/lzma-19.00/include
+CFLAGS += -DHAVE_CHD -D_7ZIP_ST
+LDFLAGS += -lm
+endif
+
 # dfinput
+ifneq "$(PLATFORM)" "libretro"
 OBJS += plugins/dfinput/main.o plugins/dfinput/pad.o plugins/dfinput/guncon.o
+endif
 
 # frontend/gui
 OBJS += frontend/cspace.o
@@ -192,13 +299,30 @@ CFLAGS += `pkg-config --cflags glib-2.0 libosso dbus-1 hildon-fm-2`
 LDFLAGS += `pkg-config --libs glib-2.0 libosso dbus-1 hildon-fm-2`
 endif
 ifeq "$(PLATFORM)" "libretro"
+ifeq "$(USE_LIBRETRO_VFS)" "1"
+OBJS += libretro-common/compat/compat_posix_string.o
+OBJS += libretro-common/compat/fopen_utf8.o
+OBJS += libretro-common/encodings/compat_strl.o
+OBJS += libretro-common/encodings/encoding_utf.o
+OBJS += libretro-common/file/file_path.o
+OBJS += libretro-common/streams/file_stream.o
+OBJS += libretro-common/streams/file_stream_transforms.o
+OBJS += libretro-common/string/stdstring.o
+OBJS += libretro-common/time/rtime.o
+OBJS += libretro-common/vfs/vfs_implementation.o
+CFLAGS += -DUSE_LIBRETRO_VFS
+endif
 OBJS += frontend/libretro.o
+CFLAGS += -Ilibretro-common/include
 CFLAGS += -DFRONTEND_SUPPORTS_RGB565
+CFLAGS += -DHAVE_LIBRETRO
 
+ifneq ($(DYNAREC),lightrec)
 ifeq ($(MMAP_WIN32),1)
 OBJS += libpcsxcore/memmap_win32.o
 endif
 endif
+endif
 
 ifeq "$(USE_PLUGIN_LIB)" "1"
 OBJS += frontend/plugin_lib.o
@@ -246,11 +370,20 @@ frontend/revision.h: FORCE
 %.o: %.S
        $(CC_AS) $(CFLAGS) -c $^ -o $@
 
+%.o: %.cpp
+       $(CXX) $(CXXFLAGS) -c -o $@ $<
+
+%.o: %.c
+       $(CC) $(CFLAGS) -c -o $@ $<
 
 target_: $(TARGET)
 
 $(TARGET): $(OBJS)
+ifeq ($(STATIC_LINKING), 1)
+       $(AR) rcs $@ $(OBJS)
+else
        $(CC_LINK) -o $@ $^ $(LDFLAGS) $(LDLIBS) $(EXTRA_LDFLAGS)
+endif
 
 clean: $(PLAT_CLEAN) clean_plugins
        $(RM) $(TARGET) $(OBJS) $(TARGET).map frontend/revision.h
index 223ba9f..1ecd359 100644 (file)
@@ -1,5 +1,13 @@
 # Makefile for PCSX ReARMed (libretro)
 
+DEBUG ?= 0
+WANT_ZLIB ?= 1
+HAVE_CHD ?= 1
+USE_LIBRETRO_VFS ?= 0
+
+# Dynarec options: lightrec, ari64
+DYNAREC ?= lightrec
+
 ifeq ($(platform),)
        platform = unix
        ifeq ($(shell uname -a),)
@@ -20,68 +28,180 @@ CC_AS ?= $(CC)
 CFLAGS ?=
 
 TARGET_NAME := pcsx_rearmed
-
-MMAP_WIN32=0
+GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)"
+ifneq ($(GIT_VERSION)," unknown")
+       CFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\"
+endif
+ifneq ($(WANT_ZLIB),1)
+LIBZ := -lz
+endif
+LIBPTHREAD := -lpthread
+ifneq ($(findstring Haiku,$(shell uname -s)),)
+LIBDL := -lroot -lnetwork
+else
+LIBDL := -ldl
+endif
+LIBM := -lm
+MMAP_WIN32 = 0
+EXTRA_LDFLAGS =
 
 # Unix
 ifeq ($(platform), unix)
        TARGET := $(TARGET_NAME)_libretro.so
        fpic := -fPIC
-       SHARED := -shared -Wl,--version-script=libretro/link.T
+       THREAD_RENDERING = 1
+ifneq ($(findstring SunOS,$(shell uname -s)),)
+       CC = gcc
+endif
+ifeq ($(ARCH), arm)
+ifneq ($(findstring __thumb__,$(shell $(CC) -E -dD $(CFLAGS) include/arm_features.h)),)
+       # must disable thumb as recompiler can't handle it
+       CFLAGS += -marm
+endif
+endif
+
+# ODROIDN2
+else ifneq (,$(findstring CortexA73_G12B,$(platform)))
+       TARGET := $(TARGET_NAME)_libretro.so
+       fpic := -fPIC
+       SHARED := -shared -Wl,-version-script=link.T
+       ARCH = arm64
+       CFLAGS += -fomit-frame-pointer -ffast-math -DARM
+       CPUFLAGS += -march=armv8-a+crc -mfpu=neon-fp-armv8 -mcpu=cortex-a73 -mtune=cortex-a73.cortex-a53
+
+# ALLWINNER H5
+else ifneq (,$(findstring h5,$(platform)))
+       TARGET := $(TARGET_NAME)_libretro.so
+       fpic := -fPIC
+       SHARED := -shared -Wl,-version-script=link.T
+       ARCH = arm64
+       DYNAREC ?= lightrec
+       CFLAGS += -fomit-frame-pointer -ffast-math -DARM
+       CPUFLAGS += -march=armv8-a+crc -mfpu=neon-fp-armv8 -mcpu=cortex-a53 -mtune=cortex-a53
+
+else ifeq ($(platform), linux-portable)
+       TARGET := $(TARGET_NAME)_libretro.so
+       fpic := -fPIC -nostdlib
+       EXTRA_LDFLAGS += -fPIC -nostdlib
+       LIBZ :=
+       LIBPTHREAD :=
+       LIBDL :=
+       LIBM :=
+       NO_UNDEF_CHECK = 1
 
 # OS X
 else ifeq ($(platform), osx)
+       DYNAREC := 0
        TARGET := $(TARGET_NAME)_libretro.dylib
        fpic := -fPIC
-       SHARED := -dynamiclib
-       OSXVER = `sw_vers -productVersion | cut -d. -f 2`
-       OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"`
-       ifeq ($(OSX_LT_MAVERICKS),"YES")
-               fpic += -mmacosx-version-min=10.5
-       endif
+       HAVE_NEON = 0
+   MACSOSVER = `sw_vers -productVersion | cut -d. -f 1`
+   OSXVER = `sw_vers -productVersion | cut -d. -f 2`
+   OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"`
+   ifeq ($(OSX_LT_MAVERICKS),YES)
+          fpic += -mmacosx-version-min=10.1
+   endif
+
+   ifeq ($(CROSS_COMPILE),1)
+               TARGET_RULE   = -target $(LIBRETRO_APPLE_PLATFORM) -isysroot $(LIBRETRO_APPLE_ISYSROOT)
+               CFLAGS   += $(TARGET_RULE)
+               CPPFLAGS += $(TARGET_RULE)
+               CXXFLAGS += $(TARGET_RULE)
+               LDFLAGS  += $(TARGET_RULE)
+   endif
+
+       CFLAGS  += $(ARCHFLAGS)
+       CXXFLAGS  += $(ARCHFLAGS)
+       LDFLAGS += $(ARCHFLAGS)
 
 # iOS
-else ifeq ($(platform), ios)
-       ARCH := arm
+else ifneq (,$(findstring ios,$(platform)))
        TARGET := $(TARGET_NAME)_libretro_ios.dylib
+       MINVERSION :=
+ifeq ($(DYNAREC),lightrec)
+       # Override
+       DYNAREC := 0
+endif
        fpic := -fPIC
-       SHARED := -dynamiclib
 
        ifeq ($(IOSSDK),)
-               IOSSDK := $(shell xcrun -sdk iphoneos -show-sdk-path)
+               IOSSDK := $(shell xcodebuild -version -sdk iphoneos Path)
        endif
 
-       CC = clang -arch armv7 -isysroot $(IOSSDK)
-       CXX = clang++ -arch armv7 -isysroot $(IOSSDK)
-       CC_AS = perl ./tools/gas-preprocessor.pl $(CC)
-       CFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -marm
-       ASFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon
+       CFLAGS += -DIOS -marm
+ifeq ($(platform),ios-arm64)
+        CC = cc -arch arm64 -isysroot $(IOSSDK)
+       CXX = c++ -arch arm64 -isysroot $(IOSSDK)
+       ARCH := arm64
+       HAVE_NEON = 0
+       BUILTIN_GPU = peops
+       DYNAREC = 0
+else
+       CC = cc -arch armv7 -isysroot $(IOSSDK)
+       CXX = c++ -arch armv7 -isysroot $(IOSSDK)
+       ARCH := arm
        HAVE_NEON = 1
        BUILTIN_GPU = neon
-       USE_DYNAREC = 1
-       CFLAGS += -DIOS
-       OSXVER = `sw_vers -productVersion | cut -d. -f 2`
-       OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"`
-       ifeq ($(OSX_LT_MAVERICKS),"YES")
-               CC +=  -miphoneos-version-min=5.0
-               CXX +=  -miphoneos-version-min=5.0
-               CC_AS +=  -miphoneos-version-min=5.0
-               CFLAGS += -miphoneos-version-min=5.0
+       CFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon
+       ASFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon
+endif
+       CC_AS = perl ./tools/gas-preprocessor.pl $(CC)
+ifeq ($(platform),$(filter $(platform),ios9 ios-arm64))
+       MINVERSION = -miphoneos-version-min=8.0
+else
+       MINVERSION = -miphoneos-version-min=5.0
+endif
+       CFLAGS += $(MINVERSION)
+
+else ifeq ($(platform), tvos-arm64)
+       TARGET := $(TARGET_NAME)_libretro_tvos.dylib
+       MINVERSION :=
+ifeq ($(DYNAREC),lightrec)
+       # Override
+       DYNAREC := 0
+endif
+       fpic := -fPIC
+
+       ifeq ($(IOSSDK),)
+               IOSSDK := $(shell xcodebuild -version -sdk appletvos Path)
        endif
 
-# PS3
-else ifeq ($(platform), ps3)
-       TARGET := $(TARGET_NAME)_libretro_ps3.a
-       CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe
-       AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe
-       CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__
+       CFLAGS += -DIOS -DTVOS -marm
+        CC = cc -arch arm64 -isysroot $(IOSSDK)
+       CXX = c++ -arch arm64 -isysroot $(IOSSDK)
+       ARCH := arm64
+       HAVE_NEON = 0
+       BUILTIN_GPU = peops
+       DYNAREC = 0
+       CC_AS = perl ./tools/gas-preprocessor.pl $(CC)
 
-# sncps3
-else ifeq ($(platform), sncps3)
-       TARGET := $(TARGET_NAME)_libretro_ps3.a
-       CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
-       AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe
-       CFLAGS += -DBLARGG_BIG_ENDIAN=1 -D__ppc__
+# Nintendo Switch (libnx)
+else ifeq ($(platform), libnx)
+   export DEPSDIR := $(CURDIR)/
+   include $(DEVKITPRO)/libnx/switch_rules
+   TARGET := $(TARGET_NAME)_libretro_$(platform).a
+   ARCH := arm64
+   BUILTIN_GPU = unai
+   HAVE_VFS_FD = 0
+   CFLAGS += -O3 -fomit-frame-pointer -ffast-math -I$(DEVKITPRO)/libnx/include/ -fPIE -Wl,--allow-multiple-definition -include $(LIBNX)/include/switch.h
+   CFLAGS += -specs=$(DEVKITPRO)/libnx/switch.specs -DNO_OS -DNO_DYLIB -DNO_SOCKET -D__arm64__ -D__ARM_NEON__
+   CFLAGS += -D__SWITCH__
+   CFLAGS += -DARM -D__aarch64__=1 -march=armv8-a -mtune=cortex-a57 -mtp=soft -DHAVE_INTTYPES -DLSB_FIRST -ffast-math -mcpu=cortex-a57+crc+fp+simd -ffunction-sections
+   CFLAGS += -ftree-vectorize
+   CFLAGS += -Ifrontend/switch -ftree-vectorize
+   LIBPTHREAD :=
+   STATIC_LINKING=1
+   # Lightning requires rw/rx patches first
+   DYNAREC := 0
+
+# Lakka Switch (arm64)
+else ifeq ($(platform), arm64)
+   TARGET := $(TARGET_NAME)_libretro.so
+   ARCH := arm64
+   BUILTIN_GPU = unai
+   fpic := -fPIC
+   CFLAGS := $(filter-out -O2, $(CFLAGS))
+   CFLAGS += -O3 -ftree-vectorize
 
 # Lightweight PS3 Homebrew SDK
 else ifeq ($(platform), psl1ght)
@@ -97,6 +217,55 @@ else ifeq ($(platform), psp1)
        AR = psp-ar$(EXE_EXT)
        CFLAGS += -DPSP -G0
 
+# Vita
+else ifeq ($(platform), vita)
+       TARGET := $(TARGET_NAME)_libretro_vita.a
+       CC = arm-vita-eabi-gcc$(EXE_EXT)
+       AR = arm-vita-eabi-ar$(EXE_EXT)
+       CFLAGS += -DVITA
+       CFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon -marm
+       CFLAGS += -fsingle-precision-constant -mword-relocations -fno-unwind-tables
+       CFLAGS += -fno-asynchronous-unwind-tables -ftree-vectorize -funroll-loops
+       CFLAGS += -fno-optimize-sibling-calls
+       CFLAGS += -I$(VITASDK)/include -Ifrontend/vita
+       CFLAGS += -DNO_SOCKET -DNO_OS -DNO_DYLIB
+       ASFLAGS += -mcpu=cortex-a8 -mtune=cortex-a8 -mfpu=neon
+
+#      CFLAGS += -U__ARM_NEON__
+       HAVE_NEON = 1
+       BUILTIN_GPU = neon
+
+       DYNAREC = ari64
+       DRC_CACHE_BASE = 0
+
+       ARCH = arm
+       STATIC_LINKING = 1
+
+# CTR(3DS)
+else ifeq ($(platform), ctr)
+       TARGET := $(TARGET_NAME)_libretro_ctr.a
+       CC = $(DEVKITARM)/bin/arm-none-eabi-gcc$(EXE_EXT)
+       CXX = $(DEVKITARM)/bin/arm-none-eabi-g++$(EXE_EXT)
+       AR = $(DEVKITARM)/bin/arm-none-eabi-ar$(EXE_EXT)
+       CFLAGS += -DARM11 -D_3DS -DNO_OS -DNO_DYLIB -DNO_SOCKET -DTHREAD_ENABLED -DGPU_UNAI_USE_FLOATMATH -DGPU_UNAI_USE_FLOAT_DIV_MULTINV
+       CFLAGS += -march=armv6k -mtune=mpcore -mfloat-abi=hard -marm -mfpu=vfp -mtp=soft
+       CFLAGS += -Wall -mword-relocations
+       CFLAGS += -fomit-frame-pointer -ffast-math -funroll-loops
+       CFLAGS += -Ifrontend/3ds -I$(CTRULIB)/include
+       CFLAGS += -Werror=implicit-function-declaration
+       CFLAGS += -DHAVE_UNISTD_H
+
+       OBJS += frontend/3ds/utils.o
+
+#      CFLAGS += -DPCSX
+       BUILTIN_GPU = unai
+       THREAD_RENDERING = 1
+       DYNAREC = ari64
+       DRC_CACHE_BASE = 0
+       ARCH = arm
+       HAVE_NEON = 0
+       STATIC_LINKING = 1
+
 # Xbox 360
 else ifeq ($(platform), xenon)
        TARGET := $(TARGET_NAME)_libretro_xenon360.a
@@ -121,24 +290,127 @@ else ifeq ($(platform), wii)
 # QNX
 else ifeq ($(platform), qnx)
        TARGET := $(TARGET_NAME)_libretro_qnx.so
+       fpic := -fPIC
        CC = qcc -Vgcc_ntoarmv7le
        CC_AS = $(CC)
        HAVE_NEON = 1
-       USE_DYNAREC = 1
+       DYNAREC = ari64
        DRC_CACHE_BASE = 0
        BUILTIN_GPU = neon
        ARCH = arm
        CFLAGS += -D__BLACKBERRY_QNX__ -marm -mcpu=cortex-a9 -mtune=cortex-a9 -mfpu=neon -mfloat-abi=softfp
-       ASFLAGS +=  -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
+       ASFLAGS += -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
+       MAIN_LDLIBS += -lsocket
+       LIBPTHREAD :=
+       LIBDL :=
+       LIBM :=
+
+#Raspberry Pi 2
+else ifeq ($(platform), rpi2)
+       TARGET := $(TARGET_NAME)_libretro.so
+       fpic := -fPIC
+       CFLAGS += -marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard
+       ASFLAGS += -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard
+       HAVE_NEON = 1
+       ARCH = arm
+       BUILTIN_GPU = neon
+       DYNAREC = ari64
+
+#Raspberry Pi 3
+else ifeq ($(platform), rpi3)
+       TARGET := $(TARGET_NAME)_libretro.so
+       fpic := -fPIC
+       CFLAGS += -marm -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard
+       ASFLAGS += -mcpu=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard
+       HAVE_NEON = 1
+       ARCH = arm
+       BUILTIN_GPU = neon
+       DYNAREC = ari64
+
+#Raspberry Pi 4 with a 32bit GNU/Linux OS
+else ifeq ($(platform), rpi4)
+       TARGET := $(TARGET_NAME)_libretro.so
+       fpic := -fPIC
+       CFLAGS += -marm -mcpu=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard
+       ASFLAGS += -mcpu=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard
+       HAVE_NEON = 1
+       ARCH = arm
+       BUILTIN_GPU = neon
+       DYNAREC = ari64
+
+#Raspberry Pi 4 with a 64bit GNU/Linux OS
+else ifeq ($(platform), rpi4_64)
+        TARGET := $(TARGET_NAME)_libretro.so
+        ARCH := arm64
+        BUILTIN_GPU = unai
+        DYNAREC = lightrec
+        fpic := -fPIC
+        CFLAGS += -march=armv8-a+crc+simd -mtune=cortex-a72 -ftree-vectorize
+
+# Classic Platforms ####################
+# Platform affix = classic_<ISA>_<µARCH>
+# Help at https://modmyclassic.com/comp
+
+# (armv7 a7, hard point, neon based) ### 
+# NESC, SNESC, C64 mini 
+else ifeq ($(platform), classic_armv7_a7)
+       TARGET := $(TARGET_NAME)_libretro.so
+       fpic := -fPIC
+       CFLAGS += -Ofast \
+       -flto=4 -fwhole-program -fuse-linker-plugin \
+       -fdata-sections -ffunction-sections -Wl,--gc-sections \
+       -fno-stack-protector -fno-ident -fomit-frame-pointer \
+       -falign-functions=1 -falign-jumps=1 -falign-loops=1 \
+       -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-unroll-loops \
+       -fmerge-all-constants -fno-math-errno \
+       -marm -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard
+       CXXFLAGS += $(CFLAGS)
+       CPPFLAGS += $(CFLAGS)
+       ASFLAGS += $(CFLAGS)
+       HAVE_NEON = 1
+       ARCH = arm
+       BUILTIN_GPU = neon
+       DYNAREC = ari64
+       ifeq ($(shell echo `$(CC) -dumpversion` "< 4.9" | bc -l), 1)
+               CFLAGS += -march=armv7-a
+       else
+               CFLAGS += -march=armv7ve
+               # If gcc is 5.0 or later
+               ifeq ($(shell echo `$(CC) -dumpversion` ">= 5" | bc -l), 1)
+                       LDFLAGS += -static-libgcc -static-libstdc++
+               endif
+       endif
+
+# (armv8 a35, hard point, neon based) ###
+# PlayStation Classic
+else ifeq ($(platform), classic_armv8_a35)
+       TARGET := $(TARGET_NAME)_libretro.so
+       fpic := -fPIC
+       CFLAGS += -Ofast \
+       -fmerge-all-constants -fno-math-errno -march=armv8-a \
+       -marm -mcpu=cortex-a35 -mtune=cortex-a35 -mfpu=neon-fp-armv8 -mfloat-abi=hard
+       HAVE_NEON = 1
+       ARCH = arm
+       BUILTIN_GPU = neon
+       DYNAREC = ari64
+       LDFLAGS += -static-libgcc -static-libstdc++ -fPIC
+
+#######################################
 
 # ARM
 else ifneq (,$(findstring armv,$(platform)))
        TARGET := $(TARGET_NAME)_libretro.so
-       SHARED := -shared -Wl,--no-undefined
+       fpic := -fPIC
+       HAVE_NEON = 0
        DRC_CACHE_BASE = 0
+       BUILTIN_GPU = peops
        ifneq (,$(findstring cortexa8,$(platform)))
                CFLAGS += -marm -mcpu=cortex-a8
                ASFLAGS += -mcpu=cortex-a8
+       else ifneq (,$(findstring cortexa7,$(platform)))
+               CFLAGS += -marm -mcpu=cortex-a7
+               ASFLAGS += -mcpu=cortex-a7
+               LIBZ :=
        else ifneq (,$(findstring cortexa9,$(platform)))
                CFLAGS += -marm -mcpu=cortex-a9
                ASFLAGS += -mcpu=cortex-a9
@@ -158,29 +430,39 @@ else ifneq (,$(findstring armv,$(platform)))
                ASFLAGS += -mfloat-abi=hard
        endif
        ARCH = arm
-       USE_DYNAREC = 1
+       DYNAREC = ari64
+
+# Emscripten
+else ifeq ($(platform), emscripten)
+   TARGET  := $(TARGET_NAME)_libretro_$(platform).bc
+   fpic    := -fPIC
+   SHARED  := -shared -Wl,--no-undefined -Wl,--version-script=link.T
+   CFLAGS += -DNO_DYLIB -DNO_SOCKET
+   STATIC_LINKING = 1
 
 # Windows
 else
        TARGET := $(TARGET_NAME)_libretro.dll
-       CC = gcc
-       fpic := -fPIC
-       LD_FLAGS := -fPIC
-       SHARED := -shared -static-libgcc -static-libstdc++ -s -Wl,--version-script=libretro/link.T
-       CFLAGS += -D__WIN32__ -D__WIN32_LIBRETRO__
+       BUILTIN_GPU = peops
+       PLATFORM = libretro
+       MAIN_LDFLAGS += -static-libgcc -static-libstdc++ -s
+       CFLAGS += -D__WIN32__ -DNO_DYLIB
        MMAP_WIN32=1
-endif
-
-CFLAGS += -fPIC
-ifeq ($(platform),win)
        MAIN_LDLIBS += -lws2_32
-else ifneq ($(platform),qnx)
-       LDLIBS += -lpthread
-       MAIN_LDLIBS += -ldl
+       LIBPTHREAD :=
+       LIBDL :=
+       LIBM :=
+       USE_LIBRETRO_VFS = 1
 endif
+
+CFLAGS += $(fpic)
 MAIN_LDFLAGS += -shared
-MAIN_LDLIBS += -lm -lz
-EXTRA_LDFLAGS =
+MAIN_LDLIBS += $(LIBPTHREAD) $(LIBM) $(LIBDL) $(LIBZ)
+
+# enable large file support if available
+ifeq ($(shell $(CC) -E -dD $(CFLAGS) include/arm_features.h | grep __SIZEOF_LONG__ | awk '{print $$3}'),4)
+CFLAGS += -D_FILE_OFFSET_BITS=64
+endif
 
 # try to autodetect stuff for the lazy
 ifndef ARCH
@@ -189,7 +471,7 @@ endif
 ifndef HAVE_NEON
 HAVE_NEON = $(shell $(CC) -E -dD - < /dev/null 2> /dev/null | grep -q __ARM_NEON__ && echo 1 || echo 0)
 endif
-ifeq ($(shell ld -v 2> /dev/null | awk '{print $$1}'),GNU)
+ifeq ($(NO_UNDEF_CHECK)$(shell ld -v 2> /dev/null | awk '{print $$1}'),GNU)
 MAIN_LDFLAGS += -Wl,--no-undefined
 endif
 
@@ -200,6 +482,15 @@ SOUND_DRIVERS = libretro
 PLUGINS =
 NO_CONFIG_MAK = yes
 
+# what does this do
+#libretro_all: all
+#ifeq ($(platform),ios)
+#ifeq ($(DYNAREC),1)
+#      make -f Makefile.libretro DYNAREC=0 platform=$(platform) clean
+#      make -f Makefile.libretro DYNAREC=0 platform=$(platform)
+#endif
+#endif
+
 include Makefile
 
 # no special AS needed for gpu_neon
index 9964410..4297f3c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 PCSX-ReARMed - yet another PCSX fork
 ====================================
 
-[![Build Status](https://travis-ci.org/notaz/pcsx_rearmed.svg?branch=master)](https://travis-ci.org/notaz/pcsx_rearmed)
+[![Build Status](https://travis-ci.org/libretro/pcsx_rearmed.svg?branch=master)](https://travis-ci.org/libretro/pcsx_rearmed)
 
 *see [readme.txt](readme.txt) for more complete documentation*
 
diff --git a/blackberry_qnx/.cproject b/blackberry_qnx/.cproject
deleted file mode 100644 (file)
index 565f4a9..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<?fileVersion 4.0.0?>
-
-<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
-       <storageModule moduleId="org.eclipse.cdt.core.settings">
-               <cconfiguration id="com.qnx.qcc.toolChain.1762498539">
-                       <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.toolChain.1762498539" moduleId="org.eclipse.cdt.core.settings" name="Device-Debug">
-                               <externalSettings/>
-                               <extensions>
-                                       <extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
-                                       <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                               </extensions>
-                       </storageModule>
-                       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
-                               <configuration artifactName="${ProjName}" buildProperties="" description="" id="com.qnx.qcc.toolChain.1762498539" name="Device-Debug" parent="org.eclipse.cdt.build.core.emptycfg">
-                                       <folderInfo id="com.qnx.qcc.toolChain.1762498539.1561488424" name="/" resourcePath="">
-                                               <toolChain id="com.qnx.qcc.toolChain.682312592" name="com.qnx.qcc.toolChain" superClass="com.qnx.qcc.toolChain">
-                                                       <option id="com.qnx.qcc.option.os.1720929524" name="Target OS:" superClass="com.qnx.qcc.option.os"/>
-                                                       <option id="com.qnx.qcc.option.cpu.2107899725" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
-                                                       <option id="com.qnx.qcc.option.compiler.596535986" name="Compiler:" superClass="com.qnx.qcc.option.compiler"/>
-                                                       <option id="com.qnx.qcc.option.runtime.742171011" name="Runtime:" superClass="com.qnx.qcc.option.runtime"/>
-                                                       <targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.982231418" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
-                                                       <builder arguments="-C .. -f Makefile.libretro platform=qnx" command="make" id="com.qnx.qcc.toolChain.1762498539.480897078" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
-                                                       <tool id="com.qnx.qcc.tool.compiler.267897021" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
-                                                               <option id="com.qnx.qcc.option.compiler.optlevel.1293751119" name="Optimization Level" superClass="com.qnx.qcc.option.compiler.optlevel" value="com.qnx.qcc.option.compiler.optlevel.0" valueType="enumerated"/>
-                                                               <option id="com.qnx.qcc.option.compiler.includePath.365274483" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-                                                                       <listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
-                                                                       <listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
-                                                               </option>
-                                                               <inputType id="com.qnx.qcc.inputType.compiler.116424583" superClass="com.qnx.qcc.inputType.compiler"/>
-                                                       </tool>
-                                                       <tool id="com.qnx.qcc.tool.assembler.1307903249" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
-                                                               <inputType id="com.qnx.qcc.inputType.assembler.1838739065" superClass="com.qnx.qcc.inputType.assembler"/>
-                                                       </tool>
-                                                       <tool id="com.qnx.qcc.tool.linker.1852803277" name="QCC Linker" superClass="com.qnx.qcc.tool.linker"/>
-                                                       <tool id="com.qnx.qcc.tool.archiver.1682937256" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
-                                               </toolChain>
-                                       </folderInfo>
-                               </configuration>
-                       </storageModule>
-                       <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
-               </cconfiguration>
-               <cconfiguration id="com.qnx.qcc.toolChain.1815033502">
-                       <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.toolChain.1815033502" moduleId="org.eclipse.cdt.core.settings" name="Device-Release">
-                               <externalSettings/>
-                               <extensions>
-                                       <extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
-                                       <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                               </extensions>
-                       </storageModule>
-                       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
-                               <configuration artifactName="${ProjName}" buildProperties="" description="" id="com.qnx.qcc.toolChain.1815033502" name="Device-Release" parent="org.eclipse.cdt.build.core.emptycfg">
-                                       <folderInfo id="com.qnx.qcc.toolChain.1815033502.1093640979" name="/" resourcePath="">
-                                               <toolChain id="com.qnx.qcc.toolChain.1811843468" name="com.qnx.qcc.toolChain" superClass="com.qnx.qcc.toolChain">
-                                                       <option id="com.qnx.qcc.option.os.66936807" name="Target OS:" superClass="com.qnx.qcc.option.os"/>
-                                                       <option id="com.qnx.qcc.option.cpu.1884625209" name="Target CPU:" superClass="com.qnx.qcc.option.cpu" value="com.qnx.qcc.option.gen.cpu.armle-v7" valueType="enumerated"/>
-                                                       <option id="com.qnx.qcc.option.compiler.903071639" name="Compiler:" superClass="com.qnx.qcc.option.compiler"/>
-                                                       <option id="com.qnx.qcc.option.runtime.901433789" name="Runtime:" superClass="com.qnx.qcc.option.runtime"/>
-                                                       <targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.1169345860" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
-                                                       <builder id="com.qnx.qcc.toolChain.1815033502.1831895405" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
-                                                       <tool id="com.qnx.qcc.tool.compiler.401658009" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
-                                                               <option id="com.qnx.qcc.option.compiler.optlevel.20820451" name="Optimization Level" superClass="com.qnx.qcc.option.compiler.optlevel" value="com.qnx.qcc.option.compiler.optlevel.0" valueType="enumerated"/>
-                                                               <option id="com.qnx.qcc.option.compiler.includePath.2022402746" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-                                                                       <listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
-                                                                       <listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
-                                                               </option>
-                                                               <inputType id="com.qnx.qcc.inputType.compiler.1180700251" superClass="com.qnx.qcc.inputType.compiler"/>
-                                                       </tool>
-                                                       <tool id="com.qnx.qcc.tool.assembler.1403530230" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
-                                                               <inputType id="com.qnx.qcc.inputType.assembler.1360707586" superClass="com.qnx.qcc.inputType.assembler"/>
-                                                       </tool>
-                                                       <tool id="com.qnx.qcc.tool.linker.577346665" name="QCC Linker" superClass="com.qnx.qcc.tool.linker"/>
-                                                       <tool id="com.qnx.qcc.tool.archiver.637344581" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
-                                               </toolChain>
-                                       </folderInfo>
-                               </configuration>
-                       </storageModule>
-                       <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
-               </cconfiguration>
-               <cconfiguration id="com.qnx.qcc.toolChain.1271074456">
-                       <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="com.qnx.qcc.toolChain.1271074456" moduleId="org.eclipse.cdt.core.settings" name="Simulator-Debug">
-                               <externalSettings/>
-                               <extensions>
-                                       <extension id="com.qnx.tools.ide.qde.core.QDEBynaryParser" point="org.eclipse.cdt.core.BinaryParser"/>
-                                       <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
-                                       <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
-                               </extensions>
-                       </storageModule>
-                       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
-                               <configuration artifactName="${ProjName}" buildProperties="" description="" id="com.qnx.qcc.toolChain.1271074456" name="Simulator-Debug" parent="org.eclipse.cdt.build.core.emptycfg">
-                                       <folderInfo id="com.qnx.qcc.toolChain.1271074456.2095507025" name="/" resourcePath="">
-                                               <toolChain id="com.qnx.qcc.toolChain.563285451" name="com.qnx.qcc.toolChain" superClass="com.qnx.qcc.toolChain">
-                                                       <option id="com.qnx.qcc.option.os.2028959839" name="Target OS:" superClass="com.qnx.qcc.option.os"/>
-                                                       <option id="com.qnx.qcc.option.cpu.460119393" name="Target CPU:" superClass="com.qnx.qcc.option.cpu"/>
-                                                       <option id="com.qnx.qcc.option.compiler.318948553" name="Compiler:" superClass="com.qnx.qcc.option.compiler"/>
-                                                       <option id="com.qnx.qcc.option.runtime.1244314155" name="Runtime:" superClass="com.qnx.qcc.option.runtime"/>
-                                                       <targetPlatform archList="all" binaryParser="com.qnx.tools.ide.qde.core.QDEBynaryParser" id="com.qnx.qcc.targetPlatform.2005367550" osList="all" superClass="com.qnx.qcc.targetPlatform"/>
-                                                       <builder id="com.qnx.qcc.toolChain.1271074456.325666051" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
-                                                       <tool id="com.qnx.qcc.tool.compiler.821983732" name="QCC Compiler" superClass="com.qnx.qcc.tool.compiler">
-                                                               <option id="com.qnx.qcc.option.compiler.optlevel.1701209030" name="Optimization Level" superClass="com.qnx.qcc.option.compiler.optlevel" value="com.qnx.qcc.option.compiler.optlevel.0" valueType="enumerated"/>
-                                                               <option id="com.qnx.qcc.option.compiler.includePath.1616908655" name="Include Directories (-I)" superClass="com.qnx.qcc.option.compiler.includePath" valueType="includePath">
-                                                                       <listOptionValue builtIn="false" value="${QNX_TARGET}/usr/include/freetype2"/>
-                                                                       <listOptionValue builtIn="false" value="${QNX_TARGET}/../target-override/usr/include"/>
-                                                               </option>
-                                                               <inputType id="com.qnx.qcc.inputType.compiler.1059435667" superClass="com.qnx.qcc.inputType.compiler"/>
-                                                       </tool>
-                                                       <tool id="com.qnx.qcc.tool.assembler.1920350417" name="QCC Assembler" superClass="com.qnx.qcc.tool.assembler">
-                                                               <inputType id="com.qnx.qcc.inputType.assembler.618235584" superClass="com.qnx.qcc.inputType.assembler"/>
-                                                       </tool>
-                                                       <tool id="com.qnx.qcc.tool.linker.1321150712" name="QCC Linker" superClass="com.qnx.qcc.tool.linker"/>
-                                                       <tool id="com.qnx.qcc.tool.archiver.1860233844" name="QCC Archiver" superClass="com.qnx.qcc.tool.archiver"/>
-                                               </toolChain>
-                                       </folderInfo>
-                               </configuration>
-                       </storageModule>
-                       <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
-               </cconfiguration>
-       </storageModule>
-       <storageModule moduleId="cdtBuildSystem" version="4.0.0">
-               <project id="pcsx_rearmed.null.446260429" name="pcsx_rearmed"/>
-       </storageModule>
-       <storageModule moduleId="scannerConfiguration">
-               <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
-               <scannerConfigBuildInfo instanceId="com.qnx.qcc.toolChain.1815033502">
-                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
-               </scannerConfigBuildInfo>
-               <scannerConfigBuildInfo instanceId="com.qnx.qcc.toolChain.1762498539">
-                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
-               </scannerConfigBuildInfo>
-               <scannerConfigBuildInfo instanceId="com.qnx.qcc.toolChain.1271074456">
-                       <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="com.qnx.tools.ide.qde.managedbuilder.core.qccScannerInfo"/>
-               </scannerConfigBuildInfo>
-       </storageModule>
-       <storageModule moduleId="refreshScope" versionNumber="1">
-               <resource resourceType="PROJECT" workspacePath="/pcsx_rearmed"/>
-       </storageModule>
-</cproject>
diff --git a/blackberry_qnx/.project b/blackberry_qnx/.project
deleted file mode 100644 (file)
index c8e1e20..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>pcsx_rearmed</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
-                       <triggers>clean,full,incremental,</triggers>
-                       <arguments>
-                               <dictionary>
-                                       <key>?name?</key>
-                                       <value></value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.append_environment</key>
-                                       <value>true</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.autoBuildTarget</key>
-                                       <value>all</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.buildArguments</key>
-                                       <value>-C .. -f Makefile.libretro platform=qnx</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.buildCommand</key>
-                                       <value>make</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
-                                       <value>clean</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.contents</key>
-                                       <value>org.eclipse.cdt.make.core.activeConfigSettings</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.enableAutoBuild</key>
-                                       <value>false</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.enableCleanBuild</key>
-                                       <value>true</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.enableFullBuild</key>
-                                       <value>true</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.fullBuildTarget</key>
-                                       <value>all</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.stopOnError</key>
-                                       <value>true</value>
-                               </dictionary>
-                               <dictionary>
-                                       <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
-                                       <value>false</value>
-                               </dictionary>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
-                       <triggers>full,incremental,</triggers>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>com.qnx.tools.bbt.xml.core.bbtXMLValidationBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.cdt.core.cnature</nature>
-               <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
-               <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
-               <nature>com.qnx.tools.ide.bbt.core.bbtnature</nature>
-       </natures>
-</projectDescription>
index c3ff68f..f3a50d1 100755 (executable)
--- a/configure
+++ b/configure
@@ -279,8 +279,6 @@ arm*)
   fi
   ;;
 *)
-  # dynarec only available on ARM
-  enable_dynarec="no"
   ;;
 esac
 
@@ -550,12 +548,15 @@ echo >> $config_mak
 
 if [ "$platform" = "libretro" ]; then
   echo "TARGET = libretro.so" >> $config_mak
+  echo "HAVE_CHD = 1" >> $config_mak
 fi
 echo "ARCH = $ARCH" >> $config_mak
 echo "PLATFORM = $platform" >> $config_mak
 echo "BUILTIN_GPU = $builtin_gpu" >> $config_mak
 echo "SOUND_DRIVERS = $sound_drivers" >> $config_mak
-echo "PLUGINS = $plugins" >> $config_mak
+if [ "$platform" != "libretro" ]; then
+  echo "PLUGINS = $plugins" >> $config_mak
+fi
 if [ "$have_arm_neon" = "yes" ]; then
   echo "HAVE_NEON = 1" >> $config_mak
 fi
diff --git a/debian_maemo/buildpkg b/debian_maemo/buildpkg
deleted file mode 100644 (file)
index 4c34f94..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash -e
-
-NAME=`head debian/changelog -n1 | sed -n 's/^\(.*\) (\(.*\)) .*/\1-\2/p'`
-[[ -z $NAME ]] && { echo "Could not extract package name and version from debian/changelog" 2>&1; exit 1; }
-
-rm -rf ../$NAME
-cp -r ../`basename $PWD` ../$NAME
-cd ../$NAME
-rm -rf .git*
-find . -depth -name .svn -type d -exec rm -r {} \;
-find . -name '*~' -exec rm {} \;
-
-LD_LIBRARY_PATH=/usr/lib dpkg-buildpackage -rfakeroot $*
diff --git a/debian_maemo/changelog b/debian_maemo/changelog
deleted file mode 100644 (file)
index e3395de..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-pcsxrearmed (0.4.0.14.13) unstable; urgency=low
-
-   * Updated source to notaz git version
-
- -- sakya <sakya_tg@yahoo.it>  Fri,  15 Feb 2013 12:50:28 +0200
-
-pcsxrearmed (0.4.0.14.12) unstable; urgency=low
-
-   * Fixed a problem with controller and vibration (Gran Turismo 2, Wipeout 3)
-   * Added dependency to libts
-
- -- sakya <sakya_tg@yahoo.it>  Wed,  16 May 2012 17:09:33 +0200
-
-pcsxrearmed (0.4.0.14.11) unstable; urgency=low
-
-   * Added option -guncon and -gunnotrigger to activate guncon controller type
-
- -- sakya <sakya_tg@yahoo.it>  Wed,  16 May 2012 09:37:12 +0200
-
-pcsxrearmed (0.4.0.14.10) unstable; urgency=low
-
-   * Added option -corners to set action to execute when clicking on display corners
-   * Fixed problem with notification using gles plugin
-   * Fixed controller problem with game "Heart Of Darkness" (maybe others?)
-
- -- sakya <sakya_tg@yahoo.it>  Fri, 11 May 2012 16:38:29 +0200
-
-pcsxrearmed (0.4.0.14.9) unstable; urgency=low
-
-   * Added support to .mdf extension
-   * Added option -vibration to activate vibration
-
- -- sakya <sakya_tg@yahoo.it>  Tue,  1 May 2012 12:19:49 +0200
-
-pcsxrearmed (0.4.0.14.8) unstable; urgency=low
-
-  * Added option -disc to set the initial disc in multi discs images (used when loading a savestate with -load)
-  * Added option -autosave
-  * Fixed disc change for multi discs images (PBP)
-  * Merged commits from Notaz git
-    * drc: inv: fix ram ofset and mirror handling
-    * support emulated RAM mapped at offset
-
- -- sakya <sakya_tg@yahoo.it>  Fri,  20 Apr 2012 20:27:19 +0200
-
-pcsxrearmed (0.4.0.14.7) unstable; urgency=low
-
-  * Fixed -displayon
-
- -- sakya <sakya_tg@yahoo.it>  Sun,  15 Apr 2012 17:22:08 +0200
-
-pcsxrearmed (0.4.0.14.6) unstable; urgency=low
-
-  * Added option -keys to set the keys config file
-  * Fixed L1/L2/R1/R2
-  * Added autopause on incoming call
-
- -- sakya <sakya_tg@yahoo.it>  Wed,  13 Apr 2012 12:51:35 +0200
-
-pcsxrearmed (0.4.0.14.5) unstable; urgency=low
-
-  * Fixed accelerometer using gles
-  * Added -analog option to use the accelerometer as the analog pad
-  * Added options to set accelerometer sens, max value, y_def
-  * Added -displayon option to keep the display on (useful when playing using the accelerometer)
-
- -- sakya <sakya_tg@yahoo.it>  Tue,  10 Apr 2012 15:34:11 +0200
-
-pcsxrearmed (0.4.0.14.4) unstable; urgency=low
-
-  * Fixed -load option
-  * Added disc change (configured a new key)
-
- -- sakya <sakya_tg@yahoo.it>  Fri,  06 Apr 2012 13:54:56 +0200
-
-pcsxrearmed (0.4.0.14.3) unstable; urgency=low
-
-  * Added options to set various gles settings
-  * Fixed save state slot selection
-  * Added notification on save state slot change
-
- -- sakya <sakya_tg@yahoo.it>  Wed,  04 Apr 2012 10:20:18 +0200
-
-pcsxrearmed (0.4.0.14.2) unstable; urgency=low
-
-  * Fixed fullscreen using gpu-gles
-  * Fixed crash when saving savestate using gpu-gles
-  * Added options to set spu reverb and interpolation (disabled by default)
-
- -- sakya <sakya_tg@yahoo.it>  Sun,  01 Apr 2012 11:42:20 +0200
-
-pcsxrearmed (0.4.0.14.1) unstable; urgency=low
-
-  * Added option to set psx region (NTSC/PAL/Auto)
-  * Use PulseAudio (better audio)
-
- -- sakya <sakya_tg@yahoo.it>  Wed,  30 Mar 2012 09:44:51 +0200
-
-pcsxrearmed (0.4.0.14) unstable; urgency=low
-
-  * Updated to r14
-  * Added --help
-  * PCSX4All
-
- -- sakya <sakya_tg@yahoo.it>  Sun,  27 Dec 2011 00:02:27 +0200
-
-pcsxrearmed (0.4.0.12.2) unstable; urgency=low
-
-  * gpu-gles
-
-
- -- Bonapart <bonapart@programist.ru>  Sun,  27 Dec 2011 00:02:27 +0200
diff --git a/debian_maemo/compat b/debian_maemo/compat
deleted file mode 100644 (file)
index 7ed6ff8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-5
diff --git a/debian_maemo/control b/debian_maemo/control
deleted file mode 100644 (file)
index 4469ed8..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-Source: pcsxrearmed
-Section: user/games
-Priority: extra
-Maintainer: Bonapart <bonapart@programist.ru>
-Build-Depends: debhelper (>= 5), zlib1g-dev, libhildon1-dev,  libpulse-dev, libasound2-dev, libbz2-dev, libgles1-sgx-img-dev, opengles-sgx-img-common-dev, libosso-dev, libdbus-1-dev, libhildonfm2-dev, libts-dev
-Standards-Version: 3.7.3
-
-Package: pcsxrearmed
-Architecture: armel
-Depends: ${shlibs:Depends}, libts-0.0-0
-Description: Sony PlayStation emulator
-XSBC-Homepage: http://notaz.gp2x.de/pcsx_rearmed.php
-XSBC-Bugtracker: http://notaz.gp2x.de/pcsx_rearmed.php
-XB-Maemo-Display-Name: PCSX-ReArmed
-XB-Maemo-Icon-26:
- iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c
- 6QAAEStJREFUaN7Fmn+wXVV1xz9r733uufe+e9+DJIRESEICEQghAUQBI8Uo
- ik7jrxm1o+3ooB2RkWrtONqZlhn7Y8bRUVudqVZsoTjFH2CrSKsVEFIQIr8C
- JARC0CDkBwkkIcl7L7n3nLP36h97n3Pvo07/7c2cOfeenB9rr/Vd3/Vd6zxh
- 7DM52b9isj+5YcGC+a9bunTpOVNTU91WK5Msy1ECIgYRMGKxzmGtQQBrHSZ9
- R8C5DOcc1hiMtTjrsM4hAtZYWq1W/H9nyZzDZVk6x9LKWmSteH2rlZNlLhw/
- fnzXszt3fmHjxo13bH74oReBwbbtO6r0ODht5UpnfXXdytOXX+mswVcl1hqc
- swjgQ0BV8T7gfSCEQFBQFFQJqqhquptpHCJiMGIQKxhjsdZircMai8kczibj
- XUaWZdi0d1lGlrVwmdN2nsvypUtZvmwpw7LY8dSTT37yX264/sGgOrNl67ZS
- AFavPudTF5y76u9fOniQZ3/7PLPHjuG9Z8wSJO7QeAABVIW0DFAFBEVANF0j
- AGh9XBWV9L3eRFAx6dr6XFDiMWMNy049VS9Yu4o/et+7xBj78u5duz78lS9/
- 8U6UoZx59lnZ2StXbMP7lT+7cyNFUWCsbQwmyLhTo1EiydvpSFogIpiIMQST
- zhOMMSAmnmcMIhYxgogFYxBjEYnnYOIWn2OjA4IiRjhj+TL98uc/K5X3W7Zs
- 2fKBf/72Pz5tZmdmz5jodJZtfeppyqqK+LQx3EYtpm0wRChYazBWMCYaasRg
- TFwAUu/TsgyIiecytkAxBjG1sTZuzfe4GIwDk4GxqMmQLAdx7PjNs/KNG75H
- 3srWLFmy5E3P79rj7Omnr7is08o+8Otnn6MYFtGIErQCyZXsqxW6B3S3gQqw
- /I6PNgEZwSPmQAMVYxERVCSSQTI8et4iYtF6MckhcXECJuWSGPbvf1EvumCN
- nDA1taIoypuNr6pFg6JgMEjGe2Ch0vpmSXdnQeuqQPeeivZtBbI6oIWiKJqS
- WLU2vM6POh2SIZjEXpIMtglGdSTib9IxEsSoFy9mBFtjmTleyJ33bMIYOevQ
- oUMnuLIs5w+LkuCr+HAP+dcqWu8PFD8SZAEwA9kGxawuOXZeBjMGXJ0BNMk4
- gpIZYbr2ZvJ6hJBrftcLEGPTfVJ+EBcfUo6pgohQhMCBgwdB4fDhw5MG6JdV
- RQgKQZAO2IuVMIDB+xzhcWF4lWP4FUPYZJATf1dCp0ROxps69LXR1mGsTZtD
- TNrbWE/i9/jbmFEiRx6oCSCRRHJZURTMzMx0nUK7LD2KIgZ0CPoM2KWQf8tj
- TlPkZGX4GRdNdiTvzzW+Nrg2voaIqb1uHUYsYm2KRNxURnBSTfdB4k5r6q0x
- qogIIShFWVKWZWa8962y8g0eRGH4GYd/Usg/GsjerHQ2VnRuK7GvC6iXhjpH
- xo+MyPOcdruNsTZyughiXFxI42mHuAyswzgLNrGRNWANYg1gUCOoMQ2DYUZ5
- JgKqahxI5n0Y4cJBeMxw7LwM+6ZA62880o454C4rmb1U4AkLrXHjY6UNqpx6
- ymKm+n2qEBgUFUemZzk8PYsPinMxIsa6xDAR71rXjFj/CJo8WdNDXeQTY4iA
- tZHVnKo61VBfCW3FXqzoUCl/bnB/ECj+0uGurGj/bcBdESifcBGLKQIN5oFu
- p8OCBfPpdDp0u13yvI1X5fnd+9jx210cOjJDnmUY4yLOE9xACEmamHoRQZtF
- aar0oBgxOJfFBYgxTjXxeGVgnqdzd4nuh9mLshizFkieHDKcyzam5nNjICjt
- djS81+sxMTHB5OQkvV6P89euoZXn3Pfgo9y16RGKMiDWRu8bQVTQEEAiPQsh
- KoAwqjApDBgjZM5F54mIa5IwA31OKL5kMYthYkeJe2ege39Bfm3Ab4fqJy7i
- PVjEW/AGCel3sHTb0fh+v8/k5CQ+KEemZ+h0u8yfN48PvvddXPvpq5ma6qMK
- 1goGk2qdIKYmZlMrLiBE+ISAAkaELMswxohx1mZSaxgBnFD8hePYBx3V92PW
- hEeFwecyjr+lA7stsgDMUkWWhLidGpBXBWRxQPvKZH+yWcA9v9rMN2+8mWd2
- Pk+/36fX6/G615zHtZ++GucsqpIkR6obgJFXVPfa+QliYgwuy7DW4sQYGdFg
- UsMC1fct1Q8c+ZdKqq9lhBds1D3WYt8zwP3JMNFc/RTBiPLcXdtZ9/LFdHtd
- +v0+/ck+Yi0vHXyZXq9Ht9ul3W5z2bqLeNsb13HrHffQytvUVdSIRPyPVfna
- +HpJxiSpL4LTEDAxHFFC12IssUz51y2oBNOSVPqF8MMu1X90QWykR7EY46iq
- ite89VImzp6Ixvf7tLIW1rbodDtMTEzQ6XTI85w8z7nowvP54U/vJs9Hyanq
- myKpKKIpAppEsWqCXhRlTlUxSbvXJTtSlYyS1tTcnKrt0CKFbSqqcZHnfeVY
- 0DupMb7X65HlOVhD3mo33s/znCzLWLl8Ka08IxBtUA1NUBVFJeoukdg0ee+Z
- mZllMBwgCM45cSGEEPHX0OzcRqaWv4y+R/GVqmqSCJJ6iM5Ep2GeXq9H1soR
- sWSt1hzjsyxj3oknMJG3KGqmqTsmiaCvo1BWnmJYUJRDKu9HjZIqzhijseSb
- RlXW+zoqkSJMoyZreWDHKms8Bt1urzG+1+vhsgwjllaWkef5qB+2lsoHfEj8
- PoZ3QQjeU5QFRVFSlRUh+Oa8qIK1gVAwxozEWLpN3Tr6oIhRjIJY0yhHsbEB
- qQWaMRapPN1uh36/z8TEBN1ul8xliAHrsjnGG2PY88I+Zo4dZ6I3EVnHB4qy
- ZDgYUpYVGkJqbUO0SAEJqAYq72MEAG+SFtc6DwREU6+bIhCA4AMWgzhpEnek
- c2KE6iJWV+I4jbA4Z2vubqK96aHHokQuo5eHRYEGT0hDBG0wLU0VltRi+qqK
- CxARX+uKV+J/1HhHcRXVo+C9EvB4FWwAYwLz5p+IwZC1crrdLp1Oh3a7jRhD
- 5QODwSAZBoPhkLvv/RXfuP4mPIbS+5iA49t4m9QcjwUt+EBRFrV0I4y8ImOV
- Q5qOKiZzrUINKlBVnrzlWLFsCWefdQbr113CLx94BCNCp9Oh0+nQarWoqujZ
- m370U3bs3MWik+Zx5OhRfnHPJnrdLsOyZPr4MarKY63BGtMYKnXhIsKmXogP
- nqIogajuGwjVTKQyd+yROnQCUJYVJ05NsWb1Kt74hks4c+XpnPKqxfT7fZ58
- 5lmyVqsxPsuilsqtsPrMM7jktWs5/bRl9HtdrvnYh7HWMhgMefHAQR7c/Dg/
- u3Mjj27djnEWI6aJQNJ0zcd7T1EMI4RUtaqTamxWMoJOUoo+KKcsWsglF13I
- 773hEk6av4B+vzcnYV8+fKQpUs45nHMcPTrNT757Heede04zwfhfcAXeuv5S
- Pvepj3PHXffw2c9/kWd378Vg0DAXRqrgK89gMCSEMJbEafxBrVoZNS55nnP5
- G9dx+frLmgJVU+TR6Vnu+O/7+Pdb/4vHt2zjfe/ZEKdsaTRTVSWLTl6Ic5ay
- qjg2e4ytTz3NDf96C4889jjHBkP+/E+v5sMfeC/tPOcdb38LU/0+7//jT3J0
- enpsXDDKCx88xTAtQKFsIKRjA6t6WqZw9qvP4PL1lzE5OcnExATtdocHHn6M
- +x/azP0PPkorb7P23HO4MG8nre6oqdmK4cCBg+zavYc77v4lP7/rHrZse4oz
- Vqxg7bnn8o4r1vPmy9Y1zATw4oGDBO/RkPJRx1pKjRAaDCMpOIGqSWIZTdqU
- URIfPjpNnrdHnncZe/e/xAknnMDVH/0Q6y+9hFVnvZp/+s73CaqM15V+v8s1
- n72W5/fsY3Z2lt9/y3o+9fErOX/NOSxfthTnRoOmF/bt58bv3sz1N93CzOzs
- qJGRxEAoSCB4z3A4yoFiVAdovB6naQYV4bnd+/jCV7/BuzdcwaVvuJjTly/i
- z675GO12m06n00gDl2WNWhyfXBw9Ms2nr7qSd2+4gkUnL6Tdzkd5oPCrBx/m
- m9d/h433PcjR6RmGRTXWTupcFKnifcWwzgERKWMEatYZCdjxAe2uF/bxtW/d
- yNe/fSNrV69i1dmvZvHCRbSyDLGW/fv38/O77uX1//CVOcl5+MhRbv/xTSw6
- eWGjX7z3TE9P88Nbf8oNN93MY1ufjHoqiUljYncW6sSlrgFRRnhfMSzqHFAt
- jJFGsMXRRuR+bSZjMULORSmxdfuveXzbMzFlxiYS5XDI3n37eenAQebPOzFC
- CeLMCXjpwEGe3P4Mt/zoNv7z9l/w/J59KYKt6NwxxlFlrIAx+h0ghEAxLOIC
- gmpRj/5C7XV5xfiiRkRiVWcdtOq5T2z9xBjaeYu/+uLf8YN/u5ULzlvNhisu
- ZzAcsOnBh9m9dy+3/+JeNm95giNHZ8haGZNT/cjxGtvGKB9CQkpACQRCwkBI
- 8jouoCxLvPfqNIRBnQOicY6TXBvlrMaGew60dCT8JIUcBWMNBw4d5t5ND3Pf
- A4/wvVt+wuzsMbZt/zXT09MMyxJjLZ1Op1GUUmuexsPjsoH4m7lsFEKgrLXQ
- KInndIdzJs9xRhPHHLFKayrtBiQZks4REWxm0QAHXz4MCoNiCBiyzKVnNJiI
- 9wmRYXTMeG2eERKca4qJLBRqNaqqRZ7nWOua1q2REPWKAs1UTALxfVkawMYb
- +9F8RxQNZvz9B6iMTbLjTUMIc7yu9Z4wFoUR89T72ODXL0oEZ4yUcQFWVcbZ
- TZtmRhtRFXm4rtIRXqnZVghGRzYzPmtPhKraDK8aVtG52J/LOjp6hUVI3lVE
- RK2NswsHlK34llCa7BeNuKd2uU0tTkA1hiJG1qNqmh6C1F01EJyzklFyJspJ
- JBNSDigStDlWGz96AZGco4qNr31qOS1F1spod9ujKXP9Uq5OgWa0B0ZHN2s8
- Qz3XTBBibpvYxLSBgI4aljpx0Yb3m1eHiaHGtZ8I5O0cUMqy9KaqyuPe+4OL
- Fy4kc07rmzH2kDjqCOnBPr4F0YCGufuAJwSPBo+G6hVbOlc9IV2j9bWEdN8k
- F9SPYEZgjH5oOdHFCxcwHBb7q6oqzNGj00cOHjz05No1q1lw4qSoD801UlfC
- Bn5a3yfOMTUWn7gF8CkR/4+NEFknfq/vXz9z9LwRtBI0gxK8Z+H8E2XtmtXs
- 3bv38enp6VlzbHb25W3bnnhANQzeseFtKBWVL0bYk9jU61jySTP1Do2XGsrT
- MOa5sU1HXZXq+LFRtyK11yXMmciB4qsCoeRd73w7RVEc37x586YjR44ctsba
- 7NChQ3m73T7ltRe+Zumac1ax9Yltenx6RsSmF26M6aRxlkpo1zQASEgevQTU
- MRgSKTJomHMMJb7pb/7RRDbWBk91/DiTUxN6zVUfkWVLlnDvvffed//99/8Y
- +I0VkWCtMc/s2DHw3i9at+71C996+Xrp9Sd01/O7ZHD8GASP+gpClfbxt097
- rY/7ilAlvPt4bHwLVUmo4n1COten65rzqmL0PXgmum3eueEK/ciH/lBOmJrU
- 2267bevtt9/+XeBRYJ8Att3OT6oqf6b3/pJ58+a96ROf+MRFZ5115sTk5JTp
- 93vSzttYF//OwaU/2siyLPatiSqNiXI8TjhoeoIRe0gjr4MGqjI6oKoqyqKk
- KAqGxRBf+TQIGFKWJbMzszozOxt27tw5e9111z1w4MCBO4H7gKeBlwWg3c5b
- 3of5VVWtUNVzgfMvvvji80477bQFS5Ys6VprTd301IaNG2iMaWBR9wKNwa/Y
- 69j8sqoqQhpeeR8Nr+V22sKePXuO7969+6WHHnroseT1x4GdwCGgbFzU7XSy
- wXDYDyGcDKwAlgOLgUmgzf/PZwgcAV4Ank2G7wemgRLgfwDIFWZCNtkwCgAA
- AABJRU5ErkJggg==
diff --git a/debian_maemo/copyright b/debian_maemo/copyright
deleted file mode 100644 (file)
index 75a6b06..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-this package was maemonized by Roman Deninberg <bonapart@programist.ru>
-Mon, 10 Jan 2011 02:00:13 +0100
diff --git a/debian_maemo/dirs b/debian_maemo/dirs
deleted file mode 100644 (file)
index 33359b8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-usr/games
diff --git a/debian_maemo/docs b/debian_maemo/docs
deleted file mode 100644 (file)
index e845566..0000000
+++ /dev/null
@@ -1 +0,0 @@
-README
diff --git a/debian_maemo/files b/debian_maemo/files
deleted file mode 100644 (file)
index 0cc57dd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-pcsxrearmed_0.4.0.14.13_armel.deb user/games extra
diff --git a/debian_maemo/install b/debian_maemo/install
deleted file mode 100644 (file)
index a260186..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-pcsx opt/maemo/usr/games/
-plugins/spunull/spunull.so opt/maemo/usr/games/plugins
-plugins/gpu_unai/gpu_unai.so opt/maemo/usr/games/plugins
-#plugins/gpu_unai/gpuPCSX4ALL.so opt/maemo/usr/games/plugins
-plugins/dfxvideo/gpu_peops.so opt/maemo/usr/games/plugins
-plugins/gpu-gles/gpu_gles.so opt/maemo/usr/games/plugins
diff --git a/debian_maemo/rules b/debian_maemo/rules
deleted file mode 100644 (file)
index 5230bf7..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/usr/bin/make -f
-# -*- makefile -*-
-
-#export DH_VERBOSE=1
-
-DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
-DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
-DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH)
-
-#GAME_VERSION := $(shell head debian/changelog -n1 | sed -n 's/.* (\(.*\)) .*/\1/p')
-CFLAGS = -Wall -g
-
-ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
-       CFLAGS += -O0
-else
-       CFLAGS += -O2
-endif
-
-build: build-stamp
-
-build-stamp:
-       dh_testdir
-       ./configure --platform=maemo --gpu=neon --sound-drivers=pulseaudio --enable-neon
-       $(MAKE)
-       strip pcsx
-       strip plugins/gpu_unai/gpu_unai.so
-       strip plugins/gpu-gles/gpu_gles.so
-       strip plugins/spunull/spunull.so
-       touch build-stamp
-
-clean:
-       dh_testdir
-       dh_testroot
-       rm -f build-stamp
-       dh_clean
-       $(MAKE) clean clean_plugins
-
-install: build
-       dh_testdir
-       dh_testroot
-       dh_installdirs
-       mkdir -p "$(CURDIR)"/debian/pcsxrearmed/opt/maemo/usr/games/screenshots
-       chmod 777 "$(CURDIR)"/debian/pcsxrearmed/opt/maemo/usr/games/screenshots
-       chown user "$(CURDIR)"/debian/pcsxrearmed/opt/maemo/usr/games/screenshots
-       dh_install
-
-binary-indep: build install
-
-binary-arch: build install
-       dh_testdir
-       dh_testroot
-       dh_installchangelogs
-       dh_installdocs
-       #dh_installmenu
-       dh_link
-       dh_strip
-       dh_compress
-       dh_fixperms
-       dh_installdeb
-       dh_makeshlibs
-       dh_shlibdeps
-       dh_gencontrol
-       #maemo-optify
-       dh_md5sums
-       dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install
diff --git a/deps/libchdr/.gitrepo b/deps/libchdr/.gitrepo
new file mode 100644 (file)
index 0000000..560b69c
--- /dev/null
@@ -0,0 +1,12 @@
+; DO NOT EDIT (unless you know what you are doing)
+;
+; This subdirectory is a git "subrepo", and this file is maintained by the
+; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
+;
+[subrepo]
+       remote = https://github.com/rtissera/libchdr
+       branch = master
+       commit = a17c0da7e9efa8cbb752c707df7d5457b2149fb8
+       parent = 2f8b37246c10773b391368f99311a192f1fb331f
+       method = merge
+       cmdver = 0.4.3
diff --git a/deps/libchdr/CMakeLists.txt b/deps/libchdr/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9842447
--- /dev/null
@@ -0,0 +1,126 @@
+cmake_minimum_required(VERSION 3.9)
+
+project(chdr C)
+
+set(CHDR_VERSION_MAJOR 0)
+set(CHDR_VERSION_MINOR 1)
+
+if(CMAKE_PROJECT_NAME STREQUAL "chdr")
+  option(BUILD_SHARED_LIBS "Build libchdr also as a shared library" ON)
+endif()
+option(INSTALL_STATIC_LIBS "Install static libraries" OFF)
+option(WITH_SYSTEM_ZLIB "Use system provided zlib library" OFF)
+
+if(CMAKE_C_COMPILER_ID MATCHES "GNU")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fPIC -O3 -flto")
+  set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
+elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
+  set(CMAKE_INTERPROCEDURAL_OPTIMIZATION OFF)
+endif()
+
+include(FindPkgConfig)
+include(GNUInstallDirs)
+
+# Detect processor type.
+if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "amd64")
+  set(CPU_ARCH "x64")
+elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "AMD64")
+  # MSVC x86/x64
+  if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+    set(CPU_ARCH "x64")
+  else()
+    set(CPU_ARCH "x86")
+  endif()
+elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386" OR
+       ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
+  set(CPU_ARCH "x86")
+elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
+  set(CPU_ARCH "aarch64")
+elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7-a")
+  set(CPU_ARCH "arm")
+else()
+  message(FATAL_ERROR "Unknown system processor: " ${CMAKE_SYSTEM_PROCESSOR})
+endif()
+
+#--------------------------------------------------
+# dependencies
+#--------------------------------------------------
+
+
+# lzma
+add_subdirectory(deps/lzma-19.00 EXCLUDE_FROM_ALL)
+  list(APPEND CHDR_LIBS lzma)
+  list(APPEND CHDR_INCLUDES lzma)
+
+# zlib
+if (WITH_SYSTEM_ZLIB)
+  pkg_check_modules(ZLIB REQUIRED zlib)
+  list(APPEND PLATFORM_INCLUDES ${ZLIB_INCLUDE_DIRS})
+  list(APPEND PLATFORM_LIBS ${ZLIB_LIBRARIES})
+else()
+  add_subdirectory(deps/zlib-1.2.11 EXCLUDE_FROM_ALL)
+  list(APPEND CHDR_LIBS zlib)
+  list(APPEND CHDR_INCLUDES zlib)
+endif()
+
+#--------------------------------------------------
+# chdr
+#--------------------------------------------------
+
+set(CHDR_SOURCES
+  src/libchdr_bitstream.c
+  src/libchdr_cdrom.c
+  src/libchdr_chd.c
+  src/libchdr_flac.c
+  src/libchdr_huffman.c
+)
+
+list(APPEND CHDR_INCLUDES ${CMAKE_CURRENT_BINARY_DIR}/include)
+
+add_library(chdr-static STATIC ${CHDR_SOURCES})
+target_include_directories(chdr-static PRIVATE ${CHDR_INCLUDES} ${PLATFORM_INCLUDES} PUBLIC include)
+target_compile_definitions(chdr-static PRIVATE ${CHDR_DEFS})
+target_link_libraries(chdr-static PRIVATE ${CHDR_LIBS} ${PLATFORM_LIBS})
+
+if (INSTALL_STATIC_LIBS)
+  install(TARGETS chdr-static ${CHDR_LIBS}
+    ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+  )
+endif()
+
+if (BUILD_SHARED_LIBS)
+  set(CMAKE_CXX_VISIBILITY_PRESET hidden)
+  set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
+
+  add_library(chdr SHARED ${CHDR_SOURCES})
+  target_include_directories(chdr PRIVATE ${CHDR_INCLUDES} ${PLATFORM_INCLUDES} PUBLIC include)
+  target_compile_definitions(chdr PRIVATE ${CHDR_DEFS})
+  target_link_libraries(chdr PRIVATE ${CHDR_LIBS} ${PLATFORM_LIBS})
+
+  if(MSVC)
+    target_compile_definitions(chdr PUBLIC "CHD_DLL")
+    target_compile_definitions(chdr PRIVATE "CHD_DLL_EXPORTS")
+  elseif(APPLE)
+    target_link_options(chdr PRIVATE -Wl,-dead_strip -Wl,-exported_symbol,_chd_*)
+  else()
+    target_link_options(chdr PRIVATE -Wl,--version-script ${CMAKE_CURRENT_SOURCE_DIR}/src/link.T -Wl,--no-undefined)
+  endif()
+
+  set_target_properties(chdr PROPERTIES PUBLIC_HEADER "include/libchdr/bitstream.h;include/libchdr/cdrom.h;include/libchdr/chd.h;include/libchdr/chdconfig.h;include/libchdr/coretypes.h;include/libchdr/flac.h;include/libchdr/huffman.h")
+  set_target_properties(chdr PROPERTIES VERSION "${CHDR_VERSION_MAJOR}.${CHDR_VERSION_MINOR}")
+
+  if (CMAKE_BUILD_TYPE MATCHES Release)
+    #add_custom_command(TARGET chdr POST_BUILD COMMAND ${CMAKE_STRIP} libchdr.so)
+  endif (CMAKE_BUILD_TYPE MATCHES Release)
+
+  install(TARGETS chdr
+    LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+    ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+    PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/libchdr"
+  )
+
+  configure_file(pkg-config.pc.in ${CMAKE_BINARY_DIR}/libchdr.pc @ONLY)
+  install(FILES ${CMAKE_BINARY_DIR}/libchdr.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
+endif()
+
diff --git a/deps/libchdr/LICENSE.txt b/deps/libchdr/LICENSE.txt
new file mode 100644 (file)
index 0000000..1c36e5b
--- /dev/null
@@ -0,0 +1,24 @@
+Copyright Romain Tisserand
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the <organization> nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/deps/libchdr/README.md b/deps/libchdr/README.md
new file mode 100644 (file)
index 0000000..940920a
--- /dev/null
@@ -0,0 +1,7 @@
+# libchdr
+
+libchdr is a standalone library for reading MAME's CHDv1-v5 formats.
+
+The code is based off of MAME's old C codebase which read up to CHDv4 with OS-dependent features removed, and CHDv5 support backported from MAME's current C++ codebase.
+
+libchdr is licensed under the BSD 3-Clause (see [LICENSE.txt](LICENSE.txt)) and uses third party libraries that are each distributed under their own terms (see each library's license in [deps/](deps/)).
diff --git a/deps/libchdr/deps/lzma-19.00/CMakeLists.txt b/deps/libchdr/deps/lzma-19.00/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fb01f60
--- /dev/null
@@ -0,0 +1,32 @@
+add_library(lzma STATIC
+  include/7zTypes.h
+  include/Alloc.h
+  include/Bra.h
+  include/Compiler.h
+  include/CpuArch.h
+  include/Delta.h
+  include/LzFind.h
+  include/LzHash.h
+  include/Lzma86.h
+  include/LzmaDec.h
+  include/LzmaEnc.h
+  include/LzmaLib.h
+  include/Precomp.h
+  include/Sort.h
+  src/Alloc.c
+  src/Bra86.c
+  src/BraIA64.c
+  src/CpuArch.c
+  src/Delta.c
+  src/LzFind.c
+  src/Lzma86Dec.c
+  src/LzmaDec.c
+  src/LzmaEnc.c
+  src/Sort.c
+)
+
+target_compile_definitions(lzma PRIVATE _7ZIP_ST)
+
+target_include_directories(lzma PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
+target_include_directories(lzma INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
+
diff --git a/deps/libchdr/deps/lzma-19.00/LICENSE b/deps/libchdr/deps/lzma-19.00/LICENSE
new file mode 100644 (file)
index 0000000..5f57051
--- /dev/null
@@ -0,0 +1,3 @@
+LZMA SDK is placed in the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute the original LZMA SDK code, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
\ No newline at end of file
diff --git a/deps/libchdr/deps/lzma-19.00/include/7zTypes.h b/deps/libchdr/deps/lzma-19.00/include/7zTypes.h
new file mode 100644 (file)
index 0000000..65b3af6
--- /dev/null
@@ -0,0 +1,375 @@
+/* 7zTypes.h -- Basic types
+2018-08-04 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#ifdef _WIN32
+/* #include <windows.h> */
+#endif
+
+#include <stddef.h>
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+
+#ifdef _WIN32
+
+/* typedef DWORD WRes; */
+typedef unsigned WRes;
+#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x)
+
+#else
+
+typedef int WRes;
+#define MY__FACILITY_WIN32 7
+#define MY__FACILITY__WRes MY__FACILITY_WIN32
+#define MY_SRes_HRESULT_FROM_WRes(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (MY__FACILITY__WRes << 16) | 0x80000000)))
+
+#endif
+
+
+#ifndef RINOK
+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+   NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#define UINT64_CONST(n) n
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#define UINT64_CONST(n) n ## ULL
+#endif
+
+#endif
+
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+typedef int BoolInt;
+/* typedef BoolInt Bool; */
+#define True 1
+#define False 0
+
+
+#ifdef _WIN32
+#define MY_STD_CALL __stdcall
+#else
+#define MY_STD_CALL
+#endif
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_FORCE_INLINE __forceinline
+
+#define MY_CDECL __cdecl
+#define MY_FAST_CALL __fastcall
+
+#else
+
+#define MY_NO_INLINE
+#define MY_FORCE_INLINE
+#define MY_CDECL
+#define MY_FAST_CALL
+
+/* inline keyword : for C++ / C99 */
+
+/* GCC, clang: */
+/*
+#if defined (__GNUC__) && (__GNUC__ >= 4)
+#define MY_FORCE_INLINE __attribute__((always_inline))
+#define MY_NO_INLINE __attribute__((noinline))
+#endif
+*/
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct IByteIn IByteIn;
+struct IByteIn
+{
+  Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */
+};
+#define IByteIn_Read(p) (p)->Read(p)
+
+
+typedef struct IByteOut IByteOut;
+struct IByteOut
+{
+  void (*Write)(const IByteOut *p, Byte b);
+};
+#define IByteOut_Write(p, b) (p)->Write(p, b)
+
+
+typedef struct ISeqInStream ISeqInStream;
+struct ISeqInStream
+{
+  SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size);
+    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+       (output(*size) < input(*size)) is allowed */
+};
+#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf);
+
+
+typedef struct ISeqOutStream ISeqOutStream;
+struct ISeqOutStream
+{
+  size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size);
+    /* Returns: result - the number of actually written bytes.
+       (result < size) means error */
+};
+#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size)
+
+typedef enum
+{
+  SZ_SEEK_SET = 0,
+  SZ_SEEK_CUR = 1,
+  SZ_SEEK_END = 2
+} ESzSeek;
+
+
+typedef struct ISeekInStream ISeekInStream;
+struct ISeekInStream
+{
+  SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size);  /* same as ISeqInStream::Read */
+  SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin);
+};
+#define ISeekInStream_Read(p, buf, size)   (p)->Read(p, buf, size)
+#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
+
+
+typedef struct ILookInStream ILookInStream;
+struct ILookInStream
+{
+  SRes (*Look)(const ILookInStream *p, const void **buf, size_t *size);
+    /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+       (output(*size) > input(*size)) is not allowed
+       (output(*size) < input(*size)) is allowed */
+  SRes (*Skip)(const ILookInStream *p, size_t offset);
+    /* offset must be <= output(*size) of Look */
+
+  SRes (*Read)(const ILookInStream *p, void *buf, size_t *size);
+    /* reads directly (without buffer). It's same as ISeqInStream::Read */
+  SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin);
+};
+
+#define ILookInStream_Look(p, buf, size)   (p)->Look(p, buf, size)
+#define ILookInStream_Skip(p, offset)      (p)->Skip(p, offset)
+#define ILookInStream_Read(p, buf, size)   (p)->Read(p, buf, size)
+#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
+
+
+SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size);
+
+
+
+typedef struct
+{
+  ILookInStream vt;
+  const ISeekInStream *realStream;
+  size_t pos;
+  size_t size; /* it's data size */
+  
+  /* the following variables must be set outside */
+  Byte *buf;
+  size_t bufSize;
+} CLookToRead2;
+
+void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead);
+
+#define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; }
+
+
+typedef struct
+{
+  ISeqInStream vt;
+  const ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+
+
+typedef struct
+{
+  ISeqInStream vt;
+  const ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+
+typedef struct ICompressProgress ICompressProgress;
+
+struct ICompressProgress
+{
+  SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize);
+    /* Returns: result. (result != SZ_OK) means break.
+       Value (UInt64)(Int64)-1 for size means unknown value. */
+};
+#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize)
+
+
+
+typedef struct ISzAlloc ISzAlloc;
+typedef const ISzAlloc * ISzAllocPtr;
+
+struct ISzAlloc
+{
+  void *(*Alloc)(ISzAllocPtr p, size_t size);
+  void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
+};
+
+#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size)
+#define ISzAlloc_Free(p, a) (p)->Free(p, a)
+
+/* deprecated */
+#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size)
+#define IAlloc_Free(p, a) ISzAlloc_Free(p, a)
+
+
+
+
+
+#ifndef MY_offsetof
+  #ifdef offsetof
+    #define MY_offsetof(type, m) offsetof(type, m)
+    /*
+    #define MY_offsetof(type, m) FIELD_OFFSET(type, m)
+    */
+  #else
+    #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
+  #endif
+#endif
+
+
+
+#ifndef MY_container_of
+
+/*
+#define MY_container_of(ptr, type, m) container_of(ptr, type, m)
+#define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m)
+#define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m)))
+#define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m))))
+*/
+
+/*
+  GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly"
+    GCC 3.4.4 : classes with constructor
+    GCC 4.8.1 : classes with non-public variable members"
+*/
+
+#define MY_container_of(ptr, type, m) ((type *)((char *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))
+
+
+#endif
+
+#define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(ptr))
+
+/*
+#define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
+*/
+#define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)
+
+#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
+/*
+#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m)
+*/
+
+
+
+#ifdef _WIN32
+
+#define CHAR_PATH_SEPARATOR '\\'
+#define WCHAR_PATH_SEPARATOR L'\\'
+#define STRING_PATH_SEPARATOR "\\"
+#define WSTRING_PATH_SEPARATOR L"\\"
+
+#else
+
+#define CHAR_PATH_SEPARATOR '/'
+#define WCHAR_PATH_SEPARATOR L'/'
+#define STRING_PATH_SEPARATOR "/"
+#define WSTRING_PATH_SEPARATOR L"/"
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/Alloc.h b/deps/libchdr/deps/lzma-19.00/include/Alloc.h
new file mode 100644 (file)
index 0000000..6482376
--- /dev/null
@@ -0,0 +1,51 @@
+/* Alloc.h -- Memory allocation functions
+2018-02-19 : Igor Pavlov : Public domain */
+
+#ifndef __COMMON_ALLOC_H
+#define __COMMON_ALLOC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+void *MyAlloc(size_t size);
+void MyFree(void *address);
+
+#ifdef _WIN32
+
+void SetLargePageSize();
+
+void *MidAlloc(size_t size);
+void MidFree(void *address);
+void *BigAlloc(size_t size);
+void BigFree(void *address);
+
+#else
+
+#define MidAlloc(size) MyAlloc(size)
+#define MidFree(address) MyFree(address)
+#define BigAlloc(size) MyAlloc(size)
+#define BigFree(address) MyFree(address)
+
+#endif
+
+extern const ISzAlloc g_Alloc;
+extern const ISzAlloc g_BigAlloc;
+extern const ISzAlloc g_MidAlloc;
+extern const ISzAlloc g_AlignedAlloc;
+
+
+typedef struct
+{
+  ISzAlloc vt;
+  ISzAllocPtr baseAlloc;
+  unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */
+  size_t offset;         /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */
+} CAlignOffsetAlloc;
+
+void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p);
+
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/Bra.h b/deps/libchdr/deps/lzma-19.00/include/Bra.h
new file mode 100644 (file)
index 0000000..855e37a
--- /dev/null
@@ -0,0 +1,64 @@
+/* Bra.h -- Branch converters for executables
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __BRA_H
+#define __BRA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+These functions convert relative addresses to absolute addresses
+in CALL instructions to increase the compression ratio.
+  
+  In:
+    data     - data buffer
+    size     - size of data
+    ip       - current virtual Instruction Pinter (IP) value
+    state    - state variable for x86 converter
+    encoding - 0 (for decoding), 1 (for encoding)
+  
+  Out:
+    state    - state variable for x86 converter
+
+  Returns:
+    The number of processed bytes. If you call these functions with multiple calls,
+    you must start next call with first byte after block of processed bytes.
+  
+  Type   Endian  Alignment  LookAhead
+  
+  x86    little      1          4
+  ARMT   little      2          2
+  ARM    little      4          0
+  PPC     big        4          0
+  SPARC   big        4          0
+  IA64   little     16          0
+
+  size must be >= Alignment + LookAhead, if it's not last block.
+  If (size < Alignment + LookAhead), converter returns 0.
+
+  Example:
+
+    UInt32 ip = 0;
+    for ()
+    {
+      ; size must be >= Alignment + LookAhead, if it's not last block
+      SizeT processed = Convert(data, size, ip, 1);
+      data += processed;
+      size -= processed;
+      ip += processed;
+    }
+*/
+
+#define x86_Convert_Init(state) { state = 0; }
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/Compiler.h b/deps/libchdr/deps/lzma-19.00/include/Compiler.h
new file mode 100644 (file)
index 0000000..0cc409d
--- /dev/null
@@ -0,0 +1,33 @@
+/* Compiler.h
+2017-04-03 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_COMPILER_H
+#define __7Z_COMPILER_H
+
+#ifdef _MSC_VER
+
+  #ifdef UNDER_CE
+    #define RPC_NO_WINDOWS_H
+    /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */
+    #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+    #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
+  #endif
+
+  #if _MSC_VER >= 1300
+    #pragma warning(disable : 4996) // This function or variable may be unsafe
+  #else
+    #pragma warning(disable : 4511) // copy constructor could not be generated
+    #pragma warning(disable : 4512) // assignment operator could not be generated
+    #pragma warning(disable : 4514) // unreferenced inline function has been removed
+    #pragma warning(disable : 4702) // unreachable code
+    #pragma warning(disable : 4710) // not inlined
+    #pragma warning(disable : 4714) // function marked as __forceinline not inlined
+    #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information
+  #endif
+
+#endif
+
+#define UNUSED_VAR(x) (void)x;
+/* #define UNUSED_VAR(x) x=x; */
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/CpuArch.h b/deps/libchdr/deps/lzma-19.00/include/CpuArch.h
new file mode 100644 (file)
index 0000000..bd42938
--- /dev/null
@@ -0,0 +1,336 @@
+/* CpuArch.h -- CPU specific code
+2018-02-18 : Igor Pavlov : Public domain */
+
+#ifndef __CPU_ARCH_H
+#define __CPU_ARCH_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+MY_CPU_LE means that CPU is LITTLE ENDIAN.
+MY_CPU_BE means that CPU is BIG ENDIAN.
+If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
+
+MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
+*/
+
+#if  defined(_M_X64) \
+  || defined(_M_AMD64) \
+  || defined(__x86_64__) \
+  || defined(__AMD64__) \
+  || defined(__amd64__)
+  #define MY_CPU_AMD64
+  #ifdef __ILP32__
+    #define MY_CPU_NAME "x32"
+  #else
+    #define MY_CPU_NAME "x64"
+  #endif
+  #define MY_CPU_64BIT
+#endif
+
+
+#if  defined(_M_IX86) \
+  || defined(__i386__)
+  #define MY_CPU_X86
+  #define MY_CPU_NAME "x86"
+  #define MY_CPU_32BIT
+#endif
+
+
+#if  defined(_M_ARM64) \
+  || defined(__AARCH64EL__) \
+  || defined(__AARCH64EB__) \
+  || defined(__aarch64__)
+  #define MY_CPU_ARM64
+  #define MY_CPU_NAME "arm64"
+  #define MY_CPU_64BIT
+#endif
+
+
+#if  defined(_M_ARM) \
+  || defined(_M_ARM_NT) \
+  || defined(_M_ARMT) \
+  || defined(__arm__) \
+  || defined(__thumb__) \
+  || defined(__ARMEL__) \
+  || defined(__ARMEB__) \
+  || defined(__THUMBEL__) \
+  || defined(__THUMBEB__)
+  #define MY_CPU_ARM
+  #define MY_CPU_NAME "arm"
+  #define MY_CPU_32BIT
+#endif
+
+
+#if  defined(_M_IA64) \
+  || defined(__ia64__)
+  #define MY_CPU_IA64
+  #define MY_CPU_NAME "ia64"
+  #define MY_CPU_64BIT
+#endif
+
+
+#if  defined(__mips64) \
+  || defined(__mips64__) \
+  || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3))
+  #define MY_CPU_NAME "mips64"
+  #define MY_CPU_64BIT
+#elif defined(__mips__)
+  #define MY_CPU_NAME "mips"
+  /* #define MY_CPU_32BIT */
+#endif
+
+
+#if  defined(__ppc64__) \
+  || defined(__powerpc64__)
+  #ifdef __ILP32__
+    #define MY_CPU_NAME "ppc64-32"
+  #else
+    #define MY_CPU_NAME "ppc64"
+  #endif
+  #define MY_CPU_64BIT
+#elif defined(__ppc__) \
+  || defined(__powerpc__)
+  #define MY_CPU_NAME "ppc"
+  #define MY_CPU_32BIT
+#endif
+
+
+#if  defined(__sparc64__)
+  #define MY_CPU_NAME "sparc64"
+  #define MY_CPU_64BIT
+#elif defined(__sparc__)
+  #define MY_CPU_NAME "sparc"
+  /* #define MY_CPU_32BIT */
+#endif
+
+
+#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
+#define MY_CPU_X86_OR_AMD64
+#endif
+
+
+#ifdef _WIN32
+
+  #ifdef MY_CPU_ARM
+  #define MY_CPU_ARM_LE
+  #endif
+
+  #ifdef MY_CPU_ARM64
+  #define MY_CPU_ARM64_LE
+  #endif
+
+  #ifdef _M_IA64
+  #define MY_CPU_IA64_LE
+  #endif
+
+#endif
+
+
+#if defined(MY_CPU_X86_OR_AMD64) \
+    || defined(MY_CPU_ARM_LE) \
+    || defined(MY_CPU_ARM64_LE) \
+    || defined(MY_CPU_IA64_LE) \
+    || defined(__LITTLE_ENDIAN__) \
+    || defined(__ARMEL__) \
+    || defined(__THUMBEL__) \
+    || defined(__AARCH64EL__) \
+    || defined(__MIPSEL__) \
+    || defined(__MIPSEL) \
+    || defined(_MIPSEL) \
+    || defined(__BFIN__) \
+    || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+  #define MY_CPU_LE
+#endif
+
+#if defined(__BIG_ENDIAN__) \
+    || defined(__ARMEB__) \
+    || defined(__THUMBEB__) \
+    || defined(__AARCH64EB__) \
+    || defined(__MIPSEB__) \
+    || defined(__MIPSEB) \
+    || defined(_MIPSEB) \
+    || defined(__m68k__) \
+    || defined(__s390__) \
+    || defined(__s390x__) \
+    || defined(__zarch__) \
+    || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+  #define MY_CPU_BE
+#endif
+
+
+#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
+  #error Stop_Compiling_Bad_Endian
+#endif
+
+
+#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT)
+  #error Stop_Compiling_Bad_32_64_BIT
+#endif
+
+
+#ifndef MY_CPU_NAME
+  #ifdef MY_CPU_LE
+    #define MY_CPU_NAME "LE"
+  #elif defined(MY_CPU_BE)
+    #define MY_CPU_NAME "BE"
+  #else
+    /*
+    #define MY_CPU_NAME ""
+    */
+  #endif
+#endif
+
+
+
+
+
+#ifdef MY_CPU_LE
+  #if defined(MY_CPU_X86_OR_AMD64) \
+      || defined(MY_CPU_ARM64) \
+      || defined(__ARM_FEATURE_UNALIGNED)
+    #define MY_CPU_LE_UNALIGN
+  #endif
+#endif
+
+
+#ifdef MY_CPU_LE_UNALIGN
+
+#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
+#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
+#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
+
+#define SetUi16(p, v) { *(UInt16 *)(p) = (v); }
+#define SetUi32(p, v) { *(UInt32 *)(p) = (v); }
+#define SetUi64(p, v) { *(UInt64 *)(p) = (v); }
+
+#else
+
+#define GetUi16(p) ( (UInt16) ( \
+             ((const Byte *)(p))[0] | \
+    ((UInt16)((const Byte *)(p))[1] << 8) ))
+
+#define GetUi32(p) ( \
+             ((const Byte *)(p))[0]        | \
+    ((UInt32)((const Byte *)(p))[1] <<  8) | \
+    ((UInt32)((const Byte *)(p))[2] << 16) | \
+    ((UInt32)((const Byte *)(p))[3] << 24))
+
+#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
+
+#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+    _ppp_[0] = (Byte)_vvv_; \
+    _ppp_[1] = (Byte)(_vvv_ >> 8); }
+
+#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+    _ppp_[0] = (Byte)_vvv_; \
+    _ppp_[1] = (Byte)(_vvv_ >> 8); \
+    _ppp_[2] = (Byte)(_vvv_ >> 16); \
+    _ppp_[3] = (Byte)(_vvv_ >> 24); }
+
+#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
+    SetUi32(_ppp2_    , (UInt32)_vvv2_); \
+    SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
+
+#endif
+
+#ifdef __has_builtin
+  #define MY__has_builtin(x) __has_builtin(x)
+#else
+  #define MY__has_builtin(x) 0
+#endif
+
+#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300)
+
+/* Note: we use bswap instruction, that is unsupported in 386 cpu */
+
+#include <stdlib.h>
+
+#pragma intrinsic(_byteswap_ushort)
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+
+/* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */
+#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
+
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
+
+#elif defined(MY_CPU_LE_UNALIGN) && ( \
+       (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
+    || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) )
+
+/* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const Byte *)(p)) */
+#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p))
+
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
+
+#else
+
+#define GetBe32(p) ( \
+    ((UInt32)((const Byte *)(p))[0] << 24) | \
+    ((UInt32)((const Byte *)(p))[1] << 16) | \
+    ((UInt32)((const Byte *)(p))[2] <<  8) | \
+             ((const Byte *)(p))[3] )
+
+#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
+
+#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+    _ppp_[0] = (Byte)(_vvv_ >> 24); \
+    _ppp_[1] = (Byte)(_vvv_ >> 16); \
+    _ppp_[2] = (Byte)(_vvv_ >> 8); \
+    _ppp_[3] = (Byte)_vvv_; }
+
+#endif
+
+
+#ifndef GetBe16
+
+#define GetBe16(p) ( (UInt16) ( \
+    ((UInt16)((const Byte *)(p))[0] << 8) | \
+             ((const Byte *)(p))[1] ))
+
+#endif
+
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+typedef struct
+{
+  UInt32 maxFunc;
+  UInt32 vendor[3];
+  UInt32 ver;
+  UInt32 b;
+  UInt32 c;
+  UInt32 d;
+} Cx86cpuid;
+
+enum
+{
+  CPU_FIRM_INTEL,
+  CPU_FIRM_AMD,
+  CPU_FIRM_VIA
+};
+
+void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
+
+BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p);
+int x86cpuid_GetFirm(const Cx86cpuid *p);
+
+#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
+#define x86cpuid_GetModel(ver)  (((ver >> 12) &  0xF0) | ((ver >> 4) & 0xF))
+#define x86cpuid_GetStepping(ver) (ver & 0xF)
+
+BoolInt CPU_Is_InOrder();
+BoolInt CPU_Is_Aes_Supported();
+BoolInt CPU_IsSupported_PageGB();
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/Delta.h b/deps/libchdr/deps/lzma-19.00/include/Delta.h
new file mode 100644 (file)
index 0000000..2fa54ad
--- /dev/null
@@ -0,0 +1,19 @@
+/* Delta.h -- Delta converter
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __DELTA_H
+#define __DELTA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define DELTA_STATE_SIZE 256
+
+void Delta_Init(Byte *state);
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/LzFind.h b/deps/libchdr/deps/lzma-19.00/include/LzFind.h
new file mode 100644 (file)
index 0000000..42c13be
--- /dev/null
@@ -0,0 +1,121 @@
+/* LzFind.h -- Match finder for LZ algorithms
+2017-06-10 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_FIND_H
+#define __LZ_FIND_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+typedef UInt32 CLzRef;
+
+typedef struct _CMatchFinder
+{
+  Byte *buffer;
+  UInt32 pos;
+  UInt32 posLimit;
+  UInt32 streamPos;
+  UInt32 lenLimit;
+
+  UInt32 cyclicBufferPos;
+  UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+  Byte streamEndWasReached;
+  Byte btMode;
+  Byte bigHash;
+  Byte directInput;
+
+  UInt32 matchMaxLen;
+  CLzRef *hash;
+  CLzRef *son;
+  UInt32 hashMask;
+  UInt32 cutValue;
+
+  Byte *bufferBase;
+  ISeqInStream *stream;
+  
+  UInt32 blockSize;
+  UInt32 keepSizeBefore;
+  UInt32 keepSizeAfter;
+
+  UInt32 numHashBytes;
+  size_t directInputRem;
+  UInt32 historySize;
+  UInt32 fixedHashSize;
+  UInt32 hashSizeSum;
+  SRes result;
+  UInt32 crc[256];
+  size_t numRefs;
+
+  UInt64 expectedDataSize;
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+#define Inline_MatchFinder_IsFinishedOK(p) \
+    ((p)->streamEndWasReached \
+        && (p)->streamPos == (p)->pos \
+        && (!(p)->directInput || (p)->directInputRem == 0))
+      
+int MatchFinder_NeedMove(CMatchFinder *p);
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* Conditions:
+     historySize <= 3 GB
+     keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
+*/
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+    ISzAllocPtr alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems);
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+    UInt32 *distances, UInt32 maxLen);
+
+/*
+Conditions:
+  Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+  Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct _IMatchFinder
+{
+  Mf_Init_Func Init;
+  Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+  Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+  Mf_GetMatches_Func GetMatches;
+  Mf_Skip_Func Skip;
+} IMatchFinder;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+
+void MatchFinder_Init_LowHash(CMatchFinder *p);
+void MatchFinder_Init_HighHash(CMatchFinder *p);
+void MatchFinder_Init_3(CMatchFinder *p, int readData);
+void MatchFinder_Init(CMatchFinder *p);
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/LzHash.h b/deps/libchdr/deps/lzma-19.00/include/LzHash.h
new file mode 100644 (file)
index 0000000..e7c9423
--- /dev/null
@@ -0,0 +1,57 @@
+/* LzHash.h -- HASH functions for LZ algorithms
+2015-04-12 : Igor Pavlov : Public domain */
+
+#ifndef __LZ_HASH_H
+#define __LZ_HASH_H
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+#define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+  h2 = temp & (kHash2Size - 1); \
+  hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+  h2 = temp & (kHash2Size - 1); \
+  temp ^= ((UInt32)cur[2] << 8); \
+  h3 = temp & (kHash3Size - 1); \
+  hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+  h2 = temp & (kHash2Size - 1); \
+  temp ^= ((UInt32)cur[2] << 8); \
+  h3 = temp & (kHash3Size - 1); \
+  temp ^= (p->crc[cur[3]] << 5); \
+  h4 = temp & (kHash4Size - 1); \
+  hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; }
+
+/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+  h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+  h2 = temp & (kHash2Size - 1); \
+  h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+  UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+  h2 = temp & (kHash2Size - 1); \
+  temp ^= ((UInt32)cur[2] << 8); \
+  h3 = temp & (kHash3Size - 1); \
+  h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/Lzma86.h b/deps/libchdr/deps/lzma-19.00/include/Lzma86.h
new file mode 100644 (file)
index 0000000..bebed5c
--- /dev/null
@@ -0,0 +1,111 @@
+/* Lzma86.h -- LZMA + x86 (BCJ) Filter
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA86_H
+#define __LZMA86_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define LZMA86_SIZE_OFFSET (1 + 5)
+#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8)
+
+/*
+It's an example for LZMA + x86 Filter use.
+You can use .lzma86 extension, if you write that stream to file.
+.lzma86 header adds one additional byte to standard .lzma header.
+.lzma86 header (14 bytes):
+  Offset Size  Description
+    0     1    = 0 - no filter, pure LZMA
+               = 1 - x86 filter + LZMA
+    1     1    lc, lp and pb in encoded form
+    2     4    dictSize (little endian)
+    6     8    uncompressed size (little endian)
+
+
+Lzma86_Encode
+-------------
+level - compression level: 0 <= level <= 9, the default value for "level" is 5.
+
+dictSize - The dictionary size in bytes. The maximum value is
+        128 MB = (1 << 27) bytes for 32-bit version
+          1 GB = (1 << 30) bytes for 64-bit version
+     The default value is 16 MB = (1 << 24) bytes, for level = 5.
+     It's recommended to use the dictionary that is larger than 4 KB and
+     that can be calculated as (1 << N) or (3 << N) sizes.
+     For better compression ratio dictSize must be >= inSize.
+
+filterMode:
+    SZ_FILTER_NO   - no Filter
+    SZ_FILTER_YES  - x86 Filter
+    SZ_FILTER_AUTO - it tries both alternatives to select best.
+              Encoder will use 2 or 3 passes:
+              2 passes when FILTER_NO provides better compression.
+              3 passes when FILTER_YES provides better compression.
+
+Lzma86Encode allocates Data with MyAlloc functions.
+RAM Requirements for compressing:
+  RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize
+      filterMode     FilterBlockSize
+     SZ_FILTER_NO         0
+     SZ_FILTER_YES      inSize
+     SZ_FILTER_AUTO     inSize
+
+
+Return code:
+  SZ_OK               - OK
+  SZ_ERROR_MEM        - Memory allocation error
+  SZ_ERROR_PARAM      - Incorrect paramater
+  SZ_ERROR_OUTPUT_EOF - output buffer overflow
+  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
+*/
+
+enum ESzFilterMode
+{
+  SZ_FILTER_NO,
+  SZ_FILTER_YES,
+  SZ_FILTER_AUTO
+};
+
+SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
+    int level, UInt32 dictSize, int filterMode);
+
+
+/*
+Lzma86_GetUnpackSize:
+  In:
+    src      - input data
+    srcLen   - input data size
+  Out:
+    unpackSize - size of uncompressed stream
+  Return code:
+    SZ_OK               - OK
+    SZ_ERROR_INPUT_EOF  - Error in headers
+*/
+
+SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize);
+
+/*
+Lzma86_Decode:
+  In:
+    dest     - output data
+    destLen  - output data size
+    src      - input data
+    srcLen   - input data size
+  Out:
+    destLen  - processed output size
+    srcLen   - processed input size
+  Return code:
+    SZ_OK           - OK
+    SZ_ERROR_DATA  - Data error
+    SZ_ERROR_MEM   - Memory allocation error
+    SZ_ERROR_UNSUPPORTED - unsupported file
+    SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer
+*/
+
+SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen);
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/LzmaDec.h b/deps/libchdr/deps/lzma-19.00/include/LzmaDec.h
new file mode 100644 (file)
index 0000000..1f0927a
--- /dev/null
@@ -0,0 +1,234 @@
+/* LzmaDec.h -- LZMA Decoder
+2018-04-21 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_DEC_H
+#define __LZMA_DEC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+   but memory usage for CLzmaDec::probs will be doubled in that case */
+
+typedef
+#ifdef _LZMA_PROB32
+  UInt32
+#else
+  UInt16
+#endif
+  CLzmaProb;
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+  Byte lc;
+  Byte lp;
+  Byte pb;
+  Byte _pad_;
+  UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+  SZ_OK
+  SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+   Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+  /* Don't change this structure. ASM code can use it. */
+  CLzmaProps prop;
+  CLzmaProb *probs;
+  CLzmaProb *probs_1664;
+  Byte *dic;
+  SizeT dicBufSize;
+  SizeT dicPos;
+  const Byte *buf;
+  UInt32 range;
+  UInt32 code;
+  UInt32 processedPos;
+  UInt32 checkDicSize;
+  UInt32 reps[4];
+  UInt32 state;
+  UInt32 remainLen;
+
+  UInt32 numProbs;
+  unsigned tempBufSize;
+  Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = NULL; (p)->probs = NULL; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+     - Stream with end mark. That end mark adds about 6 bytes to compressed size.
+     - Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+  LZMA_FINISH_ANY,   /* finish at any point */
+  LZMA_FINISH_END    /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+   You must use LZMA_FINISH_END, when you know that current output buffer
+   covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+   If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+   and output value of destLen will be less than output buffer size limit.
+   You can check status result also.
+
+   You can use multiple checks to test data integrity after full decompression:
+     1) Check Result and "status" variable.
+     2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+     3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+        You must use correct finish mode in that case. */
+
+typedef enum
+{
+  LZMA_STATUS_NOT_SPECIFIED,               /* use main error code instead */
+  LZMA_STATUS_FINISHED_WITH_MARK,          /* stream was finished with end mark. */
+  LZMA_STATUS_NOT_FINISHED,                /* stream was not finished */
+  LZMA_STATUS_NEEDS_MORE_INPUT,            /* you must provide more input bytes */
+  LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK  /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+     1) Dictionary Interface
+     2) Buffer Interface
+     3) One Call Interface
+   You can select any of these interfaces, but don't mix functions from different
+   groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+     1) LzmaDec_Allocate / LzmaDec_Free
+     2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+   You can use variant 2, if you set dictionary buffer manually.
+   For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+  SZ_OK
+  SZ_ERROR_MEM         - Memory allocation error
+  SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+   
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
+void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+   dictionary to some other external buffer.
+   You must work with CLzmaDec variables directly in this interface.
+
+   STEPS:
+     LzmaDec_Construct()
+     LzmaDec_Allocate()
+     for (each new stream)
+     {
+       LzmaDec_Init()
+       while (it needs more decompression)
+       {
+         LzmaDec_DecodeToDic()
+         use data from CLzmaDec::dic and update CLzmaDec::dicPos
+       }
+     }
+     LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+   
+   The decoding to internal dictionary buffer (CLzmaDec::dic).
+   You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+  It has meaning only if the decoding reaches output limit (dicLimit).
+  LZMA_FINISH_ANY - Decode just dicLimit bytes.
+  LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+  SZ_OK
+    status:
+      LZMA_STATUS_FINISHED_WITH_MARK
+      LZMA_STATUS_NOT_FINISHED
+      LZMA_STATUS_NEEDS_MORE_INPUT
+      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+  SZ_ERROR_DATA - Data error
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+   See LzmaDec_DecodeToDic description for information about STEPS and return results,
+   but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+   to work with CLzmaDec variables manually.
+
+finishMode:
+  It has meaning only if the decoding reaches output limit (*destLen).
+  LZMA_FINISH_ANY - Decode just destLen bytes.
+  LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+    const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+  It has meaning only if the decoding reaches output limit (*destLen).
+  LZMA_FINISH_ANY - Decode just destLen bytes.
+  LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+  SZ_OK
+    status:
+      LZMA_STATUS_FINISHED_WITH_MARK
+      LZMA_STATUS_NOT_FINISHED
+      LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+  SZ_ERROR_DATA - Data error
+  SZ_ERROR_MEM  - Memory allocation error
+  SZ_ERROR_UNSUPPORTED - Unsupported properties
+  SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+    ELzmaStatus *status, ISzAllocPtr alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/LzmaEnc.h b/deps/libchdr/deps/lzma-19.00/include/LzmaEnc.h
new file mode 100644 (file)
index 0000000..9194ee5
--- /dev/null
@@ -0,0 +1,76 @@
+/*  LzmaEnc.h -- LZMA Encoder
+2017-07-27 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_ENC_H
+#define __LZMA_ENC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaEncProps
+{
+  int level;       /* 0 <= level <= 9 */
+  UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
+                      (1 << 12) <= dictSize <= (3 << 29) for 64-bit version
+                      default = (1 << 24) */
+  int lc;          /* 0 <= lc <= 8, default = 3 */
+  int lp;          /* 0 <= lp <= 4, default = 0 */
+  int pb;          /* 0 <= pb <= 4, default = 2 */
+  int algo;        /* 0 - fast, 1 - normal, default = 1 */
+  int fb;          /* 5 <= fb <= 273, default = 32 */
+  int btMode;      /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
+  int numHashBytes; /* 2, 3 or 4, default = 4 */
+  UInt32 mc;       /* 1 <= mc <= (1 << 30), default = 32 */
+  unsigned writeEndMark;  /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
+  int numThreads;  /* 1 or 2, default = 2 */
+
+  UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1.
+                        Encoder uses this value to reduce dictionary size */
+} CLzmaEncProps;
+
+void LzmaEncProps_Init(CLzmaEncProps *p);
+void LzmaEncProps_Normalize(CLzmaEncProps *p);
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+
+
+/* ---------- CLzmaEncHandle Interface ---------- */
+
+/* LzmaEnc* functions can return the following exit codes:
+SRes:
+  SZ_OK           - OK
+  SZ_ERROR_MEM    - Memory allocation error
+  SZ_ERROR_PARAM  - Incorrect paramater in props
+  SZ_ERROR_WRITE  - ISeqOutStream write callback error
+  SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
+  SZ_ERROR_PROGRESS - some break from progress callback
+  SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
+*/
+
+typedef void * CLzmaEncHandle;
+
+CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc);
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+
+SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize);
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p);
+
+SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
+    ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+    int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+
+
+/* ---------- One Call Interface ---------- */
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+    ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/LzmaLib.h b/deps/libchdr/deps/lzma-19.00/include/LzmaLib.h
new file mode 100644 (file)
index 0000000..88fa87d
--- /dev/null
@@ -0,0 +1,131 @@
+/* LzmaLib.h -- LZMA library interface
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_LIB_H
+#define __LZMA_LIB_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define MY_STDAPI int MY_STD_CALL
+
+#define LZMA_PROPS_SIZE 5
+
+/*
+RAM requirements for LZMA:
+  for compression:   (dictSize * 11.5 + 6 MB) + state_size
+  for decompression: dictSize + state_size
+    state_size = (4 + (1.5 << (lc + lp))) KB
+    by default (lc=3, lp=0), state_size = 16 KB.
+
+LZMA properties (5 bytes) format
+    Offset Size  Description
+      0     1    lc, lp and pb in encoded form.
+      1     4    dictSize (little endian).
+*/
+
+/*
+LzmaCompress
+------------
+
+outPropsSize -
+     In:  the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
+     Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
+
+  LZMA Encoder will use defult values for any parameter, if it is
+  -1  for any from: level, loc, lp, pb, fb, numThreads
+   0  for dictSize
+  
+level - compression level: 0 <= level <= 9;
+
+  level dictSize algo  fb
+    0:    16 KB   0    32
+    1:    64 KB   0    32
+    2:   256 KB   0    32
+    3:     1 MB   0    32
+    4:     4 MB   0    32
+    5:    16 MB   1    32
+    6:    32 MB   1    32
+    7+:   64 MB   1    64
+  The default value for "level" is 5.
+
+  algo = 0 means fast method
+  algo = 1 means normal method
+
+dictSize - The dictionary size in bytes. The maximum value is
+        128 MB = (1 << 27) bytes for 32-bit version
+          1 GB = (1 << 30) bytes for 64-bit version
+     The default value is 16 MB = (1 << 24) bytes.
+     It's recommended to use the dictionary that is larger than 4 KB and
+     that can be calculated as (1 << N) or (3 << N) sizes.
+
+lc - The number of literal context bits (high bits of previous literal).
+     It can be in the range from 0 to 8. The default value is 3.
+     Sometimes lc=4 gives the gain for big files.
+
+lp - The number of literal pos bits (low bits of current position for literals).
+     It can be in the range from 0 to 4. The default value is 0.
+     The lp switch is intended for periodical data when the period is equal to 2^lp.
+     For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's
+     better to set lc=0, if you change lp switch.
+
+pb - The number of pos bits (low bits of current position).
+     It can be in the range from 0 to 4. The default value is 2.
+     The pb switch is intended for periodical data when the period is equal 2^pb.
+
+fb - Word size (the number of fast bytes).
+     It can be in the range from 5 to 273. The default value is 32.
+     Usually, a big number gives a little bit better compression ratio and
+     slower compression process.
+
+numThreads - The number of thereads. 1 or 2. The default value is 2.
+     Fast mode (algo = 0) can use only 1 thread.
+
+Out:
+  destLen  - processed output size
+Returns:
+  SZ_OK               - OK
+  SZ_ERROR_MEM        - Memory allocation error
+  SZ_ERROR_PARAM      - Incorrect paramater
+  SZ_ERROR_OUTPUT_EOF - output buffer overflow
+  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
+*/
+
+MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
+  unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */
+  int level,      /* 0 <= level <= 9, default = 5 */
+  unsigned dictSize,  /* default = (1 << 24) */
+  int lc,        /* 0 <= lc <= 8, default = 3  */
+  int lp,        /* 0 <= lp <= 4, default = 0  */
+  int pb,        /* 0 <= pb <= 4, default = 2  */
+  int fb,        /* 5 <= fb <= 273, default = 32 */
+  int numThreads /* 1 or 2, default = 2 */
+  );
+
+/*
+LzmaUncompress
+--------------
+In:
+  dest     - output data
+  destLen  - output data size
+  src      - input data
+  srcLen   - input data size
+Out:
+  destLen  - processed output size
+  srcLen   - processed input size
+Returns:
+  SZ_OK                - OK
+  SZ_ERROR_DATA        - Data error
+  SZ_ERROR_MEM         - Memory allocation arror
+  SZ_ERROR_UNSUPPORTED - Unsupported properties
+  SZ_ERROR_INPUT_EOF   - it needs more bytes in input buffer (src)
+*/
+
+MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen,
+  const unsigned char *props, size_t propsSize);
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/Precomp.h b/deps/libchdr/deps/lzma-19.00/include/Precomp.h
new file mode 100644 (file)
index 0000000..e8ff8b4
--- /dev/null
@@ -0,0 +1,10 @@
+/* Precomp.h -- StdAfx
+2013-11-12 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_PRECOMP_H
+#define __7Z_PRECOMP_H
+
+#include "Compiler.h"
+/* #include "7zTypes.h" */
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/include/Sort.h b/deps/libchdr/deps/lzma-19.00/include/Sort.h
new file mode 100644 (file)
index 0000000..2e2963a
--- /dev/null
@@ -0,0 +1,18 @@
+/* Sort.h -- Sort functions
+2014-04-05 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_SORT_H
+#define __7Z_SORT_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+void HeapSort(UInt32 *p, size_t size);
+void HeapSort64(UInt64 *p, size_t size);
+
+/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */
+
+EXTERN_C_END
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/lzma-history.txt b/deps/libchdr/deps/lzma-19.00/lzma-history.txt
new file mode 100644 (file)
index 0000000..48ee748
--- /dev/null
@@ -0,0 +1,446 @@
+HISTORY of the LZMA SDK
+-----------------------
+
+19.00          2019-02-21
+-------------------------
+- Encryption strength for 7z archives was increased:
+  the size of random initialization vector was increased from 64-bit to 128-bit,
+  and the pseudo-random number generator was improved.
+- The bug in 7zIn.c code was fixed.
+
+
+18.06          2018-12-30
+-------------------------
+- The speed for LZMA/LZMA2 compressing was increased by 3-10%,
+  and there are minor changes in compression ratio.
+- Some bugs were fixed.
+- The bug in 7-Zip 18.02-18.05 was fixed:
+  There was memory leak in multithreading xz decoder - XzDecMt_Decode(),
+  if xz stream contains only one block.
+- The changes for MSVS compiler makefiles: 
+   - the makefiles now use "PLATFORM" macroname with values (x64, x86, arm64)
+     instead of "CPU" macroname with values (AMD64, ARM64).
+   - the makefiles by default now use static version of the run-time library.
+
+
+18.05          2018-04-30
+-------------------------
+- The speed for LZMA/LZMA2 compressing was increased 
+    by 8% for fastest/fast compression levels and 
+    by 3% for normal/maximum compression levels.
+- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in
+  Windows 10 because of some BUG with "Large Pages" in Windows 10. 
+  Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299).
+- The BUG was fixed in Lzma2Enc.c
+    Lzma2Enc_Encode2() function worked incorretly,
+      if (inStream == NULL) and the number of block threads is more than 1.
+
+
+18.03 beta     2018-03-04
+-------------------------
+- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm 
+  for x64 with about 30% higher speed than main version of LZMA decoder written in C.
+- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%.
+- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
+  if there are multiple independent data chunks in LZMA2 stream.
+- 7-Zip now can use multi-threading for xz decoding,
+  if there are multiple blocks in xz stream.
+
+
+18.01          2019-01-28
+-------------------------
+- The BUG in 17.01 - 18.00 beta was fixed:
+  XzDec.c : random block unpacking and XzUnpacker_IsBlockFinished()
+  didn't work correctly for xz archives without checksum (CRC).
+
+
+18.00 beta     2019-01-10
+-------------------------
+- The BUG in xz encoder was fixed:
+  There was memory leak of 16 KB for each file compressed with 
+  xz compression method, if additional filter was used.
+
+
+17.01 beta     2017-08-28
+-------------------------
+- Minor speed optimization for LZMA2 (xz and 7z) multi-threading compression.
+  7-Zip now uses additional memory buffers for multi-block LZMA2 compression.
+  CPU utilization was slightly improved.
+- 7-zip now creates multi-block xz archives by default. Block size can be 
+  specified with -ms[Size]{m|g} switch.
+- xz decoder now can unpack random block from multi-block xz archives.
+- 7-Zip command line: @listfile now doesn't work after -- switch.
+  Use -i@listfile before -- switch instead.
+- The BUGs were fixed:
+  7-Zip 17.00 beta crashed for commands that write anti-item to 7z archive.
+
+
+17.00 beta     2017-04-29
+-------------------------
+- NewHandler.h / NewHandler.cpp: 
+    now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900).
+- C/7zTypes.h : the names of variables in interface structures were changed (vt).
+- Some bugs were fixed. 7-Zip could crash in some cases.
+- Some internal changes in code.
+
+
+16.04          2016-10-04
+-------------------------
+- The bug was fixed in DllSecur.c.
+
+
+16.03          2016-09-28
+-------------------------
+- SFX modules now use some protection against DLL preloading attack.
+- Some bugs in 7z code were fixed.
+
+
+16.02          2016-05-21
+-------------------------
+- The BUG in 16.00 - 16.01 was fixed:
+  Split Handler (SplitHandler.cpp) returned incorrect 
+  total size value (kpidSize) for split archives.
+
+
+16.01          2016-05-19
+-------------------------      
+- Some internal changes to reduce the number of compiler warnings.
+
+
+16.00          2016-05-10
+-------------------------      
+- Some bugs were fixed.
+
+
+15.12          2015-11-19
+-------------------------      
+- The BUG in C version of 7z decoder was fixed:
+  7zDec.c : SzDecodeLzma2()
+  7z decoder could mistakenly report about decoding error for some 7z archives
+  that use LZMA2 compression method.
+  The probability to get that mistaken decoding error report was about 
+  one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size). 
+- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed:
+  7zArcIn.c : SzReadHeader2()
+  7z decoder worked incorrectly for 7z archives that contain 
+  empty solid blocks, that can be placed to 7z archive, if some file is 
+  unavailable for reading during archive creation.
+
+
+15.09 beta     2015-10-16
+-------------------------      
+- The BUG in LZMA / LZMA2 encoding code was fixed.
+  The BUG in LzFind.c::MatchFinder_ReadBlock() function.
+  If input data size is larger than (4 GiB - dictionary_size),
+  the following code worked incorrectly:
+  -  LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions 
+     for compressing from memory to memory. 
+     That BUG is not related to LZMA encoder version that works via streams.
+  -  LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if 
+     default value of chunk size (CLzma2EncProps::blockSize) is changed 
+     to value larger than (4 GiB - dictionary_size).
+
+
+9.38 beta      2015-01-03
+-------------------------      
+- The BUG in 9.31-9.37 was fixed:
+  IArchiveGetRawProps interface was disabled for 7z archives.
+- The BUG in 9.26-9.36 was fixed:
+  Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows.
+
+
+9.36 beta      2014-12-26
+-------------------------      
+- The BUG in command line version was fixed:
+  7-Zip created temporary archive in current folder during update archive
+  operation, if -w{Path} switch was not specified. 
+  The fixed 7-Zip creates temporary archive in folder that contains updated archive.
+- The BUG in 9.33-9.35 was fixed:
+  7-Zip silently ignored file reading errors during 7z or gz archive creation,
+  and the created archive contained only part of file that was read before error.
+  The fixed 7-Zip stops archive creation and it reports about error.
+
+
+9.35 beta      2014-12-07
+-------------------------      
+- 7zr.exe now support AES encryption.
+- SFX mudules were added to LZMA SDK
+- Some bugs were fixed.
+
+
+9.21 beta      2011-04-11
+-------------------------      
+- New class FString for file names at file systems.
+- Speed optimization in CRC code for big-endian CPUs.
+- The BUG in Lzma2Dec.c was fixed:
+    Lzma2Decode function didn't work.
+
+
+9.18 beta      2010-11-02
+-------------------------      
+- New small SFX module for installers (SfxSetup).
+
+
+9.12 beta      2010-03-24
+-------------------------
+- The BUG in LZMA SDK 9.* was fixed: LZMA2 codec didn't work,
+  if more than 10 threads were used (or more than 20 threads in some modes).
+
+
+9.11 beta      2010-03-15
+-------------------------
+- PPMd compression method support
+   
+
+9.09           2009-12-12
+-------------------------
+- The bug was fixed:
+   Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c
+   incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8.
+- Some bugs were fixed
+
+
+9.06           2009-08-17
+-------------------------
+- Some changes in ANSI-C 7z Decoder interfaces.
+
+
+9.04           2009-05-30
+-------------------------
+- LZMA2 compression method support
+- xz format support
+
+
+4.65           2009-02-03
+-------------------------
+- Some minor fixes
+
+
+4.63           2008-12-31
+-------------------------
+- Some minor fixes
+
+
+4.61 beta      2008-11-23
+-------------------------
+- The bug in ANSI-C LZMA Decoder was fixed:
+    If encoded stream was corrupted, decoder could access memory 
+    outside of allocated range.
+- Some changes in ANSI-C 7z Decoder interfaces.
+- LZMA SDK is placed in the public domain.
+
+
+4.60 beta      2008-08-19
+-------------------------
+- Some minor fixes.
+
+
+4.59 beta      2008-08-13
+-------------------------
+- The bug was fixed:
+    LZMA Encoder in fast compression mode could access memory outside of 
+    allocated range in some rare cases.
+
+
+4.58 beta      2008-05-05
+-------------------------
+- ANSI-C LZMA Decoder was rewritten for speed optimizations.
+- ANSI-C LZMA Encoder was included to LZMA SDK.
+- C++ LZMA code now is just wrapper over ANSI-C code.
+
+
+4.57           2007-12-12
+-------------------------
+- Speed optimizations in Ã‘++ LZMA Decoder. 
+- Small changes for more compatibility with some C/C++ compilers.
+
+
+4.49 beta      2007-07-05
+-------------------------
+- .7z ANSI-C Decoder:
+     - now it supports BCJ and BCJ2 filters
+     - now it supports files larger than 4 GB.
+     - now it supports "Last Write Time" field for files.
+- C++ code for .7z archives compressing/decompressing from 7-zip 
+  was included to LZMA SDK.
+  
+
+4.43           2006-06-04
+-------------------------
+- Small changes for more compatibility with some C/C++ compilers.
+  
+
+4.42           2006-05-15
+-------------------------
+- Small changes in .h files in ANSI-C version.
+  
+
+4.39 beta      2006-04-14
+-------------------------
+- The bug in versions 4.33b:4.38b was fixed:
+  C++ version of LZMA encoder could not correctly compress 
+  files larger than 2 GB with HC4 match finder (-mfhc4).
+  
+
+4.37 beta      2005-04-06
+-------------------------
+- Fixes in C++ code: code could no be compiled if _NO_EXCEPTIONS was defined. 
+
+
+4.35 beta      2005-03-02
+-------------------------
+- The bug was fixed in C++ version of LZMA Decoder:
+    If encoded stream was corrupted, decoder could access memory 
+    outside of allocated range.
+
+
+4.34 beta      2006-02-27
+-------------------------
+- Compressing speed and memory requirements for compressing were increased
+- LZMA now can use only these match finders: HC4, BT2, BT3, BT4
+
+
+4.32           2005-12-09
+-------------------------
+- Java version of LZMA SDK was included
+
+
+4.30           2005-11-20
+-------------------------
+- Compression ratio was improved in -a2 mode
+- Speed optimizations for compressing in -a2 mode
+- -fb switch now supports values up to 273
+- The bug in 7z_C (7zIn.c) was fixed:
+  It used Alloc/Free functions from different memory pools.
+  So if program used two memory pools, it worked incorrectly.
+- 7z_C: .7z format supporting was improved
+- LZMA# SDK (C#.NET version) was included
+
+
+4.27 (Updated) 2005-09-21
+-------------------------
+- Some GUIDs/interfaces in C++ were changed.
+ IStream.h:
+   ISequentialInStream::Read now works as old ReadPart
+   ISequentialOutStream::Write now works as old WritePart
+
+
+4.27           2005-08-07
+-------------------------
+- The bug in LzmaDecodeSize.c was fixed:
+   if _LZMA_IN_CB and _LZMA_OUT_READ were defined,
+   decompressing worked incorrectly.
+
+
+4.26           2005-08-05
+-------------------------
+- Fixes in 7z_C code and LzmaTest.c:
+  previous versions could work incorrectly,
+  if malloc(0) returns 0
+
+
+4.23           2005-06-29
+-------------------------
+- Small fixes in C++ code
+
+
+4.22           2005-06-10
+-------------------------
+- Small fixes
+
+
+4.21           2005-06-08
+-------------------------
+- Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed
+- New additional version of ANSI-C LZMA Decoder with zlib-like interface:
+    - LzmaStateDecode.h
+    - LzmaStateDecode.c
+    - LzmaStateTest.c
+- ANSI-C LZMA Decoder now can decompress files larger than 4 GB
+
+
+4.17           2005-04-18
+-------------------------
+- New example for RAM->RAM compressing/decompressing: 
+  LZMA + BCJ (filter for x86 code):
+    - LzmaRam.h
+    - LzmaRam.cpp
+    - LzmaRamDecode.h
+    - LzmaRamDecode.c
+    - -f86 switch for lzma.exe
+
+
+4.16           2005-03-29
+-------------------------
+- The bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder): 
+   If _LZMA_OUT_READ was defined, and if encoded stream was corrupted,
+   decoder could access memory outside of allocated range.
+- Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster).
+  Old version of LZMA Decoder now is in file LzmaDecodeSize.c. 
+  LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c
+- Small speed optimization in LZMA C++ code
+- filter for SPARC's code was added
+- Simplified version of .7z ANSI-C Decoder was included
+
+
+4.06           2004-09-05
+-------------------------
+- The bug in v4.05 was fixed:
+    LZMA-Encoder didn't release output stream in some cases.
+
+
+4.05           2004-08-25
+-------------------------
+- Source code of filters for x86, IA-64, ARM, ARM-Thumb 
+  and PowerPC code was included to SDK
+- Some internal minor changes
+
+
+4.04           2004-07-28
+-------------------------
+- More compatibility with some C++ compilers
+
+
+4.03           2004-06-18
+-------------------------
+- "Benchmark" command was added. It measures compressing 
+  and decompressing speed and shows rating values. 
+  Also it checks hardware errors.
+
+
+4.02           2004-06-10
+-------------------------
+- C++ LZMA Encoder/Decoder code now is more portable
+  and it can be compiled by GCC on Linux.
+
+
+4.01           2004-02-15
+-------------------------
+- Some detection of data corruption was enabled.
+    LzmaDecode.c / RangeDecoderReadByte
+    .....
+    {
+      rd->ExtraBytes = 1;
+      return 0xFF;
+    }
+
+
+4.00           2004-02-13
+-------------------------
+- Original version of LZMA SDK
+
+
+
+HISTORY of the LZMA
+-------------------
+  2001-2008:  Improvements to LZMA compressing/decompressing code, 
+              keeping compatibility with original LZMA format
+  1996-2001:  Development of LZMA compression format
+
+  Some milestones:
+
+  2001-08-30: LZMA compression was added to 7-Zip
+  1999-01-02: First version of 7-Zip was released
+  
+
+End of document
diff --git a/deps/libchdr/deps/lzma-19.00/lzma.txt b/deps/libchdr/deps/lzma-19.00/lzma.txt
new file mode 100644 (file)
index 0000000..a65988f
--- /dev/null
@@ -0,0 +1,328 @@
+LZMA compression
+----------------
+Version: 9.35
+
+This file describes LZMA encoding and decoding functions written in C language.
+
+LZMA is an improved version of famous LZ77 compression algorithm. 
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for 
+decompressing.
+
+Note: you can read also LZMA Specification (lzma-specification.txt from LZMA SDK)
+
+Also you can look source code for LZMA encoding and decoding:
+  C/Util/Lzma/LzmaUtil.c
+
+
+LZMA compressed file format
+---------------------------
+Offset Size Description
+  0     1   Special LZMA properties (lc,lp, pb in encoded form)
+  1     4   Dictionary size (little endian)
+  5     8   Uncompressed size (little endian). -1 means unknown size
+ 13         Compressed data
+
+
+
+ANSI-C LZMA Decoder
+~~~~~~~~~~~~~~~~~~~
+
+Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
+If you want to use old interfaces you can download previous version of LZMA SDK
+from sourceforge.net site.
+
+To use ANSI-C LZMA Decoder you need the following files:
+1) LzmaDec.h + LzmaDec.c + 7zTypes.h + Precomp.h + Compiler.h
+
+Look example code:
+  C/Util/Lzma/LzmaUtil.c
+
+
+Memory requirements for LZMA decoding
+-------------------------------------
+
+Stack usage of LZMA decoding function for local variables is not 
+larger than 200-400 bytes.
+
+LZMA Decoder uses dictionary buffer and internal state structure.
+Internal state structure consumes
+  state_size = (4 + (1.5 << (lc + lp))) KB
+by default (lc=3, lp=0), state_size = 16 KB.
+
+
+How To decompress data
+----------------------
+
+LZMA Decoder (ANSI-C version) now supports 2 interfaces:
+1) Single-call Decompressing
+2) Multi-call State Decompressing (zlib-like interface)
+
+You must use external allocator:
+Example:
+void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
+void SzFree(void *p, void *address) { p = p; free(address); }
+ISzAlloc alloc = { SzAlloc, SzFree };
+
+You can use p = p; operator to disable compiler warnings.
+
+
+Single-call Decompressing
+-------------------------
+When to use: RAM->RAM decompressing
+Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h
+Compile defines: no defines
+Memory Requirements:
+  - Input buffer: compressed size
+  - Output buffer: uncompressed size
+  - LZMA Internal Structures: state_size (16 KB for default settings) 
+
+Interface:
+  int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+      const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, 
+      ELzmaStatus *status, ISzAlloc *alloc);
+  In: 
+    dest     - output data
+    destLen  - output data size
+    src      - input data
+    srcLen   - input data size
+    propData - LZMA properties  (5 bytes)
+    propSize - size of propData buffer (5 bytes)
+    finishMode - It has meaning only if the decoding reaches output limit (*destLen).
+         LZMA_FINISH_ANY - Decode just destLen bytes.
+         LZMA_FINISH_END - Stream must be finished after (*destLen).
+                           You can use LZMA_FINISH_END, when you know that 
+                           current output buffer covers last bytes of stream. 
+    alloc    - Memory allocator.
+
+  Out: 
+    destLen  - processed output size 
+    srcLen   - processed input size 
+
+  Output:
+    SZ_OK
+      status:
+        LZMA_STATUS_FINISHED_WITH_MARK
+        LZMA_STATUS_NOT_FINISHED 
+        LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+    SZ_ERROR_DATA - Data error
+    SZ_ERROR_MEM  - Memory allocation error
+    SZ_ERROR_UNSUPPORTED - Unsupported properties
+    SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+
+  If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
+  and output value of destLen will be less than output buffer size limit.
+
+  You can use multiple checks to test data integrity after full decompression:
+    1) Check Result and "status" variable.
+    2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+    3) Check that output(srcLen) = compressedSize, if you know real compressedSize. 
+       You must use correct finish mode in that case. */ 
+
+
+Multi-call State Decompressing (zlib-like interface)
+----------------------------------------------------
+
+When to use: file->file decompressing 
+Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h
+
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures: state_size (16 KB for default settings) 
+ - LZMA dictionary (dictionary size is encoded in LZMA properties header)
+
+1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
+   unsigned char header[LZMA_PROPS_SIZE + 8];
+   ReadFile(inFile, header, sizeof(header)
+
+2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
+
+  CLzmaDec state;
+  LzmaDec_Constr(&state);
+  res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
+  if (res != SZ_OK)
+    return res;
+
+3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
+
+  LzmaDec_Init(&state);
+  for (;;)
+  {
+    ... 
+    int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, 
+        const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
+    ...
+  }
+
+
+4) Free all allocated structures
+  LzmaDec_Free(&state, &g_Alloc);
+
+Look example code:
+  C/Util/Lzma/LzmaUtil.c
+
+
+How To compress data
+--------------------
+
+Compile files: 
+  7zTypes.h
+  Threads.h    
+  LzmaEnc.h
+  LzmaEnc.c
+  LzFind.h
+  LzFind.c
+  LzFindMt.h
+  LzFindMt.c
+  LzHash.h
+
+Memory Requirements:
+  - (dictSize * 11.5 + 6 MB) + state_size
+
+Lzma Encoder can use two memory allocators:
+1) alloc - for small arrays.
+2) allocBig - for big arrays.
+
+For example, you can use Large RAM Pages (2 MB) in allocBig allocator for 
+better compression speed. Note that Windows has bad implementation for 
+Large RAM Pages. 
+It's OK to use same allocator for alloc and allocBig.
+
+
+Single-call Compression with callbacks
+--------------------------------------
+
+Look example code:
+  C/Util/Lzma/LzmaUtil.c
+
+When to use: file->file compressing 
+
+1) you must implement callback structures for interfaces:
+ISeqInStream
+ISeqOutStream
+ICompressProgress
+ISzAlloc
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) {  p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+  CFileSeqInStream inStream;
+  CFileSeqOutStream outStream;
+
+  inStream.funcTable.Read = MyRead;
+  inStream.file = inFile;
+  outStream.funcTable.Write = MyWrite;
+  outStream.file = outFile;
+
+
+2) Create CLzmaEncHandle object;
+
+  CLzmaEncHandle enc;
+
+  enc = LzmaEnc_Create(&g_Alloc);
+  if (enc == 0)
+    return SZ_ERROR_MEM;
+
+
+3) initialize CLzmaEncProps properties;
+
+  LzmaEncProps_Init(&props);
+
+  Then you can change some properties in that structure.
+
+4) Send LZMA properties to LZMA Encoder
+
+  res = LzmaEnc_SetProps(enc, &props);
+
+5) Write encoded properties to header
+
+    Byte header[LZMA_PROPS_SIZE + 8];
+    size_t headerSize = LZMA_PROPS_SIZE;
+    UInt64 fileSize;
+    int i;
+
+    res = LzmaEnc_WriteProperties(enc, header, &headerSize);
+    fileSize = MyGetFileLength(inFile);
+    for (i = 0; i < 8; i++)
+      header[headerSize++] = (Byte)(fileSize >> (8 * i));
+    MyWriteFileAndCheck(outFile, header, headerSize)
+
+6) Call encoding function:
+      res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable, 
+        NULL, &g_Alloc, &g_Alloc);
+
+7) Destroy LZMA Encoder Object
+  LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
+
+
+If callback function return some error code, LzmaEnc_Encode also returns that code
+or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS.
+
+
+Single-call RAM->RAM Compression
+--------------------------------
+
+Single-call RAM->RAM Compression is similar to Compression with callbacks,
+but you provide pointers to buffers instead of pointers to stream callbacks:
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+    const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, 
+    ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+Return code:
+  SZ_OK               - OK
+  SZ_ERROR_MEM        - Memory allocation error 
+  SZ_ERROR_PARAM      - Incorrect paramater
+  SZ_ERROR_OUTPUT_EOF - output buffer overflow
+  SZ_ERROR_THREAD     - errors in multithreading functions (only for Mt version)
+
+
+
+Defines
+-------
+
+_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.
+
+_LZMA_PROB32   - It can increase the speed on some 32-bit CPUs, but memory usage for 
+                 some structures will be doubled in that case.
+
+_LZMA_UINT32_IS_ULONG  - Define it if int is 16-bit on your compiler and long is 32-bit.
+
+_LZMA_NO_SYSTEM_SIZE_T  - Define it if you don't want to use size_t type.
+
+
+_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder.
+
+
+C++ LZMA Encoder/Decoder 
+~~~~~~~~~~~~~~~~~~~~~~~~
+C++ LZMA code use COM-like interfaces. So if you want to use it, 
+you can study basics of COM/OLE.
+C++ LZMA code is just wrapper over ANSI-C code.
+
+
+C++ Notes
+~~~~~~~~~~~~~~~~~~~~~~~~
+If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling),
+you must check that you correctly work with "new" operator.
+7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
+So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator:
+operator new(size_t size)
+{
+  void *p = ::malloc(size);
+  if (p == 0)
+    throw CNewException();
+  return p;
+}
+If you use MSCV that throws exception for "new" operator, you can compile without 
+"NewHandler.cpp". So standard exception will be used. Actually some code of 
+7-Zip catches any exception in internal code and converts it to HRESULT code.
+So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/deps/libchdr/deps/lzma-19.00/lzma.vcxproj b/deps/libchdr/deps/lzma-19.00/lzma.vcxproj
new file mode 100644 (file)
index 0000000..a421035
--- /dev/null
@@ -0,0 +1,543 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+  <ItemGroup Label="ProjectConfigurations">\r
+    <ProjectConfiguration Include="DebugFast|ARM64">\r
+      <Configuration>DebugFast</Configuration>\r
+      <Platform>ARM64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="DebugFast|Win32">\r
+      <Configuration>DebugFast</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="DebugFast|x64">\r
+      <Configuration>DebugFast</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Debug|ARM64">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>ARM64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Debug|Win32">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Debug|x64">\r
+      <Configuration>Debug</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="ReleaseLTCG|ARM64">\r
+      <Configuration>ReleaseLTCG</Configuration>\r
+      <Platform>ARM64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="ReleaseLTCG|Win32">\r
+      <Configuration>ReleaseLTCG</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="ReleaseLTCG|x64">\r
+      <Configuration>ReleaseLTCG</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|ARM64">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>ARM64</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|Win32">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>Win32</Platform>\r
+    </ProjectConfiguration>\r
+    <ProjectConfiguration Include="Release|x64">\r
+      <Configuration>Release</Configuration>\r
+      <Platform>x64</Platform>\r
+    </ProjectConfiguration>\r
+  </ItemGroup>\r
+  <ItemGroup>\r
+    <ClCompile Include="src\Alloc.c" />\r
+    <ClCompile Include="src\Bra86.c" />\r
+    <ClCompile Include="src\BraIA64.c" />\r
+    <ClCompile Include="src\CpuArch.c" />\r
+    <ClCompile Include="src\Delta.c" />\r
+    <ClCompile Include="src\LzFind.c" />\r
+    <ClCompile Include="src\Lzma86Dec.c" />\r
+    <ClCompile Include="src\Lzma86Enc.c" />\r
+    <ClCompile Include="src\LzmaDec.c" />\r
+    <ClCompile Include="src\LzmaEnc.c" />\r
+    <ClCompile Include="src\LzmaLib.c" />\r
+    <ClCompile Include="src\Sort.c" />\r
+  </ItemGroup>\r
+  <PropertyGroup Label="Globals">\r
+    <ProjectGuid>{DD944834-7899-4C1C-A4C1-064B5009D239}</ProjectGuid>\r
+    <Keyword>Win32Proj</Keyword>\r
+    <RootNamespace>lzma</RootNamespace>\r
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>true</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+    <SpectreMitigation>false</SpectreMitigation>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+    <SpectreMitigation>false</SpectreMitigation>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+    <SpectreMitigation>false</SpectreMitigation>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+    <SpectreMitigation>false</SpectreMitigation>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+    <SpectreMitigation>false</SpectreMitigation>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'" Label="Configuration">\r
+    <ConfigurationType>StaticLibrary</ConfigurationType>\r
+    <UseDebugLibraries>false</UseDebugLibraries>\r
+    <PlatformToolset>v142</PlatformToolset>\r
+    <WholeProgramOptimization>true</WholeProgramOptimization>\r
+    <CharacterSet>NotSet</CharacterSet>\r
+    <SpectreMitigation>false</SpectreMitigation>\r
+  </PropertyGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
+  <ImportGroup Label="ExtensionSettings">\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'" Label="PropertySheets">\r
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
+  </ImportGroup>\r
+  <PropertyGroup Label="UserMacros" />\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+    <LinkIncremental>true</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'">\r
+    <IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>\r
+    <TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>\r
+    <LinkIncremental>false</LinkIncremental>\r
+    <OutDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</OutDir>\r
+  </PropertyGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <MinimalRebuild>false</MinimalRebuild>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <MinimalRebuild>false</MinimalRebuild>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <MinimalRebuild>false</MinimalRebuild>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_ITERATOR_DEBUG_LEVEL=1;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\r
+      <MinimalRebuild>false</MinimalRebuild>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <SupportJustMyCode>false</SupportJustMyCode>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_ITERATOR_DEBUG_LEVEL=1;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\r
+      <MinimalRebuild>false</MinimalRebuild>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <SupportJustMyCode>false</SupportJustMyCode>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">\r
+    <ClCompile>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <Optimization>Disabled</Optimization>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_ITERATOR_DEBUG_LEVEL=1;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <SDLCheck>true</SDLCheck>\r
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\r
+      <MinimalRebuild>false</MinimalRebuild>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <SupportJustMyCode>false</SupportJustMyCode>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
+    <ClCompile>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <WholeProgramOptimization>false</WholeProgramOptimization>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">\r
+    <ClCompile>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <WholeProgramOptimization>true</WholeProgramOptimization>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <OmitFramePointers>true</OmitFramePointers>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
+    <ClCompile>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <WholeProgramOptimization>false</WholeProgramOptimization>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">\r
+    <ClCompile>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <WholeProgramOptimization>false</WholeProgramOptimization>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">\r
+    <ClCompile>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <WholeProgramOptimization>true</WholeProgramOptimization>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <OmitFramePointers>true</OmitFramePointers>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'">\r
+    <ClCompile>\r
+      <WarningLevel>Level2</WarningLevel>\r
+      <PrecompiledHeader>\r
+      </PrecompiledHeader>\r
+      <Optimization>MaxSpeed</Optimization>\r
+      <IntrinsicFunctions>true</IntrinsicFunctions>\r
+      <PreprocessorDefinitions>_7ZIP_ST;_CRT_NONSTDC_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
+      <AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
+      <WholeProgramOptimization>true</WholeProgramOptimization>\r
+      <LanguageStandard>stdcpp17</LanguageStandard>\r
+      <OmitFramePointers>true</OmitFramePointers>\r
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r
+      <ConformanceMode>true</ConformanceMode>\r
+      <AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>\r
+    </ClCompile>\r
+    <Link>\r
+      <SubSystem>Windows</SubSystem>\r
+      <GenerateDebugInformation>true</GenerateDebugInformation>\r
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
+      <OptimizeReferences>true</OptimizeReferences>\r
+    </Link>\r
+  </ItemDefinitionGroup>\r
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
+  <ImportGroup Label="ExtensionTargets">\r
+  </ImportGroup>\r
+</Project>
\ No newline at end of file
diff --git a/deps/libchdr/deps/lzma-19.00/lzma.vcxproj.filters b/deps/libchdr/deps/lzma-19.00/lzma.vcxproj.filters
new file mode 100644 (file)
index 0000000..8725b39
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="src\BraIA64.c" />
+    <ClCompile Include="src\CpuArch.c" />
+    <ClCompile Include="src\Delta.c" />
+    <ClCompile Include="src\LzFind.c" />
+    <ClCompile Include="src\Lzma86Dec.c" />
+    <ClCompile Include="src\Lzma86Enc.c" />
+    <ClCompile Include="src\LzmaDec.c" />
+    <ClCompile Include="src\LzmaEnc.c" />
+    <ClCompile Include="src\LzmaLib.c" />
+    <ClCompile Include="src\Sort.c" />
+    <ClCompile Include="src\Alloc.c" />
+    <ClCompile Include="src\Bra86.c" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/deps/libchdr/deps/lzma-19.00/src/Alloc.c b/deps/libchdr/deps/lzma-19.00/src/Alloc.c
new file mode 100644 (file)
index 0000000..bcede4b
--- /dev/null
@@ -0,0 +1,455 @@
+/* Alloc.c -- Memory allocation functions
+2018-04-27 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdio.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <stdlib.h>
+
+#include "Alloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+#ifdef _SZ_ALLOC_DEBUG
+
+#include <stdio.h>
+int g_allocCount = 0;
+int g_allocCountMid = 0;
+int g_allocCountBig = 0;
+
+
+#define CONVERT_INT_TO_STR(charType, tempSize) \
+  unsigned char temp[tempSize]; unsigned i = 0; \
+  while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \
+  *s++ = (charType)('0' + (unsigned)val); \
+  while (i != 0) { i--; *s++ = temp[i]; } \
+  *s = 0;
+
+static void ConvertUInt64ToString(UInt64 val, char *s)
+{
+  CONVERT_INT_TO_STR(char, 24);
+}
+
+#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
+
+static void ConvertUInt64ToHex(UInt64 val, char *s)
+{
+  UInt64 v = val;
+  unsigned i;
+  for (i = 1;; i++)
+  {
+    v >>= 4;
+    if (v == 0)
+      break;
+  }
+  s[i] = 0;
+  do
+  {
+    unsigned t = (unsigned)(val & 0xF);
+    val >>= 4;
+    s[--i] = GET_HEX_CHAR(t);
+  }
+  while (i);
+}
+
+#define DEBUG_OUT_STREAM stderr
+
+static void Print(const char *s)
+{
+  fputs(s, DEBUG_OUT_STREAM);
+}
+
+static void PrintAligned(const char *s, size_t align)
+{
+  size_t len = strlen(s);
+  for(;;)
+  {
+    fputc(' ', DEBUG_OUT_STREAM);
+    if (len >= align)
+      break;
+    ++len;
+  }
+  Print(s);
+}
+
+static void PrintLn()
+{
+  Print("\n");
+}
+
+static void PrintHex(UInt64 v, size_t align)
+{
+  char s[32];
+  ConvertUInt64ToHex(v, s);
+  PrintAligned(s, align);
+}
+
+static void PrintDec(UInt64 v, size_t align)
+{
+  char s[32];
+  ConvertUInt64ToString(v, s);
+  PrintAligned(s, align);
+}
+
+static void PrintAddr(void *p)
+{
+  PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);
+}
+
+
+#define PRINT_ALLOC(name, cnt, size, ptr) \
+    Print(name " "); \
+    PrintDec(cnt++, 10); \
+    PrintHex(size, 10); \
+    PrintAddr(ptr); \
+    PrintLn();
+#define PRINT_FREE(name, cnt, ptr) if (ptr) { \
+    Print(name " "); \
+    PrintDec(--cnt, 10); \
+    PrintAddr(ptr); \
+    PrintLn(); }
+#else
+
+#define PRINT_ALLOC(name, cnt, size, ptr)
+#define PRINT_FREE(name, cnt, ptr)
+#define Print(s)
+#define PrintLn()
+#define PrintHex(v, align)
+#define PrintDec(v, align)
+#define PrintAddr(p)
+
+#endif
+
+
+
+void *MyAlloc(size_t size)
+{
+  if (size == 0)
+    return NULL;
+  #ifdef _SZ_ALLOC_DEBUG
+  {
+    void *p = malloc(size);
+    PRINT_ALLOC("Alloc    ", g_allocCount, size, p);
+    return p;
+  }
+  #else
+  return malloc(size);
+  #endif
+}
+
+void MyFree(void *address)
+{
+  PRINT_FREE("Free    ", g_allocCount, address);
+  
+  free(address);
+}
+
+#ifdef _WIN32
+
+void *MidAlloc(size_t size)
+{
+  if (size == 0)
+    return NULL;
+  
+  PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, NULL);
+  
+  return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void MidFree(void *address)
+{
+  PRINT_FREE("Free-Mid", g_allocCountMid, address);
+
+  if (!address)
+    return;
+  VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#ifndef MEM_LARGE_PAGES
+#undef _7ZIP_LARGE_PAGES
+#endif
+
+#ifdef _7ZIP_LARGE_PAGES
+SIZE_T g_LargePageSize = 0;
+typedef SIZE_T (WINAPI *GetLargePageMinimumP)();
+#endif
+
+void SetLargePageSize()
+{
+  #ifdef _7ZIP_LARGE_PAGES
+  SIZE_T size;
+  GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
+        GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
+  if (!largePageMinimum)
+    return;
+  size = largePageMinimum();
+  if (size == 0 || (size & (size - 1)) != 0)
+    return;
+  g_LargePageSize = size;
+  #endif
+}
+
+
+void *BigAlloc(size_t size)
+{
+  if (size == 0)
+    return NULL;
+
+  PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL);
+  
+  #ifdef _7ZIP_LARGE_PAGES
+  {
+    SIZE_T ps = g_LargePageSize;
+    if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))
+    {
+      size_t size2;
+      ps--;
+      size2 = (size + ps) & ~ps;
+      if (size2 >= size)
+      {
+        void *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
+        if (res)
+          return res;
+      }
+    }
+  }
+  #endif
+
+  return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
+}
+
+void BigFree(void *address)
+{
+  PRINT_FREE("Free-Big", g_allocCountBig, address);
+  
+  if (!address)
+    return;
+  VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#endif
+
+
+static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); }
+static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); }
+const ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); }
+static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); }
+const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
+
+static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); }
+static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); }
+const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+
+
+/*
+  uintptr_t : <stdint.h> C99 (optional)
+            : unsupported in VS6
+*/
+
+#ifdef _WIN32
+  typedef UINT_PTR UIntPtr;
+#else
+  /*
+  typedef uintptr_t UIntPtr;
+  */
+  typedef ptrdiff_t UIntPtr;
+#endif
+
+
+#define ADJUST_ALLOC_SIZE 0
+/*
+#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)
+*/
+/*
+  Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if
+     MyAlloc() can return address that is NOT multiple of sizeof(void *).
+*/
+
+
+/*
+#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1))))
+*/
+#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1))))
+
+#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)
+
+
+#if (_POSIX_C_SOURCE >= 200112L) && !defined(_WIN32)
+  #define USE_posix_memalign
+#endif
+
+/*
+  This posix_memalign() is for test purposes only.
+  We also need special Free() function instead of free(),
+  if this posix_memalign() is used.
+*/
+
+/*
+static int posix_memalign(void **ptr, size_t align, size_t size)
+{
+  size_t newSize = size + align;
+  void *p;
+  void *pAligned;
+  *ptr = NULL;
+  if (newSize < size)
+    return 12; // ENOMEM
+  p = MyAlloc(newSize);
+  if (!p)
+    return 12; // ENOMEM
+  pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);
+  ((void **)pAligned)[-1] = p;
+  *ptr = pAligned;
+  return 0;
+}
+*/
+
+/*
+  ALLOC_ALIGN_SIZE >= sizeof(void *)
+  ALLOC_ALIGN_SIZE >= cache_line_size
+*/
+
+#define ALLOC_ALIGN_SIZE ((size_t)1 << 7)
+
+static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)
+{
+  #ifndef USE_posix_memalign
+  
+  void *p;
+  void *pAligned;
+  size_t newSize;
+  UNUSED_VAR(pp);
+
+  /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
+     block to prevent cache line sharing with another allocated blocks */
+
+  newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;
+  if (newSize < size)
+    return NULL;
+
+  p = MyAlloc(newSize);
+  
+  if (!p)
+    return NULL;
+  pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);
+
+  Print(" size="); PrintHex(size, 8);
+  Print(" a_size="); PrintHex(newSize, 8);
+  Print(" ptr="); PrintAddr(p);
+  Print(" a_ptr="); PrintAddr(pAligned);
+  PrintLn();
+
+  ((void **)pAligned)[-1] = p;
+
+  return pAligned;
+
+  #else
+
+  void *p;
+  UNUSED_VAR(pp);
+  if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))
+    return NULL;
+
+  Print(" posix_memalign="); PrintAddr(p);
+  PrintLn();
+
+  return p;
+
+  #endif
+}
+
+
+static void SzAlignedFree(ISzAllocPtr pp, void *address)
+{
+  UNUSED_VAR(pp);
+  #ifndef USE_posix_memalign
+  if (address)
+    MyFree(((void **)address)[-1]);
+  #else
+  free(address);
+  #endif
+}
+
+
+const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
+
+
+
+#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))
+
+/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */
+#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]
+/*
+#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1]
+*/
+
+static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)
+{
+  CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);
+  void *adr;
+  void *pAligned;
+  size_t newSize;
+  size_t extra;
+  size_t alignSize = (size_t)1 << p->numAlignBits;
+
+  if (alignSize < sizeof(void *))
+    alignSize = sizeof(void *);
+  
+  if (p->offset >= alignSize)
+    return NULL;
+
+  /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
+     block to prevent cache line sharing with another allocated blocks */
+  extra = p->offset & (sizeof(void *) - 1);
+  newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;
+  if (newSize < size)
+    return NULL;
+
+  adr = ISzAlloc_Alloc(p->baseAlloc, newSize);
+  
+  if (!adr)
+    return NULL;
+
+  pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +
+      alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;
+
+  PrintLn();
+  Print("- Aligned: ");
+  Print(" size="); PrintHex(size, 8);
+  Print(" a_size="); PrintHex(newSize, 8);
+  Print(" ptr="); PrintAddr(adr);
+  Print(" a_ptr="); PrintAddr(pAligned);
+  PrintLn();
+
+  REAL_BLOCK_PTR_VAR(pAligned) = adr;
+
+  return pAligned;
+}
+
+
+static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)
+{
+  if (address)
+  {
+    CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);
+    PrintLn();
+    Print("- Aligned Free: ");
+    PrintLn();
+    ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));
+  }
+}
+
+
+void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)
+{
+  p->vt.Alloc = AlignOffsetAlloc_Alloc;
+  p->vt.Free = AlignOffsetAlloc_Free;
+}
diff --git a/deps/libchdr/deps/lzma-19.00/src/Bra86.c b/deps/libchdr/deps/lzma-19.00/src/Bra86.c
new file mode 100644 (file)
index 0000000..93ed4d7
--- /dev/null
@@ -0,0 +1,82 @@
+/* Bra86.c -- Converter for x86 code (BCJ)
+2017-04-03 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+
+#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0)
+
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
+{
+  SizeT pos = 0;
+  UInt32 mask = *state & 7;
+  if (size < 5)
+    return 0;
+  size -= 4;
+  ip += 5;
+
+  for (;;)
+  {
+    Byte *p = data + pos;
+    const Byte *limit = data + size;
+    for (; p < limit; p++)
+      if ((*p & 0xFE) == 0xE8)
+        break;
+
+    {
+      SizeT d = (SizeT)(p - data - pos);
+      pos = (SizeT)(p - data);
+      if (p >= limit)
+      {
+        *state = (d > 2 ? 0 : mask >> (unsigned)d);
+        return pos;
+      }
+      if (d > 2)
+        mask = 0;
+      else
+      {
+        mask >>= (unsigned)d;
+        if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(size_t)(mask >> 1) + 1])))
+        {
+          mask = (mask >> 1) | 4;
+          pos++;
+          continue;
+        }
+      }
+    }
+
+    if (Test86MSByte(p[4]))
+    {
+      UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+      UInt32 cur = ip + (UInt32)pos;
+      pos += 5;
+      if (encoding)
+        v += cur;
+      else
+        v -= cur;
+      if (mask != 0)
+      {
+        unsigned sh = (mask & 6) << 2;
+        if (Test86MSByte((Byte)(v >> sh)))
+        {
+          v ^= (((UInt32)0x100 << sh) - 1);
+          if (encoding)
+            v += cur;
+          else
+            v -= cur;
+        }
+        mask = 0;
+      }
+      p[1] = (Byte)v;
+      p[2] = (Byte)(v >> 8);
+      p[3] = (Byte)(v >> 16);
+      p[4] = (Byte)(0 - ((v >> 24) & 1));
+    }
+    else
+    {
+      mask = (mask >> 1) | 4;
+      pos++;
+    }
+  }
+}
diff --git a/deps/libchdr/deps/lzma-19.00/src/BraIA64.c b/deps/libchdr/deps/lzma-19.00/src/BraIA64.c
new file mode 100644 (file)
index 0000000..d1dbc62
--- /dev/null
@@ -0,0 +1,53 @@
+/* BraIA64.c -- Converter for IA-64 code
+2017-01-26 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+#include "Bra.h"
+
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+  SizeT i;
+  if (size < 16)
+    return 0;
+  size -= 16;
+  i = 0;
+  do
+  {
+    unsigned m = ((UInt32)0x334B0000 >> (data[i] & 0x1E)) & 3;
+    if (m)
+    {
+      m++;
+      do
+      {
+        Byte *p = data + (i + (size_t)m * 5 - 8);
+        if (((p[3] >> m) & 15) == 5
+            && (((p[-1] | ((UInt32)p[0] << 8)) >> m) & 0x70) == 0)
+        {
+          unsigned raw = GetUi32(p);
+          unsigned v = raw >> m;
+          v = (v & 0xFFFFF) | ((v & (1 << 23)) >> 3);
+          
+          v <<= 4;
+          if (encoding)
+            v += ip + (UInt32)i;
+          else
+            v -= ip + (UInt32)i;
+          v >>= 4;
+          
+          v &= 0x1FFFFF;
+          v += 0x700000;
+          v &= 0x8FFFFF;
+          raw &= ~((UInt32)0x8FFFFF << m);
+          raw |= (v << m);
+          SetUi32(p, raw);
+        }
+      }
+      while (++m <= 4);
+    }
+    i += 16;
+  }
+  while (i <= size);
+  return i;
+}
diff --git a/deps/libchdr/deps/lzma-19.00/src/CpuArch.c b/deps/libchdr/deps/lzma-19.00/src/CpuArch.c
new file mode 100644 (file)
index 0000000..02e482e
--- /dev/null
@@ -0,0 +1,218 @@
+/* CpuArch.c -- CPU specific code
+2018-02-18: Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
+#define USE_ASM
+#endif
+
+#if !defined(USE_ASM) && _MSC_VER >= 1500
+#include <intrin.h>
+#endif
+
+#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
+static UInt32 CheckFlag(UInt32 flag)
+{
+  #ifdef _MSC_VER
+  __asm pushfd;
+  __asm pop EAX;
+  __asm mov EDX, EAX;
+  __asm xor EAX, flag;
+  __asm push EAX;
+  __asm popfd;
+  __asm pushfd;
+  __asm pop EAX;
+  __asm xor EAX, EDX;
+  __asm push EDX;
+  __asm popfd;
+  __asm and flag, EAX;
+  #else
+  __asm__ __volatile__ (
+    "pushf\n\t"
+    "pop  %%EAX\n\t"
+    "movl %%EAX,%%EDX\n\t"
+    "xorl %0,%%EAX\n\t"
+    "push %%EAX\n\t"
+    "popf\n\t"
+    "pushf\n\t"
+    "pop  %%EAX\n\t"
+    "xorl %%EDX,%%EAX\n\t"
+    "push %%EDX\n\t"
+    "popf\n\t"
+    "andl %%EAX, %0\n\t":
+    "=c" (flag) : "c" (flag) :
+    "%eax", "%edx");
+  #endif
+  return flag;
+}
+#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
+#else
+#define CHECK_CPUID_IS_SUPPORTED
+#endif
+
+void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
+{
+  #ifdef USE_ASM
+
+  #ifdef _MSC_VER
+
+  UInt32 a2, b2, c2, d2;
+  __asm xor EBX, EBX;
+  __asm xor ECX, ECX;
+  __asm xor EDX, EDX;
+  __asm mov EAX, function;
+  __asm cpuid;
+  __asm mov a2, EAX;
+  __asm mov b2, EBX;
+  __asm mov c2, ECX;
+  __asm mov d2, EDX;
+
+  *a = a2;
+  *b = b2;
+  *c = c2;
+  *d = d2;
+
+  #else
+
+  __asm__ __volatile__ (
+  #if defined(MY_CPU_AMD64) && defined(__PIC__)
+    "mov %%rbx, %%rdi;"
+    "cpuid;"
+    "xchg %%rbx, %%rdi;"
+    : "=a" (*a) ,
+      "=D" (*b) ,
+  #elif defined(MY_CPU_X86) && defined(__PIC__)
+    "mov %%ebx, %%edi;"
+    "cpuid;"
+    "xchgl %%ebx, %%edi;"
+    : "=a" (*a) ,
+      "=D" (*b) ,
+  #else
+    "cpuid"
+    : "=a" (*a) ,
+      "=b" (*b) ,
+  #endif
+      "=c" (*c) ,
+      "=d" (*d)
+    : "0" (function)) ;
+
+  #endif
+  
+  #else
+
+  int CPUInfo[4];
+  __cpuid(CPUInfo, function);
+  *a = CPUInfo[0];
+  *b = CPUInfo[1];
+  *c = CPUInfo[2];
+  *d = CPUInfo[3];
+
+  #endif
+}
+
+BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p)
+{
+  CHECK_CPUID_IS_SUPPORTED
+  MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
+  MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
+  return True;
+}
+
+static const UInt32 kVendors[][3] =
+{
+  { 0x756E6547, 0x49656E69, 0x6C65746E},
+  { 0x68747541, 0x69746E65, 0x444D4163},
+  { 0x746E6543, 0x48727561, 0x736C7561}
+};
+
+int x86cpuid_GetFirm(const Cx86cpuid *p)
+{
+  unsigned i;
+  for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
+  {
+    const UInt32 *v = kVendors[i];
+    if (v[0] == p->vendor[0] &&
+        v[1] == p->vendor[1] &&
+        v[2] == p->vendor[2])
+      return (int)i;
+  }
+  return -1;
+}
+
+BoolInt CPU_Is_InOrder()
+{
+  Cx86cpuid p;
+  int firm;
+  UInt32 family, model;
+  if (!x86cpuid_CheckAndRead(&p))
+    return True;
+
+  family = x86cpuid_GetFamily(p.ver);
+  model = x86cpuid_GetModel(p.ver);
+  
+  firm = x86cpuid_GetFirm(&p);
+
+  switch (firm)
+  {
+    case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
+        /* In-Order Atom CPU */
+           model == 0x1C  /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
+        || model == 0x26  /* 45 nm, Z6xx */
+        || model == 0x27  /* 32 nm, Z2460 */
+        || model == 0x35  /* 32 nm, Z2760 */
+        || model == 0x36  /* 32 nm, N2xxx, D2xxx */
+        )));
+    case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
+    case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
+  }
+  return True;
+}
+
+#if !defined(MY_CPU_AMD64) && defined(_WIN32)
+#include <windows.h>
+static BoolInt CPU_Sys_Is_SSE_Supported()
+{
+  OSVERSIONINFO vi;
+  vi.dwOSVersionInfoSize = sizeof(vi);
+  if (!GetVersionEx(&vi))
+    return False;
+  return (vi.dwMajorVersion >= 5);
+}
+#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
+#else
+#define CHECK_SYS_SSE_SUPPORT
+#endif
+
+BoolInt CPU_Is_Aes_Supported()
+{
+  Cx86cpuid p;
+  CHECK_SYS_SSE_SUPPORT
+  if (!x86cpuid_CheckAndRead(&p))
+    return False;
+  return (p.c >> 25) & 1;
+}
+
+BoolInt CPU_IsSupported_PageGB()
+{
+  Cx86cpuid cpuid;
+  if (!x86cpuid_CheckAndRead(&cpuid))
+    return False;
+  {
+    UInt32 d[4] = { 0 };
+    MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]);
+    if (d[0] < 0x80000001)
+      return False;
+  }
+  {
+    UInt32 d[4] = { 0 };
+    MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]);
+    return (d[3] >> 26) & 1;
+  }
+}
+
+#endif
diff --git a/deps/libchdr/deps/lzma-19.00/src/Delta.c b/deps/libchdr/deps/lzma-19.00/src/Delta.c
new file mode 100644 (file)
index 0000000..e3edd21
--- /dev/null
@@ -0,0 +1,64 @@
+/* Delta.c -- Delta converter
+2009-05-26 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Delta.h"
+
+void Delta_Init(Byte *state)
+{
+  unsigned i;
+  for (i = 0; i < DELTA_STATE_SIZE; i++)
+    state[i] = 0;
+}
+
+static void MyMemCpy(Byte *dest, const Byte *src, unsigned size)
+{
+  unsigned i;
+  for (i = 0; i < size; i++)
+    dest[i] = src[i];
+}
+
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+  Byte buf[DELTA_STATE_SIZE];
+  unsigned j = 0;
+  MyMemCpy(buf, state, delta);
+  {
+    SizeT i;
+    for (i = 0; i < size;)
+    {
+      for (j = 0; j < delta && i < size; i++, j++)
+      {
+        Byte b = data[i];
+        data[i] = (Byte)(b - buf[j]);
+        buf[j] = b;
+      }
+    }
+  }
+  if (j == delta)
+    j = 0;
+  MyMemCpy(state, buf + j, delta - j);
+  MyMemCpy(state + delta - j, buf, j);
+}
+
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+  Byte buf[DELTA_STATE_SIZE];
+  unsigned j = 0;
+  MyMemCpy(buf, state, delta);
+  {
+    SizeT i;
+    for (i = 0; i < size;)
+    {
+      for (j = 0; j < delta && i < size; i++, j++)
+      {
+        buf[j] = data[i] = (Byte)(buf[j] + data[i]);
+      }
+    }
+  }
+  if (j == delta)
+    j = 0;
+  MyMemCpy(state, buf + j, delta - j);
+  MyMemCpy(state + delta - j, buf, j);
+}
diff --git a/deps/libchdr/deps/lzma-19.00/src/LzFind.c b/deps/libchdr/deps/lzma-19.00/src/LzFind.c
new file mode 100644 (file)
index 0000000..df55e86
--- /dev/null
@@ -0,0 +1,1127 @@
+/* LzFind.c -- Match finder for LZ algorithms
+2018-07-08 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "LzFind.h"
+#include "LzHash.h"
+
+#define kEmptyHashValue 0
+#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
+#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
+#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)7 << 29)
+
+#define kStartMaxLen 3
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)
+{
+  if (!p->directInput)
+  {
+    ISzAlloc_Free(alloc, p->bufferBase);
+    p->bufferBase = NULL;
+  }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr alloc)
+{
+  UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+  if (p->directInput)
+  {
+    p->blockSize = blockSize;
+    return 1;
+  }
+  if (!p->bufferBase || p->blockSize != blockSize)
+  {
+    LzInWindow_Free(p, alloc);
+    p->blockSize = blockSize;
+    p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, (size_t)blockSize);
+  }
+  return (p->bufferBase != NULL);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+
+UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+{
+  p->posLimit -= subValue;
+  p->pos -= subValue;
+  p->streamPos -= subValue;
+}
+
+static void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+  if (p->streamEndWasReached || p->result != SZ_OK)
+    return;
+
+  /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */
+
+  if (p->directInput)
+  {
+    UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos);
+    if (curSize > p->directInputRem)
+      curSize = (UInt32)p->directInputRem;
+    p->directInputRem -= curSize;
+    p->streamPos += curSize;
+    if (p->directInputRem == 0)
+      p->streamEndWasReached = 1;
+    return;
+  }
+  
+  for (;;)
+  {
+    Byte *dest = p->buffer + (p->streamPos - p->pos);
+    size_t size = (p->bufferBase + p->blockSize - dest);
+    if (size == 0)
+      return;
+
+    p->result = ISeqInStream_Read(p->stream, dest, &size);
+    if (p->result != SZ_OK)
+      return;
+    if (size == 0)
+    {
+      p->streamEndWasReached = 1;
+      return;
+    }
+    p->streamPos += (UInt32)size;
+    if (p->streamPos - p->pos > p->keepSizeAfter)
+      return;
+  }
+}
+
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+  memmove(p->bufferBase,
+      p->buffer - p->keepSizeBefore,
+      (size_t)(p->streamPos - p->pos) + p->keepSizeBefore);
+  p->buffer = p->bufferBase + p->keepSizeBefore;
+}
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+  if (p->directInput)
+    return 0;
+  /* if (p->streamEndWasReached) return 0; */
+  return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+  if (p->streamEndWasReached)
+    return;
+  if (p->keepSizeAfter >= p->streamPos - p->pos)
+    MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+{
+  if (MatchFinder_NeedMove(p))
+    MatchFinder_MoveBlock(p);
+  MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+  p->cutValue = 32;
+  p->btMode = 1;
+  p->numHashBytes = 4;
+  p->bigHash = 0;
+}
+
+#define kCrcPoly 0xEDB88320
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+  unsigned i;
+  p->bufferBase = NULL;
+  p->directInput = 0;
+  p->hash = NULL;
+  p->expectedDataSize = (UInt64)(Int64)-1;
+  MatchFinder_SetDefaultSettings(p);
+
+  for (i = 0; i < 256; i++)
+  {
+    UInt32 r = (UInt32)i;
+    unsigned j;
+    for (j = 0; j < 8; j++)
+      r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
+    p->crc[i] = r;
+  }
+}
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->hash);
+  p->hash = NULL;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
+{
+  MatchFinder_FreeThisClassMemory(p, alloc);
+  LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc)
+{
+  size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+  if (sizeInBytes / sizeof(CLzRef) != num)
+    return NULL;
+  return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+    UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+    ISzAllocPtr alloc)
+{
+  UInt32 sizeReserv;
+  
+  if (historySize > kMaxHistorySize)
+  {
+    MatchFinder_Free(p, alloc);
+    return 0;
+  }
+  
+  sizeReserv = historySize >> 1;
+       if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3;
+  else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2;
+  
+  sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
+
+  p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
+  p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
+  
+  /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
+  
+  if (LzInWindow_Create(p, sizeReserv, alloc))
+  {
+    UInt32 newCyclicBufferSize = historySize + 1;
+    UInt32 hs;
+    p->matchMaxLen = matchMaxLen;
+    {
+      p->fixedHashSize = 0;
+      if (p->numHashBytes == 2)
+        hs = (1 << 16) - 1;
+      else
+      {
+        hs = historySize;
+        if (hs > p->expectedDataSize)
+          hs = (UInt32)p->expectedDataSize;
+        if (hs != 0)
+          hs--;
+        hs |= (hs >> 1);
+        hs |= (hs >> 2);
+        hs |= (hs >> 4);
+        hs |= (hs >> 8);
+        hs >>= 1;
+        hs |= 0xFFFF; /* don't change it! It's required for Deflate */
+        if (hs > (1 << 24))
+        {
+          if (p->numHashBytes == 3)
+            hs = (1 << 24) - 1;
+          else
+            hs >>= 1;
+          /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
+        }
+      }
+      p->hashMask = hs;
+      hs++;
+      if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
+      if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
+      if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
+      hs += p->fixedHashSize;
+    }
+
+    {
+      size_t newSize;
+      size_t numSons;
+      p->historySize = historySize;
+      p->hashSizeSum = hs;
+      p->cyclicBufferSize = newCyclicBufferSize;
+      
+      numSons = newCyclicBufferSize;
+      if (p->btMode)
+        numSons <<= 1;
+      newSize = hs + numSons;
+
+      if (p->hash && p->numRefs == newSize)
+        return 1;
+      
+      MatchFinder_FreeThisClassMemory(p, alloc);
+      p->numRefs = newSize;
+      p->hash = AllocRefs(newSize, alloc);
+      
+      if (p->hash)
+      {
+        p->son = p->hash + p->hashSizeSum;
+        return 1;
+      }
+    }
+  }
+
+  MatchFinder_Free(p, alloc);
+  return 0;
+}
+
+static void MatchFinder_SetLimits(CMatchFinder *p)
+{
+  UInt32 limit = kMaxValForNormalize - p->pos;
+  UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
+  
+  if (limit2 < limit)
+    limit = limit2;
+  limit2 = p->streamPos - p->pos;
+  
+  if (limit2 <= p->keepSizeAfter)
+  {
+    if (limit2 > 0)
+      limit2 = 1;
+  }
+  else
+    limit2 -= p->keepSizeAfter;
+  
+  if (limit2 < limit)
+    limit = limit2;
+  
+  {
+    UInt32 lenLimit = p->streamPos - p->pos;
+    if (lenLimit > p->matchMaxLen)
+      lenLimit = p->matchMaxLen;
+    p->lenLimit = lenLimit;
+  }
+  p->posLimit = p->pos + limit;
+}
+
+
+void MatchFinder_Init_LowHash(CMatchFinder *p)
+{
+  size_t i;
+  CLzRef *items = p->hash;
+  size_t numItems = p->fixedHashSize;
+  for (i = 0; i < numItems; i++)
+    items[i] = kEmptyHashValue;
+}
+
+
+void MatchFinder_Init_HighHash(CMatchFinder *p)
+{
+  size_t i;
+  CLzRef *items = p->hash + p->fixedHashSize;
+  size_t numItems = (size_t)p->hashMask + 1;
+  for (i = 0; i < numItems; i++)
+    items[i] = kEmptyHashValue;
+}
+
+
+void MatchFinder_Init_3(CMatchFinder *p, int readData)
+{
+  p->cyclicBufferPos = 0;
+  p->buffer = p->bufferBase;
+  p->pos =
+  p->streamPos = p->cyclicBufferSize;
+  p->result = SZ_OK;
+  p->streamEndWasReached = 0;
+  
+  if (readData)
+    MatchFinder_ReadBlock(p);
+  
+  MatchFinder_SetLimits(p);
+}
+
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+  MatchFinder_Init_HighHash(p);
+  MatchFinder_Init_LowHash(p);
+  MatchFinder_Init_3(p, True);
+}
+
+  
+static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
+{
+  return (p->pos - p->historySize - 1) & kNormalizeMask;
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems)
+{
+  size_t i;
+  for (i = 0; i < numItems; i++)
+  {
+    UInt32 value = items[i];
+    if (value <= subValue)
+      value = kEmptyHashValue;
+    else
+      value -= subValue;
+    items[i] = value;
+  }
+}
+
+static void MatchFinder_Normalize(CMatchFinder *p)
+{
+  UInt32 subValue = MatchFinder_GetSubValue(p);
+  MatchFinder_Normalize3(subValue, p->hash, p->numRefs);
+  MatchFinder_ReduceOffsets(p, subValue);
+}
+
+
+MY_NO_INLINE
+static void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+  if (p->pos == kMaxValForNormalize)
+    MatchFinder_Normalize(p);
+  if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
+    MatchFinder_CheckAndMoveAndRead(p);
+  if (p->cyclicBufferPos == p->cyclicBufferSize)
+    p->cyclicBufferPos = 0;
+  MatchFinder_SetLimits(p);
+}
+
+
+/*
+  (lenLimit > maxLen)
+*/
+MY_FORCE_INLINE
+static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+    UInt32 *distances, unsigned maxLen)
+{
+  /*
+  son[_cyclicBufferPos] = curMatch;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+      return distances;
+    {
+      const Byte *pb = cur - delta;
+      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+      if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+      {
+        UInt32 len = 0;
+        while (++len != lenLimit)
+          if (pb[len] != cur[len])
+            break;
+        if (maxLen < len)
+        {
+          maxLen = len;
+          *distances++ = len;
+          *distances++ = delta - 1;
+          if (len == lenLimit)
+            return distances;
+        }
+      }
+    }
+  }
+  */
+
+  const Byte *lim = cur + lenLimit;
+  son[_cyclicBufferPos] = curMatch;
+  do
+  {
+    UInt32 delta = pos - curMatch;
+    if (delta >= _cyclicBufferSize)
+      break;
+    {
+      ptrdiff_t diff;
+      curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+      diff = (ptrdiff_t)0 - delta;
+      if (cur[maxLen] == cur[maxLen + diff])
+      {
+        const Byte *c = cur;
+        while (*c == c[diff])
+        {
+          if (++c == lim)
+          {
+            distances[0] = (UInt32)(lim - cur);
+            distances[1] = delta - 1;
+            return distances + 2;
+          }
+        }
+        {
+          unsigned len = (unsigned)(c - cur);
+          if (maxLen < len)
+          {
+            maxLen = len;
+            distances[0] = (UInt32)len;
+            distances[1] = delta - 1;
+            distances += 2;
+          }
+        }
+      }
+    }
+  }
+  while (--cutValue);
+  
+  return distances;
+}
+
+
+MY_FORCE_INLINE
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+    UInt32 *distances, UInt32 maxLen)
+{
+  CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+  CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+  unsigned len0 = 0, len1 = 0;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+    {
+      *ptr0 = *ptr1 = kEmptyHashValue;
+      return distances;
+    }
+    {
+      CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+      const Byte *pb = cur - delta;
+      unsigned len = (len0 < len1 ? len0 : len1);
+      UInt32 pair0 = pair[0];
+      if (pb[len] == cur[len])
+      {
+        if (++len != lenLimit && pb[len] == cur[len])
+          while (++len != lenLimit)
+            if (pb[len] != cur[len])
+              break;
+        if (maxLen < len)
+        {
+          maxLen = (UInt32)len;
+          *distances++ = (UInt32)len;
+          *distances++ = delta - 1;
+          if (len == lenLimit)
+          {
+            *ptr1 = pair0;
+            *ptr0 = pair[1];
+            return distances;
+          }
+        }
+      }
+      if (pb[len] < cur[len])
+      {
+        *ptr1 = curMatch;
+        ptr1 = pair + 1;
+        curMatch = *ptr1;
+        len1 = len;
+      }
+      else
+      {
+        *ptr0 = curMatch;
+        ptr0 = pair;
+        curMatch = *ptr0;
+        len0 = len;
+      }
+    }
+  }
+}
+
+static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+    UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+  CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+  CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+  unsigned len0 = 0, len1 = 0;
+  for (;;)
+  {
+    UInt32 delta = pos - curMatch;
+    if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+    {
+      *ptr0 = *ptr1 = kEmptyHashValue;
+      return;
+    }
+    {
+      CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+      const Byte *pb = cur - delta;
+      unsigned len = (len0 < len1 ? len0 : len1);
+      if (pb[len] == cur[len])
+      {
+        while (++len != lenLimit)
+          if (pb[len] != cur[len])
+            break;
+        {
+          if (len == lenLimit)
+          {
+            *ptr1 = pair[0];
+            *ptr0 = pair[1];
+            return;
+          }
+        }
+      }
+      if (pb[len] < cur[len])
+      {
+        *ptr1 = curMatch;
+        ptr1 = pair + 1;
+        curMatch = *ptr1;
+        len1 = len;
+      }
+      else
+      {
+        *ptr0 = curMatch;
+        ptr0 = pair;
+        curMatch = *ptr0;
+        len0 = len;
+      }
+    }
+  }
+}
+
+#define MOVE_POS \
+  ++p->cyclicBufferPos; \
+  p->buffer++; \
+  if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+
+#define MOVE_POS_RET MOVE_POS return (UInt32)offset;
+
+static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+  unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \
+  lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+  cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
+#define SKIP_HEADER(minLen)        GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define GET_MATCHES_FOOTER(offset, maxLen) \
+  offset = (unsigned)(GetMatchesSpec1((UInt32)lenLimit, curMatch, MF_PARAMS(p), \
+  distances + offset, (UInt32)maxLen) - distances); MOVE_POS_RET;
+
+#define SKIP_FOOTER \
+  SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+
+#define UPDATE_maxLen { \
+    ptrdiff_t diff = (ptrdiff_t)0 - d2; \
+    const Byte *c = cur + maxLen; \
+    const Byte *lim = cur + lenLimit; \
+    for (; c != lim; c++) if (*(c + diff) != *c) break; \
+    maxLen = (unsigned)(c - cur); }
+
+static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  unsigned offset;
+  GET_MATCHES_HEADER(2)
+  HASH2_CALC;
+  curMatch = p->hash[hv];
+  p->hash[hv] = p->pos;
+  offset = 0;
+  GET_MATCHES_FOOTER(offset, 1)
+}
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  unsigned offset;
+  GET_MATCHES_HEADER(3)
+  HASH_ZIP_CALC;
+  curMatch = p->hash[hv];
+  p->hash[hv] = p->pos;
+  offset = 0;
+  GET_MATCHES_FOOTER(offset, 2)
+}
+
+static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 h2, d2, pos;
+  unsigned maxLen, offset;
+  UInt32 *hash;
+  GET_MATCHES_HEADER(3)
+
+  HASH3_CALC;
+
+  hash = p->hash;
+  pos = p->pos;
+
+  d2 = pos - hash[h2];
+
+  curMatch = (hash + kFix3HashSize)[hv];
+  
+  hash[h2] = pos;
+  (hash + kFix3HashSize)[hv] = pos;
+
+  maxLen = 2;
+  offset = 0;
+
+  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+  {
+    UPDATE_maxLen
+    distances[0] = (UInt32)maxLen;
+    distances[1] = d2 - 1;
+    offset = 2;
+    if (maxLen == lenLimit)
+    {
+      SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p));
+      MOVE_POS_RET;
+    }
+  }
+  
+  GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 h2, h3, d2, d3, pos;
+  unsigned maxLen, offset;
+  UInt32 *hash;
+  GET_MATCHES_HEADER(4)
+
+  HASH4_CALC;
+
+  hash = p->hash;
+  pos = p->pos;
+
+  d2 = pos - hash                  [h2];
+  d3 = pos - (hash + kFix3HashSize)[h3];
+
+  curMatch = (hash + kFix4HashSize)[hv];
+
+  hash                  [h2] = pos;
+  (hash + kFix3HashSize)[h3] = pos;
+  (hash + kFix4HashSize)[hv] = pos;
+
+  maxLen = 0;
+  offset = 0;
+  
+  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+  {
+    maxLen = 2;
+    distances[0] = 2;
+    distances[1] = d2 - 1;
+    offset = 2;
+  }
+  
+  if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+  {
+    maxLen = 3;
+    distances[(size_t)offset + 1] = d3 - 1;
+    offset += 2;
+    d2 = d3;
+  }
+  
+  if (offset != 0)
+  {
+    UPDATE_maxLen
+    distances[(size_t)offset - 2] = (UInt32)maxLen;
+    if (maxLen == lenLimit)
+    {
+      SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p));
+      MOVE_POS_RET;
+    }
+  }
+  
+  if (maxLen < 3)
+    maxLen = 3;
+  
+  GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+/*
+static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos;
+  UInt32 *hash;
+  GET_MATCHES_HEADER(5)
+
+  HASH5_CALC;
+
+  hash = p->hash;
+  pos = p->pos;
+
+  d2 = pos - hash                  [h2];
+  d3 = pos - (hash + kFix3HashSize)[h3];
+  d4 = pos - (hash + kFix4HashSize)[h4];
+
+  curMatch = (hash + kFix5HashSize)[hv];
+
+  hash                  [h2] = pos;
+  (hash + kFix3HashSize)[h3] = pos;
+  (hash + kFix4HashSize)[h4] = pos;
+  (hash + kFix5HashSize)[hv] = pos;
+
+  maxLen = 0;
+  offset = 0;
+
+  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+  {
+    distances[0] = maxLen = 2;
+    distances[1] = d2 - 1;
+    offset = 2;
+    if (*(cur - d2 + 2) == cur[2])
+      distances[0] = maxLen = 3;
+    else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+    {
+      distances[2] = maxLen = 3;
+      distances[3] = d3 - 1;
+      offset = 4;
+      d2 = d3;
+    }
+  }
+  else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+  {
+    distances[0] = maxLen = 3;
+    distances[1] = d3 - 1;
+    offset = 2;
+    d2 = d3;
+  }
+  
+  if (d2 != d4 && d4 < p->cyclicBufferSize
+      && *(cur - d4) == *cur
+      && *(cur - d4 + 3) == *(cur + 3))
+  {
+    maxLen = 4;
+    distances[(size_t)offset + 1] = d4 - 1;
+    offset += 2;
+    d2 = d4;
+  }
+  
+  if (offset != 0)
+  {
+    UPDATE_maxLen
+    distances[(size_t)offset - 2] = maxLen;
+    if (maxLen == lenLimit)
+    {
+      SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+      MOVE_POS_RET;
+    }
+  }
+
+  if (maxLen < 4)
+    maxLen = 4;
+  
+  GET_MATCHES_FOOTER(offset, maxLen)
+}
+*/
+
+static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 h2, h3, d2, d3, pos;
+  unsigned maxLen, offset;
+  UInt32 *hash;
+  GET_MATCHES_HEADER(4)
+
+  HASH4_CALC;
+
+  hash = p->hash;
+  pos = p->pos;
+  
+  d2 = pos - hash                  [h2];
+  d3 = pos - (hash + kFix3HashSize)[h3];
+  curMatch = (hash + kFix4HashSize)[hv];
+
+  hash                  [h2] = pos;
+  (hash + kFix3HashSize)[h3] = pos;
+  (hash + kFix4HashSize)[hv] = pos;
+
+  maxLen = 0;
+  offset = 0;
+
+  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+  {
+    maxLen = 2;
+    distances[0] = 2;
+    distances[1] = d2 - 1;
+    offset = 2;
+  }
+  
+  if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+  {
+    maxLen = 3;
+    distances[(size_t)offset + 1] = d3 - 1;
+    offset += 2;
+    d2 = d3;
+  }
+  
+  if (offset != 0)
+  {
+    UPDATE_maxLen
+    distances[(size_t)offset - 2] = (UInt32)maxLen;
+    if (maxLen == lenLimit)
+    {
+      p->son[p->cyclicBufferPos] = curMatch;
+      MOVE_POS_RET;
+    }
+  }
+  
+  if (maxLen < 3)
+    maxLen = 3;
+
+  offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+      distances + offset, maxLen) - (distances));
+  MOVE_POS_RET
+}
+
+/*
+static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos
+  UInt32 *hash;
+  GET_MATCHES_HEADER(5)
+
+  HASH5_CALC;
+
+  hash = p->hash;
+  pos = p->pos;
+  
+  d2 = pos - hash                  [h2];
+  d3 = pos - (hash + kFix3HashSize)[h3];
+  d4 = pos - (hash + kFix4HashSize)[h4];
+
+  curMatch = (hash + kFix5HashSize)[hv];
+
+  hash                  [h2] = pos;
+  (hash + kFix3HashSize)[h3] = pos;
+  (hash + kFix4HashSize)[h4] = pos;
+  (hash + kFix5HashSize)[hv] = pos;
+
+  maxLen = 0;
+  offset = 0;
+
+  if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
+  {
+    distances[0] = maxLen = 2;
+    distances[1] = d2 - 1;
+    offset = 2;
+    if (*(cur - d2 + 2) == cur[2])
+      distances[0] = maxLen = 3;
+    else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+    {
+      distances[2] = maxLen = 3;
+      distances[3] = d3 - 1;
+      offset = 4;
+      d2 = d3;
+    }
+  }
+  else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
+  {
+    distances[0] = maxLen = 3;
+    distances[1] = d3 - 1;
+    offset = 2;
+    d2 = d3;
+  }
+  
+  if (d2 != d4 && d4 < p->cyclicBufferSize
+      && *(cur - d4) == *cur
+      && *(cur - d4 + 3) == *(cur + 3))
+  {
+    maxLen = 4;
+    distances[(size_t)offset + 1] = d4 - 1;
+    offset += 2;
+    d2 = d4;
+  }
+  
+  if (offset != 0)
+  {
+    UPDATE_maxLen
+    distances[(size_t)offset - 2] = maxLen;
+    if (maxLen == lenLimit)
+    {
+      p->son[p->cyclicBufferPos] = curMatch;
+      MOVE_POS_RET;
+    }
+  }
+  
+  if (maxLen < 4)
+    maxLen = 4;
+
+  offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+      distances + offset, maxLen) - (distances));
+  MOVE_POS_RET
+}
+*/
+
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+  unsigned offset;
+  GET_MATCHES_HEADER(3)
+  HASH_ZIP_CALC;
+  curMatch = p->hash[hv];
+  p->hash[hv] = p->pos;
+  offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+      distances, 2) - (distances));
+  MOVE_POS_RET
+}
+
+static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    SKIP_HEADER(2)
+    HASH2_CALC;
+    curMatch = p->hash[hv];
+    p->hash[hv] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    SKIP_HEADER(3)
+    HASH_ZIP_CALC;
+    curMatch = p->hash[hv];
+    p->hash[hv] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 h2;
+    UInt32 *hash;
+    SKIP_HEADER(3)
+    HASH3_CALC;
+    hash = p->hash;
+    curMatch = (hash + kFix3HashSize)[hv];
+    hash[h2] =
+    (hash + kFix3HashSize)[hv] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 h2, h3;
+    UInt32 *hash;
+    SKIP_HEADER(4)
+    HASH4_CALC;
+    hash = p->hash;
+    curMatch = (hash + kFix4HashSize)[hv];
+    hash                  [h2] =
+    (hash + kFix3HashSize)[h3] =
+    (hash + kFix4HashSize)[hv] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+
+/*
+static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 h2, h3, h4;
+    UInt32 *hash;
+    SKIP_HEADER(5)
+    HASH5_CALC;
+    hash = p->hash;
+    curMatch = (hash + kFix5HashSize)[hv];
+    hash                  [h2] =
+    (hash + kFix3HashSize)[h3] =
+    (hash + kFix4HashSize)[h4] =
+    (hash + kFix5HashSize)[hv] = p->pos;
+    SKIP_FOOTER
+  }
+  while (--num != 0);
+}
+*/
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 h2, h3;
+    UInt32 *hash;
+    SKIP_HEADER(4)
+    HASH4_CALC;
+    hash = p->hash;
+    curMatch = (hash + kFix4HashSize)[hv];
+    hash                  [h2] =
+    (hash + kFix3HashSize)[h3] =
+    (hash + kFix4HashSize)[hv] = p->pos;
+    p->son[p->cyclicBufferPos] = curMatch;
+    MOVE_POS
+  }
+  while (--num != 0);
+}
+
+/*
+static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    UInt32 h2, h3, h4;
+    UInt32 *hash;
+    SKIP_HEADER(5)
+    HASH5_CALC;
+    hash = p->hash;
+    curMatch = hash + kFix5HashSize)[hv];
+    hash                  [h2] =
+    (hash + kFix3HashSize)[h3] =
+    (hash + kFix4HashSize)[h4] =
+    (hash + kFix5HashSize)[hv] = p->pos;
+    p->son[p->cyclicBufferPos] = curMatch;
+    MOVE_POS
+  }
+  while (--num != 0);
+}
+*/
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+  do
+  {
+    SKIP_HEADER(3)
+    HASH_ZIP_CALC;
+    curMatch = p->hash[hv];
+    p->hash[hv] = p->pos;
+    p->son[p->cyclicBufferPos] = curMatch;
+    MOVE_POS
+  }
+  while (--num != 0);
+}
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+{
+  vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+  vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+  vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+  if (!p->btMode)
+  {
+    /* if (p->numHashBytes <= 4) */
+    {
+      vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+      vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+    }
+    /*
+    else
+    {
+      vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;
+      vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip;
+    }
+    */
+  }
+  else if (p->numHashBytes == 2)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+  }
+  else if (p->numHashBytes == 3)
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+  }
+  else /* if (p->numHashBytes == 4) */
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+  }
+  /*
+  else
+  {
+    vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;
+    vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip;
+  }
+  */
+}
diff --git a/deps/libchdr/deps/lzma-19.00/src/Lzma86Dec.c b/deps/libchdr/deps/lzma-19.00/src/Lzma86Dec.c
new file mode 100644 (file)
index 0000000..2103174
--- /dev/null
@@ -0,0 +1,54 @@
+/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder
+2016-05-16 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Lzma86.h"
+
+#include "Alloc.h"
+#include "Bra.h"
+#include "LzmaDec.h"
+
+SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize)
+{
+  unsigned i;
+  if (srcLen < LZMA86_HEADER_SIZE)
+    return SZ_ERROR_INPUT_EOF;
+  *unpackSize = 0;
+  for (i = 0; i < sizeof(UInt64); i++)
+    *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i);
+  return SZ_OK;
+}
+
+SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen)
+{
+  SRes res;
+  int useFilter;
+  SizeT inSizePure;
+  ELzmaStatus status;
+
+  if (*srcLen < LZMA86_HEADER_SIZE)
+    return SZ_ERROR_INPUT_EOF;
+
+  useFilter = src[0];
+
+  if (useFilter > 1)
+  {
+    *destLen = 0;
+    return SZ_ERROR_UNSUPPORTED;
+  }
+
+  inSizePure = *srcLen - LZMA86_HEADER_SIZE;
+  res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure,
+      src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc);
+  *srcLen = inSizePure + LZMA86_HEADER_SIZE;
+  if (res != SZ_OK)
+    return res;
+  if (useFilter == 1)
+  {
+    UInt32 x86State;
+    x86_Convert_Init(x86State);
+    x86_Convert(dest, *destLen, 0, &x86State, 0);
+  }
+  return SZ_OK;
+}
diff --git a/deps/libchdr/deps/lzma-19.00/src/LzmaDec.c b/deps/libchdr/deps/lzma-19.00/src/LzmaDec.c
new file mode 100644 (file)
index 0000000..ba3e1dd
--- /dev/null
@@ -0,0 +1,1185 @@
+/* LzmaDec.c -- LZMA Decoder
+2018-07-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #include "CpuArch.h" */
+#include "LzmaDec.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_INIT_SIZE 5
+
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+  { UPDATE_0(p); i = (i + i); A0; } else \
+  { UPDATE_1(p); i = (i + i) + 1; A1; }
+
+#define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); }
+
+#define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \
+  { UPDATE_0(p + i); A0; } else \
+  { UPDATE_1(p + i); A1; }
+#define REV_BIT_VAR(  p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; )
+#define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m;       , i += m * 2; )
+#define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m        , ; )
+
+#define TREE_DECODE(probs, limit, i) \
+  { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define _LZMA_SIZE_OPT */
+
+#ifdef _LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+  { i = 1; \
+  TREE_GET_BIT(probs, i); \
+  TREE_GET_BIT(probs, i); \
+  TREE_GET_BIT(probs, i); \
+  TREE_GET_BIT(probs, i); \
+  TREE_GET_BIT(probs, i); \
+  TREE_GET_BIT(probs, i); \
+  i -= 0x40; }
+#endif
+
+#define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol)
+#define MATCHED_LITER_DEC \
+  matchByte += matchByte; \
+  bit = offs; \
+  offs &= matchByte; \
+  probLit = prob + (offs + bit + symbol); \
+  GET_BIT2(probLit, symbol, offs ^= bit; , ;)
+
+
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+  { UPDATE_0_CHECK; i = (i + i); A0; } else \
+  { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+  { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \
+  { UPDATE_0_CHECK; i += m; m += m; } else \
+  { UPDATE_1_CHECK; m += m; i += m; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenLow 0
+#define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+#define LenChoice LenLow
+#define LenChoice2 (LenLow + (1 << kLenNumLowBits))
+
+#define kNumStates 12
+#define kNumStates2 16
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols)
+
+/* External ASM code needs same CLzmaProb array layout. So don't change it. */
+
+/* (probs_1664) is faster and better for code size at some platforms */
+/*
+#ifdef MY_CPU_X86_OR_AMD64
+*/
+#define kStartOffset 1664
+#define GET_PROBS p->probs_1664
+/*
+#define GET_PROBS p->probs + kStartOffset
+#else
+#define kStartOffset 0
+#define GET_PROBS p->probs
+#endif
+*/
+
+#define SpecPos (-kStartOffset)
+#define IsRep0Long (SpecPos + kNumFullDistances)
+#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax))
+#define LenCoder (RepLenCoder + kNumLenProbs)
+#define IsMatch (LenCoder + kNumLenProbs)
+#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax))
+#define IsRep (Align + kAlignTableSize)
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define PosSlot (IsRepG2 + kNumStates)
+#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define NUM_BASE_PROBS (Literal + kStartOffset)
+
+#if Align != 0 && kStartOffset != 0
+  #error Stop_Compiling_Bad_LZMA_kAlign
+#endif
+
+#if NUM_BASE_PROBS != 1984
+  #error Stop_Compiling_Bad_LZMA_PROBS
+#endif
+
+
+#define LZMA_LIT_SIZE 0x300
+
+#define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+
+#define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4)
+#define COMBINED_PS_STATE (posState + state)
+#define GET_LEN_STATE (posState)
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/*
+p->remainLen : shows status of LZMA decoder:
+    < kMatchSpecLenStart : normal remain
+    = kMatchSpecLenStart : finished
+    = kMatchSpecLenStart + 1 : need init range coder
+    = kMatchSpecLenStart + 2 : need init range coder and state
+*/
+
+/* ---------- LZMA_DECODE_REAL ---------- */
+/*
+LzmaDec_DecodeReal_3() can be implemented in external ASM file.
+3 - is the code compatibility version of that function for check at link time.
+*/
+
+#define LZMA_DECODE_REAL LzmaDec_DecodeReal_3
+
+/*
+LZMA_DECODE_REAL()
+In:
+  RangeCoder is normalized
+  if (p->dicPos == limit)
+  {
+    LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases.
+    So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol
+    is not END_OF_PAYALOAD_MARKER, then function returns error code.
+  }
+
+Processing:
+  first LZMA symbol will be decoded in any case
+  All checks for limits are at the end of main loop,
+  It will decode new LZMA-symbols while (p->buf < bufLimit && dicPos < limit),
+  RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked.
+
+Out:
+  RangeCoder is normalized
+  Result:
+    SZ_OK - OK
+    SZ_ERROR_DATA - Error
+  p->remainLen:
+    < kMatchSpecLenStart : normal remain
+    = kMatchSpecLenStart : finished
+*/
+
+
+#ifdef _LZMA_DEC_OPT
+
+int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit);
+
+#else
+
+static
+int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+  CLzmaProb *probs = GET_PROBS;
+  unsigned state = (unsigned)p->state;
+  UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+  unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+  unsigned lc = p->prop.lc;
+  unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc);
+
+  Byte *dic = p->dic;
+  SizeT dicBufSize = p->dicBufSize;
+  SizeT dicPos = p->dicPos;
+  
+  UInt32 processedPos = p->processedPos;
+  UInt32 checkDicSize = p->checkDicSize;
+  unsigned len = 0;
+
+  const Byte *buf = p->buf;
+  UInt32 range = p->range;
+  UInt32 code = p->code;
+
+  do
+  {
+    CLzmaProb *prob;
+    UInt32 bound;
+    unsigned ttt;
+    unsigned posState = CALC_POS_STATE(processedPos, pbMask);
+
+    prob = probs + IsMatch + COMBINED_PS_STATE;
+    IF_BIT_0(prob)
+    {
+      unsigned symbol;
+      UPDATE_0(prob);
+      prob = probs + Literal;
+      if (processedPos != 0 || checkDicSize != 0)
+        prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc);
+      processedPos++;
+
+      if (state < kNumLitStates)
+      {
+        state -= (state < 4) ? state : 3;
+        symbol = 1;
+        #ifdef _LZMA_SIZE_OPT
+        do { NORMAL_LITER_DEC } while (symbol < 0x100);
+        #else
+        NORMAL_LITER_DEC
+        NORMAL_LITER_DEC
+        NORMAL_LITER_DEC
+        NORMAL_LITER_DEC
+        NORMAL_LITER_DEC
+        NORMAL_LITER_DEC
+        NORMAL_LITER_DEC
+        NORMAL_LITER_DEC
+        #endif
+      }
+      else
+      {
+        unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+        unsigned offs = 0x100;
+        state -= (state < 10) ? 3 : 6;
+        symbol = 1;
+        #ifdef _LZMA_SIZE_OPT
+        do
+        {
+          unsigned bit;
+          CLzmaProb *probLit;
+          MATCHED_LITER_DEC
+        }
+        while (symbol < 0x100);
+        #else
+        {
+          unsigned bit;
+          CLzmaProb *probLit;
+          MATCHED_LITER_DEC
+          MATCHED_LITER_DEC
+          MATCHED_LITER_DEC
+          MATCHED_LITER_DEC
+          MATCHED_LITER_DEC
+          MATCHED_LITER_DEC
+          MATCHED_LITER_DEC
+          MATCHED_LITER_DEC
+        }
+        #endif
+      }
+
+      dic[dicPos++] = (Byte)symbol;
+      continue;
+    }
+    
+    {
+      UPDATE_1(prob);
+      prob = probs + IsRep + state;
+      IF_BIT_0(prob)
+      {
+        UPDATE_0(prob);
+        state += kNumStates;
+        prob = probs + LenCoder;
+      }
+      else
+      {
+        UPDATE_1(prob);
+        /*
+        // that case was checked before with kBadRepCode
+        if (checkDicSize == 0 && processedPos == 0)
+          return SZ_ERROR_DATA;
+        */
+        prob = probs + IsRepG0 + state;
+        IF_BIT_0(prob)
+        {
+          UPDATE_0(prob);
+          prob = probs + IsRep0Long + COMBINED_PS_STATE;
+          IF_BIT_0(prob)
+          {
+            UPDATE_0(prob);
+            dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+            dicPos++;
+            processedPos++;
+            state = state < kNumLitStates ? 9 : 11;
+            continue;
+          }
+          UPDATE_1(prob);
+        }
+        else
+        {
+          UInt32 distance;
+          UPDATE_1(prob);
+          prob = probs + IsRepG1 + state;
+          IF_BIT_0(prob)
+          {
+            UPDATE_0(prob);
+            distance = rep1;
+          }
+          else
+          {
+            UPDATE_1(prob);
+            prob = probs + IsRepG2 + state;
+            IF_BIT_0(prob)
+            {
+              UPDATE_0(prob);
+              distance = rep2;
+            }
+            else
+            {
+              UPDATE_1(prob);
+              distance = rep3;
+              rep3 = rep2;
+            }
+            rep2 = rep1;
+          }
+          rep1 = rep0;
+          rep0 = distance;
+        }
+        state = state < kNumLitStates ? 8 : 11;
+        prob = probs + RepLenCoder;
+      }
+      
+      #ifdef _LZMA_SIZE_OPT
+      {
+        unsigned lim, offset;
+        CLzmaProb *probLen = prob + LenChoice;
+        IF_BIT_0(probLen)
+        {
+          UPDATE_0(probLen);
+          probLen = prob + LenLow + GET_LEN_STATE;
+          offset = 0;
+          lim = (1 << kLenNumLowBits);
+        }
+        else
+        {
+          UPDATE_1(probLen);
+          probLen = prob + LenChoice2;
+          IF_BIT_0(probLen)
+          {
+            UPDATE_0(probLen);
+            probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+            offset = kLenNumLowSymbols;
+            lim = (1 << kLenNumLowBits);
+          }
+          else
+          {
+            UPDATE_1(probLen);
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols * 2;
+            lim = (1 << kLenNumHighBits);
+          }
+        }
+        TREE_DECODE(probLen, lim, len);
+        len += offset;
+      }
+      #else
+      {
+        CLzmaProb *probLen = prob + LenChoice;
+        IF_BIT_0(probLen)
+        {
+          UPDATE_0(probLen);
+          probLen = prob + LenLow + GET_LEN_STATE;
+          len = 1;
+          TREE_GET_BIT(probLen, len);
+          TREE_GET_BIT(probLen, len);
+          TREE_GET_BIT(probLen, len);
+          len -= 8;
+        }
+        else
+        {
+          UPDATE_1(probLen);
+          probLen = prob + LenChoice2;
+          IF_BIT_0(probLen)
+          {
+            UPDATE_0(probLen);
+            probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+            len = 1;
+            TREE_GET_BIT(probLen, len);
+            TREE_GET_BIT(probLen, len);
+            TREE_GET_BIT(probLen, len);
+          }
+          else
+          {
+            UPDATE_1(probLen);
+            probLen = prob + LenHigh;
+            TREE_DECODE(probLen, (1 << kLenNumHighBits), len);
+            len += kLenNumLowSymbols * 2;
+          }
+        }
+      }
+      #endif
+
+      if (state >= kNumStates)
+      {
+        UInt32 distance;
+        prob = probs + PosSlot +
+            ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+        TREE_6_DECODE(prob, distance);
+        if (distance >= kStartPosModelIndex)
+        {
+          unsigned posSlot = (unsigned)distance;
+          unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
+          distance = (2 | (distance & 1));
+          if (posSlot < kEndPosModelIndex)
+          {
+            distance <<= numDirectBits;
+            prob = probs + SpecPos;
+            {
+              UInt32 m = 1;
+              distance++;
+              do
+              {
+                REV_BIT_VAR(prob, distance, m);
+              }
+              while (--numDirectBits);
+              distance -= m;
+            }
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              NORMALIZE
+              range >>= 1;
+              
+              {
+                UInt32 t;
+                code -= range;
+                t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+                distance = (distance << 1) + (t + 1);
+                code += range & t;
+              }
+              /*
+              distance <<= 1;
+              if (code >= range)
+              {
+                code -= range;
+                distance |= 1;
+              }
+              */
+            }
+            while (--numDirectBits);
+            prob = probs + Align;
+            distance <<= kNumAlignBits;
+            {
+              unsigned i = 1;
+              REV_BIT_CONST(prob, i, 1);
+              REV_BIT_CONST(prob, i, 2);
+              REV_BIT_CONST(prob, i, 4);
+              REV_BIT_LAST (prob, i, 8);
+              distance |= i;
+            }
+            if (distance == (UInt32)0xFFFFFFFF)
+            {
+              len = kMatchSpecLenStart;
+              state -= kNumStates;
+              break;
+            }
+          }
+        }
+        
+        rep3 = rep2;
+        rep2 = rep1;
+        rep1 = rep0;
+        rep0 = distance + 1;
+        state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+        if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize))
+        {
+          p->dicPos = dicPos;
+          return SZ_ERROR_DATA;
+        }
+      }
+
+      len += kMatchMinLen;
+
+      {
+        SizeT rem;
+        unsigned curLen;
+        SizeT pos;
+        
+        if ((rem = limit - dicPos) == 0)
+        {
+          p->dicPos = dicPos;
+          return SZ_ERROR_DATA;
+        }
+        
+        curLen = ((rem < len) ? (unsigned)rem : len);
+        pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
+
+        processedPos += (UInt32)curLen;
+
+        len -= curLen;
+        if (curLen <= dicBufSize - pos)
+        {
+          Byte *dest = dic + dicPos;
+          ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+          const Byte *lim = dest + curLen;
+          dicPos += (SizeT)curLen;
+          do
+            *(dest) = (Byte)*(dest + src);
+          while (++dest != lim);
+        }
+        else
+        {
+          do
+          {
+            dic[dicPos++] = dic[pos];
+            if (++pos == dicBufSize)
+              pos = 0;
+          }
+          while (--curLen != 0);
+        }
+      }
+    }
+  }
+  while (dicPos < limit && buf < bufLimit);
+
+  NORMALIZE;
+  
+  p->buf = buf;
+  p->range = range;
+  p->code = code;
+  p->remainLen = (UInt32)len;
+  p->dicPos = dicPos;
+  p->processedPos = processedPos;
+  p->reps[0] = rep0;
+  p->reps[1] = rep1;
+  p->reps[2] = rep2;
+  p->reps[3] = rep3;
+  p->state = (UInt32)state;
+
+  return SZ_OK;
+}
+#endif
+
+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+  if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
+  {
+    Byte *dic = p->dic;
+    SizeT dicPos = p->dicPos;
+    SizeT dicBufSize = p->dicBufSize;
+    unsigned len = (unsigned)p->remainLen;
+    SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */
+    SizeT rem = limit - dicPos;
+    if (rem < len)
+      len = (unsigned)(rem);
+
+    if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+      p->checkDicSize = p->prop.dicSize;
+
+    p->processedPos += (UInt32)len;
+    p->remainLen -= (UInt32)len;
+    while (len != 0)
+    {
+      len--;
+      dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+      dicPos++;
+    }
+    p->dicPos = dicPos;
+  }
+}
+
+
+#define kRange0 0xFFFFFFFF
+#define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))
+#define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)))
+#if kBadRepCode != (0xC0000000 - 0x400)
+  #error Stop_Compiling_Bad_LZMA_Check
+#endif
+
+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+  do
+  {
+    SizeT limit2 = limit;
+    if (p->checkDicSize == 0)
+    {
+      UInt32 rem = p->prop.dicSize - p->processedPos;
+      if (limit - p->dicPos > rem)
+        limit2 = p->dicPos + rem;
+
+      if (p->processedPos == 0)
+        if (p->code >= kBadRepCode)
+          return SZ_ERROR_DATA;
+    }
+
+    RINOK(LZMA_DECODE_REAL(p, limit2, bufLimit));
+    
+    if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize)
+      p->checkDicSize = p->prop.dicSize;
+    
+    LzmaDec_WriteRem(p, limit);
+  }
+  while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
+
+  return 0;
+}
+
+typedef enum
+{
+  DUMMY_ERROR, /* unexpected end of input stream */
+  DUMMY_LIT,
+  DUMMY_MATCH,
+  DUMMY_REP
+} ELzmaDummy;
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
+{
+  UInt32 range = p->range;
+  UInt32 code = p->code;
+  const Byte *bufLimit = buf + inSize;
+  const CLzmaProb *probs = GET_PROBS;
+  unsigned state = (unsigned)p->state;
+  ELzmaDummy res;
+
+  {
+    const CLzmaProb *prob;
+    UInt32 bound;
+    unsigned ttt;
+    unsigned posState = CALC_POS_STATE(p->processedPos, (1 << p->prop.pb) - 1);
+
+    prob = probs + IsMatch + COMBINED_PS_STATE;
+    IF_BIT_0_CHECK(prob)
+    {
+      UPDATE_0_CHECK
+
+      /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
+
+      prob = probs + Literal;
+      if (p->checkDicSize != 0 || p->processedPos != 0)
+        prob += ((UInt32)LZMA_LIT_SIZE *
+            ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+            (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+      if (state < kNumLitStates)
+      {
+        unsigned symbol = 1;
+        do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+      }
+      else
+      {
+        unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+            (p->dicPos < p->reps[0] ? p->dicBufSize : 0)];
+        unsigned offs = 0x100;
+        unsigned symbol = 1;
+        do
+        {
+          unsigned bit;
+          const CLzmaProb *probLit;
+          matchByte += matchByte;
+          bit = offs;
+          offs &= matchByte;
+          probLit = prob + (offs + bit + symbol);
+          GET_BIT2_CHECK(probLit, symbol, offs ^= bit; , ; )
+        }
+        while (symbol < 0x100);
+      }
+      res = DUMMY_LIT;
+    }
+    else
+    {
+      unsigned len;
+      UPDATE_1_CHECK;
+
+      prob = probs + IsRep + state;
+      IF_BIT_0_CHECK(prob)
+      {
+        UPDATE_0_CHECK;
+        state = 0;
+        prob = probs + LenCoder;
+        res = DUMMY_MATCH;
+      }
+      else
+      {
+        UPDATE_1_CHECK;
+        res = DUMMY_REP;
+        prob = probs + IsRepG0 + state;
+        IF_BIT_0_CHECK(prob)
+        {
+          UPDATE_0_CHECK;
+          prob = probs + IsRep0Long + COMBINED_PS_STATE;
+          IF_BIT_0_CHECK(prob)
+          {
+            UPDATE_0_CHECK;
+            NORMALIZE_CHECK;
+            return DUMMY_REP;
+          }
+          else
+          {
+            UPDATE_1_CHECK;
+          }
+        }
+        else
+        {
+          UPDATE_1_CHECK;
+          prob = probs + IsRepG1 + state;
+          IF_BIT_0_CHECK(prob)
+          {
+            UPDATE_0_CHECK;
+          }
+          else
+          {
+            UPDATE_1_CHECK;
+            prob = probs + IsRepG2 + state;
+            IF_BIT_0_CHECK(prob)
+            {
+              UPDATE_0_CHECK;
+            }
+            else
+            {
+              UPDATE_1_CHECK;
+            }
+          }
+        }
+        state = kNumStates;
+        prob = probs + RepLenCoder;
+      }
+      {
+        unsigned limit, offset;
+        const CLzmaProb *probLen = prob + LenChoice;
+        IF_BIT_0_CHECK(probLen)
+        {
+          UPDATE_0_CHECK;
+          probLen = prob + LenLow + GET_LEN_STATE;
+          offset = 0;
+          limit = 1 << kLenNumLowBits;
+        }
+        else
+        {
+          UPDATE_1_CHECK;
+          probLen = prob + LenChoice2;
+          IF_BIT_0_CHECK(probLen)
+          {
+            UPDATE_0_CHECK;
+            probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+            offset = kLenNumLowSymbols;
+            limit = 1 << kLenNumLowBits;
+          }
+          else
+          {
+            UPDATE_1_CHECK;
+            probLen = prob + LenHigh;
+            offset = kLenNumLowSymbols * 2;
+            limit = 1 << kLenNumHighBits;
+          }
+        }
+        TREE_DECODE_CHECK(probLen, limit, len);
+        len += offset;
+      }
+
+      if (state < 4)
+      {
+        unsigned posSlot;
+        prob = probs + PosSlot +
+            ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) <<
+            kNumPosSlotBits);
+        TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+        if (posSlot >= kStartPosModelIndex)
+        {
+          unsigned numDirectBits = ((posSlot >> 1) - 1);
+
+          /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+          if (posSlot < kEndPosModelIndex)
+          {
+            prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits);
+          }
+          else
+          {
+            numDirectBits -= kNumAlignBits;
+            do
+            {
+              NORMALIZE_CHECK
+              range >>= 1;
+              code -= range & (((code - range) >> 31) - 1);
+              /* if (code >= range) code -= range; */
+            }
+            while (--numDirectBits);
+            prob = probs + Align;
+            numDirectBits = kNumAlignBits;
+          }
+          {
+            unsigned i = 1;
+            unsigned m = 1;
+            do
+            {
+              REV_BIT_CHECK(prob, i, m);
+            }
+            while (--numDirectBits);
+          }
+        }
+      }
+    }
+  }
+  NORMALIZE_CHECK;
+  return res;
+}
+
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState)
+{
+  p->remainLen = kMatchSpecLenStart + 1;
+  p->tempBufSize = 0;
+
+  if (initDic)
+  {
+    p->processedPos = 0;
+    p->checkDicSize = 0;
+    p->remainLen = kMatchSpecLenStart + 2;
+  }
+  if (initState)
+    p->remainLen = kMatchSpecLenStart + 2;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+  p->dicPos = 0;
+  LzmaDec_InitDicAndState(p, True, True);
+}
+
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+    ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+  SizeT inSize = *srcLen;
+  (*srcLen) = 0;
+  
+  *status = LZMA_STATUS_NOT_SPECIFIED;
+
+  if (p->remainLen > kMatchSpecLenStart)
+  {
+    for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+      p->tempBuf[p->tempBufSize++] = *src++;
+    if (p->tempBufSize != 0 && p->tempBuf[0] != 0)
+      return SZ_ERROR_DATA;
+    if (p->tempBufSize < RC_INIT_SIZE)
+    {
+      *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+      return SZ_OK;
+    }
+    p->code =
+        ((UInt32)p->tempBuf[1] << 24)
+      | ((UInt32)p->tempBuf[2] << 16)
+      | ((UInt32)p->tempBuf[3] << 8)
+      | ((UInt32)p->tempBuf[4]);
+    p->range = 0xFFFFFFFF;
+    p->tempBufSize = 0;
+
+    if (p->remainLen > kMatchSpecLenStart + 1)
+    {
+      SizeT numProbs = LzmaProps_GetNumProbs(&p->prop);
+      SizeT i;
+      CLzmaProb *probs = p->probs;
+      for (i = 0; i < numProbs; i++)
+        probs[i] = kBitModelTotal >> 1;
+      p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+      p->state = 0;
+    }
+
+    p->remainLen = 0;
+  }
+
+  LzmaDec_WriteRem(p, dicLimit);
+
+  while (p->remainLen != kMatchSpecLenStart)
+  {
+      int checkEndMarkNow = 0;
+
+      if (p->dicPos >= dicLimit)
+      {
+        if (p->remainLen == 0 && p->code == 0)
+        {
+          *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+          return SZ_OK;
+        }
+        if (finishMode == LZMA_FINISH_ANY)
+        {
+          *status = LZMA_STATUS_NOT_FINISHED;
+          return SZ_OK;
+        }
+        if (p->remainLen != 0)
+        {
+          *status = LZMA_STATUS_NOT_FINISHED;
+          return SZ_ERROR_DATA;
+        }
+        checkEndMarkNow = 1;
+      }
+
+      if (p->tempBufSize == 0)
+      {
+        SizeT processed;
+        const Byte *bufLimit;
+        if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+        {
+          int dummyRes = LzmaDec_TryDummy(p, src, inSize);
+          if (dummyRes == DUMMY_ERROR)
+          {
+            memcpy(p->tempBuf, src, inSize);
+            p->tempBufSize = (unsigned)inSize;
+            (*srcLen) += inSize;
+            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+            return SZ_OK;
+          }
+          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+          {
+            *status = LZMA_STATUS_NOT_FINISHED;
+            return SZ_ERROR_DATA;
+          }
+          bufLimit = src;
+        }
+        else
+          bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+        p->buf = src;
+        if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
+          return SZ_ERROR_DATA;
+        processed = (SizeT)(p->buf - src);
+        (*srcLen) += processed;
+        src += processed;
+        inSize -= processed;
+      }
+      else
+      {
+        unsigned rem = p->tempBufSize, lookAhead = 0;
+        while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
+          p->tempBuf[rem++] = src[lookAhead++];
+        p->tempBufSize = rem;
+        if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+        {
+          int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, (SizeT)rem);
+          if (dummyRes == DUMMY_ERROR)
+          {
+            (*srcLen) += (SizeT)lookAhead;
+            *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+            return SZ_OK;
+          }
+          if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+          {
+            *status = LZMA_STATUS_NOT_FINISHED;
+            return SZ_ERROR_DATA;
+          }
+        }
+        p->buf = p->tempBuf;
+        if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
+          return SZ_ERROR_DATA;
+        
+        {
+          unsigned kkk = (unsigned)(p->buf - p->tempBuf);
+          if (rem < kkk)
+            return SZ_ERROR_FAIL; /* some internal error */
+          rem -= kkk;
+          if (lookAhead < rem)
+            return SZ_ERROR_FAIL; /* some internal error */
+          lookAhead -= rem;
+        }
+        (*srcLen) += (SizeT)lookAhead;
+        src += lookAhead;
+        inSize -= (SizeT)lookAhead;
+        p->tempBufSize = 0;
+      }
+  }
+  
+  if (p->code != 0)
+    return SZ_ERROR_DATA;
+  *status = LZMA_STATUS_FINISHED_WITH_MARK;
+  return SZ_OK;
+}
+
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+  SizeT outSize = *destLen;
+  SizeT inSize = *srcLen;
+  *srcLen = *destLen = 0;
+  for (;;)
+  {
+    SizeT inSizeCur = inSize, outSizeCur, dicPos;
+    ELzmaFinishMode curFinishMode;
+    SRes res;
+    if (p->dicPos == p->dicBufSize)
+      p->dicPos = 0;
+    dicPos = p->dicPos;
+    if (outSize > p->dicBufSize - dicPos)
+    {
+      outSizeCur = p->dicBufSize;
+      curFinishMode = LZMA_FINISH_ANY;
+    }
+    else
+    {
+      outSizeCur = dicPos + outSize;
+      curFinishMode = finishMode;
+    }
+
+    res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+    src += inSizeCur;
+    inSize -= inSizeCur;
+    *srcLen += inSizeCur;
+    outSizeCur = p->dicPos - dicPos;
+    memcpy(dest, p->dic + dicPos, outSizeCur);
+    dest += outSizeCur;
+    outSize -= outSizeCur;
+    *destLen += outSizeCur;
+    if (res != 0)
+      return res;
+    if (outSizeCur == 0 || outSize == 0)
+      return SZ_OK;
+  }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->probs);
+  p->probs = NULL;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->dic);
+  p->dic = NULL;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc)
+{
+  LzmaDec_FreeProbs(p, alloc);
+  LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+  UInt32 dicSize;
+  Byte d;
+  
+  if (size < LZMA_PROPS_SIZE)
+    return SZ_ERROR_UNSUPPORTED;
+  else
+    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+  if (dicSize < LZMA_DIC_MIN)
+    dicSize = LZMA_DIC_MIN;
+  p->dicSize = dicSize;
+
+  d = data[0];
+  if (d >= (9 * 5 * 5))
+    return SZ_ERROR_UNSUPPORTED;
+
+  p->lc = (Byte)(d % 9);
+  d /= 9;
+  p->pb = (Byte)(d / 5);
+  p->lp = (Byte)(d % 5);
+
+  return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc)
+{
+  UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+  if (!p->probs || numProbs != p->numProbs)
+  {
+    LzmaDec_FreeProbs(p, alloc);
+    p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb));
+    if (!p->probs)
+      return SZ_ERROR_MEM;
+    p->probs_1664 = p->probs + 1664;
+    p->numProbs = numProbs;
+  }
+  return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc)
+{
+  CLzmaProps propNew;
+  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+  p->prop = propNew;
+  return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc)
+{
+  CLzmaProps propNew;
+  SizeT dicBufSize;
+  RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+  RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+
+  {
+    UInt32 dictSize = propNew.dicSize;
+    SizeT mask = ((UInt32)1 << 12) - 1;
+         if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1;
+    else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;;
+    dicBufSize = ((SizeT)dictSize + mask) & ~mask;
+    if (dicBufSize < dictSize)
+      dicBufSize = dictSize;
+  }
+
+  if (!p->dic || dicBufSize != p->dicBufSize)
+  {
+    LzmaDec_FreeDict(p, alloc);
+    p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize);
+    if (!p->dic)
+    {
+      LzmaDec_FreeProbs(p, alloc);
+      return SZ_ERROR_MEM;
+    }
+  }
+  p->dicBufSize = dicBufSize;
+  p->prop = propNew;
+  return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+    const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+    ELzmaStatus *status, ISzAllocPtr alloc)
+{
+  CLzmaDec p;
+  SRes res;
+  SizeT outSize = *destLen, inSize = *srcLen;
+  *destLen = *srcLen = 0;
+  *status = LZMA_STATUS_NOT_SPECIFIED;
+  if (inSize < RC_INIT_SIZE)
+    return SZ_ERROR_INPUT_EOF;
+  LzmaDec_Construct(&p);
+  RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc));
+  p.dic = dest;
+  p.dicBufSize = outSize;
+  LzmaDec_Init(&p);
+  *srcLen = inSize;
+  res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+  *destLen = p.dicPos;
+  if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+    res = SZ_ERROR_INPUT_EOF;
+  LzmaDec_FreeProbs(&p, alloc);
+  return res;
+}
diff --git a/deps/libchdr/deps/lzma-19.00/src/LzmaEnc.c b/deps/libchdr/deps/lzma-19.00/src/LzmaEnc.c
new file mode 100644 (file)
index 0000000..2d3839d
--- /dev/null
@@ -0,0 +1,1330 @@
+/* LzmaEnc.c -- LZMA Encoder
+2019-01-10: Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #define SHOW_STAT */
+/* #define SHOW_STAT2 */
+
+#if defined(SHOW_STAT) || defined(SHOW_STAT2)
+#include <stdio.h>
+#endif
+
+#include "LzmaEnc.h"
+
+#include "LzFind.h"
+#ifndef _7ZIP_ST
+#include "LzFindMt.h"
+#endif
+
+#ifdef SHOW_STAT
+static unsigned g_STAT_OFFSET = 0;
+#endif
+
+#define kLzmaMaxHistorySize ((UInt32)3 << 29)
+/* #define kLzmaMaxHistorySize ((UInt32)7 << 29) */
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+#define kProbInitValue (kBitModelTotal >> 1)
+
+#define kNumMoveReducingBits 4
+#define kNumBitPriceShiftBits 4
+#define kBitPrice (1 << kNumBitPriceShiftBits)
+
+#define REP_LEN_COUNT 64
+
+void LzmaEncProps_Init(CLzmaEncProps *p)
+{
+  p->level = 5;
+  p->dictSize = p->mc = 0;
+  p->reduceSize = (UInt64)(Int64)-1;
+  p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
+  p->writeEndMark = 0;
+}
+
+void LzmaEncProps_Normalize(CLzmaEncProps *p)
+{
+  int level = p->level;
+  if (level < 0) level = 5;
+  p->level = level;
+  
+  if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level <= 7 ? (1 << 25) : (1 << 26)));
+  if (p->dictSize > p->reduceSize)
+  {
+    unsigned i;
+    UInt32 reduceSize = (UInt32)p->reduceSize;
+    for (i = 11; i <= 30; i++)
+    {
+      if (reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; }
+      if (reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; }
+    }
+  }
+
+  if (p->lc < 0) p->lc = 3;
+  if (p->lp < 0) p->lp = 0;
+  if (p->pb < 0) p->pb = 2;
+
+  if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
+  if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
+  if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
+  if (p->numHashBytes < 0) p->numHashBytes = 4;
+  if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
+  
+  if (p->numThreads < 0)
+    p->numThreads =
+      #ifndef _7ZIP_ST
+      ((p->btMode && p->algo) ? 2 : 1);
+      #else
+      1;
+      #endif
+}
+
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+{
+  CLzmaEncProps props = *props2;
+  LzmaEncProps_Normalize(&props);
+  return props.dictSize;
+}
+
+#if (_MSC_VER >= 1400)
+/* BSR code is fast for some new CPUs */
+/* #define LZMA_LOG_BSR */
+#endif
+
+#ifdef LZMA_LOG_BSR
+
+#define kDicLogSizeMaxCompress 32
+
+#define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); res = (zz + zz) + ((pos >> (zz - 1)) & 1); }
+
+static unsigned GetPosSlot1(UInt32 pos)
+{
+  unsigned res;
+  BSR2_RET(pos, res);
+  return res;
+}
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
+
+#else
+
+#define kNumLogBits (9 + sizeof(size_t) / 2)
+/* #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) */
+
+#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+
+static void LzmaEnc_FastPosInit(Byte *g_FastPos)
+{
+  unsigned slot;
+  g_FastPos[0] = 0;
+  g_FastPos[1] = 1;
+  g_FastPos += 2;
+  
+  for (slot = 2; slot < kNumLogBits * 2; slot++)
+  {
+    size_t k = ((size_t)1 << ((slot >> 1) - 1));
+    size_t j;
+    for (j = 0; j < k; j++)
+      g_FastPos[j] = (Byte)slot;
+    g_FastPos += k;
+  }
+}
+
+/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */
+/*
+#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \
+  (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
+  res = p->g_FastPos[pos >> zz] + (zz * 2); }
+*/
+
+/*
+#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \
+  (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \
+  res = p->g_FastPos[pos >> zz] + (zz * 2); }
+*/
+
+#define BSR2_RET(pos, res) { unsigned zz = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \
+  res = p->g_FastPos[pos >> zz] + (zz * 2); }
+
+/*
+#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
+  p->g_FastPos[pos >> 6] + 12 : \
+  p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
+*/
+
+#define GetPosSlot1(pos) p->g_FastPos[pos]
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); }
+
+#endif
+
+
+#define LZMA_NUM_REPS 4
+
+typedef UInt16 CState;
+typedef UInt16 CExtra;
+
+typedef struct
+{
+  UInt32 price;
+  CState state;
+  CExtra extra;
+      // 0   : normal
+      // 1   : LIT : MATCH
+      // > 1 : MATCH (extra-1) : LIT : REP0 (len)
+  UInt32 len;
+  UInt32 dist;
+  UInt32 reps[LZMA_NUM_REPS];
+} COptimal;
+
+
+// 18.06
+#define kNumOpts (1 << 11)
+#define kPackReserve (kNumOpts * 8)
+// #define kNumOpts (1 << 12)
+// #define kPackReserve (1 + kNumOpts * 2)
+
+#define kNumLenToPosStates 4
+#define kNumPosSlotBits 6
+#define kDicLogSizeMin 0
+#define kDicLogSizeMax 32
+#define kDistTableSizeMax (kDicLogSizeMax * 2)
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+#define kAlignMask (kAlignTableSize - 1)
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+typedef
+#ifdef _LZMA_PROB32
+  UInt32
+#else
+  UInt16
+#endif
+  CLzmaProb;
+
+#define LZMA_PB_MAX 4
+#define LZMA_LC_MAX 8
+#define LZMA_LP_MAX 4
+
+#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+#define kLenNumSymbolsTotal (kLenNumLowSymbols * 2 + kLenNumHighSymbols)
+
+#define LZMA_MATCH_LEN_MIN 2
+#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
+
+#define kNumStates 12
+
+
+typedef struct
+{
+  CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)];
+  CLzmaProb high[kLenNumHighSymbols];
+} CLenEnc;
+
+
+typedef struct
+{
+  unsigned tableSize;
+  UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
+  // UInt32 prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2];
+  // UInt32 prices2[kLenNumSymbolsTotal];
+} CLenPriceEnc;
+
+#define GET_PRICE_LEN(p, posState, len) \
+    ((p)->prices[posState][(size_t)(len) - LZMA_MATCH_LEN_MIN])
+
+/*
+#define GET_PRICE_LEN(p, posState, len) \
+    ((p)->prices2[(size_t)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9)))
+*/
+
+typedef struct
+{
+  UInt32 range;
+  unsigned cache;
+  UInt64 low;
+  UInt64 cacheSize;
+  Byte *buf;
+  Byte *bufLim;
+  Byte *bufBase;
+  ISeqOutStream *outStream;
+  UInt64 processed;
+  SRes res;
+} CRangeEnc;
+
+
+typedef struct
+{
+  CLzmaProb *litProbs;
+
+  unsigned state;
+  UInt32 reps[LZMA_NUM_REPS];
+
+  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+  CLzmaProb isRep[kNumStates];
+  CLzmaProb isRepG0[kNumStates];
+  CLzmaProb isRepG1[kNumStates];
+  CLzmaProb isRepG2[kNumStates];
+  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+  CLzmaProb posEncoders[kNumFullDistances];
+  
+  CLenEnc lenProbs;
+  CLenEnc repLenProbs;
+
+} CSaveState;
+
+
+typedef UInt32 CProbPrice;
+
+
+typedef struct
+{
+  void *matchFinderObj;
+  IMatchFinder matchFinder;
+
+  unsigned optCur;
+  unsigned optEnd;
+
+  unsigned longestMatchLen;
+  unsigned numPairs;
+  UInt32 numAvail;
+
+  unsigned state;
+  unsigned numFastBytes;
+  unsigned additionalOffset;
+  UInt32 reps[LZMA_NUM_REPS];
+  unsigned lpMask, pbMask;
+  CLzmaProb *litProbs;
+  CRangeEnc rc;
+
+  UInt32 backRes;
+
+  unsigned lc, lp, pb;
+  unsigned lclp;
+
+  BoolInt fastMode;
+  BoolInt writeEndMark;
+  BoolInt finished;
+  BoolInt multiThread;
+  BoolInt needInit;
+  // BoolInt _maxMode;
+
+  UInt64 nowPos64;
+  
+  unsigned matchPriceCount;
+  // unsigned alignPriceCount;
+  int repLenEncCounter;
+
+  unsigned distTableSize;
+
+  UInt32 dictSize;
+  SRes result;
+
+  #ifndef _7ZIP_ST
+  BoolInt mtMode;
+  // begin of CMatchFinderMt is used in LZ thread
+  CMatchFinderMt matchFinderMt;
+  // end of CMatchFinderMt is used in BT and HASH threads
+  #endif
+
+  CMatchFinder matchFinderBase;
+
+  #ifndef _7ZIP_ST
+  Byte pad[128];
+  #endif
+  
+  // LZ thread
+  CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+
+  UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
+
+  UInt32 alignPrices[kAlignTableSize];
+  UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
+  UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
+
+  CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+  CLzmaProb isRep[kNumStates];
+  CLzmaProb isRepG0[kNumStates];
+  CLzmaProb isRepG1[kNumStates];
+  CLzmaProb isRepG2[kNumStates];
+  CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+  CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+  CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+  CLzmaProb posEncoders[kNumFullDistances];
+  
+  CLenEnc lenProbs;
+  CLenEnc repLenProbs;
+
+  #ifndef LZMA_LOG_BSR
+  Byte g_FastPos[1 << kNumLogBits];
+  #endif
+
+  CLenPriceEnc lenEnc;
+  CLenPriceEnc repLenEnc;
+
+  COptimal opt[kNumOpts];
+
+  CSaveState saveState;
+
+  #ifndef _7ZIP_ST
+  Byte pad2[128];
+  #endif
+} CLzmaEnc;
+
+
+SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
+{
+  CLzmaEnc *p = (CLzmaEnc *)pp;
+  CLzmaEncProps props = *props2;
+  LzmaEncProps_Normalize(&props);
+
+  if (props.lc > LZMA_LC_MAX
+      || props.lp > LZMA_LP_MAX
+      || props.pb > LZMA_PB_MAX
+      || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress)
+      || props.dictSize > kLzmaMaxHistorySize)
+    return SZ_ERROR_PARAM;
+
+  p->dictSize = props.dictSize;
+  {
+    unsigned fb = props.fb;
+    if (fb < 5)
+      fb = 5;
+    if (fb > LZMA_MATCH_LEN_MAX)
+      fb = LZMA_MATCH_LEN_MAX;
+    p->numFastBytes = fb;
+  }
+  p->lc = props.lc;
+  p->lp = props.lp;
+  p->pb = props.pb;
+  p->fastMode = (props.algo == 0);
+  // p->_maxMode = True;
+  p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0);
+  {
+    unsigned numHashBytes = 4;
+    if (props.btMode)
+    {
+      if (props.numHashBytes < 2)
+        numHashBytes = 2;
+      else if (props.numHashBytes < 4)
+        numHashBytes = props.numHashBytes;
+    }
+    p->matchFinderBase.numHashBytes = numHashBytes;
+  }
+
+  p->matchFinderBase.cutValue = props.mc;
+
+  p->writeEndMark = props.writeEndMark;
+
+  #ifndef _7ZIP_ST
+  /*
+  if (newMultiThread != _multiThread)
+  {
+    ReleaseMatchFinder();
+    _multiThread = newMultiThread;
+  }
+  */
+  p->multiThread = (props.numThreads > 1);
+  #endif
+
+  return SZ_OK;
+}
+
+
+void LzmaEnc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize)
+{
+  CLzmaEnc *p = (CLzmaEnc *)pp;
+  p->matchFinderBase.expectedDataSize = expectedDataSiize;
+}
+
+
+#define kState_Start 0
+#define kState_LitAfterMatch 4
+#define kState_LitAfterRep   5
+#define kState_MatchAfterLit 7
+#define kState_RepAfterLit   8
+
+static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
+static const Byte kMatchNextStates[kNumStates]   = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+static const Byte kRepNextStates[kNumStates]     = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+static const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+#define IsLitState(s) ((s) < 7)
+#define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : kNumLenToPosStates - 1)
+#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
+
+#define kInfinityPrice (1 << 30)
+
+static void RangeEnc_Construct(CRangeEnc *p)
+{
+  p->outStream = NULL;
+  p->bufBase = NULL;
+}
+
+#define RangeEnc_GetProcessed(p)       ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
+#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + ((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize)
+
+#define RC_BUF_SIZE (1 << 16)
+
+static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc)
+{
+  if (!p->bufBase)
+  {
+    p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE);
+    if (!p->bufBase)
+      return 0;
+    p->bufLim = p->bufBase + RC_BUF_SIZE;
+  }
+  return 1;
+}
+
+static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->bufBase);
+  p->bufBase = 0;
+}
+
+static void RangeEnc_Init(CRangeEnc *p)
+{
+  /* Stream.Init(); */
+  p->range = 0xFFFFFFFF;
+  p->cache = 0;
+  p->low = 0;
+  p->cacheSize = 0;
+
+  p->buf = p->bufBase;
+
+  p->processed = 0;
+  p->res = SZ_OK;
+}
+
+MY_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p)
+{
+  size_t num;
+  if (p->res != SZ_OK)
+    return;
+  num = p->buf - p->bufBase;
+  if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num))
+    p->res = SZ_ERROR_WRITE;
+  p->processed += num;
+  p->buf = p->bufBase;
+}
+
+MY_NO_INLINE static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
+{
+  UInt32 low = (UInt32)p->low;
+  unsigned high = (unsigned)(p->low >> 32);
+  p->low = (UInt32)(low << 8);
+  if (low < (UInt32)0xFF000000 || high != 0)
+  {
+    {
+      Byte *buf = p->buf;
+      *buf++ = (Byte)(p->cache + high);
+      p->cache = (unsigned)(low >> 24);
+      p->buf = buf;
+      if (buf == p->bufLim)
+        RangeEnc_FlushStream(p);
+      if (p->cacheSize == 0)
+        return;
+    }
+    high += 0xFF;
+    for (;;)
+    {
+      Byte *buf = p->buf;
+      *buf++ = (Byte)(high);
+      p->buf = buf;
+      if (buf == p->bufLim)
+        RangeEnc_FlushStream(p);
+      if (--p->cacheSize == 0)
+        return;
+    }
+  }
+  p->cacheSize++;
+}
+
+static void RangeEnc_FlushData(CRangeEnc *p)
+{
+  int i;
+  for (i = 0; i < 5; i++)
+    RangeEnc_ShiftLow(p);
+}
+
+#define RC_NORM(p) if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(p); }
+
+#define RC_BIT_PRE(p, prob) \
+  ttt = *(prob); \
+  newBound = (range >> kNumBitModelTotalBits) * ttt;
+
+// #define _LZMA_ENC_USE_BRANCH
+
+#ifdef _LZMA_ENC_USE_BRANCH
+
+#define RC_BIT(p, prob, bit) { \
+  RC_BIT_PRE(p, prob) \
+  if (bit == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } \
+  else { (p)->low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; } \
+  *(prob) = (CLzmaProb)ttt; \
+  RC_NORM(p) \
+  }
+
+#else
+
+#define RC_BIT(p, prob, bit) { \
+  UInt32 mask; \
+  RC_BIT_PRE(p, prob) \
+  mask = 0 - (UInt32)bit; \
+  range &= mask; \
+  mask &= newBound; \
+  range -= mask; \
+  (p)->low += mask; \
+  mask = (UInt32)bit - 1; \
+  range += newBound & mask; \
+  mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \
+  mask += ((1 << kNumMoveBits) - 1); \
+  ttt += (Int32)(mask - ttt) >> kNumMoveBits; \
+  *(prob) = (CLzmaProb)ttt; \
+  RC_NORM(p) \
+  }
+
+#endif
+
+
+
+
+#define RC_BIT_0_BASE(p, prob) \
+  range = newBound; *(prob) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+
+#define RC_BIT_1_BASE(p, prob) \
+  range -= newBound; (p)->low += newBound; *(prob) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); \
+
+#define RC_BIT_0(p, prob) \
+  RC_BIT_0_BASE(p, prob) \
+  RC_NORM(p)
+
+#define RC_BIT_1(p, prob) \
+  RC_BIT_1_BASE(p, prob) \
+  RC_NORM(p)
+
+static void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob)
+{
+  UInt32 range, ttt, newBound;
+  range = p->range;
+  RC_BIT_PRE(p, prob)
+  RC_BIT_0(p, prob)
+  p->range = range;
+}
+
+static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym)
+{
+  UInt32 range = p->range;
+  sym |= 0x100;
+  do
+  {
+    UInt32 ttt, newBound;
+    // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1);
+    CLzmaProb *prob = probs + (sym >> 8);
+    UInt32 bit = (sym >> 7) & 1;
+    sym <<= 1;
+    RC_BIT(p, prob, bit);
+  }
+  while (sym < 0x10000);
+  p->range = range;
+}
+
+static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices)
+{
+  UInt32 i;
+  for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++)
+  {
+    const unsigned kCyclesBits = kNumBitPriceShiftBits;
+    UInt32 w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1));
+    unsigned bitCount = 0;
+    unsigned j;
+    for (j = 0; j < kCyclesBits; j++)
+    {
+      w = w * w;
+      bitCount <<= 1;
+      while (w >= ((UInt32)1 << 16))
+      {
+        w >>= 1;
+        bitCount++;
+      }
+    }
+    ProbPrices[i] = (CProbPrice)((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
+    // printf("\n%3d: %5d", i, ProbPrices[i]);
+  }
+}
+
+
+#define GET_PRICE(prob, bit) \
+  p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICEa(prob, bit) \
+     ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
+
+#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+#define GET_PRICEa_0(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICEa_1(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+
+static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 sym, const CProbPrice *ProbPrices)
+{
+  UInt32 price = 0;
+  sym |= 0x100;
+  do
+  {
+    unsigned bit = sym & 1;
+    sym >>= 1;
+    price += GET_PRICEa(probs[sym], bit);
+  }
+  while (sym >= 2);
+  return price;
+}
+
+
+static UInt32 LitEnc_Matched_GetPrice(const CLzmaProb *probs, UInt32 sym, UInt32 matchByte, const CProbPrice *ProbPrices)
+{
+  UInt32 price = 0;
+  UInt32 offs = 0x100;
+  sym |= 0x100;
+  do
+  {
+    matchByte <<= 1;
+    price += GET_PRICEa(probs[offs + (matchByte & offs) + (sym >> 8)], (sym >> 7) & 1);
+    sym <<= 1;
+    offs &= ~(matchByte ^ sym);
+  }
+  while (sym < 0x10000);
+  return price;
+}
+
+
+
+static void LenEnc_Init(CLenEnc *p)
+{
+  unsigned i;
+  for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++)
+    p->low[i] = kProbInitValue;
+  for (i = 0; i < kLenNumHighSymbols; i++)
+    p->high[i] = kProbInitValue;
+}
+
+static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posState)
+{
+  UInt32 range, ttt, newBound;
+  CLzmaProb *probs = p->low;
+  range = rc->range;
+  RC_BIT_PRE(rc, probs);
+  if (sym >= kLenNumLowSymbols)
+  {
+    RC_BIT_1(rc, probs);
+    probs += kLenNumLowSymbols;
+    RC_BIT_PRE(rc, probs);
+    if (sym >= kLenNumLowSymbols * 2)
+    {
+      RC_BIT_1(rc, probs);
+      rc->range = range;
+      // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2);
+      LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2);
+      return;
+    }
+    sym -= kLenNumLowSymbols;
+  }
+
+  // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym);
+  {
+    unsigned m;
+    unsigned bit;
+    RC_BIT_0(rc, probs);
+    probs += (posState << (1 + kLenNumLowBits));
+    bit = (sym >> 2)    ; RC_BIT(rc, probs + 1, bit); m = (1 << 1) + bit;
+    bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit); m = (m << 1) + bit;
+    bit =  sym       & 1; RC_BIT(rc, probs + m, bit);
+    rc->range = range;
+  }
+}
+
+static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *prices, const CProbPrice *ProbPrices)
+{
+  unsigned i;
+  for (i = 0; i < 8; i += 2)
+  {
+    UInt32 price = startPrice;
+    UInt32 prob;
+    price += GET_PRICEa(probs[1           ], (i >> 2));
+    price += GET_PRICEa(probs[2 + (i >> 2)], (i >> 1) & 1);
+    prob = probs[4 + (i >> 1)];
+    prices[i    ] = price + GET_PRICEa_0(prob);
+    prices[i + 1] = price + GET_PRICEa_1(prob);
+  }
+}
+
+
+MY_NO_INLINE static void MY_FAST_CALL LenPriceEnc_UpdateTables(
+    CLenPriceEnc *p,
+    unsigned numPosStates,
+    const CLenEnc *enc,
+    const CProbPrice *ProbPrices)
+{
+  UInt32 b;
+  {
+    unsigned prob = enc->low[0];
+    UInt32 a, c;
+    unsigned posState;
+    b = GET_PRICEa_1(prob);
+    a = GET_PRICEa_0(prob);
+    c = b + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
+    for (posState = 0; posState < numPosStates; posState++)
+    {
+      UInt32 *prices = p->prices[posState];
+      const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits));
+      SetPrices_3(probs, a, prices, ProbPrices);
+      SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices);
+    }
+  }
+
+  /*
+  {
+    unsigned i;
+    UInt32 b;
+    a = GET_PRICEa_0(enc->low[0]);
+    for (i = 0; i < kLenNumLowSymbols; i++)
+      p->prices2[i] = a;
+    a = GET_PRICEa_1(enc->low[0]);
+    b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
+    for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++)
+      p->prices2[i] = b;
+    a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
+  }
+  */
+  // p->counter = numSymbols;
+  // p->counter = 64;
+
+  {
+    unsigned i = p->tableSize;
+    
+    if (i > kLenNumLowSymbols * 2)
+    {
+      const CLzmaProb *probs = enc->high;
+      UInt32 *prices = p->prices[0] + kLenNumLowSymbols * 2;
+      i -= kLenNumLowSymbols * 2 - 1;
+      i >>= 1;
+      b += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
+      do
+      {
+        /*
+        p->prices2[i] = a +
+        // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices);
+        LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices);
+        */
+        // UInt32 price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices);
+        unsigned sym = --i + (1 << (kLenNumHighBits - 1));
+        UInt32 price = b;
+        do
+        {
+          unsigned bit = sym & 1;
+          sym >>= 1;
+          price += GET_PRICEa(probs[sym], bit);
+        }
+        while (sym >= 2);
+
+        {
+          unsigned prob = probs[(size_t)i + (1 << (kLenNumHighBits - 1))];
+          prices[(size_t)i * 2    ] = price + GET_PRICEa_0(prob);
+          prices[(size_t)i * 2 + 1] = price + GET_PRICEa_1(prob);
+        }
+      }
+      while (i);
+
+      {
+        unsigned posState;
+        size_t num = (p->tableSize - kLenNumLowSymbols * 2) * sizeof(p->prices[0][0]);
+        for (posState = 1; posState < numPosStates; posState++)
+          memcpy(p->prices[posState] + kLenNumLowSymbols * 2, p->prices[0] + kLenNumLowSymbols * 2, num);
+      }
+    }
+  }
+}
+
+/*
+  #ifdef SHOW_STAT
+  g_STAT_OFFSET += num;
+  printf("\n MovePos %u", num);
+  #endif
+*/
+  
+#define MOVE_POS(p, num) { \
+    p->additionalOffset += (num); \
+    p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); }
+
+
+#define MARK_LIT ((UInt32)(Int32)-1)
+
+#define MakeAs_Lit(p)       { (p)->dist = MARK_LIT; (p)->extra = 0; }
+#define MakeAs_ShortRep(p)  { (p)->dist = 0; (p)->extra = 0; }
+#define IsShortRep(p)       ((p)->dist == 0)
+
+
+#define GetPrice_ShortRep(p, state, posState) \
+  ( GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState]))
+
+#define GetPrice_Rep_0(p, state, posState) ( \
+    GET_PRICE_1(p->isMatch[state][posState]) \
+  + GET_PRICE_1(p->isRep0Long[state][posState])) \
+  + GET_PRICE_1(p->isRep[state]) \
+  + GET_PRICE_0(p->isRepG0[state])
+  
+MY_FORCE_INLINE
+static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState)
+{
+  UInt32 price;
+  UInt32 prob = p->isRepG0[state];
+  if (repIndex == 0)
+  {
+    price = GET_PRICE_0(prob);
+    price += GET_PRICE_1(p->isRep0Long[state][posState]);
+  }
+  else
+  {
+    price = GET_PRICE_1(prob);
+    prob = p->isRepG1[state];
+    if (repIndex == 1)
+      price += GET_PRICE_0(prob);
+    else
+    {
+      price += GET_PRICE_1(prob);
+      price += GET_PRICE(p->isRepG2[state], repIndex - 2);
+    }
+  }
+  return price;
+}
+
+
+static SRes CheckErrors(CLzmaEnc *p)
+{
+  if (p->result != SZ_OK)
+    return p->result;
+  if (p->rc.res != SZ_OK)
+    p->result = SZ_ERROR_WRITE;
+  if (p->matchFinderBase.result != SZ_OK)
+    p->result = SZ_ERROR_READ;
+  if (p->result != SZ_OK)
+    p->finished = True;
+  return p->result;
+}
+
+
+MY_NO_INLINE static void FillAlignPrices(CLzmaEnc *p)
+{
+  unsigned i;
+  const CProbPrice *ProbPrices = p->ProbPrices;
+  const CLzmaProb *probs = p->posAlignEncoder;
+  // p->alignPriceCount = 0;
+  for (i = 0; i < kAlignTableSize / 2; i++)
+  {
+    UInt32 price = 0;
+    unsigned sym = i;
+    unsigned m = 1;
+    unsigned bit;
+    UInt32 prob;
+    bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
+    bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
+    bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
+    prob = probs[m];
+    p->alignPrices[i    ] = price + GET_PRICEa_0(prob);
+    p->alignPrices[i + 8] = price + GET_PRICEa_1(prob);
+    // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
+  }
+}
+
+
+MY_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p)
+{
+  // int y; for (y = 0; y < 100; y++) {
+
+  UInt32 tempPrices[kNumFullDistances];
+  unsigned i, lps;
+
+  const CProbPrice *ProbPrices = p->ProbPrices;
+  p->matchPriceCount = 0;
+
+  for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++)
+  {
+    unsigned posSlot = GetPosSlot1(i);
+    unsigned footerBits = (posSlot >> 1) - 1;
+    unsigned base = ((2 | (posSlot & 1)) << footerBits);
+    const CLzmaProb *probs = p->posEncoders + (size_t)base * 2;
+    // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices);
+    UInt32 price = 0;
+    unsigned m = 1;
+    unsigned sym = i;
+    unsigned offset = (unsigned)1 << footerBits;
+    base += i;
+    
+    if (footerBits)
+    do
+    {
+      unsigned bit = sym & 1;
+      sym >>= 1;
+      price += GET_PRICEa(probs[m], bit);
+      m = (m << 1) + bit;
+    }
+    while (--footerBits);
+
+    {
+      unsigned prob = probs[m];
+      tempPrices[base         ] = price + GET_PRICEa_0(prob);
+      tempPrices[base + offset] = price + GET_PRICEa_1(prob);
+    }
+  }
+
+  for (lps = 0; lps < kNumLenToPosStates; lps++)
+  {
+    unsigned slot;
+    unsigned distTableSize2 = (p->distTableSize + 1) >> 1;
+    UInt32 *posSlotPrices = p->posSlotPrices[lps];
+    const CLzmaProb *probs = p->posSlotEncoder[lps];
+    
+    for (slot = 0; slot < distTableSize2; slot++)
+    {
+      // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices);
+      UInt32 price;
+      unsigned bit;
+      unsigned sym = slot + (1 << (kNumPosSlotBits - 1));
+      unsigned prob;
+      bit = sym & 1; sym >>= 1; price  = GET_PRICEa(probs[sym], bit);
+      bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+      bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+      bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+      bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+      prob = probs[(size_t)slot + (1 << (kNumPosSlotBits - 1))];
+      posSlotPrices[(size_t)slot * 2    ] = price + GET_PRICEa_0(prob);
+      posSlotPrices[(size_t)slot * 2 + 1] = price + GET_PRICEa_1(prob);
+    }
+    
+    {
+      UInt32 delta = ((UInt32)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
+      for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++)
+      {
+        posSlotPrices[(size_t)slot * 2    ] += delta;
+        posSlotPrices[(size_t)slot * 2 + 1] += delta;
+        delta += ((UInt32)1 << kNumBitPriceShiftBits);
+      }
+    }
+
+    {
+      UInt32 *dp = p->distancesPrices[lps];
+      
+      dp[0] = posSlotPrices[0];
+      dp[1] = posSlotPrices[1];
+      dp[2] = posSlotPrices[2];
+      dp[3] = posSlotPrices[3];
+
+      for (i = 4; i < kNumFullDistances; i += 2)
+      {
+        UInt32 slotPrice = posSlotPrices[GetPosSlot1(i)];
+        dp[i    ] = slotPrice + tempPrices[i];
+        dp[i + 1] = slotPrice + tempPrices[i + 1];
+      }
+    }
+  }
+  // }
+}
+
+
+
+void LzmaEnc_Construct(CLzmaEnc *p)
+{
+  RangeEnc_Construct(&p->rc);
+  MatchFinder_Construct(&p->matchFinderBase);
+  
+  #ifndef _7ZIP_ST
+  MatchFinderMt_Construct(&p->matchFinderMt);
+  p->matchFinderMt.MatchFinder = &p->matchFinderBase;
+  #endif
+
+  {
+    CLzmaEncProps props;
+    LzmaEncProps_Init(&props);
+    LzmaEnc_SetProps(p, &props);
+  }
+
+  #ifndef LZMA_LOG_BSR
+  LzmaEnc_FastPosInit(p->g_FastPos);
+  #endif
+
+  LzmaEnc_InitPriceTables(p->ProbPrices);
+  p->litProbs = NULL;
+  p->saveState.litProbs = NULL;
+
+}
+
+CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc)
+{
+  void *p;
+  p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc));
+  if (p)
+    LzmaEnc_Construct((CLzmaEnc *)p);
+  return p;
+}
+
+void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc)
+{
+  ISzAlloc_Free(alloc, p->litProbs);
+  ISzAlloc_Free(alloc, p->saveState.litProbs);
+  p->litProbs = NULL;
+  p->saveState.litProbs = NULL;
+}
+
+void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+  #ifndef _7ZIP_ST
+  MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+  #endif
+  
+  MatchFinder_Free(&p->matchFinderBase, allocBig);
+  LzmaEnc_FreeLits(p, alloc);
+  RangeEnc_Free(&p->rc, alloc);
+}
+
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+  LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
+  ISzAlloc_Free(alloc, p);
+}
+
+
+#define kBigHashDicLimit ((UInt32)1 << 24)
+
+static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+  UInt32 beforeSize = kNumOpts;
+  if (!RangeEnc_Alloc(&p->rc, alloc))
+    return SZ_ERROR_MEM;
+
+  #ifndef _7ZIP_ST
+  p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0));
+  #endif
+
+  {
+    unsigned lclp = p->lc + p->lp;
+    if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp)
+    {
+      LzmaEnc_FreeLits(p, alloc);
+      p->litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+      p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+      if (!p->litProbs || !p->saveState.litProbs)
+      {
+        LzmaEnc_FreeLits(p, alloc);
+        return SZ_ERROR_MEM;
+      }
+      p->lclp = lclp;
+    }
+  }
+
+  p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0);
+
+  if (beforeSize + p->dictSize < keepWindowSize)
+    beforeSize = keepWindowSize - p->dictSize;
+
+  #ifndef _7ZIP_ST
+  if (p->mtMode)
+  {
+    RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes,
+        LZMA_MATCH_LEN_MAX
+        + 1  /* 18.04 */
+        , allocBig));
+    p->matchFinderObj = &p->matchFinderMt;
+    p->matchFinderBase.bigHash = (Byte)(
+        (p->dictSize > kBigHashDicLimit && p->matchFinderBase.hashMask >= 0xFFFFFF) ? 1 : 0);
+    MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
+  }
+  else
+  #endif
+  {
+    if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
+      return SZ_ERROR_MEM;
+    p->matchFinderObj = &p->matchFinderBase;
+    MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
+  }
+  
+  return SZ_OK;
+}
+
+void LzmaEnc_Init(CLzmaEnc *p)
+{
+  unsigned i;
+  p->state = 0;
+  p->reps[0] =
+  p->reps[1] =
+  p->reps[2] =
+  p->reps[3] = 1;
+
+  RangeEnc_Init(&p->rc);
+
+  for (i = 0; i < (1 << kNumAlignBits); i++)
+    p->posAlignEncoder[i] = kProbInitValue;
+
+  for (i = 0; i < kNumStates; i++)
+  {
+    unsigned j;
+    for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
+    {
+      p->isMatch[i][j] = kProbInitValue;
+      p->isRep0Long[i][j] = kProbInitValue;
+    }
+    p->isRep[i] = kProbInitValue;
+    p->isRepG0[i] = kProbInitValue;
+    p->isRepG1[i] = kProbInitValue;
+    p->isRepG2[i] = kProbInitValue;
+  }
+
+  {
+    for (i = 0; i < kNumLenToPosStates; i++)
+    {
+      CLzmaProb *probs = p->posSlotEncoder[i];
+      unsigned j;
+      for (j = 0; j < (1 << kNumPosSlotBits); j++)
+        probs[j] = kProbInitValue;
+    }
+  }
+  {
+    for (i = 0; i < kNumFullDistances; i++)
+      p->posEncoders[i] = kProbInitValue;
+  }
+
+  {
+    UInt32 num = (UInt32)0x300 << (p->lp + p->lc);
+    UInt32 k;
+    CLzmaProb *probs = p->litProbs;
+    for (k = 0; k < num; k++)
+      probs[k] = kProbInitValue;
+  }
+
+
+  LenEnc_Init(&p->lenProbs);
+  LenEnc_Init(&p->repLenProbs);
+
+  p->optEnd = 0;
+  p->optCur = 0;
+
+  {
+    for (i = 0; i < kNumOpts; i++)
+      p->opt[i].price = kInfinityPrice;
+  }
+
+  p->additionalOffset = 0;
+
+  p->pbMask = (1 << p->pb) - 1;
+  p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc);
+}
+
+
+void LzmaEnc_InitPrices(CLzmaEnc *p)
+{
+  if (!p->fastMode)
+  {
+    FillDistancesPrices(p);
+    FillAlignPrices(p);
+  }
+
+  p->lenEnc.tableSize =
+  p->repLenEnc.tableSize =
+      p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
+
+  p->repLenEncCounter = REP_LEN_COUNT;
+
+  LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
+  LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, &p->repLenProbs, p->ProbPrices);
+}
+
+typedef struct
+{
+  ISeqOutStream vt;
+  Byte *data;
+  SizeT rem;
+  BoolInt overflow;
+} CLzmaEnc_SeqOutStreamBuf;
+
+static size_t SeqOutStreamBuf_Write(const ISeqOutStream *pp, const void *data, size_t size)
+{
+  CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt);
+  if (p->rem < size)
+  {
+    size = p->rem;
+    p->overflow = True;
+  }
+  memcpy(p->data, data, size);
+  p->rem -= size;
+  p->data += size;
+  return size;
+}
+
+
+UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
+{
+  const CLzmaEnc *p = (CLzmaEnc *)pp;
+  return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+}
+
+
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
+{
+  const CLzmaEnc *p = (CLzmaEnc *)pp;
+  return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+}
+
+
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
+{
+  CLzmaEnc *p = (CLzmaEnc *)pp;
+  unsigned i;
+  UInt32 dictSize = p->dictSize;
+  if (*size < LZMA_PROPS_SIZE)
+    return SZ_ERROR_PARAM;
+  *size = LZMA_PROPS_SIZE;
+  props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
+
+  if (dictSize >= ((UInt32)1 << 22))
+  {
+    UInt32 kDictMask = ((UInt32)1 << 20) - 1;
+    if (dictSize < (UInt32)0xFFFFFFFF - kDictMask)
+      dictSize = (dictSize + kDictMask) & ~kDictMask;
+  }
+  else for (i = 11; i <= 30; i++)
+  {
+    if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; }
+    if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; }
+  }
+
+  for (i = 0; i < 4; i++)
+    props[1 + i] = (Byte)(dictSize >> (8 * i));
+  return SZ_OK;
+}
+
+
+
+
diff --git a/deps/libchdr/deps/lzma-19.00/src/Sort.c b/deps/libchdr/deps/lzma-19.00/src/Sort.c
new file mode 100644 (file)
index 0000000..e1097e3
--- /dev/null
@@ -0,0 +1,141 @@
+/* Sort.c -- Sort functions
+2014-04-05 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Sort.h"
+
+#define HeapSortDown(p, k, size, temp) \
+  { for (;;) { \
+    size_t s = (k << 1); \
+    if (s > size) break; \
+    if (s < size && p[s + 1] > p[s]) s++; \
+    if (temp >= p[s]) break; \
+    p[k] = p[s]; k = s; \
+  } p[k] = temp; }
+
+void HeapSort(UInt32 *p, size_t size)
+{
+  if (size <= 1)
+    return;
+  p--;
+  {
+    size_t i = size / 2;
+    do
+    {
+      UInt32 temp = p[i];
+      size_t k = i;
+      HeapSortDown(p, k, size, temp)
+    }
+    while (--i != 0);
+  }
+  /*
+  do
+  {
+    size_t k = 1;
+    UInt32 temp = p[size];
+    p[size--] = p[1];
+    HeapSortDown(p, k, size, temp)
+  }
+  while (size > 1);
+  */
+  while (size > 3)
+  {
+    UInt32 temp = p[size];
+    size_t k = (p[3] > p[2]) ? 3 : 2;
+    p[size--] = p[1];
+    p[1] = p[k];
+    HeapSortDown(p, k, size, temp)
+  }
+  {
+    UInt32 temp = p[size];
+    p[size] = p[1];
+    if (size > 2 && p[2] < temp)
+    {
+      p[1] = p[2];
+      p[2] = temp;
+    }
+    else
+      p[1] = temp;
+  }
+}
+
+void HeapSort64(UInt64 *p, size_t size)
+{
+  if (size <= 1)
+    return;
+  p--;
+  {
+    size_t i = size / 2;
+    do
+    {
+      UInt64 temp = p[i];
+      size_t k = i;
+      HeapSortDown(p, k, size, temp)
+    }
+    while (--i != 0);
+  }
+  /*
+  do
+  {
+    size_t k = 1;
+    UInt64 temp = p[size];
+    p[size--] = p[1];
+    HeapSortDown(p, k, size, temp)
+  }
+  while (size > 1);
+  */
+  while (size > 3)
+  {
+    UInt64 temp = p[size];
+    size_t k = (p[3] > p[2]) ? 3 : 2;
+    p[size--] = p[1];
+    p[1] = p[k];
+    HeapSortDown(p, k, size, temp)
+  }
+  {
+    UInt64 temp = p[size];
+    p[size] = p[1];
+    if (size > 2 && p[2] < temp)
+    {
+      p[1] = p[2];
+      p[2] = temp;
+    }
+    else
+      p[1] = temp;
+  }
+}
+
+/*
+#define HeapSortRefDown(p, vals, n, size, temp) \
+  { size_t k = n; UInt32 val = vals[temp]; for (;;) { \
+    size_t s = (k << 1); \
+    if (s > size) break; \
+    if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \
+    if (val >= vals[p[s]]) break; \
+    p[k] = p[s]; k = s; \
+  } p[k] = temp; }
+
+void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size)
+{
+  if (size <= 1)
+    return;
+  p--;
+  {
+    size_t i = size / 2;
+    do
+    {
+      UInt32 temp = p[i];
+      HeapSortRefDown(p, vals, i, size, temp);
+    }
+    while (--i != 0);
+  }
+  do
+  {
+    UInt32 temp = p[size];
+    p[size--] = p[1];
+    HeapSortRefDown(p, vals, 1, size, temp);
+  }
+  while (size > 1);
+}
+*/
diff --git a/deps/libchdr/deps/zlib-1.2.11/CMakeLists.txt b/deps/libchdr/deps/zlib-1.2.11/CMakeLists.txt
new file mode 100644 (file)
index 0000000..37b04b9
--- /dev/null
@@ -0,0 +1,27 @@
+add_library(zlib STATIC
+  zconf.h
+  zlib.h
+  adler32.c
+  compress.c
+  crc32.c
+  crc32.h
+  deflate.c
+  deflate.h
+  gzguts.h
+  infback.c
+  inffast.c
+  inffast.h
+  inffixed.h
+  inflate.c
+  inflate.h
+  inftrees.c
+  inftrees.h
+  trees.c
+  trees.h
+  uncompr.c
+  zutil.c
+  zutil.h
+)
+
+target_include_directories(zlib PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
+target_include_directories(zlib INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
diff --git a/deps/libchdr/deps/zlib-1.2.11/ChangeLog b/deps/libchdr/deps/zlib-1.2.11/ChangeLog
new file mode 100644 (file)
index 0000000..30199a6
--- /dev/null
@@ -0,0 +1,1515 @@
+
+                ChangeLog file for zlib
+
+Changes in 1.2.11 (15 Jan 2017)
+- Fix deflate stored bug when pulling last block from window
+- Permit immediate deflateParams changes before any deflate input
+
+Changes in 1.2.10 (2 Jan 2017)
+- Avoid warnings on snprintf() return value
+- Fix bug in deflate_stored() for zero-length input
+- Fix bug in gzwrite.c that produced corrupt gzip files
+- Remove files to be installed before copying them in Makefile.in
+- Add warnings when compiling with assembler code
+
+Changes in 1.2.9 (31 Dec 2016)
+- Fix contrib/minizip to permit unzipping with desktop API [Zouzou]
+- Improve contrib/blast to return unused bytes
+- Assure that gzoffset() is correct when appending
+- Improve compress() and uncompress() to support large lengths
+- Fix bug in test/example.c where error code not saved
+- Remedy Coverity warning [Randers-Pehrson]
+- Improve speed of gzprintf() in transparent mode
+- Fix inflateInit2() bug when windowBits is 16 or 32
+- Change DEBUG macro to ZLIB_DEBUG
+- Avoid uninitialized access by gzclose_w()
+- Allow building zlib outside of the source directory
+- Fix bug that accepted invalid zlib header when windowBits is zero
+- Fix gzseek() problem on MinGW due to buggy _lseeki64 there
+- Loop on write() calls in gzwrite.c in case of non-blocking I/O
+- Add --warn (-w) option to ./configure for more compiler warnings
+- Reject a window size of 256 bytes if not using the zlib wrapper
+- Fix bug when level 0 used with Z_HUFFMAN or Z_RLE
+- Add --debug (-d) option to ./configure to define ZLIB_DEBUG
+- Fix bugs in creating a very large gzip header
+- Add uncompress2() function, which returns the input size used
+- Assure that deflateParams() will not switch functions mid-block
+- Dramatically speed up deflation for level 0 (storing)
+- Add gzfread(), duplicating the interface of fread()
+- Add gzfwrite(), duplicating the interface of fwrite()
+- Add deflateGetDictionary() function
+- Use snprintf() for later versions of Microsoft C
+- Fix *Init macros to use z_ prefix when requested
+- Replace as400 with os400 for OS/400 support [Monnerat]
+- Add crc32_z() and adler32_z() functions with size_t lengths
+- Update Visual Studio project files [AraHaan]
+
+Changes in 1.2.8 (28 Apr 2013)
+- Update contrib/minizip/iowin32.c for Windows RT [Vollant]
+- Do not force Z_CONST for C++
+- Clean up contrib/vstudio [Roß]
+- Correct spelling error in zlib.h
+- Fix mixed line endings in contrib/vstudio
+
+Changes in 1.2.7.3 (13 Apr 2013)
+- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc
+
+Changes in 1.2.7.2 (13 Apr 2013)
+- Change check for a four-byte type back to hexadecimal
+- Fix typo in win32/Makefile.msc
+- Add casts in gzwrite.c for pointer differences
+
+Changes in 1.2.7.1 (24 Mar 2013)
+- Replace use of unsafe string functions with snprintf if available
+- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink]
+- Fix gzgetc undefine when Z_PREFIX set [Turk]
+- Eliminate use of mktemp in Makefile (not always available)
+- Fix bug in 'F' mode for gzopen()
+- Add inflateGetDictionary() function
+- Correct comment in deflate.h
+- Use _snprintf for snprintf in Microsoft C
+- On Darwin, only use /usr/bin/libtool if libtool is not Apple
+- Delete "--version" file if created by "ar --version" [Richard G.]
+- Fix configure check for veracity of compiler error return codes
+- Fix CMake compilation of static lib for MSVC2010 x64
+- Remove unused variable in infback9.c
+- Fix argument checks in gzlog_compress() and gzlog_write()
+- Clean up the usage of z_const and respect const usage within zlib
+- Clean up examples/gzlog.[ch] comparisons of different types
+- Avoid shift equal to bits in type (caused endless loop)
+- Fix uninitialized value bug in gzputc() introduced by const patches
+- Fix memory allocation error in examples/zran.c [Nor]
+- Fix bug where gzopen(), gzclose() would write an empty file
+- Fix bug in gzclose() when gzwrite() runs out of memory
+- Check for input buffer malloc failure in examples/gzappend.c
+- Add note to contrib/blast to use binary mode in stdio
+- Fix comparisons of differently signed integers in contrib/blast
+- Check for invalid code length codes in contrib/puff
+- Fix serious but very rare decompression bug in inftrees.c
+- Update inflateBack() comments, since inflate() can be faster
+- Use underscored I/O function names for WINAPI_FAMILY
+- Add _tr_flush_bits to the external symbols prefixed by --zprefix
+- Add contrib/vstudio/vc10 pre-build step for static only
+- Quote --version-script argument in CMakeLists.txt
+- Don't specify --version-script on Apple platforms in CMakeLists.txt
+- Fix casting error in contrib/testzlib/testzlib.c
+- Fix types in contrib/minizip to match result of get_crc_table()
+- Simplify contrib/vstudio/vc10 with 'd' suffix
+- Add TOP support to win32/Makefile.msc
+- Suport i686 and amd64 assembler builds in CMakeLists.txt
+- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h
+- Add vc11 and vc12 build files to contrib/vstudio
+- Add gzvprintf() as an undocumented function in zlib
+- Fix configure for Sun shell
+- Remove runtime check in configure for four-byte integer type
+- Add casts and consts to ease user conversion to C++
+- Add man pages for minizip and miniunzip
+- In Makefile uninstall, don't rm if preceding cd fails
+- Do not return Z_BUF_ERROR if deflateParam() has nothing to write
+
+Changes in 1.2.7 (2 May 2012)
+- Replace use of memmove() with a simple copy for portability
+- Test for existence of strerror
+- Restore gzgetc_ for backward compatibility with 1.2.6
+- Fix build with non-GNU make on Solaris
+- Require gcc 4.0 or later on Mac OS X to use the hidden attribute
+- Include unistd.h for Watcom C
+- Use __WATCOMC__ instead of __WATCOM__
+- Do not use the visibility attribute if NO_VIZ defined
+- Improve the detection of no hidden visibility attribute
+- Avoid using __int64 for gcc or solo compilation
+- Cast to char * in gzprintf to avoid warnings [Zinser]
+- Fix make_vms.com for VAX [Zinser]
+- Don't use library or built-in byte swaps
+- Simplify test and use of gcc hidden attribute
+- Fix bug in gzclose_w() when gzwrite() fails to allocate memory
+- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen()
+- Fix bug in test/minigzip.c for configure --solo
+- Fix contrib/vstudio project link errors [Mohanathas]
+- Add ability to choose the builder in make_vms.com [Schweda]
+- Add DESTDIR support to mingw32 win32/Makefile.gcc
+- Fix comments in win32/Makefile.gcc for proper usage
+- Allow overriding the default install locations for cmake
+- Generate and install the pkg-config file with cmake
+- Build both a static and a shared version of zlib with cmake
+- Include version symbols for cmake builds
+- If using cmake with MSVC, add the source directory to the includes
+- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta]
+- Move obsolete emx makefile to old [Truta]
+- Allow the use of -Wundef when compiling or using zlib
+- Avoid the use of the -u option with mktemp
+- Improve inflate() documentation on the use of Z_FINISH
+- Recognize clang as gcc
+- Add gzopen_w() in Windows for wide character path names
+- Rename zconf.h in CMakeLists.txt to move it out of the way
+- Add source directory in CMakeLists.txt for building examples
+- Look in build directory for zlib.pc in CMakeLists.txt
+- Remove gzflags from zlibvc.def in vc9 and vc10
+- Fix contrib/minizip compilation in the MinGW environment
+- Update ./configure for Solaris, support --64 [Mooney]
+- Remove -R. from Solaris shared build (possible security issue)
+- Avoid race condition for parallel make (-j) running example
+- Fix type mismatch between get_crc_table() and crc_table
+- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler]
+- Fix the path to zlib.map in CMakeLists.txt
+- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe]
+- Add instructions to win32/Makefile.gcc for shared install [Torri]
+
+Changes in 1.2.6.1 (12 Feb 2012)
+- Avoid the use of the Objective-C reserved name "id"
+- Include io.h in gzguts.h for Microsoft compilers
+- Fix problem with ./configure --prefix and gzgetc macro
+- Include gz_header definition when compiling zlib solo
+- Put gzflags() functionality back in zutil.c
+- Avoid library header include in crc32.c for Z_SOLO
+- Use name in GCC_CLASSIC as C compiler for coverage testing, if set
+- Minor cleanup in contrib/minizip/zip.c [Vollant]
+- Update make_vms.com [Zinser]
+- Remove unnecessary gzgetc_ function
+- Use optimized byte swap operations for Microsoft and GNU [Snyder]
+- Fix minor typo in zlib.h comments [Rzesniowiecki]
+
+Changes in 1.2.6 (29 Jan 2012)
+- Update the Pascal interface in contrib/pascal
+- Fix function numbers for gzgetc_ in zlibvc.def files
+- Fix configure.ac for contrib/minizip [Schiffer]
+- Fix large-entry detection in minizip on 64-bit systems [Schiffer]
+- Have ./configure use the compiler return code for error indication
+- Fix CMakeLists.txt for cross compilation [McClure]
+- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes]
+- Fix compilation of contrib/minizip on FreeBSD [Marquez]
+- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath]
+- Include io.h for Turbo C / Borland C on all platforms [Truta]
+- Make version explicit in contrib/minizip/configure.ac [Bosmans]
+- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant]
+- Minor cleanup up contrib/minizip/unzip.c [Vollant]
+- Fix bug when compiling minizip with C++ [Vollant]
+- Protect for long name and extra fields in contrib/minizip [Vollant]
+- Avoid some warnings in contrib/minizip [Vollant]
+- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip
+- Add missing libs to minizip linker command
+- Add support for VPATH builds in contrib/minizip
+- Add an --enable-demos option to contrib/minizip/configure
+- Add the generation of configure.log by ./configure
+- Exit when required parameters not provided to win32/Makefile.gcc
+- Have gzputc return the character written instead of the argument
+- Use the -m option on ldconfig for BSD systems [Tobias]
+- Correct in zlib.map when deflateResetKeep was added
+
+Changes in 1.2.5.3 (15 Jan 2012)
+- Restore gzgetc function for binary compatibility
+- Do not use _lseeki64 under Borland C++ [Truta]
+- Update win32/Makefile.msc to build test/*.c [Truta]
+- Remove old/visualc6 given CMakefile and other alternatives
+- Update AS400 build files and documentation [Monnerat]
+- Update win32/Makefile.gcc to build test/*.c [Truta]
+- Permit stronger flushes after Z_BLOCK flushes
+- Avoid extraneous empty blocks when doing empty flushes
+- Permit Z_NULL arguments to deflatePending
+- Allow deflatePrime() to insert bits in the middle of a stream
+- Remove second empty static block for Z_PARTIAL_FLUSH
+- Write out all of the available bits when using Z_BLOCK
+- Insert the first two strings in the hash table after a flush
+
+Changes in 1.2.5.2 (17 Dec 2011)
+- fix ld error: unable to find version dependency 'ZLIB_1.2.5'
+- use relative symlinks for shared libs
+- Avoid searching past window for Z_RLE strategy
+- Assure that high-water mark initialization is always applied in deflate
+- Add assertions to fill_window() in deflate.c to match comments
+- Update python link in README
+- Correct spelling error in gzread.c
+- Fix bug in gzgets() for a concatenated empty gzip stream
+- Correct error in comment for gz_make()
+- Change gzread() and related to ignore junk after gzip streams
+- Allow gzread() and related to continue after gzclearerr()
+- Allow gzrewind() and gzseek() after a premature end-of-file
+- Simplify gzseek() now that raw after gzip is ignored
+- Change gzgetc() to a macro for speed (~40% speedup in testing)
+- Fix gzclose() to return the actual error last encountered
+- Always add large file support for windows
+- Include zconf.h for windows large file support
+- Include zconf.h.cmakein for windows large file support
+- Update zconf.h.cmakein on make distclean
+- Merge vestigial vsnprintf determination from zutil.h to gzguts.h
+- Clarify how gzopen() appends in zlib.h comments
+- Correct documentation of gzdirect() since junk at end now ignored
+- Add a transparent write mode to gzopen() when 'T' is in the mode
+- Update python link in zlib man page
+- Get inffixed.h and MAKEFIXED result to match
+- Add a ./config --solo option to make zlib subset with no library use
+- Add undocumented inflateResetKeep() function for CAB file decoding
+- Add --cover option to ./configure for gcc coverage testing
+- Add #define ZLIB_CONST option to use const in the z_stream interface
+- Add comment to gzdopen() in zlib.h to use dup() when using fileno()
+- Note behavior of uncompress() to provide as much data as it can
+- Add files in contrib/minizip to aid in building libminizip
+- Split off AR options in Makefile.in and configure
+- Change ON macro to Z_ARG to avoid application conflicts
+- Facilitate compilation with Borland C++ for pragmas and vsnprintf
+- Include io.h for Turbo C / Borland C++
+- Move example.c and minigzip.c to test/
+- Simplify incomplete code table filling in inflate_table()
+- Remove code from inflate.c and infback.c that is impossible to execute
+- Test the inflate code with full coverage
+- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw)
+- Add deflateResetKeep and fix inflateResetKeep to retain dictionary
+- Fix gzwrite.c to accommodate reduced memory zlib compilation
+- Have inflate() with Z_FINISH avoid the allocation of a window
+- Do not set strm->adler when doing raw inflate
+- Fix gzeof() to behave just like feof() when read is not past end of file
+- Fix bug in gzread.c when end-of-file is reached
+- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF
+- Document gzread() capability to read concurrently written files
+- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo]
+
+Changes in 1.2.5.1 (10 Sep 2011)
+- Update FAQ entry on shared builds (#13)
+- Avoid symbolic argument to chmod in Makefile.in
+- Fix bug and add consts in contrib/puff [Oberhumer]
+- Update contrib/puff/zeros.raw test file to have all block types
+- Add full coverage test for puff in contrib/puff/Makefile
+- Fix static-only-build install in Makefile.in
+- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno]
+- Add libz.a dependency to shared in Makefile.in for parallel builds
+- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out
+- Replace $(...) with `...` in configure for non-bash sh [Bowler]
+- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen]
+- Add solaris* to Linux* in configure to allow gcc use [Groffen]
+- Add *bsd* to Linux* case in configure [Bar-Lev]
+- Add inffast.obj to dependencies in win32/Makefile.msc
+- Correct spelling error in deflate.h [Kohler]
+- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc
+- Add test to configure for GNU C looking for gcc in output of $cc -v
+- Add zlib.pc generation to win32/Makefile.gcc [Weigelt]
+- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not
+- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense
+- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser)
+- Make stronger test in zconf.h to include unistd.h for LFS
+- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack]
+- Fix zlib.h LFS support when Z_PREFIX used
+- Add updated as400 support (removed from old) [Monnerat]
+- Avoid deflate sensitivity to volatile input data
+- Avoid division in adler32_combine for NO_DIVIDE
+- Clarify the use of Z_FINISH with deflateBound() amount of space
+- Set binary for output file in puff.c
+- Use u4 type for crc_table to avoid conversion warnings
+- Apply casts in zlib.h to avoid conversion warnings
+- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller]
+- Improve inflateSync() documentation to note indeterminancy
+- Add deflatePending() function to return the amount of pending output
+- Correct the spelling of "specification" in FAQ [Randers-Pehrson]
+- Add a check in configure for stdarg.h, use for gzprintf()
+- Check that pointers fit in ints when gzprint() compiled old style
+- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler]
+- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt]
+- Add debug records in assmebler code [Londer]
+- Update RFC references to use http://tools.ietf.org/html/... [Li]
+- Add --archs option, use of libtool to configure for Mac OS X [Borstel]
+
+Changes in 1.2.5 (19 Apr 2010)
+- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev]
+- Default to libdir as sharedlibdir in configure [Nieder]
+- Update copyright dates on modified source files
+- Update trees.c to be able to generate modified trees.h
+- Exit configure for MinGW, suggesting win32/Makefile.gcc
+- Check for NULL path in gz_open [Homurlu]
+
+Changes in 1.2.4.5 (18 Apr 2010)
+- Set sharedlibdir in configure [Torok]
+- Set LDFLAGS in Makefile.in [Bar-Lev]
+- Avoid mkdir objs race condition in Makefile.in [Bowler]
+- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays
+- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C
+- Don't use hidden attribute when it is a warning generator (e.g. Solaris)
+
+Changes in 1.2.4.4 (18 Apr 2010)
+- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok]
+- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty
+- Try to use bash or ksh regardless of functionality of /bin/sh
+- Fix configure incompatibility with NetBSD sh
+- Remove attempt to run under bash or ksh since have better NetBSD fix
+- Fix win32/Makefile.gcc for MinGW [Bar-Lev]
+- Add diagnostic messages when using CROSS_PREFIX in configure
+- Added --sharedlibdir option to configure [Weigelt]
+- Use hidden visibility attribute when available [Frysinger]
+
+Changes in 1.2.4.3 (10 Apr 2010)
+- Only use CROSS_PREFIX in configure for ar and ranlib if they exist
+- Use CROSS_PREFIX for nm [Bar-Lev]
+- Assume _LARGEFILE64_SOURCE defined is equivalent to true
+- Avoid use of undefined symbols in #if with && and ||
+- Make *64 prototypes in gzguts.h consistent with functions
+- Add -shared load option for MinGW in configure [Bowler]
+- Move z_off64_t to public interface, use instead of off64_t
+- Remove ! from shell test in configure (not portable to Solaris)
+- Change +0 macro tests to -0 for possibly increased portability
+
+Changes in 1.2.4.2 (9 Apr 2010)
+- Add consistent carriage returns to readme.txt's in masmx86 and masmx64
+- Really provide prototypes for *64 functions when building without LFS
+- Only define unlink() in minigzip.c if unistd.h not included
+- Update README to point to contrib/vstudio project files
+- Move projects/vc6 to old/ and remove projects/
+- Include stdlib.h in minigzip.c for setmode() definition under WinCE
+- Clean up assembler builds in win32/Makefile.msc [Rowe]
+- Include sys/types.h for Microsoft for off_t definition
+- Fix memory leak on error in gz_open()
+- Symbolize nm as $NM in configure [Weigelt]
+- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt]
+- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined
+- Fix bug in gzeof() to take into account unused input data
+- Avoid initialization of structures with variables in puff.c
+- Updated win32/README-WIN32.txt [Rowe]
+
+Changes in 1.2.4.1 (28 Mar 2010)
+- Remove the use of [a-z] constructs for sed in configure [gentoo 310225]
+- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech]
+- Restore "for debugging" comment on sprintf() in gzlib.c
+- Remove fdopen for MVS from gzguts.h
+- Put new README-WIN32.txt in win32 [Rowe]
+- Add check for shell to configure and invoke another shell if needed
+- Fix big fat stinking bug in gzseek() on uncompressed files
+- Remove vestigial F_OPEN64 define in zutil.h
+- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE
+- Avoid errors on non-LFS systems when applications define LFS macros
+- Set EXE to ".exe" in configure for MINGW [Kahle]
+- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill]
+- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev]
+- Add DLL install in win32/makefile.gcc [Bar-Lev]
+- Allow Linux* or linux* from uname in configure [Bar-Lev]
+- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev]
+- Add cross-compilation prefixes to configure [Bar-Lev]
+- Match type exactly in gz_load() invocation in gzread.c
+- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func
+- Provide prototypes for *64 functions when building zlib without LFS
+- Don't use -lc when linking shared library on MinGW
+- Remove errno.h check in configure and vestigial errno code in zutil.h
+
+Changes in 1.2.4 (14 Mar 2010)
+- Fix VER3 extraction in configure for no fourth subversion
+- Update zlib.3, add docs to Makefile.in to make .pdf out of it
+- Add zlib.3.pdf to distribution
+- Don't set error code in gzerror() if passed pointer is NULL
+- Apply destination directory fixes to CMakeLists.txt [Lowman]
+- Move #cmakedefine's to a new zconf.in.cmakein
+- Restore zconf.h for builds that don't use configure or cmake
+- Add distclean to dummy Makefile for convenience
+- Update and improve INDEX, README, and FAQ
+- Update CMakeLists.txt for the return of zconf.h [Lowman]
+- Update contrib/vstudio/vc9 and vc10 [Vollant]
+- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc
+- Apply license and readme changes to contrib/asm686 [Raiter]
+- Check file name lengths and add -c option in minigzip.c [Li]
+- Update contrib/amd64 and contrib/masmx86/ [Vollant]
+- Avoid use of "eof" parameter in trees.c to not shadow library variable
+- Update make_vms.com for removal of zlibdefs.h [Zinser]
+- Update assembler code and vstudio projects in contrib [Vollant]
+- Remove outdated assembler code contrib/masm686 and contrib/asm586
+- Remove old vc7 and vc8 from contrib/vstudio
+- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe]
+- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open()
+- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant]
+- Remove *64 functions from win32/zlib.def (they're not 64-bit yet)
+- Fix bug in void-returning vsprintf() case in gzwrite.c
+- Fix name change from inflate.h in contrib/inflate86/inffas86.c
+- Check if temporary file exists before removing in make_vms.com [Zinser]
+- Fix make install and uninstall for --static option
+- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta]
+- Update readme.txt in contrib/masmx64 and masmx86 to assemble
+
+Changes in 1.2.3.9 (21 Feb 2010)
+- Expunge gzio.c
+- Move as400 build information to old
+- Fix updates in contrib/minizip and contrib/vstudio
+- Add const to vsnprintf test in configure to avoid warnings [Weigelt]
+- Delete zconf.h (made by configure) [Weigelt]
+- Change zconf.in.h to zconf.h.in per convention [Weigelt]
+- Check for NULL buf in gzgets()
+- Return empty string for gzgets() with len == 1 (like fgets())
+- Fix description of gzgets() in zlib.h for end-of-file, NULL return
+- Update minizip to 1.1 [Vollant]
+- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c
+- Note in zlib.h that gzerror() should be used to distinguish from EOF
+- Remove use of snprintf() from gzlib.c
+- Fix bug in gzseek()
+- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant]
+- Fix zconf.h generation in CMakeLists.txt [Lowman]
+- Improve comments in zconf.h where modified by configure
+
+Changes in 1.2.3.8 (13 Feb 2010)
+- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer]
+- Use z_off64_t in gz_zero() and gz_skip() to match state->skip
+- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t)
+- Revert to Makefile.in from 1.2.3.6 (live with the clutter)
+- Fix missing error return in gzflush(), add zlib.h note
+- Add *64 functions to zlib.map [Levin]
+- Fix signed/unsigned comparison in gz_comp()
+- Use SFLAGS when testing shared linking in configure
+- Add --64 option to ./configure to use -m64 with gcc
+- Fix ./configure --help to correctly name options
+- Have make fail if a test fails [Levin]
+- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson]
+- Remove assembler object files from contrib
+
+Changes in 1.2.3.7 (24 Jan 2010)
+- Always gzopen() with O_LARGEFILE if available
+- Fix gzdirect() to work immediately after gzopen() or gzdopen()
+- Make gzdirect() more precise when the state changes while reading
+- Improve zlib.h documentation in many places
+- Catch memory allocation failure in gz_open()
+- Complete close operation if seek forward in gzclose_w() fails
+- Return Z_ERRNO from gzclose_r() if close() fails
+- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL
+- Return zero for gzwrite() errors to match zlib.h description
+- Return -1 on gzputs() error to match zlib.h description
+- Add zconf.in.h to allow recovery from configure modification [Weigelt]
+- Fix static library permissions in Makefile.in [Weigelt]
+- Avoid warnings in configure tests that hide functionality [Weigelt]
+- Add *BSD and DragonFly to Linux case in configure [gentoo 123571]
+- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212]
+- Avoid access of uninitialized data for first inflateReset2 call [Gomes]
+- Keep object files in subdirectories to reduce the clutter somewhat
+- Remove default Makefile and zlibdefs.h, add dummy Makefile
+- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_
+- Remove zlibdefs.h completely -- modify zconf.h instead
+
+Changes in 1.2.3.6 (17 Jan 2010)
+- Avoid void * arithmetic in gzread.c and gzwrite.c
+- Make compilers happier with const char * for gz_error message
+- Avoid unused parameter warning in inflate.c
+- Avoid signed-unsigned comparison warning in inflate.c
+- Indent #pragma's for traditional C
+- Fix usage of strwinerror() in glib.c, change to gz_strwinerror()
+- Correct email address in configure for system options
+- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser]
+- Update zlib.map [Brown]
+- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok]
+- Apply various fixes to CMakeLists.txt [Lowman]
+- Add checks on len in gzread() and gzwrite()
+- Add error message for no more room for gzungetc()
+- Remove zlib version check in gzwrite()
+- Defer compression of gzprintf() result until need to
+- Use snprintf() in gzdopen() if available
+- Remove USE_MMAP configuration determination (only used by minigzip)
+- Remove examples/pigz.c (available separately)
+- Update examples/gun.c to 1.6
+
+Changes in 1.2.3.5 (8 Jan 2010)
+- Add space after #if in zutil.h for some compilers
+- Fix relatively harmless bug in deflate_fast() [Exarevsky]
+- Fix same problem in deflate_slow()
+- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown]
+- Add deflate_rle() for faster Z_RLE strategy run-length encoding
+- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding
+- Change name of "write" variable in inffast.c to avoid library collisions
+- Fix premature EOF from gzread() in gzio.c [Brown]
+- Use zlib header window size if windowBits is 0 in inflateInit2()
+- Remove compressBound() call in deflate.c to avoid linking compress.o
+- Replace use of errno in gz* with functions, support WinCE [Alves]
+- Provide alternative to perror() in minigzip.c for WinCE [Alves]
+- Don't use _vsnprintf on later versions of MSVC [Lowman]
+- Add CMake build script and input file [Lowman]
+- Update contrib/minizip to 1.1 [Svensson, Vollant]
+- Moved nintendods directory from contrib to .
+- Replace gzio.c with a new set of routines with the same functionality
+- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above
+- Update contrib/minizip to 1.1b
+- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h
+
+Changes in 1.2.3.4 (21 Dec 2009)
+- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility
+- Update comments in configure and Makefile.in for default --shared
+- Fix test -z's in configure [Marquess]
+- Build examplesh and minigzipsh when not testing
+- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h
+- Import LDFLAGS from the environment in configure
+- Fix configure to populate SFLAGS with discovered CFLAGS options
+- Adapt make_vms.com to the new Makefile.in [Zinser]
+- Add zlib2ansi script for C++ compilation [Marquess]
+- Add _FILE_OFFSET_BITS=64 test to make test (when applicable)
+- Add AMD64 assembler code for longest match to contrib [Teterin]
+- Include options from $SFLAGS when doing $LDSHARED
+- Simplify 64-bit file support by introducing z_off64_t type
+- Make shared object files in objs directory to work around old Sun cc
+- Use only three-part version number for Darwin shared compiles
+- Add rc option to ar in Makefile.in for when ./configure not run
+- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4*
+- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile
+- Protect against _FILE_OFFSET_BITS being defined when compiling zlib
+- Rename Makefile.in targets allstatic to static and allshared to shared
+- Fix static and shared Makefile.in targets to be independent
+- Correct error return bug in gz_open() by setting state [Brown]
+- Put spaces before ;;'s in configure for better sh compatibility
+- Add pigz.c (parallel implementation of gzip) to examples/
+- Correct constant in crc32.c to UL [Leventhal]
+- Reject negative lengths in crc32_combine()
+- Add inflateReset2() function to work like inflateEnd()/inflateInit2()
+- Include sys/types.h for _LARGEFILE64_SOURCE [Brown]
+- Correct typo in doc/algorithm.txt [Janik]
+- Fix bug in adler32_combine() [Zhu]
+- Catch missing-end-of-block-code error in all inflates and in puff
+    Assures that random input to inflate eventually results in an error
+- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/
+- Update ENOUGH and its usage to reflect discovered bounds
+- Fix gzerror() error report on empty input file [Brown]
+- Add ush casts in trees.c to avoid pedantic runtime errors
+- Fix typo in zlib.h uncompress() description [Reiss]
+- Correct inflate() comments with regard to automatic header detection
+- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays)
+- Put new version of gzlog (2.0) in examples with interruption recovery
+- Add puff compile option to permit invalid distance-too-far streams
+- Add puff TEST command options, ability to read piped input
+- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but
+  _LARGEFILE64_SOURCE not defined
+- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart
+- Fix deflateSetDictionary() to use all 32K for output consistency
+- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h)
+- Clear bytes after deflate lookahead to avoid use of uninitialized data
+- Change a limit in inftrees.c to be more transparent to Coverity Prevent
+- Update win32/zlib.def with exported symbols from zlib.h
+- Correct spelling errors in zlib.h [Willem, Sobrado]
+- Allow Z_BLOCK for deflate() to force a new block
+- Allow negative bits in inflatePrime() to delete existing bit buffer
+- Add Z_TREES flush option to inflate() to return at end of trees
+- Add inflateMark() to return current state information for random access
+- Add Makefile for NintendoDS to contrib [Costa]
+- Add -w in configure compile tests to avoid spurious warnings [Beucler]
+- Fix typos in zlib.h comments for deflateSetDictionary()
+- Fix EOF detection in transparent gzread() [Maier]
+
+Changes in 1.2.3.3 (2 October 2006)
+- Make --shared the default for configure, add a --static option
+- Add compile option to permit invalid distance-too-far streams
+- Add inflateUndermine() function which is required to enable above
+- Remove use of "this" variable name for C++ compatibility [Marquess]
+- Add testing of shared library in make test, if shared library built
+- Use ftello() and fseeko() if available instead of ftell() and fseek()
+- Provide two versions of all functions that use the z_off_t type for
+  binary compatibility -- a normal version and a 64-bit offset version,
+  per the Large File Support Extension when _LARGEFILE64_SOURCE is
+  defined; use the 64-bit versions by default when _FILE_OFFSET_BITS
+  is defined to be 64
+- Add a --uname= option to configure to perhaps help with cross-compiling
+
+Changes in 1.2.3.2 (3 September 2006)
+- Turn off silly Borland warnings [Hay]
+- Use off64_t and define _LARGEFILE64_SOURCE when present
+- Fix missing dependency on inffixed.h in Makefile.in
+- Rig configure --shared to build both shared and static [Teredesai, Truta]
+- Remove zconf.in.h and instead create a new zlibdefs.h file
+- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant]
+- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt]
+
+Changes in 1.2.3.1 (16 August 2006)
+- Add watcom directory with OpenWatcom make files [Daniel]
+- Remove #undef of FAR in zconf.in.h for MVS [Fedtke]
+- Update make_vms.com [Zinser]
+- Use -fPIC for shared build in configure [Teredesai, Nicholson]
+- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen]
+- Use fdopen() (not _fdopen()) for Interix in zutil.h [Bäck]
+- Add some FAQ entries about the contrib directory
+- Update the MVS question in the FAQ
+- Avoid extraneous reads after EOF in gzio.c [Brown]
+- Correct spelling of "successfully" in gzio.c [Randers-Pehrson]
+- Add comments to zlib.h about gzerror() usage [Brown]
+- Set extra flags in gzip header in gzopen() like deflate() does
+- Make configure options more compatible with double-dash conventions
+  [Weigelt]
+- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen]
+- Fix uninstall target in Makefile.in [Truta]
+- Add pkgconfig support [Weigelt]
+- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt]
+- Replace set_data_type() with a more accurate detect_data_type() in
+  trees.c, according to the txtvsbin.txt document [Truta]
+- Swap the order of #include <stdio.h> and #include "zlib.h" in
+  gzio.c, example.c and minigzip.c [Truta]
+- Shut up annoying VS2005 warnings about standard C deprecation [Rowe,
+  Truta] (where?)
+- Fix target "clean" from win32/Makefile.bor [Truta]
+- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe]
+- Update zlib www home address in win32/DLL_FAQ.txt [Truta]
+- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove]
+- Enable browse info in the "Debug" and "ASM Debug" configurations in
+  the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta]
+- Add pkgconfig support [Weigelt]
+- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h,
+  for use in win32/zlib1.rc [Polushin, Rowe, Truta]
+- Add a document that explains the new text detection scheme to
+  doc/txtvsbin.txt [Truta]
+- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta]
+- Move algorithm.txt into doc/ [Truta]
+- Synchronize FAQ with website
+- Fix compressBound(), was low for some pathological cases [Fearnley]
+- Take into account wrapper variations in deflateBound()
+- Set examples/zpipe.c input and output to binary mode for Windows
+- Update examples/zlib_how.html with new zpipe.c (also web site)
+- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems
+  that gcc became pickier in 4.0)
+- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain
+  un-versioned, the patch adds versioning only for symbols introduced in
+  zlib-1.2.0 or later.  It also declares as local those symbols which are
+  not designed to be exported." [Levin]
+- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure
+- Do not initialize global static by default in trees.c, add a response
+  NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess]
+- Don't use strerror() in gzio.c under WinCE [Yakimov]
+- Don't use errno.h in zutil.h under WinCE [Yakimov]
+- Move arguments for AR to its usage to allow replacing ar [Marot]
+- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson]
+- Improve inflateInit() and inflateInit2() documentation
+- Fix structure size comment in inflate.h
+- Change configure help option from --h* to --help [Santos]
+
+Changes in 1.2.3 (18 July 2005)
+- Apply security vulnerability fixes to contrib/infback9 as well
+- Clean up some text files (carriage returns, trailing space)
+- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant]
+
+Changes in 1.2.2.4 (11 July 2005)
+- Add inflatePrime() function for starting inflation at bit boundary
+- Avoid some Visual C warnings in deflate.c
+- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit
+  compile
+- Fix some spelling errors in comments [Betts]
+- Correct inflateInit2() error return documentation in zlib.h
+- Add zran.c example of compressed data random access to examples
+  directory, shows use of inflatePrime()
+- Fix cast for assignments to strm->state in inflate.c and infback.c
+- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer]
+- Move declarations of gf2 functions to right place in crc32.c [Oberhumer]
+- Add cast in trees.c t avoid a warning [Oberhumer]
+- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer]
+- Update make_vms.com [Zinser]
+- Initialize state->write in inflateReset() since copied in inflate_fast()
+- Be more strict on incomplete code sets in inflate_table() and increase
+  ENOUGH and MAXD -- this repairs a possible security vulnerability for
+  invalid inflate input.  Thanks to Tavis Ormandy and Markus Oberhumer for
+  discovering the vulnerability and providing test cases.
+- Add ia64 support to configure for HP-UX [Smith]
+- Add error return to gzread() for format or i/o error [Levin]
+- Use malloc.h for OS/2 [Necasek]
+
+Changes in 1.2.2.3 (27 May 2005)
+- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile
+- Typecast fread() return values in gzio.c [Vollant]
+- Remove trailing space in minigzip.c outmode (VC++ can't deal with it)
+- Fix crc check bug in gzread() after gzungetc() [Heiner]
+- Add the deflateTune() function to adjust internal compression parameters
+- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack)
+- Remove an incorrect assertion in examples/zpipe.c
+- Add C++ wrapper in infback9.h [Donais]
+- Fix bug in inflateCopy() when decoding fixed codes
+- Note in zlib.h how much deflateSetDictionary() actually uses
+- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used)
+- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer]
+- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer]
+- Add gzdirect() function to indicate transparent reads
+- Update contrib/minizip [Vollant]
+- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer]
+- Add casts in crc32.c to avoid warnings [Oberhumer]
+- Add contrib/masmx64 [Vollant]
+- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant]
+
+Changes in 1.2.2.2 (30 December 2004)
+- Replace structure assignments in deflate.c and inflate.c with zmemcpy to
+  avoid implicit memcpy calls (portability for no-library compilation)
+- Increase sprintf() buffer size in gzdopen() to allow for large numbers
+- Add INFLATE_STRICT to check distances against zlib header
+- Improve WinCE errno handling and comments [Chang]
+- Remove comment about no gzip header processing in FAQ
+- Add Z_FIXED strategy option to deflateInit2() to force fixed trees
+- Add updated make_vms.com [Coghlan], update README
+- Create a new "examples" directory, move gzappend.c there, add zpipe.c,
+  fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html.
+- Add FAQ entry and comments in deflate.c on uninitialized memory access
+- Add Solaris 9 make options in configure [Gilbert]
+- Allow strerror() usage in gzio.c for STDC
+- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer]
+- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant]
+- Use z_off_t for adler32_combine() and crc32_combine() lengths
+- Make adler32() much faster for small len
+- Use OS_CODE in deflate() default gzip header
+
+Changes in 1.2.2.1 (31 October 2004)
+- Allow inflateSetDictionary() call for raw inflate
+- Fix inflate header crc check bug for file names and comments
+- Add deflateSetHeader() and gz_header structure for custom gzip headers
+- Add inflateGetheader() to retrieve gzip headers
+- Add crc32_combine() and adler32_combine() functions
+- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list
+- Use zstreamp consistently in zlib.h (inflate_back functions)
+- Remove GUNZIP condition from definition of inflate_mode in inflate.h
+  and in contrib/inflate86/inffast.S [Truta, Anderson]
+- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson]
+- Update projects/README.projects and projects/visualc6 [Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta]
+- Deprecate Z_ASCII; use Z_TEXT instead [Truta]
+- Use a new algorithm for setting strm->data_type in trees.c [Truta]
+- Do not define an exit() prototype in zutil.c unless DEBUG defined
+- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta]
+- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate()
+- Fix Darwin build version identification [Peterson]
+
+Changes in 1.2.2 (3 October 2004)
+- Update zlib.h comments on gzip in-memory processing
+- Set adler to 1 in inflateReset() to support Java test suite [Walles]
+- Add contrib/dotzlib [Ravn]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update contrib/minizip [Vollant]
+- Move contrib/visual-basic.txt to old/ [Truta]
+- Fix assembler builds in projects/visualc6/ [Truta]
+
+Changes in 1.2.1.2 (9 September 2004)
+- Update INDEX file
+- Fix trees.c to update strm->data_type (no one ever noticed!)
+- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown]
+- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE)
+- Add limited multitasking protection to DYNAMIC_CRC_TABLE
+- Add NO_vsnprintf for VMS in zutil.h [Mozilla]
+- Don't declare strerror() under VMS [Mozilla]
+- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize
+- Update contrib/ada [Anisimkov]
+- Update contrib/minizip [Vollant]
+- Fix configure to not hardcode directories for Darwin [Peterson]
+- Fix gzio.c to not return error on empty files [Brown]
+- Fix indentation; update version in contrib/delphi/ZLib.pas and
+  contrib/pascal/zlibpas.pas [Truta]
+- Update mkasm.bat in contrib/masmx86 [Truta]
+- Update contrib/untgz [Truta]
+- Add projects/README.projects [Truta]
+- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta]
+- Remove an unnecessary assignment to curr in inftrees.c [Truta]
+- Add OS/2 to exe builds in configure [Poltorak]
+- Remove err dummy parameter in zlib.h [Kientzle]
+
+Changes in 1.2.1.1 (9 January 2004)
+- Update email address in README
+- Several FAQ updates
+- Fix a big fat bug in inftrees.c that prevented decoding valid
+  dynamic blocks with only literals and no distance codes --
+  Thanks to "Hot Emu" for the bug report and sample file
+- Add a note to puff.c on no distance codes case.
+
+Changes in 1.2.1 (17 November 2003)
+- Remove a tab in contrib/gzappend/gzappend.c
+- Update some interfaces in contrib for new zlib functions
+- Update zlib version number in some contrib entries
+- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta]
+- Support shared libraries on Hurd and KFreeBSD [Brown]
+- Fix error in NO_DIVIDE option of adler32.c
+
+Changes in 1.2.0.8 (4 November 2003)
+- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas
+- Add experimental NO_DIVIDE #define in adler32.c
+    - Possibly faster on some processors (let me know if it is)
+- Correct Z_BLOCK to not return on first inflate call if no wrap
+- Fix strm->data_type on inflate() return to correctly indicate EOB
+- Add deflatePrime() function for appending in the middle of a byte
+- Add contrib/gzappend for an example of appending to a stream
+- Update win32/DLL_FAQ.txt [Truta]
+- Delete Turbo C comment in README [Truta]
+- Improve some indentation in zconf.h [Truta]
+- Fix infinite loop on bad input in configure script [Church]
+- Fix gzeof() for concatenated gzip files [Johnson]
+- Add example to contrib/visual-basic.txt [Michael B.]
+- Add -p to mkdir's in Makefile.in [vda]
+- Fix configure to properly detect presence or lack of printf functions
+- Add AS400 support [Monnerat]
+- Add a little Cygwin support [Wilson]
+
+Changes in 1.2.0.7 (21 September 2003)
+- Correct some debug formats in contrib/infback9
+- Cast a type in a debug statement in trees.c
+- Change search and replace delimiter in configure from % to # [Beebe]
+- Update contrib/untgz to 0.2 with various fixes [Truta]
+- Add build support for Amiga [Nikl]
+- Remove some directories in old that have been updated to 1.2
+- Add dylib building for Mac OS X in configure and Makefile.in
+- Remove old distribution stuff from Makefile
+- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X
+- Update links in README
+
+Changes in 1.2.0.6 (13 September 2003)
+- Minor FAQ updates
+- Update contrib/minizip to 1.00 [Vollant]
+- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta]
+- Update POSTINC comment for 68060 [Nikl]
+- Add contrib/infback9 with deflate64 decoding (unsupported)
+- For MVS define NO_vsnprintf and undefine FAR [van Burik]
+- Add pragma for fdopen on MVS [van Burik]
+
+Changes in 1.2.0.5 (8 September 2003)
+- Add OF to inflateBackEnd() declaration in zlib.h
+- Remember start when using gzdopen in the middle of a file
+- Use internal off_t counters in gz* functions to properly handle seeks
+- Perform more rigorous check for distance-too-far in inffast.c
+- Add Z_BLOCK flush option to return from inflate at block boundary
+- Set strm->data_type on return from inflate
+    - Indicate bits unused, if at block boundary, and if in last block
+- Replace size_t with ptrdiff_t in crc32.c, and check for correct size
+- Add condition so old NO_DEFLATE define still works for compatibility
+- FAQ update regarding the Windows DLL [Truta]
+- INDEX update: add qnx entry, remove aix entry [Truta]
+- Install zlib.3 into mandir [Wilson]
+- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta]
+- Adapt the zlib interface to the new DLL convention guidelines [Truta]
+- Introduce ZLIB_WINAPI macro to allow the export of functions using
+  the WINAPI calling convention, for Visual Basic [Vollant, Truta]
+- Update msdos and win32 scripts and makefiles [Truta]
+- Export symbols by name, not by ordinal, in win32/zlib.def [Truta]
+- Add contrib/ada [Anisimkov]
+- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta]
+- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant]
+- Add contrib/masm686 [Truta]
+- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm
+  [Truta, Vollant]
+- Update contrib/delphi; rename to contrib/pascal; add example [Truta]
+- Remove contrib/delphi2; add a new contrib/delphi [Truta]
+- Avoid inclusion of the nonstandard <memory.h> in contrib/iostream,
+  and fix some method prototypes [Truta]
+- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip
+  [Truta]
+- Avoid the use of backslash (\) in contrib/minizip [Vollant]
+- Fix file time handling in contrib/untgz; update makefiles [Truta]
+- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines
+  [Vollant]
+- Remove contrib/vstudio/vc15_16 [Vollant]
+- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta]
+- Update README.contrib [Truta]
+- Invert the assignment order of match_head and s->prev[...] in
+  INSERT_STRING [Truta]
+- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings
+  [Truta]
+- Compare function pointers with 0, not with NULL or Z_NULL [Truta]
+- Fix prototype of syncsearch in inflate.c [Truta]
+- Introduce ASMINF macro to be enabled when using an ASM implementation
+  of inflate_fast [Truta]
+- Change NO_DEFLATE to NO_GZCOMPRESS [Truta]
+- Modify test_gzio in example.c to take a single file name as a
+  parameter [Truta]
+- Exit the example.c program if gzopen fails [Truta]
+- Add type casts around strlen in example.c [Truta]
+- Remove casting to sizeof in minigzip.c; give a proper type
+  to the variable compared with SUFFIX_LEN [Truta]
+- Update definitions of STDC and STDC99 in zconf.h [Truta]
+- Synchronize zconf.h with the new Windows DLL interface [Truta]
+- Use SYS16BIT instead of __32BIT__ to distinguish between
+  16- and 32-bit platforms [Truta]
+- Use far memory allocators in small 16-bit memory models for
+  Turbo C [Truta]
+- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in
+  zlibCompileFlags [Truta]
+- Cygwin has vsnprintf [Wilson]
+- In Windows16, OS_CODE is 0, as in MSDOS [Truta]
+- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson]
+
+Changes in 1.2.0.4 (10 August 2003)
+- Minor FAQ updates
+- Be more strict when checking inflateInit2's windowBits parameter
+- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well
+- Add gzip wrapper option to deflateInit2 using windowBits
+- Add updated QNX rule in configure and qnx directory [Bonnefoy]
+- Make inflate distance-too-far checks more rigorous
+- Clean up FAR usage in inflate
+- Add casting to sizeof() in gzio.c and minigzip.c
+
+Changes in 1.2.0.3 (19 July 2003)
+- Fix silly error in gzungetc() implementation [Vollant]
+- Update contrib/minizip and contrib/vstudio [Vollant]
+- Fix printf format in example.c
+- Correct cdecl support in zconf.in.h [Anisimkov]
+- Minor FAQ updates
+
+Changes in 1.2.0.2 (13 July 2003)
+- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons
+- Attempt to avoid warnings in crc32.c for pointer-int conversion
+- Add AIX to configure, remove aix directory [Bakker]
+- Add some casts to minigzip.c
+- Improve checking after insecure sprintf() or vsprintf() calls
+- Remove #elif's from crc32.c
+- Change leave label to inf_leave in inflate.c and infback.c to avoid
+  library conflicts
+- Remove inflate gzip decoding by default--only enable gzip decoding by
+  special request for stricter backward compatibility
+- Add zlibCompileFlags() function to return compilation information
+- More typecasting in deflate.c to avoid warnings
+- Remove leading underscore from _Capital #defines [Truta]
+- Fix configure to link shared library when testing
+- Add some Windows CE target adjustments [Mai]
+- Remove #define ZLIB_DLL in zconf.h [Vollant]
+- Add zlib.3 [Rodgers]
+- Update RFC URL in deflate.c and algorithm.txt [Mai]
+- Add zlib_dll_FAQ.txt to contrib [Truta]
+- Add UL to some constants [Truta]
+- Update minizip and vstudio [Vollant]
+- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h
+- Expand use of NO_DUMMY_DECL to avoid all dummy structures
+- Added iostream3 to contrib [Schwardt]
+- Replace rewind() with fseek() for WinCE [Truta]
+- Improve setting of zlib format compression level flags
+    - Report 0 for huffman and rle strategies and for level == 0 or 1
+    - Report 2 only for level == 6
+- Only deal with 64K limit when necessary at compile time [Truta]
+- Allow TOO_FAR check to be turned off at compile time [Truta]
+- Add gzclearerr() function [Souza]
+- Add gzungetc() function
+
+Changes in 1.2.0.1 (17 March 2003)
+- Add Z_RLE strategy for run-length encoding [Truta]
+    - When Z_RLE requested, restrict matches to distance one
+    - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE
+- Correct FASTEST compilation to allow level == 0
+- Clean up what gets compiled for FASTEST
+- Incorporate changes to zconf.in.h [Vollant]
+    - Refine detection of Turbo C need for dummy returns
+    - Refine ZLIB_DLL compilation
+    - Include additional header file on VMS for off_t typedef
+- Try to use _vsnprintf where it supplants vsprintf [Vollant]
+- Add some casts in inffast.c
+- Enchance comments in zlib.h on what happens if gzprintf() tries to
+  write more than 4095 bytes before compression
+- Remove unused state from inflateBackEnd()
+- Remove exit(0) from minigzip.c, example.c
+- Get rid of all those darn tabs
+- Add "check" target to Makefile.in that does the same thing as "test"
+- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in
+- Update contrib/inflate86 [Anderson]
+- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant]
+- Add msdos and win32 directories with makefiles [Truta]
+- More additions and improvements to the FAQ
+
+Changes in 1.2.0 (9 March 2003)
+- New and improved inflate code
+    - About 20% faster
+    - Does not allocate 32K window unless and until needed
+    - Automatically detects and decompresses gzip streams
+    - Raw inflate no longer needs an extra dummy byte at end
+    - Added inflateBack functions using a callback interface--even faster
+      than inflate, useful for file utilities (gzip, zip)
+    - Added inflateCopy() function to record state for random access on
+      externally generated deflate streams (e.g. in gzip files)
+    - More readable code (I hope)
+- New and improved crc32()
+    - About 50% faster, thanks to suggestions from Rodney Brown
+- Add deflateBound() and compressBound() functions
+- Fix memory leak in deflateInit2()
+- Permit setting dictionary for raw deflate (for parallel deflate)
+- Fix const declaration for gzwrite()
+- Check for some malloc() failures in gzio.c
+- Fix bug in gzopen() on single-byte file 0x1f
+- Fix bug in gzread() on concatenated file with 0x1f at end of buffer
+  and next buffer doesn't start with 0x8b
+- Fix uncompress() to return Z_DATA_ERROR on truncated input
+- Free memory at end of example.c
+- Remove MAX #define in trees.c (conflicted with some libraries)
+- Fix static const's in deflate.c, gzio.c, and zutil.[ch]
+- Declare malloc() and free() in gzio.c if STDC not defined
+- Use malloc() instead of calloc() in zutil.c if int big enough
+- Define STDC for AIX
+- Add aix/ with approach for compiling shared library on AIX
+- Add HP-UX support for shared libraries in configure
+- Add OpenUNIX support for shared libraries in configure
+- Use $cc instead of gcc to build shared library
+- Make prefix directory if needed when installing
+- Correct Macintosh avoidance of typedef Byte in zconf.h
+- Correct Turbo C memory allocation when under Linux
+- Use libz.a instead of -lz in Makefile (assure use of compiled library)
+- Update configure to check for snprintf or vsnprintf functions and their
+  return value, warn during make if using an insecure function
+- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that
+  is lost when library is used--resolution is to build new zconf.h
+- Documentation improvements (in zlib.h):
+    - Document raw deflate and inflate
+    - Update RFCs URL
+    - Point out that zlib and gzip formats are different
+    - Note that Z_BUF_ERROR is not fatal
+    - Document string limit for gzprintf() and possible buffer overflow
+    - Note requirement on avail_out when flushing
+    - Note permitted values of flush parameter of inflate()
+- Add some FAQs (and even answers) to the FAQ
+- Add contrib/inflate86/ for x86 faster inflate
+- Add contrib/blast/ for PKWare Data Compression Library decompression
+- Add contrib/puff/ simple inflate for deflate format description
+
+Changes in 1.1.4 (11 March 2002)
+- ZFREE was repeated on same allocation on some error conditions.
+  This creates a security problem described in
+  http://www.zlib.org/advisory-2002-03-11.txt
+- Returned incorrect error (Z_MEM_ERROR) on some invalid data
+- Avoid accesses before window for invalid distances with inflate window
+  less than 32K.
+- force windowBits > 8 to avoid a bug in the encoder for a window size
+  of 256 bytes. (A complete fix will be available in 1.1.5).
+
+Changes in 1.1.3 (9 July 1998)
+- fix "an inflate input buffer bug that shows up on rare but persistent
+  occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+  (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+  See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+- Support gzdopen on Mac with Metrowerks (Jason Linhart)
+- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
+- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
+- avoid some warnings with Borland C (Tom Tanner)
+- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
+- emulate utime() for WIN32 in contrib/untgz  (Gilles Vollant)
+- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
+- use libdir and includedir in Makefile.in (Tim Mooney)
+- support shared libraries on OSF1 V4 (Tim Mooney)
+- remove so_locations in "make clean"  (Tim Mooney)
+- fix maketree.c compilation error (Glenn, Mark)
+- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
+- new Makefile.riscos (Rich Walker)
+- initialize static descriptors in trees.c for embedded targets (Nick Smith)
+- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
+- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
+- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
+- fix maketree.c to allow clean compilation of inffixed.h (Mark)
+- fix parameter check in deflateCopy (Gunther Nikl)
+- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
+- Many portability patches by Christian Spieler:
+  . zutil.c, zutil.h: added "const" for zmem*
+  . Make_vms.com: fixed some typos
+  . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
+  . msdos/Makefile.msc: remove "default rtl link library" info from obj files
+  . msdos/Makefile.*: use model-dependent name for the built zlib library
+  . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
+     new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
+- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
+- replace __far with _far for better portability (Christian Spieler, Tom Lane)
+- fix test for errno.h in configure (Tim Newsham)
+
+Changes in 1.1.2 (19 March 98)
+- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
+  See http://www.winimage.com/zLibDll/unzip.html
+- preinitialize the inflate tables for fixed codes, to make the code
+  completely thread safe (Mark)
+- some simplifications and slight speed-up to the inflate code (Mark)
+- fix gzeof on non-compressed files (Allan Schrum)
+- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
+- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
+- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
+- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
+- do not wrap extern "C" around system includes (Tom Lane)
+- mention zlib binding for TCL in README (Andreas Kupries)
+- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
+- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
+- allow "configure --prefix $HOME" (Tim Mooney)
+- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
+- move Makefile.sas to amiga/Makefile.sas
+
+Changes in 1.1.1 (27 Feb 98)
+- fix macros _tr_tally_* in deflate.h for debug mode  (Glenn Randers-Pehrson)
+- remove block truncation heuristic which had very marginal effect for zlib
+  (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
+  compression ratio on some files. This also allows inlining _tr_tally for
+  matches in deflate_slow.
+- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
+
+Changes in 1.1.0 (24 Feb 98)
+- do not return STREAM_END prematurely in inflate (John Bowler)
+- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
+- compile with -DFASTEST to get compression code optimized for speed only
+- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
+- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
+  on Sun but significant on HP)
+
+- add a pointer to experimental unzip library in README (Gilles Vollant)
+- initialize variable gcc in configure (Chris Herborth)
+
+Changes in 1.0.9 (17 Feb 1998)
+- added gzputs and gzgets functions
+- do not clear eof flag in gzseek (Mark Diekhans)
+- fix gzseek for files in transparent mode (Mark Diekhans)
+- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
+- replace EXPORT with ZEXPORT to avoid conflict with other programs
+- added compress2 in zconf.h, zlib.def, zlib.dnt
+- new asm code from Gilles Vollant in contrib/asm386
+- simplify the inflate code (Mark):
+ . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
+ . ZALLOC the length list in inflate_trees_fixed() instead of using stack
+ . ZALLOC the value area for huft_build() instead of using stack
+ . Simplify Z_FINISH check in inflate()
+
+- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
+- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
+- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
+  the declaration of FAR (Gilles VOllant)
+- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
+- read_buf buf parameter of type Bytef* instead of charf*
+- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
+- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
+- fix check for presence of directories in "make install" (Ian Willis)
+
+Changes in 1.0.8 (27 Jan 1998)
+- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
+- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
+- added compress2() to allow setting the compression level
+- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
+- use constant arrays for the static trees in trees.c instead of computing
+  them at run time (thanks to Ken Raeburn for this suggestion). To create
+  trees.h, compile with GEN_TREES_H and run "make test".
+- check return code of example in "make test" and display result
+- pass minigzip command line options to file_compress
+- simplifying code of inflateSync to avoid gcc 2.8 bug
+
+- support CC="gcc -Wall" in configure -s (QingLong)
+- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
+- fix test for shared library support to avoid compiler warnings
+- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
+- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
+- do not use fdopen for Metrowerks on Mac (Brad Pettit))
+- add checks for gzputc and gzputc in example.c
+- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
+- use const for the CRC table (Ken Raeburn)
+- fixed "make uninstall" for shared libraries
+- use Tracev instead of Trace in infblock.c
+- in example.c use correct compressed length for test_sync
+- suppress +vnocompatwarnings in configure for HPUX (not always supported)
+
+Changes in 1.0.7 (20 Jan 1998)
+- fix gzseek which was broken in write mode
+- return error for gzseek to negative absolute position
+- fix configure for Linux (Chun-Chung Chen)
+- increase stack space for MSC (Tim Wegner)
+- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
+- define EXPORTVA for gzprintf (Gilles Vollant)
+- added man page zlib.3 (Rick Rodgers)
+- for contrib/untgz, fix makedir() and improve Makefile
+
+- check gzseek in write mode in example.c
+- allocate extra buffer for seeks only if gzseek is actually called
+- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
+- add inflateSyncPoint in zconf.h
+- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def
+
+Changes in 1.0.6 (19 Jan 1998)
+- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
+  gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
+- Fix a deflate bug occurring only with compression level 0 (thanks to
+  Andy Buckler for finding this one).
+- In minigzip, pass transparently also the first byte for .Z files.
+- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
+- check Z_FINISH in inflate (thanks to Marc Schluper)
+- Implement deflateCopy (thanks to Adam Costello)
+- make static libraries by default in configure, add --shared option.
+- move MSDOS or Windows specific files to directory msdos
+- suppress the notion of partial flush to simplify the interface
+  (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
+- suppress history buffer provided by application to simplify the interface
+  (this feature was not implemented anyway in 1.0.4)
+- next_in and avail_in must be initialized before calling inflateInit or
+  inflateInit2
+- add EXPORT in all exported functions (for Windows DLL)
+- added Makefile.nt (thanks to Stephen Williams)
+- added the unsupported "contrib" directory:
+   contrib/asm386/ by Gilles Vollant <info@winimage.com>
+        386 asm code replacing longest_match().
+   contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
+        A C++ I/O streams interface to the zlib gz* functions
+   contrib/iostream2/  by Tyge Løvset <Tyge.Lovset@cmr.no>
+        Another C++ I/O streams interface
+   contrib/untgz/  by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
+        A very simple tar.gz file extractor using zlib
+   contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
+        How to use compress(), uncompress() and the gz* functions from VB.
+- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
+  level) in minigzip (thanks to Tom Lane)
+
+- use const for rommable constants in deflate
+- added test for gzseek and gztell in example.c
+- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
+- add undocumented function zError to convert error code to string
+  (for Tim Smithers)
+- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
+- Use default memcpy for Symantec MSDOS compiler.
+- Add EXPORT keyword for check_func (needed for Windows DLL)
+- add current directory to LD_LIBRARY_PATH for "make test"
+- create also a link for libz.so.1
+- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
+- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
+- added -soname for Linux in configure (Chun-Chung Chen,
+- assign numbers to the exported functions in zlib.def (for Windows DLL)
+- add advice in zlib.h for best usage of deflateSetDictionary
+- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
+- allow compilation with ANSI keywords only enabled for TurboC in large model
+- avoid "versionString"[0] (Borland bug)
+- add NEED_DUMMY_RETURN for Borland
+- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
+- allow compilation with CC
+- defined STDC for OS/2 (David Charlap)
+- limit external names to 8 chars for MVS (Thomas Lund)
+- in minigzip.c, use static buffers only for 16-bit systems
+- fix suffix check for "minigzip -d foo.gz"
+- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
+- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
+- added makelcc.bat for lcc-win32 (Tom St Denis)
+- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
+- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
+- check for unistd.h in configure (for off_t)
+- remove useless check parameter in inflate_blocks_free
+- avoid useless assignment of s->check to itself in inflate_blocks_new
+- do not flush twice in gzclose (thanks to Ken Raeburn)
+- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
+- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
+- work around buggy fclose on pipes for HP/UX
+- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
+- fix configure if CC is already equal to gcc
+
+Changes in 1.0.5 (3 Jan 98)
+- Fix inflate to terminate gracefully when fed corrupted or invalid data
+- Use const for rommable constants in inflate
+- Eliminate memory leaks on error conditions in inflate
+- Removed some vestigial code in inflate
+- Update web address in README
+
+Changes in 1.0.4 (24 Jul 96)
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+  bit, so the decompressor could decompress all the correct data but went
+  on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+- use z_error only for DEBUG (avoid problem with DLLs)
+
+Changes in 1.0.3 (2 Jul 96)
+- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
+  small and medium models; this makes the library incompatible with previous
+  versions for these models. (No effect in large model or on other systems.)
+- return OK instead of BUF_ERROR if previous deflate call returned with
+  avail_out as zero but there is nothing to do
+- added memcmp for non STDC compilers
+- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
+- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
+- better check for 16-bit mode MSC (avoids problem with Symantec)
+
+Changes in 1.0.2 (23 May 96)
+- added Windows DLL support
+- added a function zlibVersion (for the DLL support)
+- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
+- Bytef is define's instead of typedef'd only for Borland C
+- avoid reading uninitialized memory in example.c
+- mention in README that the zlib format is now RFC1950
+- updated Makefile.dj2
+- added algorithm.doc
+
+Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
+- fix array overlay in deflate.c which sometimes caused bad compressed data
+- fix inflate bug with empty stored block
+- fix MSDOS medium model which was broken in 0.99
+- fix deflateParams() which could generate bad compressed data.
+- Bytef is define'd instead of typedef'ed (work around Borland bug)
+- added an INDEX file
+- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
+  Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
+- speed up adler32 for modern machines without auto-increment
+- added -ansi for IRIX in configure
+- static_init_done in trees.c is an int
+- define unlink as delete for VMS
+- fix configure for QNX
+- add configure branch for SCO and HPUX
+- avoid many warnings (unused variables, dead assignments, etc...)
+- no fdopen for BeOS
+- fix the Watcom fix for 32 bit mode (define FAR as empty)
+- removed redefinition of Byte for MKWERKS
+- work around an MWKERKS bug (incorrect merge of all .h files)
+
+Changes in 0.99 (27 Jan 96)
+- allow preset dictionary shared between compressor and decompressor
+- allow compression level 0 (no compression)
+- add deflateParams in zlib.h: allow dynamic change of compression level
+  and compression strategy.
+- test large buffers and deflateParams in example.c
+- add optional "configure" to build zlib as a shared library
+- suppress Makefile.qnx, use configure instead
+- fixed deflate for 64-bit systems (detected on Cray)
+- fixed inflate_blocks for 64-bit systems (detected on Alpha)
+- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
+- always return Z_BUF_ERROR when deflate() has nothing to do
+- deflateInit and inflateInit are now macros to allow version checking
+- prefix all global functions and types with z_ with -DZ_PREFIX
+- make falloc completely reentrant (inftrees.c)
+- fixed very unlikely race condition in ct_static_init
+- free in reverse order of allocation to help memory manager
+- use zlib-1.0/* instead of zlib/* inside the tar.gz
+- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
+  -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
+- allow gzread on concatenated .gz files
+- deflateEnd now returns Z_DATA_ERROR if it was premature
+- deflate is finally (?) fully deterministic (no matches beyond end of input)
+- Document Z_SYNC_FLUSH
+- add uninstall in Makefile
+- Check for __cpluplus in zlib.h
+- Better test in ct_align for partial flush
+- avoid harmless warnings for Borland C++
+- initialize hash_head in deflate.c
+- avoid warning on fdopen (gzio.c) for HP cc -Aa
+- include stdlib.h for STDC compilers
+- include errno.h for Cray
+- ignore error if ranlib doesn't exist
+- call ranlib twice for NeXTSTEP
+- use exec_prefix instead of prefix for libz.a
+- renamed ct_* as _tr_* to avoid conflict with applications
+- clear z->msg in inflateInit2 before any error return
+- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
+- fixed typo in zconf.h (_GNUC__ => __GNUC__)
+- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
+- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
+- in fcalloc, normalize pointer if size > 65520 bytes
+- don't use special fcalloc for 32 bit Borland C++
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use Z_BINARY instead of BINARY
+- document that gzclose after gzdopen will close the file
+- allow "a" as mode in gzopen.
+- fix error checking in gzread
+- allow skipping .gz extra-field on pipes
+- added reference to Perl interface in README
+- put the crc table in FAR data (I dislike more and more the medium model :)
+- added get_crc_table
+- added a dimension to all arrays (Borland C can't count).
+- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
+- guard against multiple inclusion of *.h (for precompiled header on Mac)
+- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
+- don't use unsized arrays to avoid silly warnings by Visual C++:
+     warning C4746: 'inflate_mask' : unsized array treated as  '__far'
+     (what's wrong with far data in far model?).
+- define enum out of inflate_blocks_state to allow compilation with C++
+
+Changes in 0.95 (16 Aug 95)
+- fix MSDOS small and medium model (now easier to adapt to any compiler)
+- inlined send_bits
+- fix the final (:-) bug for deflate with flush (output was correct but
+  not completely flushed in rare occasions).
+- default window size is same for compression and decompression
+  (it's now sufficient to set MAX_WBITS in zconf.h).
+- voidp -> voidpf and voidnp -> voidp (for consistency with other
+  typedefs and because voidnp was not near in large model).
+
+Changes in 0.94 (13 Aug 95)
+- support MSDOS medium model
+- fix deflate with flush (could sometimes generate bad output)
+- fix deflateReset (zlib header was incorrectly suppressed)
+- added support for VMS
+- allow a compression level in gzopen()
+- gzflush now calls fflush
+- For deflate with flush, flush even if no more input is provided.
+- rename libgz.a as libz.a
+- avoid complex expression in infcodes.c triggering Turbo C bug
+- work around a problem with gcc on Alpha (in INSERT_STRING)
+- don't use inline functions (problem with some gcc versions)
+- allow renaming of Byte, uInt, etc... with #define.
+- avoid warning about (unused) pointer before start of array in deflate.c
+- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
+- avoid reserved word 'new' in trees.c
+
+Changes in 0.93 (25 June 95)
+- temporarily disable inline functions
+- make deflate deterministic
+- give enough lookahead for PARTIAL_FLUSH
+- Set binary mode for stdin/stdout in minigzip.c for OS/2
+- don't even use signed char in inflate (not portable enough)
+- fix inflate memory leak for segmented architectures
+
+Changes in 0.92 (3 May 95)
+- don't assume that char is signed (problem on SGI)
+- Clear bit buffer when starting a stored block
+- no memcpy on Pyramid
+- suppressed inftest.c
+- optimized fill_window, put longest_match inline for gcc
+- optimized inflate on stored blocks.
+- untabify all sources to simplify patches
+
+Changes in 0.91 (2 May 95)
+- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
+- Document the memory requirements in zconf.h
+- added "make install"
+- fix sync search logic in inflateSync
+- deflate(Z_FULL_FLUSH) now works even if output buffer too short
+- after inflateSync, don't scare people with just "lo world"
+- added support for DJGPP
+
+Changes in 0.9 (1 May 95)
+- don't assume that zalloc clears the allocated memory (the TurboC bug
+  was Mark's bug after all :)
+- let again gzread copy uncompressed data unchanged (was working in 0.71)
+- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
+- added a test of inflateSync in example.c
+- moved MAX_WBITS to zconf.h because users might want to change that.
+- document explicitly that zalloc(64K) on MSDOS must return a normalized
+  pointer (zero offset)
+- added Makefiles for Microsoft C, Turbo C, Borland C++
+- faster crc32()
+
+Changes in 0.8 (29 April 95)
+- added fast inflate (inffast.c)
+- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
+  is incompatible with previous versions of zlib which returned Z_OK.
+- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
+  (actually that was not a compiler bug, see 0.81 above)
+- gzread no longer reads one extra byte in certain cases
+- In gzio destroy(), don't reference a freed structure
+- avoid many warnings for MSDOS
+- avoid the ERROR symbol which is used by MS Windows
+
+Changes in 0.71 (14 April 95)
+- Fixed more MSDOS compilation problems :( There is still a bug with
+  TurboC large model.
+
+Changes in 0.7 (14 April 95)
+- Added full inflate support.
+- Simplified the crc32() interface. The pre- and post-conditioning
+  (one's complement) is now done inside crc32(). WARNING: this is
+  incompatible with previous versions; see zlib.h for the new usage.
+
+Changes in 0.61 (12 April 95)
+- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
+
+Changes in 0.6 (11 April 95)
+- added minigzip.c
+- added gzdopen to reopen a file descriptor as gzFile
+- added transparent reading of non-gziped files in gzread.
+- fixed bug in gzread (don't read crc as data)
+- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
+- don't allocate big arrays in the stack (for MSDOS)
+- fix some MSDOS compilation problems
+
+Changes in 0.5:
+- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
+  not yet Z_FULL_FLUSH.
+- support decompression but only in a single step (forced Z_FINISH)
+- added opaque object for zalloc and zfree.
+- added deflateReset and inflateReset
+- added a variable zlib_version for consistency checking.
+- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
+  Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
+
+Changes in 0.4:
+- avoid "zip" everywhere, use zlib instead of ziplib.
+- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
+  if compression method == 8.
+- added adler32 and crc32
+- renamed deflateOptions as deflateInit2, call one or the other but not both
+- added the method parameter for deflateInit2.
+- added inflateInit2
+- simplied considerably deflateInit and inflateInit by not supporting
+  user-provided history buffer. This is supported only in deflateInit2
+  and inflateInit2.
+
+Changes in 0.3:
+- prefix all macro names with Z_
+- use Z_FINISH instead of deflateEnd to finish compression.
+- added Z_HUFFMAN_ONLY
+- added gzerror()
diff --git a/deps/libchdr/deps/zlib-1.2.11/FAQ b/deps/libchdr/deps/zlib-1.2.11/FAQ
new file mode 100644 (file)
index 0000000..99b7cf9
--- /dev/null
@@ -0,0 +1,368 @@
+
+                Frequently Asked Questions about zlib
+
+
+If your question is not there, please check the zlib home page
+http://zlib.net/ which may have more recent information.
+The lastest zlib FAQ is at http://zlib.net/zlib_faq.html
+
+
+ 1. Is zlib Y2K-compliant?
+
+    Yes. zlib doesn't handle dates.
+
+ 2. Where can I get a Windows DLL version?
+
+    The zlib sources can be compiled without change to produce a DLL.  See the
+    file win32/DLL_FAQ.txt in the zlib distribution.  Pointers to the
+    precompiled DLL are found in the zlib web site at http://zlib.net/ .
+
+ 3. Where can I get a Visual Basic interface to zlib?
+
+    See
+        * http://marknelson.us/1997/01/01/zlib-engine/
+        * win32/DLL_FAQ.txt in the zlib distribution
+
+ 4. compress() returns Z_BUF_ERROR.
+
+    Make sure that before the call of compress(), the length of the compressed
+    buffer is equal to the available size of the compressed buffer and not
+    zero.  For Visual Basic, check that this parameter is passed by reference
+    ("as any"), not by value ("as long").
+
+ 5. deflate() or inflate() returns Z_BUF_ERROR.
+
+    Before making the call, make sure that avail_in and avail_out are not zero.
+    When setting the parameter flush equal to Z_FINISH, also make sure that
+    avail_out is big enough to allow processing all pending input.  Note that a
+    Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be
+    made with more input or output space.  A Z_BUF_ERROR may in fact be
+    unavoidable depending on how the functions are used, since it is not
+    possible to tell whether or not there is more output pending when
+    strm.avail_out returns with zero.  See http://zlib.net/zlib_how.html for a
+    heavily annotated example.
+
+ 6. Where's the zlib documentation (man pages, etc.)?
+
+    It's in zlib.h .  Examples of zlib usage are in the files test/example.c
+    and test/minigzip.c, with more in examples/ .
+
+ 7. Why don't you use GNU autoconf or libtool or ...?
+
+    Because we would like to keep zlib as a very small and simple package.
+    zlib is rather portable and doesn't need much configuration.
+
+ 8. I found a bug in zlib.
+
+    Most of the time, such problems are due to an incorrect usage of zlib.
+    Please try to reproduce the problem with a small program and send the
+    corresponding source to us at zlib@gzip.org .  Do not send multi-megabyte
+    data files without prior agreement.
+
+ 9. Why do I get "undefined reference to gzputc"?
+
+    If "make test" produces something like
+
+       example.o(.text+0x154): undefined reference to `gzputc'
+
+    check that you don't have old files libz.* in /usr/lib, /usr/local/lib or
+    /usr/X11R6/lib. Remove any old versions, then do "make install".
+
+10. I need a Delphi interface to zlib.
+
+    See the contrib/delphi directory in the zlib distribution.
+
+11. Can zlib handle .zip archives?
+
+    Not by itself, no.  See the directory contrib/minizip in the zlib
+    distribution.
+
+12. Can zlib handle .Z files?
+
+    No, sorry.  You have to spawn an uncompress or gunzip subprocess, or adapt
+    the code of uncompress on your own.
+
+13. How can I make a Unix shared library?
+
+    By default a shared (and a static) library is built for Unix.  So:
+
+    make distclean
+    ./configure
+    make
+
+14. How do I install a shared zlib library on Unix?
+
+    After the above, then:
+
+    make install
+
+    However, many flavors of Unix come with a shared zlib already installed.
+    Before going to the trouble of compiling a shared version of zlib and
+    trying to install it, you may want to check if it's already there!  If you
+    can #include <zlib.h>, it's there.  The -lz option will probably link to
+    it.  You can check the version at the top of zlib.h or with the
+    ZLIB_VERSION symbol defined in zlib.h .
+
+15. I have a question about OttoPDF.
+
+    We are not the authors of OttoPDF. The real author is on the OttoPDF web
+    site: Joel Hainley, jhainley@myndkryme.com.
+
+16. Can zlib decode Flate data in an Adobe PDF file?
+
+    Yes. See http://www.pdflib.com/ . To modify PDF forms, see
+    http://sourceforge.net/projects/acroformtool/ .
+
+17. Why am I getting this "register_frame_info not found" error on Solaris?
+
+    After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib
+    generates an error such as:
+
+        ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so:
+        symbol __register_frame_info: referenced symbol not found
+
+    The symbol __register_frame_info is not part of zlib, it is generated by
+    the C compiler (cc or gcc).  You must recompile applications using zlib
+    which have this problem.  This problem is specific to Solaris.  See
+    http://www.sunfreeware.com for Solaris versions of zlib and applications
+    using zlib.
+
+18. Why does gzip give an error on a file I make with compress/deflate?
+
+    The compress and deflate functions produce data in the zlib format, which
+    is different and incompatible with the gzip format.  The gz* functions in
+    zlib on the other hand use the gzip format.  Both the zlib and gzip formats
+    use the same compressed data format internally, but have different headers
+    and trailers around the compressed data.
+
+19. Ok, so why are there two different formats?
+
+    The gzip format was designed to retain the directory information about a
+    single file, such as the name and last modification date.  The zlib format
+    on the other hand was designed for in-memory and communication channel
+    applications, and has a much more compact header and trailer and uses a
+    faster integrity check than gzip.
+
+20. Well that's nice, but how do I make a gzip file in memory?
+
+    You can request that deflate write the gzip format instead of the zlib
+    format using deflateInit2().  You can also request that inflate decode the
+    gzip format using inflateInit2().  Read zlib.h for more details.
+
+21. Is zlib thread-safe?
+
+    Yes.  However any library routines that zlib uses and any application-
+    provided memory allocation routines must also be thread-safe.  zlib's gz*
+    functions use stdio library routines, and most of zlib's functions use the
+    library memory allocation routines by default.  zlib's *Init* functions
+    allow for the application to provide custom memory allocation routines.
+
+    Of course, you should only operate on any given zlib or gzip stream from a
+    single thread at a time.
+
+22. Can I use zlib in my commercial application?
+
+    Yes.  Please read the license in zlib.h.
+
+23. Is zlib under the GNU license?
+
+    No.  Please read the license in zlib.h.
+
+24. The license says that altered source versions must be "plainly marked". So
+    what exactly do I need to do to meet that requirement?
+
+    You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h.  In
+    particular, the final version number needs to be changed to "f", and an
+    identification string should be appended to ZLIB_VERSION.  Version numbers
+    x.x.x.f are reserved for modifications to zlib by others than the zlib
+    maintainers.  For example, if the version of the base zlib you are altering
+    is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and
+    ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3".  You can also
+    update the version strings in deflate.c and inftrees.c.
+
+    For altered source distributions, you should also note the origin and
+    nature of the changes in zlib.h, as well as in ChangeLog and README, along
+    with the dates of the alterations.  The origin should include at least your
+    name (or your company's name), and an email address to contact for help or
+    issues with the library.
+
+    Note that distributing a compiled zlib library along with zlib.h and
+    zconf.h is also a source distribution, and so you should change
+    ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes
+    in zlib.h as you would for a full source distribution.
+
+25. Will zlib work on a big-endian or little-endian architecture, and can I
+    exchange compressed data between them?
+
+    Yes and yes.
+
+26. Will zlib work on a 64-bit machine?
+
+    Yes.  It has been tested on 64-bit machines, and has no dependence on any
+    data types being limited to 32-bits in length.  If you have any
+    difficulties, please provide a complete problem report to zlib@gzip.org
+
+27. Will zlib decompress data from the PKWare Data Compression Library?
+
+    No.  The PKWare DCL uses a completely different compressed data format than
+    does PKZIP and zlib.  However, you can look in zlib's contrib/blast
+    directory for a possible solution to your problem.
+
+28. Can I access data randomly in a compressed stream?
+
+    No, not without some preparation.  If when compressing you periodically use
+    Z_FULL_FLUSH, carefully write all the pending data at those points, and
+    keep an index of those locations, then you can start decompression at those
+    points.  You have to be careful to not use Z_FULL_FLUSH too often, since it
+    can significantly degrade compression.  Alternatively, you can scan a
+    deflate stream once to generate an index, and then use that index for
+    random access.  See examples/zran.c .
+
+29. Does zlib work on MVS, OS/390, CICS, etc.?
+
+    It has in the past, but we have not heard of any recent evidence.  There
+    were working ports of zlib 1.1.4 to MVS, but those links no longer work.
+    If you know of recent, successful applications of zlib on these operating
+    systems, please let us know.  Thanks.
+
+30. Is there some simpler, easier to read version of inflate I can look at to
+    understand the deflate format?
+
+    First off, you should read RFC 1951.  Second, yes.  Look in zlib's
+    contrib/puff directory.
+
+31. Does zlib infringe on any patents?
+
+    As far as we know, no.  In fact, that was originally the whole point behind
+    zlib.  Look here for some more information:
+
+    http://www.gzip.org/#faq11
+
+32. Can zlib work with greater than 4 GB of data?
+
+    Yes.  inflate() and deflate() will process any amount of data correctly.
+    Each call of inflate() or deflate() is limited to input and output chunks
+    of the maximum value that can be stored in the compiler's "unsigned int"
+    type, but there is no limit to the number of chunks.  Note however that the
+    strm.total_in and strm_total_out counters may be limited to 4 GB.  These
+    counters are provided as a convenience and are not used internally by
+    inflate() or deflate().  The application can easily set up its own counters
+    updated after each call of inflate() or deflate() to count beyond 4 GB.
+    compress() and uncompress() may be limited to 4 GB, since they operate in a
+    single call.  gzseek() and gztell() may be limited to 4 GB depending on how
+    zlib is compiled.  See the zlibCompileFlags() function in zlib.h.
+
+    The word "may" appears several times above since there is a 4 GB limit only
+    if the compiler's "long" type is 32 bits.  If the compiler's "long" type is
+    64 bits, then the limit is 16 exabytes.
+
+33. Does zlib have any security vulnerabilities?
+
+    The only one that we are aware of is potentially in gzprintf().  If zlib is
+    compiled to use sprintf() or vsprintf(), then there is no protection
+    against a buffer overflow of an 8K string space (or other value as set by
+    gzbuffer()), other than the caller of gzprintf() assuring that the output
+    will not exceed 8K.  On the other hand, if zlib is compiled to use
+    snprintf() or vsnprintf(), which should normally be the case, then there is
+    no vulnerability.  The ./configure script will display warnings if an
+    insecure variation of sprintf() will be used by gzprintf().  Also the
+    zlibCompileFlags() function will return information on what variant of
+    sprintf() is used by gzprintf().
+
+    If you don't have snprintf() or vsnprintf() and would like one, you can
+    find a portable implementation here:
+
+        http://www.ijs.si/software/snprintf/
+
+    Note that you should be using the most recent version of zlib.  Versions
+    1.1.3 and before were subject to a double-free vulnerability, and versions
+    1.2.1 and 1.2.2 were subject to an access exception when decompressing
+    invalid compressed data.
+
+34. Is there a Java version of zlib?
+
+    Probably what you want is to use zlib in Java. zlib is already included
+    as part of the Java SDK in the java.util.zip package. If you really want
+    a version of zlib written in the Java language, look on the zlib home
+    page for links: http://zlib.net/ .
+
+35. I get this or that compiler or source-code scanner warning when I crank it
+    up to maximally-pedantic. Can't you guys write proper code?
+
+    Many years ago, we gave up attempting to avoid warnings on every compiler
+    in the universe.  It just got to be a waste of time, and some compilers
+    were downright silly as well as contradicted each other.  So now, we simply
+    make sure that the code always works.
+
+36. Valgrind (or some similar memory access checker) says that deflate is
+    performing a conditional jump that depends on an uninitialized value.
+    Isn't that a bug?
+
+    No.  That is intentional for performance reasons, and the output of deflate
+    is not affected.  This only started showing up recently since zlib 1.2.x
+    uses malloc() by default for allocations, whereas earlier versions used
+    calloc(), which zeros out the allocated memory.  Even though the code was
+    correct, versions 1.2.4 and later was changed to not stimulate these
+    checkers.
+
+37. Will zlib read the (insert any ancient or arcane format here) compressed
+    data format?
+
+    Probably not. Look in the comp.compression FAQ for pointers to various
+    formats and associated software.
+
+38. How can I encrypt/decrypt zip files with zlib?
+
+    zlib doesn't support encryption.  The original PKZIP encryption is very
+    weak and can be broken with freely available programs.  To get strong
+    encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib
+    compression.  For PKZIP compatible "encryption", look at
+    http://www.info-zip.org/
+
+39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
+
+    "gzip" is the gzip format, and "deflate" is the zlib format.  They should
+    probably have called the second one "zlib" instead to avoid confusion with
+    the raw deflate compressed data format.  While the HTTP 1.1 RFC 2616
+    correctly points to the zlib specification in RFC 1950 for the "deflate"
+    transfer encoding, there have been reports of servers and browsers that
+    incorrectly produce or expect raw deflate data per the deflate
+    specification in RFC 1951, most notably Microsoft.  So even though the
+    "deflate" transfer encoding using the zlib format would be the more
+    efficient approach (and in fact exactly what the zlib format was designed
+    for), using the "gzip" transfer encoding is probably more reliable due to
+    an unfortunate choice of name on the part of the HTTP 1.1 authors.
+
+    Bottom line: use the gzip format for HTTP 1.1 encoding.
+
+40. Does zlib support the new "Deflate64" format introduced by PKWare?
+
+    No.  PKWare has apparently decided to keep that format proprietary, since
+    they have not documented it as they have previous compression formats.  In
+    any case, the compression improvements are so modest compared to other more
+    modern approaches, that it's not worth the effort to implement.
+
+41. I'm having a problem with the zip functions in zlib, can you help?
+
+    There are no zip functions in zlib.  You are probably using minizip by
+    Giles Vollant, which is found in the contrib directory of zlib.  It is not
+    part of zlib.  In fact none of the stuff in contrib is part of zlib.  The
+    files in there are not supported by the zlib authors.  You need to contact
+    the authors of the respective contribution for help.
+
+42. The match.asm code in contrib is under the GNU General Public License.
+    Since it's part of zlib, doesn't that mean that all of zlib falls under the
+    GNU GPL?
+
+    No.  The files in contrib are not part of zlib.  They were contributed by
+    other authors and are provided as a convenience to the user within the zlib
+    distribution.  Each item in contrib has its own license.
+
+43. Is zlib subject to export controls?  What is its ECCN?
+
+    zlib is not subject to export controls, and so is classified as EAR99.
+
+44. Can you please sign these lengthy legal documents and fax them back to us
+    so that we can use your software in our product?
+
+    No. Go away. Shoo.
diff --git a/deps/libchdr/deps/zlib-1.2.11/INDEX b/deps/libchdr/deps/zlib-1.2.11/INDEX
new file mode 100644 (file)
index 0000000..2ba0641
--- /dev/null
@@ -0,0 +1,68 @@
+CMakeLists.txt  cmake build file
+ChangeLog       history of changes
+FAQ             Frequently Asked Questions about zlib
+INDEX           this file
+Makefile        dummy Makefile that tells you to ./configure
+Makefile.in     template for Unix Makefile
+README          guess what
+configure       configure script for Unix
+make_vms.com    makefile for VMS
+test/example.c  zlib usages examples for build testing
+test/minigzip.c minimal gzip-like functionality for build testing
+test/infcover.c inf*.c code coverage for build coverage testing
+treebuild.xml   XML description of source file dependencies
+zconf.h.cmakein zconf.h template for cmake
+zconf.h.in      zconf.h template for configure
+zlib.3          Man page for zlib
+zlib.3.pdf      Man page in PDF format
+zlib.map        Linux symbol information
+zlib.pc.in      Template for pkg-config descriptor
+zlib.pc.cmakein zlib.pc template for cmake
+zlib2ansi       perl script to convert source files for C++ compilation
+
+amiga/          makefiles for Amiga SAS C
+as400/          makefiles for AS/400
+doc/            documentation for formats and algorithms
+msdos/          makefiles for MSDOS
+nintendods/     makefile for Nintendo DS
+old/            makefiles for various architectures and zlib documentation
+                files that have not yet been updated for zlib 1.2.x
+qnx/            makefiles for QNX
+watcom/         makefiles for OpenWatcom
+win32/          makefiles for Windows
+
+                zlib public header files (required for library use):
+zconf.h
+zlib.h
+
+                private source files used to build the zlib library:
+adler32.c
+compress.c
+crc32.c
+crc32.h
+deflate.c
+deflate.h
+gzclose.c
+gzguts.h
+gzlib.c
+gzread.c
+gzwrite.c
+infback.c
+inffast.c
+inffast.h
+inffixed.h
+inflate.c
+inflate.h
+inftrees.c
+inftrees.h
+trees.c
+trees.h
+uncompr.c
+zutil.c
+zutil.h
+
+                source files for sample programs
+See examples/README.examples
+
+                unsupported contributions by third parties
+See contrib/README.contrib
diff --git a/deps/libchdr/deps/zlib-1.2.11/Makefile b/deps/libchdr/deps/zlib-1.2.11/Makefile
new file mode 100644 (file)
index 0000000..6bba86c
--- /dev/null
@@ -0,0 +1,5 @@
+all:
+       -@echo "Please use ./configure first.  Thank you."
+
+distclean:
+       make -f Makefile.in distclean
diff --git a/deps/libchdr/deps/zlib-1.2.11/Makefile.in b/deps/libchdr/deps/zlib-1.2.11/Makefile.in
new file mode 100644 (file)
index 0000000..5a77949
--- /dev/null
@@ -0,0 +1,410 @@
+# Makefile for zlib
+# Copyright (C) 1995-2017 Jean-loup Gailly, Mark Adler
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+#    ./configure; make test
+# Normally configure builds both a static and a shared library.
+# If you want to build just a static library, use: ./configure --static
+
+# To use the asm code, type:
+#    cp contrib/asm?86/match.S ./match.S
+#    make LOC=-DASMV OBJA=match.o
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+#    make install
+# To install in $HOME instead of /usr/local, use:
+#    make install prefix=$HOME
+
+CC=cc
+
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DZLIB_DEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+#           -Wstrict-prototypes -Wmissing-prototypes
+
+SFLAGS=-O
+LDFLAGS=
+TEST_LDFLAGS=-L. libz.a
+LDSHARED=$(CC)
+CPP=$(CC) -E
+
+STATICLIB=libz.a
+SHAREDLIB=libz.so
+SHAREDLIBV=libz.so.1.2.11
+SHAREDLIBM=libz.so.1
+LIBS=$(STATICLIB) $(SHAREDLIBV)
+
+AR=ar
+ARFLAGS=rc
+RANLIB=ranlib
+LDCONFIG=ldconfig
+LDSHAREDLIBC=-lc
+TAR=tar
+SHELL=/bin/sh
+EXE=
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+libdir = ${exec_prefix}/lib
+sharedlibdir = ${libdir}
+includedir = ${prefix}/include
+mandir = ${prefix}/share/man
+man3dir = ${mandir}/man3
+pkgconfigdir = ${libdir}/pkgconfig
+SRCDIR=
+ZINC=
+ZINCOUT=-I.
+
+OBJZ = adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o
+OBJG = compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o
+OBJC = $(OBJZ) $(OBJG)
+
+PIC_OBJZ = adler32.lo crc32.lo deflate.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo zutil.lo
+PIC_OBJG = compress.lo uncompr.lo gzclose.lo gzlib.lo gzread.lo gzwrite.lo
+PIC_OBJC = $(PIC_OBJZ) $(PIC_OBJG)
+
+# to use the asm code: make OBJA=match.o, PIC_OBJA=match.lo
+OBJA =
+PIC_OBJA =
+
+OBJS = $(OBJC) $(OBJA)
+
+PIC_OBJS = $(PIC_OBJC) $(PIC_OBJA)
+
+all: static shared
+
+static: example$(EXE) minigzip$(EXE)
+
+shared: examplesh$(EXE) minigzipsh$(EXE)
+
+all64: example64$(EXE) minigzip64$(EXE)
+
+check: test
+
+test: all teststatic testshared
+
+teststatic: static
+       @TMPST=tmpst_$$; \
+       if echo hello world | ./minigzip | ./minigzip -d && ./example $$TMPST ; then \
+         echo '                *** zlib test OK ***'; \
+       else \
+         echo '                *** zlib test FAILED ***'; false; \
+       fi; \
+       rm -f $$TMPST
+
+testshared: shared
+       @LD_LIBRARY_PATH=`pwd`:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+       LD_LIBRARYN32_PATH=`pwd`:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \
+       DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \
+       SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \
+       TMPSH=tmpsh_$$; \
+       if echo hello world | ./minigzipsh | ./minigzipsh -d && ./examplesh $$TMPSH; then \
+         echo '                *** zlib shared test OK ***'; \
+       else \
+         echo '                *** zlib shared test FAILED ***'; false; \
+       fi; \
+       rm -f $$TMPSH
+
+test64: all64
+       @TMP64=tmp64_$$; \
+       if echo hello world | ./minigzip64 | ./minigzip64 -d && ./example64 $$TMP64; then \
+         echo '                *** zlib 64-bit test OK ***'; \
+       else \
+         echo '                *** zlib 64-bit test FAILED ***'; false; \
+       fi; \
+       rm -f $$TMP64
+
+infcover.o: $(SRCDIR)test/infcover.c $(SRCDIR)zlib.h zconf.h
+       $(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/infcover.c
+
+infcover: infcover.o libz.a
+       $(CC) $(CFLAGS) -o $@ infcover.o libz.a
+
+cover: infcover
+       rm -f *.gcda
+       ./infcover
+       gcov inf*.c
+
+libz.a: $(OBJS)
+       $(AR) $(ARFLAGS) $@ $(OBJS)
+       -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+       $(CPP) match.S > _match.s
+       $(CC) -c _match.s
+       mv _match.o match.o
+       rm -f _match.s
+
+match.lo: match.S
+       $(CPP) match.S > _match.s
+       $(CC) -c -fPIC _match.s
+       mv _match.o match.lo
+       rm -f _match.s
+
+example.o: $(SRCDIR)test/example.c $(SRCDIR)zlib.h zconf.h
+       $(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/example.c
+
+minigzip.o: $(SRCDIR)test/minigzip.c $(SRCDIR)zlib.h zconf.h
+       $(CC) $(CFLAGS) $(ZINCOUT) -c -o $@ $(SRCDIR)test/minigzip.c
+
+example64.o: $(SRCDIR)test/example.c $(SRCDIR)zlib.h zconf.h
+       $(CC) $(CFLAGS) $(ZINCOUT) -D_FILE_OFFSET_BITS=64 -c -o $@ $(SRCDIR)test/example.c
+
+minigzip64.o: $(SRCDIR)test/minigzip.c $(SRCDIR)zlib.h zconf.h
+       $(CC) $(CFLAGS) $(ZINCOUT) -D_FILE_OFFSET_BITS=64 -c -o $@ $(SRCDIR)test/minigzip.c
+
+
+adler32.o: $(SRCDIR)adler32.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)adler32.c
+
+crc32.o: $(SRCDIR)crc32.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)crc32.c
+
+deflate.o: $(SRCDIR)deflate.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)deflate.c
+
+infback.o: $(SRCDIR)infback.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)infback.c
+
+inffast.o: $(SRCDIR)inffast.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)inffast.c
+
+inflate.o: $(SRCDIR)inflate.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)inflate.c
+
+inftrees.o: $(SRCDIR)inftrees.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)inftrees.c
+
+trees.o: $(SRCDIR)trees.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)trees.c
+
+zutil.o: $(SRCDIR)zutil.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)zutil.c
+
+compress.o: $(SRCDIR)compress.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)compress.c
+
+uncompr.o: $(SRCDIR)uncompr.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)uncompr.c
+
+gzclose.o: $(SRCDIR)gzclose.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzclose.c
+
+gzlib.o: $(SRCDIR)gzlib.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzlib.c
+
+gzread.o: $(SRCDIR)gzread.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzread.c
+
+gzwrite.o: $(SRCDIR)gzwrite.c
+       $(CC) $(CFLAGS) $(ZINC) -c -o $@ $(SRCDIR)gzwrite.c
+
+
+adler32.lo: $(SRCDIR)adler32.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/adler32.o $(SRCDIR)adler32.c
+       -@mv objs/adler32.o $@
+
+crc32.lo: $(SRCDIR)crc32.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/crc32.o $(SRCDIR)crc32.c
+       -@mv objs/crc32.o $@
+
+deflate.lo: $(SRCDIR)deflate.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/deflate.o $(SRCDIR)deflate.c
+       -@mv objs/deflate.o $@
+
+infback.lo: $(SRCDIR)infback.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/infback.o $(SRCDIR)infback.c
+       -@mv objs/infback.o $@
+
+inffast.lo: $(SRCDIR)inffast.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/inffast.o $(SRCDIR)inffast.c
+       -@mv objs/inffast.o $@
+
+inflate.lo: $(SRCDIR)inflate.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/inflate.o $(SRCDIR)inflate.c
+       -@mv objs/inflate.o $@
+
+inftrees.lo: $(SRCDIR)inftrees.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/inftrees.o $(SRCDIR)inftrees.c
+       -@mv objs/inftrees.o $@
+
+trees.lo: $(SRCDIR)trees.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/trees.o $(SRCDIR)trees.c
+       -@mv objs/trees.o $@
+
+zutil.lo: $(SRCDIR)zutil.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/zutil.o $(SRCDIR)zutil.c
+       -@mv objs/zutil.o $@
+
+compress.lo: $(SRCDIR)compress.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/compress.o $(SRCDIR)compress.c
+       -@mv objs/compress.o $@
+
+uncompr.lo: $(SRCDIR)uncompr.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/uncompr.o $(SRCDIR)uncompr.c
+       -@mv objs/uncompr.o $@
+
+gzclose.lo: $(SRCDIR)gzclose.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzclose.o $(SRCDIR)gzclose.c
+       -@mv objs/gzclose.o $@
+
+gzlib.lo: $(SRCDIR)gzlib.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzlib.o $(SRCDIR)gzlib.c
+       -@mv objs/gzlib.o $@
+
+gzread.lo: $(SRCDIR)gzread.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzread.o $(SRCDIR)gzread.c
+       -@mv objs/gzread.o $@
+
+gzwrite.lo: $(SRCDIR)gzwrite.c
+       -@mkdir objs 2>/dev/null || test -d objs
+       $(CC) $(SFLAGS) $(ZINC) -DPIC -c -o objs/gzwrite.o $(SRCDIR)gzwrite.c
+       -@mv objs/gzwrite.o $@
+
+
+placebo $(SHAREDLIBV): $(PIC_OBJS) libz.a
+       $(LDSHARED) $(SFLAGS) -o $@ $(PIC_OBJS) $(LDSHAREDLIBC) $(LDFLAGS)
+       rm -f $(SHAREDLIB) $(SHAREDLIBM)
+       ln -s $@ $(SHAREDLIB)
+       ln -s $@ $(SHAREDLIBM)
+       -@rmdir objs
+
+example$(EXE): example.o $(STATICLIB)
+       $(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS)
+
+minigzip$(EXE): minigzip.o $(STATICLIB)
+       $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS)
+
+examplesh$(EXE): example.o $(SHAREDLIBV)
+       $(CC) $(CFLAGS) -o $@ example.o -L. $(SHAREDLIBV)
+
+minigzipsh$(EXE): minigzip.o $(SHAREDLIBV)
+       $(CC) $(CFLAGS) -o $@ minigzip.o -L. $(SHAREDLIBV)
+
+example64$(EXE): example64.o $(STATICLIB)
+       $(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS)
+
+minigzip64$(EXE): minigzip64.o $(STATICLIB)
+       $(CC) $(CFLAGS) -o $@ minigzip64.o $(TEST_LDFLAGS)
+
+install-libs: $(LIBS)
+       -@if [ ! -d $(DESTDIR)$(exec_prefix)  ]; then mkdir -p $(DESTDIR)$(exec_prefix); fi
+       -@if [ ! -d $(DESTDIR)$(libdir)       ]; then mkdir -p $(DESTDIR)$(libdir); fi
+       -@if [ ! -d $(DESTDIR)$(sharedlibdir) ]; then mkdir -p $(DESTDIR)$(sharedlibdir); fi
+       -@if [ ! -d $(DESTDIR)$(man3dir)      ]; then mkdir -p $(DESTDIR)$(man3dir); fi
+       -@if [ ! -d $(DESTDIR)$(pkgconfigdir) ]; then mkdir -p $(DESTDIR)$(pkgconfigdir); fi
+       rm -f $(DESTDIR)$(libdir)/$(STATICLIB)
+       cp $(STATICLIB) $(DESTDIR)$(libdir)
+       chmod 644 $(DESTDIR)$(libdir)/$(STATICLIB)
+       -@($(RANLIB) $(DESTDIR)$(libdir)/libz.a || true) >/dev/null 2>&1
+       -@if test -n "$(SHAREDLIBV)"; then \
+         rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV); \
+         cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir); \
+         echo "cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)"; \
+         chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV); \
+         echo "chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV)"; \
+         rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \
+         ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB); \
+         ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \
+         ($(LDCONFIG) || true)  >/dev/null 2>&1; \
+       fi
+       rm -f $(DESTDIR)$(man3dir)/zlib.3
+       cp $(SRCDIR)zlib.3 $(DESTDIR)$(man3dir)
+       chmod 644 $(DESTDIR)$(man3dir)/zlib.3
+       rm -f $(DESTDIR)$(pkgconfigdir)/zlib.pc
+       cp zlib.pc $(DESTDIR)$(pkgconfigdir)
+       chmod 644 $(DESTDIR)$(pkgconfigdir)/zlib.pc
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+install: install-libs
+       -@if [ ! -d $(DESTDIR)$(includedir)   ]; then mkdir -p $(DESTDIR)$(includedir); fi
+       rm -f $(DESTDIR)$(includedir)/zlib.h $(DESTDIR)$(includedir)/zconf.h
+       cp $(SRCDIR)zlib.h zconf.h $(DESTDIR)$(includedir)
+       chmod 644 $(DESTDIR)$(includedir)/zlib.h $(DESTDIR)$(includedir)/zconf.h
+
+uninstall:
+       cd $(DESTDIR)$(includedir) && rm -f zlib.h zconf.h
+       cd $(DESTDIR)$(libdir) && rm -f libz.a; \
+       if test -n "$(SHAREDLIBV)" -a -f $(SHAREDLIBV); then \
+         rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
+       fi
+       cd $(DESTDIR)$(man3dir) && rm -f zlib.3
+       cd $(DESTDIR)$(pkgconfigdir) && rm -f zlib.pc
+
+docs: zlib.3.pdf
+
+zlib.3.pdf: $(SRCDIR)zlib.3
+       groff -mandoc -f H -T ps $(SRCDIR)zlib.3 | ps2pdf - $@
+
+zconf.h.cmakein: $(SRCDIR)zconf.h.in
+       -@ TEMPFILE=zconfh_$$; \
+       echo "/#define ZCONF_H/ a\\\\\n#cmakedefine Z_PREFIX\\\\\n#cmakedefine Z_HAVE_UNISTD_H\n" >> $$TEMPFILE &&\
+       sed -f $$TEMPFILE $(SRCDIR)zconf.h.in > $@ &&\
+       touch -r $(SRCDIR)zconf.h.in $@ &&\
+       rm $$TEMPFILE
+
+zconf: $(SRCDIR)zconf.h.in
+       cp -p $(SRCDIR)zconf.h.in zconf.h
+
+mostlyclean: clean
+clean:
+       rm -f *.o *.lo *~ \
+          example$(EXE) minigzip$(EXE) examplesh$(EXE) minigzipsh$(EXE) \
+          example64$(EXE) minigzip64$(EXE) \
+          infcover \
+          libz.* foo.gz so_locations \
+          _match.s maketree contrib/infback9/*.o
+       rm -rf objs
+       rm -f *.gcda *.gcno *.gcov
+       rm -f contrib/infback9/*.gcda contrib/infback9/*.gcno contrib/infback9/*.gcov
+
+maintainer-clean: distclean
+distclean: clean zconf zconf.h.cmakein docs
+       rm -f Makefile zlib.pc configure.log
+       -@rm -f .DS_Store
+       @if [ -f Makefile.in ]; then \
+       printf 'all:\n\t-@echo "Please use ./configure first.  Thank you."\n' > Makefile ; \
+       printf '\ndistclean:\n\tmake -f Makefile.in distclean\n' >> Makefile ; \
+       touch -r $(SRCDIR)Makefile.in Makefile ; fi
+       @if [ ! -f zconf.h.in ]; then rm -f zconf.h zconf.h.cmakein ; fi
+       @if [ ! -f zlib.3 ]; then rm -f zlib.3.pdf ; fi
+
+tags:
+       etags $(SRCDIR)*.[ch]
+
+adler32.o zutil.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h
+gzclose.o gzlib.o gzread.o gzwrite.o: $(SRCDIR)zlib.h zconf.h $(SRCDIR)gzguts.h
+compress.o example.o minigzip.o uncompr.o: $(SRCDIR)zlib.h zconf.h
+crc32.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)crc32.h
+deflate.o: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h
+infback.o inflate.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR)inflate.h $(SRCDIR)inffast.h $(SRCDIR)inffixed.h
+inffast.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR)inflate.h $(SRCDIR)inffast.h
+inftrees.o: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h
+trees.o: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)trees.h
+
+adler32.lo zutil.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h
+gzclose.lo gzlib.lo gzread.lo gzwrite.lo: $(SRCDIR)zlib.h zconf.h $(SRCDIR)gzguts.h
+compress.lo example.lo minigzip.lo uncompr.lo: $(SRCDIR)zlib.h zconf.h
+crc32.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)crc32.h
+deflate.lo: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h
+infback.lo inflate.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR)inflate.h $(SRCDIR)inffast.h $(SRCDIR)inffixed.h
+inffast.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h $(SRCDIR)inflate.h $(SRCDIR)inffast.h
+inftrees.lo: $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)inftrees.h
+trees.lo: $(SRCDIR)deflate.h $(SRCDIR)zutil.h $(SRCDIR)zlib.h zconf.h $(SRCDIR)trees.h
diff --git a/deps/libchdr/deps/zlib-1.2.11/README b/deps/libchdr/deps/zlib-1.2.11/README
new file mode 100644 (file)
index 0000000..51106de
--- /dev/null
@@ -0,0 +1,115 @@
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.11 is a general purpose data compression library.  All the code is
+thread safe.  The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
+rfc1952 (gzip format).
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org).  A usage example
+of the library is given in the file test/example.c which also tests that
+the library is working correctly.  Another example is given in the file
+test/minigzip.c.  The compression library itself is composed of all source
+files in the root directory.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile.in.  In short "./configure; make test", and if that goes
+well, "make install" should work for most flavors of Unix.  For Windows, use
+one of the special makefiles in win32/ or contrib/vstudio/ .  For VMS, use
+make_vms.com.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
+<info@winimage.com> for the Windows DLL version.  The zlib home page is
+http://zlib.net/ .  Before reporting a problem, please check this site to
+verify that you have the latest version of zlib; otherwise get the latest
+version and check whether the problem still exists or not.
+
+PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan.  1997
+issue of Dr.  Dobb's Journal; a copy of the article is available at
+http://marknelson.us/1997/01/01/zlib-engine/ .
+
+The changes made in version 1.2.11 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory contrib/ .
+
+zlib is available in Java using the java.util.zip package, documented at
+http://java.sun.com/developer/technicalArticles/Programming/compression/ .
+
+A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is available
+at CPAN (Comprehensive Perl Archive Network) sites, including
+http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .
+
+A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
+available in Python 1.5 and later versions, see
+http://docs.python.org/library/zlib.html .
+
+zlib is built into tcl: http://wiki.tcl.tk/4610 .
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info@winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+  -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+  compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+  when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+  necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+  other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS or BEOS.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+
+Acknowledgments:
+
+  The deflate format used by zlib was defined by Phil Katz.  The deflate and
+  zlib specifications were written by L.  Peter Deutsch.  Thanks to all the
+  people who reported problems and suggested various improvements in zlib; they
+  are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2017 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not* receiving
+lengthy legal documents to sign.  The sources are provided for free but without
+warranty of any kind.  The library has been entirely written by Jean-loup
+Gailly and Mark Adler; it does not include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include in
+the file ChangeLog history information documenting your changes.  Please read
+the FAQ for more information on the distribution of modified source versions.
diff --git a/deps/libchdr/deps/zlib-1.2.11/adler32.c b/deps/libchdr/deps/zlib-1.2.11/adler32.c
new file mode 100644 (file)
index 0000000..d0be438
--- /dev/null
@@ -0,0 +1,186 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2011, 2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
+
+#define BASE 65521U     /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware --
+   try it both ways to see which is faster */
+#ifdef NO_DIVIDE
+/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
+   (thank you to John Reiser for pointing this out) */
+#  define CHOP(a) \
+    do { \
+        unsigned long tmp = a >> 16; \
+        a &= 0xffffUL; \
+        a += (tmp << 4) - tmp; \
+    } while (0)
+#  define MOD28(a) \
+    do { \
+        CHOP(a); \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#  define MOD(a) \
+    do { \
+        CHOP(a); \
+        MOD28(a); \
+    } while (0)
+#  define MOD63(a) \
+    do { /* this assumes a is not negative */ \
+        z_off64_t tmp = a >> 32; \
+        a &= 0xffffffffL; \
+        a += (tmp << 8) - (tmp << 5) + tmp; \
+        tmp = a >> 16; \
+        a &= 0xffffL; \
+        a += (tmp << 4) - tmp; \
+        tmp = a >> 16; \
+        a &= 0xffffL; \
+        a += (tmp << 4) - tmp; \
+        if (a >= BASE) a -= BASE; \
+    } while (0)
+#else
+#  define MOD(a) a %= BASE
+#  define MOD28(a) a %= BASE
+#  define MOD63(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_z(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    z_size_t len;
+{
+    unsigned long sum2;
+    unsigned n;
+
+    /* split Adler-32 into component sums */
+    sum2 = (adler >> 16) & 0xffff;
+    adler &= 0xffff;
+
+    /* in case user likes doing a byte at a time, keep it fast */
+    if (len == 1) {
+        adler += buf[0];
+        if (adler >= BASE)
+            adler -= BASE;
+        sum2 += adler;
+        if (sum2 >= BASE)
+            sum2 -= BASE;
+        return adler | (sum2 << 16);
+    }
+
+    /* initial Adler-32 value (deferred check for len == 1 speed) */
+    if (buf == Z_NULL)
+        return 1L;
+
+    /* in case short lengths are provided, keep it somewhat fast */
+    if (len < 16) {
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        if (adler >= BASE)
+            adler -= BASE;
+        MOD28(sum2);            /* only added so many BASE's */
+        return adler | (sum2 << 16);
+    }
+
+    /* do length NMAX blocks -- requires just one modulo operation */
+    while (len >= NMAX) {
+        len -= NMAX;
+        n = NMAX / 16;          /* NMAX is divisible by 16 */
+        do {
+            DO16(buf);          /* 16 sums unrolled */
+            buf += 16;
+        } while (--n);
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* do remaining bytes (less than NMAX, still just one modulo) */
+    if (len) {                  /* avoid modulos if none remaining */
+        while (len >= 16) {
+            len -= 16;
+            DO16(buf);
+            buf += 16;
+        }
+        while (len--) {
+            adler += *buf++;
+            sum2 += adler;
+        }
+        MOD(adler);
+        MOD(sum2);
+    }
+
+    /* return recombined sums */
+    return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    return adler32_z(adler, buf, len);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off64_t len2;
+{
+    unsigned long sum1;
+    unsigned long sum2;
+    unsigned rem;
+
+    /* for negative len, return invalid adler32 as a clue for debugging */
+    if (len2 < 0)
+        return 0xffffffffUL;
+
+    /* the derivation of this formula is left as an exercise for the reader */
+    MOD63(len2);                /* assumes len2 >= 0 */
+    rem = (unsigned)len2;
+    sum1 = adler1 & 0xffff;
+    sum2 = rem * sum1;
+    MOD(sum2);
+    sum1 += (adler2 & 0xffff) + BASE - 1;
+    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+    if (sum1 >= BASE) sum1 -= BASE;
+    if (sum1 >= BASE) sum1 -= BASE;
+    if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
+    if (sum2 >= BASE) sum2 -= BASE;
+    return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off_t len2;
+{
+    return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+    uLong adler1;
+    uLong adler2;
+    z_off64_t len2;
+{
+    return adler32_combine_(adler1, adler2, len2);
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/compress.c b/deps/libchdr/deps/zlib-1.2.11/compress.c
new file mode 100644 (file)
index 0000000..e2db404
--- /dev/null
@@ -0,0 +1,86 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least 0.1% larger than sourceLen plus
+   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+    int level;
+{
+    z_stream stream;
+    int err;
+    const uInt max = (uInt)-1;
+    uLong left;
+
+    left = *destLen;
+    *destLen = 0;
+
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = deflateInit(&stream, level);
+    if (err != Z_OK) return err;
+
+    stream.next_out = dest;
+    stream.avail_out = 0;
+    stream.next_in = (z_const Bytef *)source;
+    stream.avail_in = 0;
+
+    do {
+        if (stream.avail_out == 0) {
+            stream.avail_out = left > (uLong)max ? max : (uInt)left;
+            left -= stream.avail_out;
+        }
+        if (stream.avail_in == 0) {
+            stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen;
+            sourceLen -= stream.avail_in;
+        }
+        err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);
+    } while (err == Z_OK);
+
+    *destLen = stream.total_out;
+    deflateEnd(&stream);
+    return err == Z_STREAM_END ? Z_OK : err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+     If the default memLevel or windowBits for deflateInit() is changed, then
+   this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+    uLong sourceLen;
+{
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+           (sourceLen >> 25) + 13;
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/configure b/deps/libchdr/deps/zlib-1.2.11/configure
new file mode 100755 (executable)
index 0000000..e974d1f
--- /dev/null
@@ -0,0 +1,921 @@
+#!/bin/sh
+# configure script for zlib.
+#
+# Normally configure builds both a static and a shared library.
+# If you want to build just a static library, use: ./configure --static
+#
+# To impose specific compiler or flags or install directory, use for example:
+#    prefix=$HOME CC=cc CFLAGS="-O4" ./configure
+# or for csh/tcsh users:
+#    (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
+
+# Incorrect settings of CC or CFLAGS may prevent creating a shared library.
+# If you have problems, try without defining CC and CFLAGS before reporting
+# an error.
+
+# start off configure.log
+echo -------------------- >> configure.log
+echo $0 $* >> configure.log
+date >> configure.log
+
+# get source directory
+SRCDIR=`dirname $0`
+if test $SRCDIR = "."; then
+    ZINC=""
+    ZINCOUT="-I."
+    SRCDIR=""
+else
+    ZINC='-include zconf.h'
+    ZINCOUT='-I. -I$(SRCDIR)'
+    SRCDIR="$SRCDIR/"
+fi
+
+# set command prefix for cross-compilation
+if [ -n "${CHOST}" ]; then
+    uname="`echo "${CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/'`"
+    CROSS_PREFIX="${CHOST}-"
+fi
+
+# destination name for static library
+STATICLIB=libz.a
+
+# extract zlib version numbers from zlib.h
+VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < ${SRCDIR}zlib.h`
+VER3=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\\.[0-9]*\).*/\1/p' < ${SRCDIR}zlib.h`
+VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < ${SRCDIR}zlib.h`
+VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < ${SRCDIR}zlib.h`
+
+# establish commands for library building
+if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then
+    AR=${AR-"${CROSS_PREFIX}ar"}
+    test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log
+else
+    AR=${AR-"ar"}
+    test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log
+fi
+ARFLAGS=${ARFLAGS-"rc"}
+if "${CROSS_PREFIX}ranlib" --version >/dev/null 2>/dev/null || test $? -lt 126; then
+    RANLIB=${RANLIB-"${CROSS_PREFIX}ranlib"}
+    test -n "${CROSS_PREFIX}" && echo Using ${RANLIB} | tee -a configure.log
+else
+    RANLIB=${RANLIB-"ranlib"}
+fi
+if "${CROSS_PREFIX}nm" --version >/dev/null 2>/dev/null || test $? -lt 126; then
+    NM=${NM-"${CROSS_PREFIX}nm"}
+    test -n "${CROSS_PREFIX}" && echo Using ${NM} | tee -a configure.log
+else
+    NM=${NM-"nm"}
+fi
+
+# set defaults before processing command line options
+LDCONFIG=${LDCONFIG-"ldconfig"}
+LDSHAREDLIBC="${LDSHAREDLIBC--lc}"
+ARCHS=
+prefix=${prefix-/usr/local}
+exec_prefix=${exec_prefix-'${prefix}'}
+libdir=${libdir-'${exec_prefix}/lib'}
+sharedlibdir=${sharedlibdir-'${libdir}'}
+includedir=${includedir-'${prefix}/include'}
+mandir=${mandir-'${prefix}/share/man'}
+shared_ext='.so'
+shared=1
+solo=0
+cover=0
+zprefix=0
+zconst=0
+build64=0
+gcc=0
+warn=0
+debug=0
+old_cc="$CC"
+old_cflags="$CFLAGS"
+OBJC='$(OBJZ) $(OBJG)'
+PIC_OBJC='$(PIC_OBJZ) $(PIC_OBJG)'
+
+# leave this script, optionally in a bad way
+leave()
+{
+  if test "$*" != "0"; then
+    echo "** $0 aborting." | tee -a configure.log
+  fi
+  rm -f $test.[co] $test $test$shared_ext $test.gcno ./--version
+  echo -------------------- >> configure.log
+  echo >> configure.log
+  echo >> configure.log
+  exit $1
+}
+
+# process command line options
+while test $# -ge 1
+do
+case "$1" in
+    -h* | --help)
+      echo 'usage:' | tee -a configure.log
+      echo '  configure [--const] [--zprefix] [--prefix=PREFIX]  [--eprefix=EXPREFIX]' | tee -a configure.log
+      echo '    [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log
+      echo '    [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log
+        exit 0 ;;
+    -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;;
+    -e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;;
+    -l*=* | --libdir=*) libdir=`echo $1 | sed 's/.*=//'`; shift ;;
+    --sharedlibdir=*) sharedlibdir=`echo $1 | sed 's/.*=//'`; shift ;;
+    -i*=* | --includedir=*) includedir=`echo $1 | sed 's/.*=//'`;shift ;;
+    -u*=* | --uname=*) uname=`echo $1 | sed 's/.*=//'`;shift ;;
+    -p* | --prefix) prefix="$2"; shift; shift ;;
+    -e* | --eprefix) exec_prefix="$2"; shift; shift ;;
+    -l* | --libdir) libdir="$2"; shift; shift ;;
+    -i* | --includedir) includedir="$2"; shift; shift ;;
+    -s* | --shared | --enable-shared) shared=1; shift ;;
+    -t | --static) shared=0; shift ;;
+    --solo) solo=1; shift ;;
+    --cover) cover=1; shift ;;
+    -z* | --zprefix) zprefix=1; shift ;;
+    -6* | --64) build64=1; shift ;;
+    -a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;;
+    --sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;;
+    --localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;;
+    -c* | --const) zconst=1; shift ;;
+    -w* | --warn) warn=1; shift ;;
+    -d* | --debug) debug=1; shift ;;
+    *)
+      echo "unknown option: $1" | tee -a configure.log
+      echo "$0 --help for help" | tee -a configure.log
+      leave 1;;
+    esac
+done
+
+# temporary file name
+test=ztest$$
+
+# put arguments in log, also put test file in log if used in arguments
+show()
+{
+  case "$*" in
+    *$test.c*)
+      echo === $test.c === >> configure.log
+      cat $test.c >> configure.log
+      echo === >> configure.log;;
+  esac
+  echo $* >> configure.log
+}
+
+# check for gcc vs. cc and set compile and link flags based on the system identified by uname
+cat > $test.c <<EOF
+extern int getchar();
+int hello() {return getchar();}
+EOF
+
+test -z "$CC" && echo Checking for ${CROSS_PREFIX}gcc... | tee -a configure.log
+cc=${CC-${CROSS_PREFIX}gcc}
+cflags=${CFLAGS-"-O3"}
+# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure
+case "$cc" in
+  *gcc*) gcc=1 ;;
+  *clang*) gcc=1 ;;
+esac
+case `$cc -v 2>&1` in
+  *gcc*) gcc=1 ;;
+  *clang*) gcc=1 ;;
+esac
+
+show $cc -c $test.c
+if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then
+  echo ... using gcc >> configure.log
+  CC="$cc"
+  CFLAGS="${CFLAGS--O3}"
+  SFLAGS="${CFLAGS--O3} -fPIC"
+  if test "$ARCHS"; then
+    CFLAGS="${CFLAGS} ${ARCHS}"
+    LDFLAGS="${LDFLAGS} ${ARCHS}"
+  fi
+  if test $build64 -eq 1; then
+    CFLAGS="${CFLAGS} -m64"
+    SFLAGS="${SFLAGS} -m64"
+  fi
+  if test "$warn" -eq 1; then
+    if test "$zconst" -eq 1; then
+      CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -pedantic -DZLIB_CONST"
+    else
+      CFLAGS="${CFLAGS} -Wall -Wextra -pedantic"
+    fi
+  fi
+  if test $debug -eq 1; then
+    CFLAGS="${CFLAGS} -DZLIB_DEBUG"
+    SFLAGS="${SFLAGS} -DZLIB_DEBUG"
+  fi
+  if test -z "$uname"; then
+    uname=`(uname -s || echo unknown) 2>/dev/null`
+  fi
+  case "$uname" in
+  Linux* | linux* | GNU | GNU/* | solaris*)
+        LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} ;;
+  *BSD | *bsd* | DragonFly)
+        LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"}
+        LDCONFIG="ldconfig -m" ;;
+  CYGWIN* | Cygwin* | cygwin* | OS/2*)
+        EXE='.exe' ;;
+  MINGW* | mingw*)
+# temporary bypass
+        rm -f $test.[co] $test $test$shared_ext
+        echo "Please use win32/Makefile.gcc instead." | tee -a configure.log
+        leave 1
+        LDSHARED=${LDSHARED-"$cc -shared"}
+        LDSHAREDLIBC=""
+        EXE='.exe' ;;
+  QNX*)  # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4
+         # (alain.bonnefoy@icbt.com)
+                 LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;;
+  HP-UX*)
+         LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"}
+         case `(uname -m || echo unknown) 2>/dev/null` in
+         ia64)
+                 shared_ext='.so'
+                 SHAREDLIB='libz.so' ;;
+         *)
+                 shared_ext='.sl'
+                 SHAREDLIB='libz.sl' ;;
+         esac ;;
+  Darwin* | darwin*)
+             shared_ext='.dylib'
+             SHAREDLIB=libz$shared_ext
+             SHAREDLIBV=libz.$VER$shared_ext
+             SHAREDLIBM=libz.$VER1$shared_ext
+             LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"}
+             if libtool -V 2>&1 | grep Apple > /dev/null; then
+                 AR="libtool"
+             else
+                 AR="/usr/bin/libtool"
+             fi
+             ARFLAGS="-o" ;;
+  *)             LDSHARED=${LDSHARED-"$cc -shared"} ;;
+  esac
+else
+  # find system name and corresponding cc options
+  CC=${CC-cc}
+  gcc=0
+  echo ... using $CC >> configure.log
+  if test -z "$uname"; then
+    uname=`(uname -sr || echo unknown) 2>/dev/null`
+  fi
+  case "$uname" in
+  HP-UX*)    SFLAGS=${CFLAGS-"-O +z"}
+             CFLAGS=${CFLAGS-"-O"}
+#            LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"}
+             LDSHARED=${LDSHARED-"ld -b"}
+         case `(uname -m || echo unknown) 2>/dev/null` in
+         ia64)
+             shared_ext='.so'
+             SHAREDLIB='libz.so' ;;
+         *)
+             shared_ext='.sl'
+             SHAREDLIB='libz.sl' ;;
+         esac ;;
+  IRIX*)     SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
+             CFLAGS=${CFLAGS-"-ansi -O2"}
+             LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;;
+  OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"}
+             CFLAGS=${CFLAGS-"-O -std1"}
+             LDFLAGS="${LDFLAGS} -Wl,-rpath,."
+             LDSHARED=${LDSHARED-"cc -shared  -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"} ;;
+  OSF1*)     SFLAGS=${CFLAGS-"-O -std1"}
+             CFLAGS=${CFLAGS-"-O -std1"}
+             LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;;
+  QNX*)      SFLAGS=${CFLAGS-"-4 -O"}
+             CFLAGS=${CFLAGS-"-4 -O"}
+             LDSHARED=${LDSHARED-"cc"}
+             RANLIB=${RANLIB-"true"}
+             AR="cc"
+             ARFLAGS="-A" ;;
+  SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
+             CFLAGS=${CFLAGS-"-O3"}
+             LDSHARED=${LDSHARED-"cc -dy -KPIC -G"} ;;
+  SunOS\ 5* | solaris*)
+         LDSHARED=${LDSHARED-"cc -G -h libz$shared_ext.$VER1"}
+         SFLAGS=${CFLAGS-"-fast -KPIC"}
+         CFLAGS=${CFLAGS-"-fast"}
+         if test $build64 -eq 1; then
+             # old versions of SunPRO/Workshop/Studio don't support -m64,
+             # but newer ones do.  Check for it.
+             flag64=`$CC -flags | egrep -- '^-m64'`
+             if test x"$flag64" != x"" ; then
+                 CFLAGS="${CFLAGS} -m64"
+                 SFLAGS="${SFLAGS} -m64"
+             else
+                 case `(uname -m || echo unknown) 2>/dev/null` in
+                   i86*)
+                     SFLAGS="$SFLAGS -xarch=amd64"
+                     CFLAGS="$CFLAGS -xarch=amd64" ;;
+                   *)
+                     SFLAGS="$SFLAGS -xarch=v9"
+                     CFLAGS="$CFLAGS -xarch=v9" ;;
+                 esac
+             fi
+         fi
+         if test -n "$ZINC"; then
+             ZINC='-I- -I. -I$(SRCDIR)'
+         fi
+         ;;
+  SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
+             CFLAGS=${CFLAGS-"-O2"}
+             LDSHARED=${LDSHARED-"ld"} ;;
+  SunStudio\ 9*) SFLAGS=${CFLAGS-"-fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"}
+             CFLAGS=${CFLAGS-"-fast -xtarget=ultra3 -xarch=v9b"}
+             LDSHARED=${LDSHARED-"cc -xarch=v9b"} ;;
+  UNIX_System_V\ 4.2.0)
+             SFLAGS=${CFLAGS-"-KPIC -O"}
+             CFLAGS=${CFLAGS-"-O"}
+             LDSHARED=${LDSHARED-"cc -G"} ;;
+  UNIX_SV\ 4.2MP)
+             SFLAGS=${CFLAGS-"-Kconform_pic -O"}
+             CFLAGS=${CFLAGS-"-O"}
+             LDSHARED=${LDSHARED-"cc -G"} ;;
+  OpenUNIX\ 5)
+             SFLAGS=${CFLAGS-"-KPIC -O"}
+             CFLAGS=${CFLAGS-"-O"}
+             LDSHARED=${LDSHARED-"cc -G"} ;;
+  AIX*)  # Courtesy of dbakker@arrayasolutions.com
+             SFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+             CFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+             LDSHARED=${LDSHARED-"xlc -G"} ;;
+  # send working options for other systems to zlib@gzip.org
+  *)         SFLAGS=${CFLAGS-"-O"}
+             CFLAGS=${CFLAGS-"-O"}
+             LDSHARED=${LDSHARED-"cc -shared"} ;;
+  esac
+fi
+
+# destination names for shared library if not defined above
+SHAREDLIB=${SHAREDLIB-"libz$shared_ext"}
+SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"}
+SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"}
+
+echo >> configure.log
+
+# define functions for testing compiler and library characteristics and logging the results
+
+cat > $test.c <<EOF
+#error error
+EOF
+if ($CC -c $CFLAGS $test.c) 2>/dev/null; then
+  try()
+  {
+    show $*
+    test "`( $* ) 2>&1 | tee -a configure.log`" = ""
+  }
+  echo - using any output from compiler to indicate an error >> configure.log
+else
+  try()
+  {
+    show $*
+    ( $* ) >> configure.log 2>&1
+    ret=$?
+    if test $ret -ne 0; then
+      echo "(exit code "$ret")" >> configure.log
+    fi
+    return $ret
+  }
+fi
+
+tryboth()
+{
+  show $*
+  got=`( $* ) 2>&1`
+  ret=$?
+  printf %s "$got" >> configure.log
+  if test $ret -ne 0; then
+    return $ret
+  fi
+  test "$got" = ""
+}
+
+cat > $test.c << EOF
+int foo() { return 0; }
+EOF
+echo "Checking for obsessive-compulsive compiler options..." >> configure.log
+if try $CC -c $CFLAGS $test.c; then
+  :
+else
+  echo "Compiler error reporting is too harsh for $0 (perhaps remove -Werror)." | tee -a configure.log
+  leave 1
+fi
+
+echo >> configure.log
+
+# see if shared library build supported
+cat > $test.c <<EOF
+extern int getchar();
+int hello() {return getchar();}
+EOF
+if test $shared -eq 1; then
+  echo Checking for shared library support... | tee -a configure.log
+  # we must test in two steps (cc then ld), required at least on SunOS 4.x
+  if try $CC -w -c $SFLAGS $test.c &&
+     try $LDSHARED $SFLAGS -o $test$shared_ext $test.o; then
+    echo Building shared library $SHAREDLIBV with $CC. | tee -a configure.log
+  elif test -z "$old_cc" -a -z "$old_cflags"; then
+    echo No shared library support. | tee -a configure.log
+    shared=0;
+  else
+    echo 'No shared library support; try without defining CC and CFLAGS' | tee -a configure.log
+    shared=0;
+  fi
+fi
+if test $shared -eq 0; then
+  LDSHARED="$CC"
+  ALL="static"
+  TEST="all teststatic"
+  SHAREDLIB=""
+  SHAREDLIBV=""
+  SHAREDLIBM=""
+  echo Building static library $STATICLIB version $VER with $CC. | tee -a configure.log
+else
+  ALL="static shared"
+  TEST="all teststatic testshared"
+fi
+
+# check for underscores in external names for use by assembler code
+CPP=${CPP-"$CC -E"}
+case $CFLAGS in
+  *ASMV*)
+    echo >> configure.log
+    show "$NM $test.o | grep _hello"
+    if test "`$NM $test.o | grep _hello | tee -a configure.log`" = ""; then
+      CPP="$CPP -DNO_UNDERLINE"
+      echo Checking for underline in external names... No. | tee -a configure.log
+    else
+      echo Checking for underline in external names... Yes. | tee -a configure.log
+    fi ;;
+esac
+
+echo >> configure.log
+
+# check for size_t
+cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdlib.h>
+size_t dummy = 0;
+EOF
+if try $CC -c $CFLAGS $test.c; then
+  echo "Checking for size_t... Yes." | tee -a configure.log
+  need_sizet=0
+else
+  echo "Checking for size_t... No." | tee -a configure.log
+  need_sizet=1
+fi
+
+echo >> configure.log
+
+# find the size_t integer type, if needed
+if test $need_sizet -eq 1; then
+  cat > $test.c <<EOF
+long long dummy = 0;
+EOF
+  if try $CC -c $CFLAGS $test.c; then
+    echo "Checking for long long... Yes." | tee -a configure.log
+    cat > $test.c <<EOF
+#include <stdio.h>
+int main(void) {
+    if (sizeof(void *) <= sizeof(int)) puts("int");
+    else if (sizeof(void *) <= sizeof(long)) puts("long");
+    else puts("z_longlong");
+    return 0;
+}
+EOF
+  else
+    echo "Checking for long long... No." | tee -a configure.log
+    cat > $test.c <<EOF
+#include <stdio.h>
+int main(void) {
+    if (sizeof(void *) <= sizeof(int)) puts("int");
+    else puts("long");
+    return 0;
+}
+EOF
+  fi
+  if try $CC $CFLAGS -o $test $test.c; then
+    sizet=`./$test`
+    echo "Checking for a pointer-size integer type..." $sizet"." | tee -a configure.log
+  else
+    echo "Failed to find a pointer-size integer type." | tee -a configure.log
+    leave 1
+  fi
+fi
+
+if test $need_sizet -eq 1; then
+  CFLAGS="${CFLAGS} -DNO_SIZE_T=${sizet}"
+  SFLAGS="${SFLAGS} -DNO_SIZE_T=${sizet}"
+fi
+
+echo >> configure.log
+
+# check for large file support, and if none, check for fseeko()
+cat > $test.c <<EOF
+#include <sys/types.h>
+off64_t dummy = 0;
+EOF
+if try $CC -c $CFLAGS -D_LARGEFILE64_SOURCE=1 $test.c; then
+  CFLAGS="${CFLAGS} -D_LARGEFILE64_SOURCE=1"
+  SFLAGS="${SFLAGS} -D_LARGEFILE64_SOURCE=1"
+  ALL="${ALL} all64"
+  TEST="${TEST} test64"
+  echo "Checking for off64_t... Yes." | tee -a configure.log
+  echo "Checking for fseeko... Yes." | tee -a configure.log
+else
+  echo "Checking for off64_t... No." | tee -a configure.log
+  echo >> configure.log
+  cat > $test.c <<EOF
+#include <stdio.h>
+int main(void) {
+  fseeko(NULL, 0, 0);
+  return 0;
+}
+EOF
+  if try $CC $CFLAGS -o $test $test.c; then
+    echo "Checking for fseeko... Yes." | tee -a configure.log
+  else
+    CFLAGS="${CFLAGS} -DNO_FSEEKO"
+    SFLAGS="${SFLAGS} -DNO_FSEEKO"
+    echo "Checking for fseeko... No." | tee -a configure.log
+  fi
+fi
+
+echo >> configure.log
+
+# check for strerror() for use by gz* functions
+cat > $test.c <<EOF
+#include <string.h>
+#include <errno.h>
+int main() { return strlen(strerror(errno)); }
+EOF
+if try $CC $CFLAGS -o $test $test.c; then
+  echo "Checking for strerror... Yes." | tee -a configure.log
+else
+  CFLAGS="${CFLAGS} -DNO_STRERROR"
+  SFLAGS="${SFLAGS} -DNO_STRERROR"
+  echo "Checking for strerror... No." | tee -a configure.log
+fi
+
+# copy clean zconf.h for subsequent edits
+cp -p ${SRCDIR}zconf.h.in zconf.h
+
+echo >> configure.log
+
+# check for unistd.h and save result in zconf.h
+cat > $test.c <<EOF
+#include <unistd.h>
+int main() { return 0; }
+EOF
+if try $CC -c $CFLAGS $test.c; then
+  sed < zconf.h "/^#ifdef HAVE_UNISTD_H.* may be/s/def HAVE_UNISTD_H\(.*\) may be/ 1\1 was/" > zconf.temp.h
+  mv zconf.temp.h zconf.h
+  echo "Checking for unistd.h... Yes." | tee -a configure.log
+else
+  echo "Checking for unistd.h... No." | tee -a configure.log
+fi
+
+echo >> configure.log
+
+# check for stdarg.h and save result in zconf.h
+cat > $test.c <<EOF
+#include <stdarg.h>
+int main() { return 0; }
+EOF
+if try $CC -c $CFLAGS $test.c; then
+  sed < zconf.h "/^#ifdef HAVE_STDARG_H.* may be/s/def HAVE_STDARG_H\(.*\) may be/ 1\1 was/" > zconf.temp.h
+  mv zconf.temp.h zconf.h
+  echo "Checking for stdarg.h... Yes." | tee -a configure.log
+else
+  echo "Checking for stdarg.h... No." | tee -a configure.log
+fi
+
+# if the z_ prefix was requested, save that in zconf.h
+if test $zprefix -eq 1; then
+  sed < zconf.h "/#ifdef Z_PREFIX.* may be/s/def Z_PREFIX\(.*\) may be/ 1\1 was/" > zconf.temp.h
+  mv zconf.temp.h zconf.h
+  echo >> configure.log
+  echo "Using z_ prefix on all symbols." | tee -a configure.log
+fi
+
+# if --solo compilation was requested, save that in zconf.h and remove gz stuff from object lists
+if test $solo -eq 1; then
+  sed '/#define ZCONF_H/a\
+#define Z_SOLO
+
+' < zconf.h > zconf.temp.h
+  mv zconf.temp.h zconf.h
+OBJC='$(OBJZ)'
+PIC_OBJC='$(PIC_OBJZ)'
+fi
+
+# if code coverage testing was requested, use older gcc if defined, e.g. "gcc-4.2" on Mac OS X
+if test $cover -eq 1; then
+  CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage"
+  if test -n "$GCC_CLASSIC"; then
+    CC=$GCC_CLASSIC
+  fi
+fi
+
+echo >> configure.log
+
+# conduct a series of tests to resolve eight possible cases of using "vs" or "s" printf functions
+# (using stdarg or not), with or without "n" (proving size of buffer), and with or without a
+# return value.  The most secure result is vsnprintf() with a return value.  snprintf() with a
+# return value is secure as well, but then gzprintf() will be limited to 20 arguments.
+cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+#include "zconf.h"
+int main()
+{
+#ifndef STDC
+  choke me
+#endif
+  return 0;
+}
+EOF
+if try $CC -c $CFLAGS $test.c; then
+  echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()." | tee -a configure.log
+
+  echo >> configure.log
+  cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+int mytest(const char *fmt, ...)
+{
+  char buf[20];
+  va_list ap;
+  va_start(ap, fmt);
+  vsnprintf(buf, sizeof(buf), fmt, ap);
+  va_end(ap);
+  return 0;
+}
+int main()
+{
+  return (mytest("Hello%d\n", 1));
+}
+EOF
+  if try $CC $CFLAGS -o $test $test.c; then
+    echo "Checking for vsnprintf() in stdio.h... Yes." | tee -a configure.log
+
+    echo >> configure.log
+    cat >$test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+int mytest(const char *fmt, ...)
+{
+  int n;
+  char buf[20];
+  va_list ap;
+  va_start(ap, fmt);
+  n = vsnprintf(buf, sizeof(buf), fmt, ap);
+  va_end(ap);
+  return n;
+}
+int main()
+{
+  return (mytest("Hello%d\n", 1));
+}
+EOF
+
+    if try $CC -c $CFLAGS $test.c; then
+      echo "Checking for return value of vsnprintf()... Yes." | tee -a configure.log
+    else
+      CFLAGS="$CFLAGS -DHAS_vsnprintf_void"
+      SFLAGS="$SFLAGS -DHAS_vsnprintf_void"
+      echo "Checking for return value of vsnprintf()... No." | tee -a configure.log
+      echo "  WARNING: apparently vsnprintf() does not return a value. zlib" | tee -a configure.log
+      echo "  can build but will be open to possible string-format security" | tee -a configure.log
+      echo "  vulnerabilities." | tee -a configure.log
+    fi
+  else
+    CFLAGS="$CFLAGS -DNO_vsnprintf"
+    SFLAGS="$SFLAGS -DNO_vsnprintf"
+    echo "Checking for vsnprintf() in stdio.h... No." | tee -a configure.log
+    echo "  WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" | tee -a configure.log
+    echo "  can build but will be open to possible buffer-overflow security" | tee -a configure.log
+    echo "  vulnerabilities." | tee -a configure.log
+
+    echo >> configure.log
+    cat >$test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+int mytest(const char *fmt, ...)
+{
+  int n;
+  char buf[20];
+  va_list ap;
+  va_start(ap, fmt);
+  n = vsprintf(buf, fmt, ap);
+  va_end(ap);
+  return n;
+}
+int main()
+{
+  return (mytest("Hello%d\n", 1));
+}
+EOF
+
+    if try $CC -c $CFLAGS $test.c; then
+      echo "Checking for return value of vsprintf()... Yes." | tee -a configure.log
+    else
+      CFLAGS="$CFLAGS -DHAS_vsprintf_void"
+      SFLAGS="$SFLAGS -DHAS_vsprintf_void"
+      echo "Checking for return value of vsprintf()... No." | tee -a configure.log
+      echo "  WARNING: apparently vsprintf() does not return a value. zlib" | tee -a configure.log
+      echo "  can build but will be open to possible string-format security" | tee -a configure.log
+      echo "  vulnerabilities." | tee -a configure.log
+    fi
+  fi
+else
+  echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()." | tee -a configure.log
+
+  echo >> configure.log
+  cat >$test.c <<EOF
+#include <stdio.h>
+int mytest()
+{
+  char buf[20];
+  snprintf(buf, sizeof(buf), "%s", "foo");
+  return 0;
+}
+int main()
+{
+  return (mytest());
+}
+EOF
+
+  if try $CC $CFLAGS -o $test $test.c; then
+    echo "Checking for snprintf() in stdio.h... Yes." | tee -a configure.log
+
+    echo >> configure.log
+    cat >$test.c <<EOF
+#include <stdio.h>
+int mytest()
+{
+  char buf[20];
+  return snprintf(buf, sizeof(buf), "%s", "foo");
+}
+int main()
+{
+  return (mytest());
+}
+EOF
+
+    if try $CC -c $CFLAGS $test.c; then
+      echo "Checking for return value of snprintf()... Yes." | tee -a configure.log
+    else
+      CFLAGS="$CFLAGS -DHAS_snprintf_void"
+      SFLAGS="$SFLAGS -DHAS_snprintf_void"
+      echo "Checking for return value of snprintf()... No." | tee -a configure.log
+      echo "  WARNING: apparently snprintf() does not return a value. zlib" | tee -a configure.log
+      echo "  can build but will be open to possible string-format security" | tee -a configure.log
+      echo "  vulnerabilities." | tee -a configure.log
+    fi
+  else
+    CFLAGS="$CFLAGS -DNO_snprintf"
+    SFLAGS="$SFLAGS -DNO_snprintf"
+    echo "Checking for snprintf() in stdio.h... No." | tee -a configure.log
+    echo "  WARNING: snprintf() not found, falling back to sprintf(). zlib" | tee -a configure.log
+    echo "  can build but will be open to possible buffer-overflow security" | tee -a configure.log
+    echo "  vulnerabilities." | tee -a configure.log
+
+    echo >> configure.log
+    cat >$test.c <<EOF
+#include <stdio.h>
+int mytest()
+{
+  char buf[20];
+  return sprintf(buf, "%s", "foo");
+}
+int main()
+{
+  return (mytest());
+}
+EOF
+
+    if try $CC -c $CFLAGS $test.c; then
+      echo "Checking for return value of sprintf()... Yes." | tee -a configure.log
+    else
+      CFLAGS="$CFLAGS -DHAS_sprintf_void"
+      SFLAGS="$SFLAGS -DHAS_sprintf_void"
+      echo "Checking for return value of sprintf()... No." | tee -a configure.log
+      echo "  WARNING: apparently sprintf() does not return a value. zlib" | tee -a configure.log
+      echo "  can build but will be open to possible string-format security" | tee -a configure.log
+      echo "  vulnerabilities." | tee -a configure.log
+    fi
+  fi
+fi
+
+# see if we can hide zlib internal symbols that are linked between separate source files
+if test "$gcc" -eq 1; then
+  echo >> configure.log
+  cat > $test.c <<EOF
+#define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+int ZLIB_INTERNAL foo;
+int main()
+{
+  return 0;
+}
+EOF
+  if tryboth $CC -c $CFLAGS $test.c; then
+    CFLAGS="$CFLAGS -DHAVE_HIDDEN"
+    SFLAGS="$SFLAGS -DHAVE_HIDDEN"
+    echo "Checking for attribute(visibility) support... Yes." | tee -a configure.log
+  else
+    echo "Checking for attribute(visibility) support... No." | tee -a configure.log
+  fi
+fi
+
+# show the results in the log
+echo >> configure.log
+echo ALL = $ALL >> configure.log
+echo AR = $AR >> configure.log
+echo ARFLAGS = $ARFLAGS >> configure.log
+echo CC = $CC >> configure.log
+echo CFLAGS = $CFLAGS >> configure.log
+echo CPP = $CPP >> configure.log
+echo EXE = $EXE >> configure.log
+echo LDCONFIG = $LDCONFIG >> configure.log
+echo LDFLAGS = $LDFLAGS >> configure.log
+echo LDSHARED = $LDSHARED >> configure.log
+echo LDSHAREDLIBC = $LDSHAREDLIBC >> configure.log
+echo OBJC = $OBJC >> configure.log
+echo PIC_OBJC = $PIC_OBJC >> configure.log
+echo RANLIB = $RANLIB >> configure.log
+echo SFLAGS = $SFLAGS >> configure.log
+echo SHAREDLIB = $SHAREDLIB >> configure.log
+echo SHAREDLIBM = $SHAREDLIBM >> configure.log
+echo SHAREDLIBV = $SHAREDLIBV >> configure.log
+echo STATICLIB = $STATICLIB >> configure.log
+echo TEST = $TEST >> configure.log
+echo VER = $VER >> configure.log
+echo Z_U4 = $Z_U4 >> configure.log
+echo SRCDIR = $SRCDIR >> configure.log
+echo exec_prefix = $exec_prefix >> configure.log
+echo includedir = $includedir >> configure.log
+echo libdir = $libdir >> configure.log
+echo mandir = $mandir >> configure.log
+echo prefix = $prefix >> configure.log
+echo sharedlibdir = $sharedlibdir >> configure.log
+echo uname = $uname >> configure.log
+
+# udpate Makefile with the configure results
+sed < ${SRCDIR}Makefile.in "
+/^CC *=/s#=.*#=$CC#
+/^CFLAGS *=/s#=.*#=$CFLAGS#
+/^SFLAGS *=/s#=.*#=$SFLAGS#
+/^LDFLAGS *=/s#=.*#=$LDFLAGS#
+/^LDSHARED *=/s#=.*#=$LDSHARED#
+/^CPP *=/s#=.*#=$CPP#
+/^STATICLIB *=/s#=.*#=$STATICLIB#
+/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
+/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
+/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
+/^AR *=/s#=.*#=$AR#
+/^ARFLAGS *=/s#=.*#=$ARFLAGS#
+/^RANLIB *=/s#=.*#=$RANLIB#
+/^LDCONFIG *=/s#=.*#=$LDCONFIG#
+/^LDSHAREDLIBC *=/s#=.*#=$LDSHAREDLIBC#
+/^EXE *=/s#=.*#=$EXE#
+/^SRCDIR *=/s#=.*#=$SRCDIR#
+/^ZINC *=/s#=.*#=$ZINC#
+/^ZINCOUT *=/s#=.*#=$ZINCOUT#
+/^prefix *=/s#=.*#=$prefix#
+/^exec_prefix *=/s#=.*#=$exec_prefix#
+/^libdir *=/s#=.*#=$libdir#
+/^sharedlibdir *=/s#=.*#=$sharedlibdir#
+/^includedir *=/s#=.*#=$includedir#
+/^mandir *=/s#=.*#=$mandir#
+/^OBJC *=/s#=.*#= $OBJC#
+/^PIC_OBJC *=/s#=.*#= $PIC_OBJC#
+/^all: */s#:.*#: $ALL#
+/^test: */s#:.*#: $TEST#
+" > Makefile
+
+# create zlib.pc with the configure results
+sed < ${SRCDIR}zlib.pc.in "
+/^CC *=/s#=.*#=$CC#
+/^CFLAGS *=/s#=.*#=$CFLAGS#
+/^CPP *=/s#=.*#=$CPP#
+/^LDSHARED *=/s#=.*#=$LDSHARED#
+/^STATICLIB *=/s#=.*#=$STATICLIB#
+/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
+/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
+/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
+/^AR *=/s#=.*#=$AR#
+/^ARFLAGS *=/s#=.*#=$ARFLAGS#
+/^RANLIB *=/s#=.*#=$RANLIB#
+/^EXE *=/s#=.*#=$EXE#
+/^prefix *=/s#=.*#=$prefix#
+/^exec_prefix *=/s#=.*#=$exec_prefix#
+/^libdir *=/s#=.*#=$libdir#
+/^sharedlibdir *=/s#=.*#=$sharedlibdir#
+/^includedir *=/s#=.*#=$includedir#
+/^mandir *=/s#=.*#=$mandir#
+/^LDFLAGS *=/s#=.*#=$LDFLAGS#
+" | sed -e "
+s/\@VERSION\@/$VER/g;
+" > zlib.pc
+
+# done
+leave 0
diff --git a/deps/libchdr/deps/zlib-1.2.11/crc32.c b/deps/libchdr/deps/zlib-1.2.11/crc32.c
new file mode 100644 (file)
index 0000000..9580440
--- /dev/null
@@ -0,0 +1,442 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors.  This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+  Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+  protection on the static variables used to control the first-use generation
+  of the crc tables.  Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+  first call get_crc_table() to initialize the tables before allowing more than
+  one thread to use crc32().
+
+  DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.
+ */
+
+#ifdef MAKECRCH
+#  include <stdio.h>
+#  ifndef DYNAMIC_CRC_TABLE
+#    define DYNAMIC_CRC_TABLE
+#  endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h"      /* for STDC and FAR definitions */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#if !defined(NOBYFOUR) && defined(Z_U4)
+#  define BYFOUR
+#endif
+#ifdef BYFOUR
+   local unsigned long crc32_little OF((unsigned long,
+                        const unsigned char FAR *, z_size_t));
+   local unsigned long crc32_big OF((unsigned long,
+                        const unsigned char FAR *, z_size_t));
+#  define TBLS 8
+#else
+#  define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+                                         unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));
+
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local z_crc_t FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+   local void write_table OF((FILE *, const z_crc_t FAR *));
+#endif /* MAKECRCH */
+/*
+  Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+  Polynomials over GF(2) are represented in binary, one bit per coefficient,
+  with the lowest powers in the most significant bit.  Then adding polynomials
+  is just exclusive-or, and multiplying a polynomial by x is a right shift by
+  one.  If we call the above polynomial p, and represent a byte as the
+  polynomial q, also with the lowest power in the most significant bit (so the
+  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+  where a mod b means the remainder after dividing a by b.
+
+  This calculation is done using the shift-register method of multiplying and
+  taking the remainder.  The register is initialized to zero, and for each
+  incoming bit, x^32 is added mod p to the register if the bit is a one (where
+  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+  x (which is shifting right by one and adding x^32 mod p if the bit shifted
+  out is a one).  We start with the highest power (least significant bit) of
+  q and repeat for all eight bits of q.
+
+  The first table is simply the CRC of all possible eight bit values.  This is
+  all the information needed to generate CRCs on data a byte at a time for all
+  combinations of CRC register values and incoming bytes.  The remaining tables
+  allow for word-at-a-time CRC calculation for both big-endian and little-
+  endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+    z_crc_t c;
+    int n, k;
+    z_crc_t poly;                       /* polynomial exclusive-or pattern */
+    /* terms of polynomial defining this crc (except x^32): */
+    static volatile int first = 1;      /* flag to limit concurrent making */
+    static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+    /* See if another task is already doing this (not thread-safe, but better
+       than nothing -- significantly reduces duration of vulnerability in
+       case the advice about DYNAMIC_CRC_TABLE is ignored) */
+    if (first) {
+        first = 0;
+
+        /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+        poly = 0;
+        for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
+            poly |= (z_crc_t)1 << (31 - p[n]);
+
+        /* generate a crc for every 8-bit value */
+        for (n = 0; n < 256; n++) {
+            c = (z_crc_t)n;
+            for (k = 0; k < 8; k++)
+                c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+            crc_table[0][n] = c;
+        }
+
+#ifdef BYFOUR
+        /* generate crc for each value followed by one, two, and three zeros,
+           and then the byte reversal of those as well as the first table */
+        for (n = 0; n < 256; n++) {
+            c = crc_table[0][n];
+            crc_table[4][n] = ZSWAP32(c);
+            for (k = 1; k < 4; k++) {
+                c = crc_table[0][c & 0xff] ^ (c >> 8);
+                crc_table[k][n] = c;
+                crc_table[k + 4][n] = ZSWAP32(c);
+            }
+        }
+#endif /* BYFOUR */
+
+        crc_table_empty = 0;
+    }
+    else {      /* not first */
+        /* wait for the other guy to finish (not efficient, but rare) */
+        while (crc_table_empty)
+            ;
+    }
+
+#ifdef MAKECRCH
+    /* write out CRC tables to crc32.h */
+    {
+        FILE *out;
+
+        out = fopen("crc32.h", "w");
+        if (out == NULL) return;
+        fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+        fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+        fprintf(out, "local const z_crc_t FAR ");
+        fprintf(out, "crc_table[TBLS][256] =\n{\n  {\n");
+        write_table(out, crc_table[0]);
+#  ifdef BYFOUR
+        fprintf(out, "#ifdef BYFOUR\n");
+        for (k = 1; k < 8; k++) {
+            fprintf(out, "  },\n  {\n");
+            write_table(out, crc_table[k]);
+        }
+        fprintf(out, "#endif\n");
+#  endif /* BYFOUR */
+        fprintf(out, "  }\n};\n");
+        fclose(out);
+    }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+    FILE *out;
+    const z_crc_t FAR *table;
+{
+    int n;
+
+    for (n = 0; n < 256; n++)
+        fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : "    ",
+                (unsigned long)(table[n]),
+                n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const z_crc_t FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+    return (const z_crc_t FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32_z(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    z_size_t len;
+{
+    if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+    if (crc_table_empty)
+        make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+    if (sizeof(void *) == sizeof(ptrdiff_t)) {
+        z_crc_t endian;
+
+        endian = 1;
+        if (*((unsigned char *)(&endian)))
+            return crc32_little(crc, buf, len);
+        else
+            return crc32_big(crc, buf, len);
+    }
+#endif /* BYFOUR */
+    crc = crc ^ 0xffffffffUL;
+    while (len >= 8) {
+        DO8;
+        len -= 8;
+    }
+    if (len) do {
+        DO1;
+    } while (--len);
+    return crc ^ 0xffffffffUL;
+}
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    uInt len;
+{
+    return crc32_z(crc, buf, len);
+}
+
+#ifdef BYFOUR
+
+/*
+   This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit
+   integer pointer type. This violates the strict aliasing rule, where a
+   compiler can assume, for optimization purposes, that two pointers to
+   fundamentally different types won't ever point to the same memory. This can
+   manifest as a problem only if one of the pointers is written to. This code
+   only reads from those pointers. So long as this code remains isolated in
+   this compilation unit, there won't be a problem. For this reason, this code
+   should not be copied and pasted into a compilation unit in which other code
+   writes to the buffer that is passed to these routines.
+ */
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+        c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+            crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    z_size_t len;
+{
+    register z_crc_t c;
+    register const z_crc_t FAR *buf4;
+
+    c = (z_crc_t)crc;
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+        len--;
+    }
+
+    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+    while (len >= 32) {
+        DOLIT32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOLIT4;
+        len -= 4;
+    }
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *buf4++; \
+        c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+            crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+    unsigned long crc;
+    const unsigned char FAR *buf;
+    z_size_t len;
+{
+    register z_crc_t c;
+    register const z_crc_t FAR *buf4;
+
+    c = ZSWAP32((z_crc_t)crc);
+    c = ~c;
+    while (len && ((ptrdiff_t)buf & 3)) {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+        len--;
+    }
+
+    buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+    while (len >= 32) {
+        DOBIG32;
+        len -= 32;
+    }
+    while (len >= 4) {
+        DOBIG4;
+        len -= 4;
+    }
+    buf = (const unsigned char FAR *)buf4;
+
+    if (len) do {
+        c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+    } while (--len);
+    c = ~c;
+    return (unsigned long)(ZSWAP32(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32      /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+    unsigned long *mat;
+    unsigned long vec;
+{
+    unsigned long sum;
+
+    sum = 0;
+    while (vec) {
+        if (vec & 1)
+            sum ^= *mat;
+        vec >>= 1;
+        mat++;
+    }
+    return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+    unsigned long *square;
+    unsigned long *mat;
+{
+    int n;
+
+    for (n = 0; n < GF2_DIM; n++)
+        square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+local uLong crc32_combine_(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off64_t len2;
+{
+    int n;
+    unsigned long row;
+    unsigned long even[GF2_DIM];    /* even-power-of-two zeros operator */
+    unsigned long odd[GF2_DIM];     /* odd-power-of-two zeros operator */
+
+    /* degenerate case (also disallow negative lengths) */
+    if (len2 <= 0)
+        return crc1;
+
+    /* put operator for one zero bit in odd */
+    odd[0] = 0xedb88320UL;          /* CRC-32 polynomial */
+    row = 1;
+    for (n = 1; n < GF2_DIM; n++) {
+        odd[n] = row;
+        row <<= 1;
+    }
+
+    /* put operator for two zero bits in even */
+    gf2_matrix_square(even, odd);
+
+    /* put operator for four zero bits in odd */
+    gf2_matrix_square(odd, even);
+
+    /* apply len2 zeros to crc1 (first square will put the operator for one
+       zero byte, eight zero bits, in even) */
+    do {
+        /* apply zeros operator for this bit of len2 */
+        gf2_matrix_square(even, odd);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(even, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+        if (len2 == 0)
+            break;
+
+        /* another iteration of the loop with odd and even swapped */
+        gf2_matrix_square(odd, even);
+        if (len2 & 1)
+            crc1 = gf2_matrix_times(odd, crc1);
+        len2 >>= 1;
+
+        /* if no more bits set, then done */
+    } while (len2 != 0);
+
+    /* return combined crc */
+    crc1 ^= crc2;
+    return crc1;
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off_t len2;
+{
+    return crc32_combine_(crc1, crc2, len2);
+}
+
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+    uLong crc1;
+    uLong crc2;
+    z_off64_t len2;
+{
+    return crc32_combine_(crc1, crc2, len2);
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/crc32.h b/deps/libchdr/deps/zlib-1.2.11/crc32.h
new file mode 100644 (file)
index 0000000..9e0c778
--- /dev/null
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const z_crc_t FAR crc_table[TBLS][256] =
+{
+  {
+    0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+    0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+    0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+    0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+    0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+    0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+    0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+    0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+    0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+    0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+    0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+    0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+    0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+    0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+    0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+    0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+    0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+    0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+    0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+    0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+    0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+    0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+    0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+    0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+    0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+    0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+    0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+    0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+    0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+    0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+    0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+    0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+    0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+    0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+    0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+    0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+    0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+    0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+    0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+    0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+    0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+    0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+    0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+    0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+    0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+    0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+    0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+    0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+    0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+    0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+    0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+    0x2d02ef8dUL
+#ifdef BYFOUR
+  },
+  {
+    0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+    0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+    0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+    0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+    0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+    0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+    0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+    0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+    0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+    0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+    0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+    0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+    0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+    0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+    0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+    0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+    0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+    0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+    0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+    0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+    0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+    0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+    0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+    0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+    0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+    0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+    0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+    0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+    0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+    0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+    0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+    0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+    0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+    0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+    0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+    0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+    0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+    0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+    0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+    0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+    0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+    0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+    0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+    0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+    0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+    0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+    0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+    0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+    0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+    0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+    0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+    0x9324fd72UL
+  },
+  {
+    0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+    0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+    0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+    0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+    0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+    0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+    0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+    0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+    0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+    0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+    0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+    0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+    0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+    0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+    0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+    0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+    0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+    0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+    0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+    0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+    0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+    0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+    0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+    0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+    0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+    0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+    0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+    0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+    0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+    0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+    0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+    0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+    0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+    0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+    0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+    0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+    0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+    0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+    0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+    0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+    0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+    0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+    0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+    0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+    0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+    0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+    0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+    0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+    0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+    0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+    0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+    0xbe9834edUL
+  },
+  {
+    0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+    0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+    0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+    0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+    0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+    0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+    0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+    0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+    0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+    0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+    0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+    0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+    0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+    0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+    0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+    0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+    0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+    0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+    0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+    0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+    0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+    0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+    0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+    0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+    0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+    0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+    0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+    0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+    0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+    0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+    0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+    0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+    0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+    0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+    0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+    0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+    0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+    0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+    0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+    0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+    0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+    0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+    0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+    0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+    0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+    0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+    0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+    0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+    0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+    0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+    0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+    0xde0506f1UL
+  },
+  {
+    0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+    0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+    0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+    0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+    0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+    0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+    0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+    0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+    0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+    0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+    0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+    0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+    0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+    0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+    0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+    0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+    0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+    0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+    0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+    0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+    0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+    0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+    0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+    0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+    0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+    0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+    0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+    0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+    0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+    0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+    0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+    0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+    0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+    0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+    0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+    0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+    0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+    0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+    0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+    0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+    0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+    0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+    0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+    0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+    0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+    0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+    0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+    0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+    0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+    0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+    0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+    0x8def022dUL
+  },
+  {
+    0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+    0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+    0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+    0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+    0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+    0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+    0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+    0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+    0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+    0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+    0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+    0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+    0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+    0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+    0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+    0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+    0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+    0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+    0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+    0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+    0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+    0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+    0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+    0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+    0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+    0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+    0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+    0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+    0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+    0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+    0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+    0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+    0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+    0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+    0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+    0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+    0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+    0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+    0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+    0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+    0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+    0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+    0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+    0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+    0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+    0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+    0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+    0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+    0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+    0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+    0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+    0x72fd2493UL
+  },
+  {
+    0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+    0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+    0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+    0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+    0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+    0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+    0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+    0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+    0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+    0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+    0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+    0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+    0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+    0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+    0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+    0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+    0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+    0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+    0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+    0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+    0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+    0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+    0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+    0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+    0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+    0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+    0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+    0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+    0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+    0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+    0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+    0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+    0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+    0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+    0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+    0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+    0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+    0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+    0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+    0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+    0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+    0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+    0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+    0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+    0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+    0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+    0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+    0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+    0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+    0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+    0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+    0xed3498beUL
+  },
+  {
+    0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+    0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+    0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+    0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+    0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+    0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+    0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+    0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+    0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+    0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+    0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+    0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+    0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+    0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+    0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+    0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+    0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+    0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+    0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+    0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+    0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+    0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+    0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+    0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+    0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+    0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+    0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+    0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+    0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+    0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+    0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+    0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+    0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+    0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+    0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+    0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+    0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+    0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+    0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+    0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+    0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+    0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+    0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+    0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+    0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+    0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+    0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+    0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+    0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+    0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+    0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+    0xf10605deUL
+#endif
+  }
+};
diff --git a/deps/libchdr/deps/zlib-1.2.11/deflate.c b/deps/libchdr/deps/zlib-1.2.11/deflate.c
new file mode 100644 (file)
index 0000000..1ec7614
--- /dev/null
@@ -0,0 +1,2163 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in http://tools.ietf.org/html/rfc1951
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+   " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local int deflateStateCheck      OF((z_streamp strm));
+local void slide_hash     OF((deflate_state *s));
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+#endif
+local block_state deflate_rle    OF((deflate_state *s, int flush));
+local block_state deflate_huff   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local unsigned read_buf   OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+#  pragma message("Assembler code may have bugs -- use at your own risk")
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef ZLIB_DEBUG
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */
+#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0))
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to UPDATE_HASH are made with consecutive input
+ *    characters, so that a running hash key can be computed from the previous
+ *    key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN  assertion: all calls to INSERT_STRING are made with consecutive input
+ *    characters and the first MIN_MATCH bytes of str are valid (except for
+ *    the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ===========================================================================
+ * Slide the hash table when sliding the window down (could be avoided with 32
+ * bit values at the expense of memory usage). We slide even when level == 0 to
+ * keep the hash table consistent if we switch back to level > 0 later.
+ */
+local void slide_hash(s)
+    deflate_state *s;
+{
+    unsigned n, m;
+    Posf *p;
+    uInt wsize = s->w_size;
+
+    n = s->hash_size;
+    p = &s->head[n];
+    do {
+        m = *--p;
+        *p = (Pos)(m >= wsize ? m - wsize : NIL);
+    } while (--n);
+    n = wsize;
+#ifndef FASTEST
+    p = &s->prev[n];
+    do {
+        m = *--p;
+        *p = (Pos)(m >= wsize ? m - wsize : NIL);
+        /* If n is not on any hash chain, prev[n] is garbage but
+         * its value will never be used.
+         */
+    } while (--n);
+#endif
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+                         Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+                  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int wrap = 1;
+    static const char my_version[] = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+        return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+    if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+#endif
+    }
+    if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+        strm->zfree = zcfree;
+#endif
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+    if (windowBits < 0) { /* suppress zlib wrapper */
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+#ifdef GZIP
+    else if (windowBits > 15) {
+        wrap = 2;       /* write gzip wrapper instead */
+        windowBits -= 16;
+    }
+#endif
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+        strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) {
+        return Z_STREAM_ERROR;
+    }
+    if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+    s->status = INIT_STATE;     /* to pass state test in deflateReset() */
+
+    s->wrap = wrap;
+    s->gzhead = Z_NULL;
+    s->w_bits = (uInt)windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = (uInt)memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->high_water = 0;      /* nothing written to s->window yet */
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        s->status = FINISH_STATE;
+        strm->msg = ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* =========================================================================
+ * Check for a valid deflate stream state. Return 0 if ok, 1 if not.
+ */
+local int deflateStateCheck (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+    if (strm == Z_NULL ||
+        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
+        return 1;
+    s = strm->state;
+    if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE &&
+#ifdef GZIP
+                                           s->status != GZIP_STATE &&
+#endif
+                                           s->status != EXTRA_STATE &&
+                                           s->status != NAME_STATE &&
+                                           s->status != COMMENT_STATE &&
+                                           s->status != HCRC_STATE &&
+                                           s->status != BUSY_STATE &&
+                                           s->status != FINISH_STATE))
+        return 1;
+    return 0;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt str, n;
+    int wrap;
+    unsigned avail;
+    z_const unsigned char *next;
+
+    if (deflateStateCheck(strm) || dictionary == Z_NULL)
+        return Z_STREAM_ERROR;
+    s = strm->state;
+    wrap = s->wrap;
+    if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)
+        return Z_STREAM_ERROR;
+
+    /* when using zlib wrappers, compute Adler-32 for provided dictionary */
+    if (wrap == 1)
+        strm->adler = adler32(strm->adler, dictionary, dictLength);
+    s->wrap = 0;                    /* avoid computing Adler-32 in read_buf */
+
+    /* if dictionary would fill window, just replace the history */
+    if (dictLength >= s->w_size) {
+        if (wrap == 0) {            /* already empty otherwise */
+            CLEAR_HASH(s);
+            s->strstart = 0;
+            s->block_start = 0L;
+            s->insert = 0;
+        }
+        dictionary += dictLength - s->w_size;  /* use the tail */
+        dictLength = s->w_size;
+    }
+
+    /* insert dictionary into window and hash */
+    avail = strm->avail_in;
+    next = strm->next_in;
+    strm->avail_in = dictLength;
+    strm->next_in = (z_const Bytef *)dictionary;
+    fill_window(s);
+    while (s->lookahead >= MIN_MATCH) {
+        str = s->strstart;
+        n = s->lookahead - (MIN_MATCH-1);
+        do {
+            UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+            s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+            s->head[s->ins_h] = (Pos)str;
+            str++;
+        } while (--n);
+        s->strstart = str;
+        s->lookahead = MIN_MATCH-1;
+        fill_window(s);
+    }
+    s->strstart += s->lookahead;
+    s->block_start = (long)s->strstart;
+    s->insert = s->lookahead;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    strm->next_in = next;
+    strm->avail_in = avail;
+    s->wrap = wrap;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    Bytef *dictionary;
+    uInt  *dictLength;
+{
+    deflate_state *s;
+    uInt len;
+
+    if (deflateStateCheck(strm))
+        return Z_STREAM_ERROR;
+    s = strm->state;
+    len = s->strstart + s->lookahead;
+    if (len > s->w_size)
+        len = s->w_size;
+    if (dictionary != Z_NULL && len)
+        zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len);
+    if (dictLength != Z_NULL)
+        *dictLength = len;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateResetKeep (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+
+    if (deflateStateCheck(strm)) {
+        return Z_STREAM_ERROR;
+    }
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->wrap < 0) {
+        s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+    }
+    s->status =
+#ifdef GZIP
+        s->wrap == 2 ? GZIP_STATE :
+#endif
+        s->wrap ? INIT_STATE : BUSY_STATE;
+    strm->adler =
+#ifdef GZIP
+        s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+        adler32(0L, Z_NULL, 0);
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+    z_streamp strm;
+{
+    int ret;
+
+    ret = deflateResetKeep(strm);
+    if (ret == Z_OK)
+        lm_init(strm->state);
+    return ret;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+    z_streamp strm;
+    gz_headerp head;
+{
+    if (deflateStateCheck(strm) || strm->state->wrap != 2)
+        return Z_STREAM_ERROR;
+    strm->state->gzhead = head;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePending (strm, pending, bits)
+    unsigned *pending;
+    int *bits;
+    z_streamp strm;
+{
+    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
+    if (pending != Z_NULL)
+        *pending = strm->state->pending;
+    if (bits != Z_NULL)
+        *bits = strm->state->bi_valid;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+    z_streamp strm;
+    int bits;
+    int value;
+{
+    deflate_state *s;
+    int put;
+
+    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
+    s = strm->state;
+    if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
+        return Z_BUF_ERROR;
+    do {
+        put = Buf_size - s->bi_valid;
+        if (put > bits)
+            put = bits;
+        s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);
+        s->bi_valid += put;
+        _tr_flush_bits(s);
+        value >>= put;
+        bits -= put;
+    } while (bits);
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+
+    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
+    s = strm->state;
+
+#ifdef FASTEST
+    if (level != 0) level = 1;
+#else
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+        return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if ((strategy != s->strategy || func != configuration_table[level].func) &&
+        s->high_water) {
+        /* Flush the last buffer: */
+        int err = deflate(strm, Z_BLOCK);
+        if (err == Z_STREAM_ERROR)
+            return err;
+        if (strm->avail_out == 0)
+            return Z_BUF_ERROR;
+    }
+    if (s->level != level) {
+        if (s->level == 0 && s->matches != 0) {
+            if (s->matches == 1)
+                slide_hash(s);
+            else
+                CLEAR_HASH(s);
+            s->matches = 0;
+        }
+        s->level = level;
+        s->max_lazy_match   = configuration_table[level].max_lazy;
+        s->good_match       = configuration_table[level].good_length;
+        s->nice_match       = configuration_table[level].nice_length;
+        s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+    z_streamp strm;
+    int good_length;
+    int max_lazy;
+    int nice_length;
+    int max_chain;
+{
+    deflate_state *s;
+
+    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
+    s = strm->state;
+    s->good_match = (uInt)good_length;
+    s->max_lazy_match = (uInt)max_lazy;
+    s->nice_match = nice_length;
+    s->max_chain_length = (uInt)max_chain;
+    return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well.  The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds for
+ * every combination of windowBits and memLevel.  But even the conservative
+ * upper bound of about 14% expansion does not seem onerous for output buffer
+ * allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+    z_streamp strm;
+    uLong sourceLen;
+{
+    deflate_state *s;
+    uLong complen, wraplen;
+
+    /* conservative upper bound for compressed data */
+    complen = sourceLen +
+              ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
+
+    /* if can't get parameters, return conservative bound plus zlib wrapper */
+    if (deflateStateCheck(strm))
+        return complen + 6;
+
+    /* compute wrapper length */
+    s = strm->state;
+    switch (s->wrap) {
+    case 0:                                 /* raw deflate */
+        wraplen = 0;
+        break;
+    case 1:                                 /* zlib wrapper */
+        wraplen = 6 + (s->strstart ? 4 : 0);
+        break;
+#ifdef GZIP
+    case 2:                                 /* gzip wrapper */
+        wraplen = 18;
+        if (s->gzhead != Z_NULL) {          /* user-supplied gzip header */
+            Bytef *str;
+            if (s->gzhead->extra != Z_NULL)
+                wraplen += 2 + s->gzhead->extra_len;
+            str = s->gzhead->name;
+            if (str != Z_NULL)
+                do {
+                    wraplen++;
+                } while (*str++);
+            str = s->gzhead->comment;
+            if (str != Z_NULL)
+                do {
+                    wraplen++;
+                } while (*str++);
+            if (s->gzhead->hcrc)
+                wraplen += 2;
+        }
+        break;
+#endif
+    default:                                /* for compiler happiness */
+        wraplen = 6;
+    }
+
+    /* if not default parameters, return conservative bound */
+    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+        return complen + wraplen;
+
+    /* default settings: return tight bound for that case */
+    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+           (sourceLen >> 25) + 13 - 6 + wraplen;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output, except for
+ * some deflate_stored() output, goes through this function so some
+ * applications may wish to modify it to avoid allocating a large
+ * strm->next_out buffer and copying into it. (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    unsigned len;
+    deflate_state *s = strm->state;
+
+    _tr_flush_bits(s);
+    len = s->pending;
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    zmemcpy(strm->next_out, s->pending_out, len);
+    strm->next_out  += len;
+    s->pending_out  += len;
+    strm->total_out += len;
+    strm->avail_out -= len;
+    s->pending      -= len;
+    if (s->pending == 0) {
+        s->pending_out = s->pending_buf;
+    }
+}
+
+/* ===========================================================================
+ * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1].
+ */
+#define HCRC_UPDATE(beg) \
+    do { \
+        if (s->gzhead->hcrc && s->pending > (beg)) \
+            strm->adler = crc32(strm->adler, s->pending_buf + (beg), \
+                                s->pending - (beg)); \
+    } while (0)
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = strm->state;
+
+    if (strm->next_out == Z_NULL ||
+        (strm->avail_in != 0 && strm->next_in == Z_NULL) ||
+        (s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+            /* Since avail_out is 0, deflate will be called again with
+             * more output space, but possibly with both pending and
+             * avail_in equal to zero. There won't be anything to do,
+             * but this is not an error situation so make sure we
+             * return OK instead of BUF_ERROR at next call of deflate:
+             */
+            s->last_flush = -1;
+            return Z_OK;
+        }
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
+               flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Write the header */
+    if (s->status == INIT_STATE) {
+        /* zlib header */
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags;
+
+        if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+            level_flags = 0;
+        else if (s->level < 6)
+            level_flags = 1;
+        else if (s->level == 6)
+            level_flags = 2;
+        else
+            level_flags = 3;
+        header |= (level_flags << 6);
+        if (s->strstart != 0) header |= PRESET_DICT;
+        header += 31 - (header % 31);
+
+        putShortMSB(s, header);
+
+        /* Save the adler32 of the preset dictionary: */
+        if (s->strstart != 0) {
+            putShortMSB(s, (uInt)(strm->adler >> 16));
+            putShortMSB(s, (uInt)(strm->adler & 0xffff));
+        }
+        strm->adler = adler32(0L, Z_NULL, 0);
+        s->status = BUSY_STATE;
+
+        /* Compression must start with an empty pending buffer */
+        flush_pending(strm);
+        if (s->pending != 0) {
+            s->last_flush = -1;
+            return Z_OK;
+        }
+    }
+#ifdef GZIP
+    if (s->status == GZIP_STATE) {
+        /* gzip header */
+        strm->adler = crc32(0L, Z_NULL, 0);
+        put_byte(s, 31);
+        put_byte(s, 139);
+        put_byte(s, 8);
+        if (s->gzhead == Z_NULL) {
+            put_byte(s, 0);
+            put_byte(s, 0);
+            put_byte(s, 0);
+            put_byte(s, 0);
+            put_byte(s, 0);
+            put_byte(s, s->level == 9 ? 2 :
+                     (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                      4 : 0));
+            put_byte(s, OS_CODE);
+            s->status = BUSY_STATE;
+
+            /* Compression must start with an empty pending buffer */
+            flush_pending(strm);
+            if (s->pending != 0) {
+                s->last_flush = -1;
+                return Z_OK;
+            }
+        }
+        else {
+            put_byte(s, (s->gzhead->text ? 1 : 0) +
+                     (s->gzhead->hcrc ? 2 : 0) +
+                     (s->gzhead->extra == Z_NULL ? 0 : 4) +
+                     (s->gzhead->name == Z_NULL ? 0 : 8) +
+                     (s->gzhead->comment == Z_NULL ? 0 : 16)
+                     );
+            put_byte(s, (Byte)(s->gzhead->time & 0xff));
+            put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+            put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+            put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+            put_byte(s, s->level == 9 ? 2 :
+                     (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+                      4 : 0));
+            put_byte(s, s->gzhead->os & 0xff);
+            if (s->gzhead->extra != Z_NULL) {
+                put_byte(s, s->gzhead->extra_len & 0xff);
+                put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+            }
+            if (s->gzhead->hcrc)
+                strm->adler = crc32(strm->adler, s->pending_buf,
+                                    s->pending);
+            s->gzindex = 0;
+            s->status = EXTRA_STATE;
+        }
+    }
+    if (s->status == EXTRA_STATE) {
+        if (s->gzhead->extra != Z_NULL) {
+            ulg beg = s->pending;   /* start of bytes to update crc */
+            uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex;
+            while (s->pending + left > s->pending_buf_size) {
+                uInt copy = s->pending_buf_size - s->pending;
+                zmemcpy(s->pending_buf + s->pending,
+                        s->gzhead->extra + s->gzindex, copy);
+                s->pending = s->pending_buf_size;
+                HCRC_UPDATE(beg);
+                s->gzindex += copy;
+                flush_pending(strm);
+                if (s->pending != 0) {
+                    s->last_flush = -1;
+                    return Z_OK;
+                }
+                beg = 0;
+                left -= copy;
+            }
+            zmemcpy(s->pending_buf + s->pending,
+                    s->gzhead->extra + s->gzindex, left);
+            s->pending += left;
+            HCRC_UPDATE(beg);
+            s->gzindex = 0;
+        }
+        s->status = NAME_STATE;
+    }
+    if (s->status == NAME_STATE) {
+        if (s->gzhead->name != Z_NULL) {
+            ulg beg = s->pending;   /* start of bytes to update crc */
+            int val;
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    HCRC_UPDATE(beg);
+                    flush_pending(strm);
+                    if (s->pending != 0) {
+                        s->last_flush = -1;
+                        return Z_OK;
+                    }
+                    beg = 0;
+                }
+                val = s->gzhead->name[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            HCRC_UPDATE(beg);
+            s->gzindex = 0;
+        }
+        s->status = COMMENT_STATE;
+    }
+    if (s->status == COMMENT_STATE) {
+        if (s->gzhead->comment != Z_NULL) {
+            ulg beg = s->pending;   /* start of bytes to update crc */
+            int val;
+            do {
+                if (s->pending == s->pending_buf_size) {
+                    HCRC_UPDATE(beg);
+                    flush_pending(strm);
+                    if (s->pending != 0) {
+                        s->last_flush = -1;
+                        return Z_OK;
+                    }
+                    beg = 0;
+                }
+                val = s->gzhead->comment[s->gzindex++];
+                put_byte(s, val);
+            } while (val != 0);
+            HCRC_UPDATE(beg);
+        }
+        s->status = HCRC_STATE;
+    }
+    if (s->status == HCRC_STATE) {
+        if (s->gzhead->hcrc) {
+            if (s->pending + 2 > s->pending_buf_size) {
+                flush_pending(strm);
+                if (s->pending != 0) {
+                    s->last_flush = -1;
+                    return Z_OK;
+                }
+            }
+            put_byte(s, (Byte)(strm->adler & 0xff));
+            put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+            strm->adler = crc32(0L, Z_NULL, 0);
+        }
+        s->status = BUSY_STATE;
+
+        /* Compression must start with an empty pending buffer */
+        flush_pending(strm);
+        if (s->pending != 0) {
+            s->last_flush = -1;
+            return Z_OK;
+        }
+    }
+#endif
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+        bstate = s->level == 0 ? deflate_stored(s, flush) :
+                 s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+                 s->strategy == Z_RLE ? deflate_rle(s, flush) :
+                 (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+            if (strm->avail_out == 0) {
+                s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+            }
+            return Z_OK;
+            /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+             * of deflate should use the same flush parameter to make sure
+             * that the flush is complete. So we don't have to output an
+             * empty block here, this will be done at next call. This also
+             * ensures that for a very small output buffer, we emit at most
+             * one empty block.
+             */
+        }
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+            } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                    if (s->lookahead == 0) {
+                        s->strstart = 0;
+                        s->block_start = 0L;
+                        s->insert = 0;
+                    }
+                }
+            }
+            flush_pending(strm);
+            if (strm->avail_out == 0) {
+              s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+              return Z_OK;
+            }
+        }
+    }
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->wrap <= 0) return Z_STREAM_END;
+
+    /* Write the trailer */
+#ifdef GZIP
+    if (s->wrap == 2) {
+        put_byte(s, (Byte)(strm->adler & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+        put_byte(s, (Byte)(strm->total_in & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+        put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+    }
+    else
+#endif
+    {
+        putShortMSB(s, (uInt)(strm->adler >> 16));
+        putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    }
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+
+    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
+
+    status = strm->state->status;
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, strm->state->pending_buf);
+    TRY_FREE(strm, strm->state->head);
+    TRY_FREE(strm, strm->state->prev);
+    TRY_FREE(strm, strm->state->window);
+
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+#ifdef MAXSEG_64K
+    return Z_STREAM_ERROR;
+#else
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+
+    if (deflateStateCheck(source) || dest == Z_NULL) {
+        return Z_STREAM_ERROR;
+    }
+
+    ss = source->state;
+
+    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* following zmemcpy do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local unsigned read_buf(strm, buf, size)
+    z_streamp strm;
+    Bytef *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    zmemcpy(buf, strm->next_in, len);
+    if (strm->state->wrap == 1) {
+        strm->adler = adler32(strm->adler, buf, len);
+    }
+#ifdef GZIP
+    else if (strm->state->wrap == 2) {
+        strm->adler = crc32(strm->adler, buf, len);
+    }
+#endif
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->insert = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                      /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = (int)s->prev_length;         /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2.  Note that the checks below
+         * for insufficient lookahead only occur occasionally for performance
+         * reasons.  Therefore uninitialized memory will be accessed, and
+         * conditional jumps will be made that depend on those values.
+         * However the length of the match is limited to the lookahead, so
+         * the output of deflate is not affected by the uninitialized values.
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+
+#else /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    Assert(cur_match < s->strstart, "no future");
+
+    match = s->window + cur_match;
+
+    /* Return failure if the match length is less than 2:
+     */
+    if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+    /* The check at best_len-1 can be removed because it will be made
+     * again later. (This heuristic is not always a win.)
+     * It is not necessary to compare scan[2] and match[2] since they
+     * are always equal when the other bytes match, given that
+     * the hash keys are equal and that HASH_BITS >= 8.
+     */
+    scan += 2, match += 2;
+    Assert(*scan == *match, "match[2]?");
+
+    /* We check for insufficient lookahead only every 8th comparison;
+     * the 256th check will be made at strstart+258.
+     */
+    do {
+    } while (*++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             *++scan == *++match && *++scan == *++match &&
+             scan < strend);
+
+    Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+    len = MAX_MATCH - (int)(strend - scan);
+
+    if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+    s->match_start = cur_match;
+    return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#endif /* FASTEST */
+
+#ifdef ZLIB_DEBUG
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp(s->window + match,
+                s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+                start, match, length);
+        do {
+            fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+        } while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif /* ZLIB_DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    unsigned n;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (sizeof(int) <= 2) {
+            if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+                more = wsize;
+
+            } else if (more == (unsigned)(-1)) {
+                /* Very unlikely, but possible on 16 bit machine if
+                 * strstart == 0 && lookahead == 1 (input done a byte at time)
+                 */
+                more--;
+            }
+        }
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+            slide_hash(s);
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) break;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead + s->insert >= MIN_MATCH) {
+            uInt str = s->strstart - s->insert;
+            s->ins_h = s->window[str];
+            UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+            while (s->insert) {
+                UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+                s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+                s->head[s->ins_h] = (Pos)str;
+                str++;
+                s->insert--;
+                if (s->lookahead + s->insert < MIN_MATCH)
+                    break;
+            }
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+    /* If the WIN_INIT bytes after the end of the current data have never been
+     * written, then zero those bytes in order to avoid memory check reports of
+     * the use of uninitialized (or uninitialised as Julian writes) bytes by
+     * the longest match routines.  Update the high water mark for the next
+     * time through here.  WIN_INIT is set to MAX_MATCH since the longest match
+     * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+     */
+    if (s->high_water < s->window_size) {
+        ulg curr = s->strstart + (ulg)(s->lookahead);
+        ulg init;
+
+        if (s->high_water < curr) {
+            /* Previous high water mark below current data -- zero WIN_INIT
+             * bytes or up to end of window, whichever is less.
+             */
+            init = s->window_size - curr;
+            if (init > WIN_INIT)
+                init = WIN_INIT;
+            zmemzero(s->window + curr, (unsigned)init);
+            s->high_water = curr + init;
+        }
+        else if (s->high_water < (ulg)curr + WIN_INIT) {
+            /* High water mark at or above current data, but below current data
+             * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+             * to end of window, whichever is less.
+             */
+            init = (ulg)curr + WIN_INIT - s->high_water;
+            if (init > s->window_size - s->high_water)
+                init = s->window_size - s->high_water;
+            zmemzero(s->window + s->high_water, (unsigned)init);
+            s->high_water += init;
+        }
+    }
+
+    Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
+           "not enough room for search");
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, last) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+                (ulg)((long)s->strstart - s->block_start), \
+                (last)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, last) { \
+   FLUSH_BLOCK_ONLY(s, last); \
+   if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
+}
+
+/* Maximum stored block length in deflate format (not including header). */
+#define MAX_STORED 65535
+
+/* Minimum of a and b. */
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ *
+ * In case deflateParams() is used to later switch to a non-zero compression
+ * level, s->matches (otherwise unused when storing) keeps track of the number
+ * of hash table slides to perform. If s->matches is 1, then one hash table
+ * slide will be done when switching. If s->matches is 2, the maximum value
+ * allowed here, then the hash table will be cleared, since two or more slides
+ * is the same as a clear.
+ *
+ * deflate_stored() is written to minimize the number of times an input byte is
+ * copied. It is most efficient with large input and output buffers, which
+ * maximizes the opportunites to have a single copy from next_in to next_out.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Smallest worthy block size when not flushing or finishing. By default
+     * this is 32K. This can be as small as 507 bytes for memLevel == 1. For
+     * large input and output buffers, the stored block size will be larger.
+     */
+    unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);
+
+    /* Copy as many min_block or larger stored blocks directly to next_out as
+     * possible. If flushing, copy the remaining available input to next_out as
+     * stored blocks, if there is enough space.
+     */
+    unsigned len, left, have, last = 0;
+    unsigned used = s->strm->avail_in;
+    do {
+        /* Set len to the maximum size block that we can copy directly with the
+         * available input data and output space. Set left to how much of that
+         * would be copied from what's left in the window.
+         */
+        len = MAX_STORED;       /* maximum deflate stored block length */
+        have = (s->bi_valid + 42) >> 3;         /* number of header bytes */
+        if (s->strm->avail_out < have)          /* need room for header */
+            break;
+            /* maximum stored block length that will fit in avail_out: */
+        have = s->strm->avail_out - have;
+        left = s->strstart - s->block_start;    /* bytes left in window */
+        if (len > (ulg)left + s->strm->avail_in)
+            len = left + s->strm->avail_in;     /* limit len to the input */
+        if (len > have)
+            len = have;                         /* limit len to the output */
+
+        /* If the stored block would be less than min_block in length, or if
+         * unable to copy all of the available input when flushing, then try
+         * copying to the window and the pending buffer instead. Also don't
+         * write an empty block when flushing -- deflate() does that.
+         */
+        if (len < min_block && ((len == 0 && flush != Z_FINISH) ||
+                                flush == Z_NO_FLUSH ||
+                                len != left + s->strm->avail_in))
+            break;
+
+        /* Make a dummy stored block in pending to get the header bytes,
+         * including any pending bits. This also updates the debugging counts.
+         */
+        last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0;
+        _tr_stored_block(s, (char *)0, 0L, last);
+
+        /* Replace the lengths in the dummy stored block with len. */
+        s->pending_buf[s->pending - 4] = len;
+        s->pending_buf[s->pending - 3] = len >> 8;
+        s->pending_buf[s->pending - 2] = ~len;
+        s->pending_buf[s->pending - 1] = ~len >> 8;
+
+        /* Write the stored block header bytes. */
+        flush_pending(s->strm);
+
+#ifdef ZLIB_DEBUG
+        /* Update debugging counts for the data about to be copied. */
+        s->compressed_len += len << 3;
+        s->bits_sent += len << 3;
+#endif
+
+        /* Copy uncompressed bytes from the window to next_out. */
+        if (left) {
+            if (left > len)
+                left = len;
+            zmemcpy(s->strm->next_out, s->window + s->block_start, left);
+            s->strm->next_out += left;
+            s->strm->avail_out -= left;
+            s->strm->total_out += left;
+            s->block_start += left;
+            len -= left;
+        }
+
+        /* Copy uncompressed bytes directly from next_in to next_out, updating
+         * the check value.
+         */
+        if (len) {
+            read_buf(s->strm, s->strm->next_out, len);
+            s->strm->next_out += len;
+            s->strm->avail_out -= len;
+            s->strm->total_out += len;
+        }
+    } while (last == 0);
+
+    /* Update the sliding window with the last s->w_size bytes of the copied
+     * data, or append all of the copied data to the existing window if less
+     * than s->w_size bytes were copied. Also update the number of bytes to
+     * insert in the hash tables, in the event that deflateParams() switches to
+     * a non-zero compression level.
+     */
+    used -= s->strm->avail_in;      /* number of input bytes directly copied */
+    if (used) {
+        /* If any input was used, then no unused input remains in the window,
+         * therefore s->block_start == s->strstart.
+         */
+        if (used >= s->w_size) {    /* supplant the previous history */
+            s->matches = 2;         /* clear hash */
+            zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);
+            s->strstart = s->w_size;
+        }
+        else {
+            if (s->window_size - s->strstart <= used) {
+                /* Slide the window down. */
+                s->strstart -= s->w_size;
+                zmemcpy(s->window, s->window + s->w_size, s->strstart);
+                if (s->matches < 2)
+                    s->matches++;   /* add a pending slide_hash() */
+            }
+            zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);
+            s->strstart += used;
+        }
+        s->block_start = s->strstart;
+        s->insert += MIN(used, s->w_size - s->insert);
+    }
+    if (s->high_water < s->strstart)
+        s->high_water = s->strstart;
+
+    /* If the last block was written to next_out, then done. */
+    if (last)
+        return finish_done;
+
+    /* If flushing and all input has been consumed, then done. */
+    if (flush != Z_NO_FLUSH && flush != Z_FINISH &&
+        s->strm->avail_in == 0 && (long)s->strstart == s->block_start)
+        return block_done;
+
+    /* Fill the window with any remaining input. */
+    have = s->window_size - s->strstart - 1;
+    if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) {
+        /* Slide the window down. */
+        s->block_start -= s->w_size;
+        s->strstart -= s->w_size;
+        zmemcpy(s->window, s->window + s->w_size, s->strstart);
+        if (s->matches < 2)
+            s->matches++;           /* add a pending slide_hash() */
+        have += s->w_size;          /* more space now */
+    }
+    if (have > s->strm->avail_in)
+        have = s->strm->avail_in;
+    if (have) {
+        read_buf(s->strm, s->window + s->strstart, have);
+        s->strstart += have;
+    }
+    if (s->high_water < s->strstart)
+        s->high_water = s->strstart;
+
+    /* There was not enough avail_out to write a complete worthy or flushed
+     * stored block to next_out. Write a stored block to pending instead, if we
+     * have enough input for a worthy block, or if flushing and there is enough
+     * room for the remaining input as a stored block in the pending buffer.
+     */
+    have = (s->bi_valid + 42) >> 3;         /* number of header bytes */
+        /* maximum stored block length that will fit in pending: */
+    have = MIN(s->pending_buf_size - have, MAX_STORED);
+    min_block = MIN(have, s->w_size);
+    left = s->strstart - s->block_start;
+    if (left >= min_block ||
+        ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH &&
+         s->strm->avail_in == 0 && left <= have)) {
+        len = MIN(left, have);
+        last = flush == Z_FINISH && s->strm->avail_in == 0 &&
+               len == left ? 1 : 0;
+        _tr_stored_block(s, (charf *)s->window + s->block_start, len, last);
+        s->block_start += len;
+        flush_pending(s->strm);
+    }
+
+    /* We've done all we can with the available input and output. */
+    return last ? finish_started : need_more;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head;       /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        hash_head = NIL;
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            s->match_length = longest_match (s, hash_head);
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            _tr_tally_dist(s, s->strstart - s->match_start,
+                           s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+#ifndef FASTEST
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++;
+            } else
+#endif
+            {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+    if (flush == Z_FINISH) {
+        FLUSH_BLOCK(s, 1);
+        return finish_done;
+    }
+    if (s->last_lit)
+        FLUSH_BLOCK(s, 0);
+    return block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head;          /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        hash_head = NIL;
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            s->match_length = longest_match (s, hash_head);
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+                || (s->match_length == MIN_MATCH &&
+                    s->strstart - s->match_start > TOO_FAR)
+#endif
+                )) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+                           s->prev_length - MIN_MATCH, bflush);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+            if (bflush) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+        s->match_available = 0;
+    }
+    s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+    if (flush == Z_FINISH) {
+        FLUSH_BLOCK(s, 1);
+        return finish_done;
+    }
+    if (s->last_lit)
+        FLUSH_BLOCK(s, 0);
+    return block_done;
+}
+#endif /* FASTEST */
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one.  Do not maintain a hash table.  (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;             /* set if current block must be flushed */
+    uInt prev;              /* byte at distance one to match */
+    Bytef *scan, *strend;   /* scan goes up to strend for length of run */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the longest run, plus one for the unrolled loop.
+         */
+        if (s->lookahead <= MAX_MATCH) {
+            fill_window(s);
+            if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {
+                return need_more;
+            }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* See how many times the previous byte repeats */
+        s->match_length = 0;
+        if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
+            scan = s->window + s->strstart - 1;
+            prev = *scan;
+            if (prev == *++scan && prev == *++scan && prev == *++scan) {
+                strend = s->window + s->strstart + MAX_MATCH;
+                do {
+                } while (prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         prev == *++scan && prev == *++scan &&
+                         scan < strend);
+                s->match_length = MAX_MATCH - (uInt)(strend - scan);
+                if (s->match_length > s->lookahead)
+                    s->match_length = s->lookahead;
+            }
+            Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
+        }
+
+        /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->strstart - 1, s->match_length);
+
+            _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
+
+            s->lookahead -= s->match_length;
+            s->strstart += s->match_length;
+            s->match_length = 0;
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            _tr_tally_lit (s, s->window[s->strstart], bflush);
+            s->lookahead--;
+            s->strstart++;
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    s->insert = 0;
+    if (flush == Z_FINISH) {
+        FLUSH_BLOCK(s, 1);
+        return finish_done;
+    }
+    if (s->last_lit)
+        FLUSH_BLOCK(s, 0);
+    return block_done;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches.  Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+local block_state deflate_huff(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    int bflush;             /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we have a literal to write. */
+        if (s->lookahead == 0) {
+            fill_window(s);
+            if (s->lookahead == 0) {
+                if (flush == Z_NO_FLUSH)
+                    return need_more;
+                break;      /* flush the current block */
+            }
+        }
+
+        /* Output a literal byte */
+        s->match_length = 0;
+        Tracevv((stderr,"%c", s->window[s->strstart]));
+        _tr_tally_lit (s, s->window[s->strstart], bflush);
+        s->lookahead--;
+        s->strstart++;
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    s->insert = 0;
+    if (flush == Z_FINISH) {
+        FLUSH_BLOCK(s, 1);
+        return finish_done;
+    }
+    if (s->last_lit)
+        FLUSH_BLOCK(s, 0);
+    return block_done;
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/deflate.h b/deps/libchdr/deps/zlib-1.2.11/deflate.h
new file mode 100644 (file)
index 0000000..23ecdd3
--- /dev/null
@@ -0,0 +1,349 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2016 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer creation by deflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip encoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define Buf_size 16
+/* size of bit buffer in bi_buf */
+
+#define INIT_STATE    42    /* zlib header -> BUSY_STATE */
+#ifdef GZIP
+#  define GZIP_STATE  57    /* gzip header -> BUSY_STATE | EXTRA_STATE */
+#endif
+#define EXTRA_STATE   69    /* gzip extra block -> NAME_STATE */
+#define NAME_STATE    73    /* gzip file name -> COMMENT_STATE */
+#define COMMENT_STATE 91    /* gzip comment -> HCRC_STATE */
+#define HCRC_STATE   103    /* gzip header CRC -> BUSY_STATE */
+#define BUSY_STATE   113    /* deflate -> FINISH_STATE */
+#define FINISH_STATE 666    /* stream complete */
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    const static_tree_desc *stat_desc;  /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    ulg   pending;       /* nb of bytes in the pending buffer */
+    int   wrap;          /* bit 0 true for zlib, bit 1 true for gzip */
+    gz_headerp  gzhead;  /* gzip header information to write */
+    ulg   gzindex;       /* where in extra, name, or comment */
+    Byte  method;        /* can only be DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to suppress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    uInt matches;       /* number of string matches in current block */
+    uInt insert;        /* bytes at end of window left to insert */
+
+#ifdef ZLIB_DEBUG
+    ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+    ulg bits_sent;      /* bit length of compressed data sent mod 2^32 */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+    ulg high_water;
+    /* High water mark offset in window for initialized bytes -- bytes above
+     * this are set to zero in order to avoid memory check warnings when
+     * longest match routines access bytes past the input.  This is then
+     * updated to the new high water mark.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define WIN_INIT MAX_MATCH
+/* Number of bytes after end of data in window to initialize in order to avoid
+   memory checker errors from longest match routines */
+
+        /* in trees.c */
+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
+                        ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
+                        ulg stored_len, int last));
+
+#define d_code(dist) \
+   ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef ZLIB_DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+  extern uch ZLIB_INTERNAL _length_code[];
+  extern uch ZLIB_INTERNAL _dist_code[];
+#else
+  extern const uch ZLIB_INTERNAL _length_code[];
+  extern const uch ZLIB_INTERNAL _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+  { uch cc = (c); \
+    s->d_buf[s->last_lit] = 0; \
+    s->l_buf[s->last_lit++] = cc; \
+    s->dyn_ltree[cc].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+   }
+# define _tr_tally_dist(s, distance, length, flush) \
+  { uch len = (uch)(length); \
+    ush dist = (ush)(distance); \
+    s->d_buf[s->last_lit] = dist; \
+    s->l_buf[s->last_lit++] = len; \
+    dist--; \
+    s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+    s->dyn_dtree[d_code(dist)].Freq++; \
+    flush = (s->last_lit == s->lit_bufsize-1); \
+  }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+              flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/deps/libchdr/deps/zlib-1.2.11/doc/algorithm.txt b/deps/libchdr/deps/zlib-1.2.11/doc/algorithm.txt
new file mode 100644 (file)
index 0000000..c97f495
--- /dev/null
@@ -0,0 +1,209 @@
+1. Compression algorithm (deflate)
+
+The deflation algorithm used by gzip (also zip and zlib) is a variation of
+LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in
+the input data.  The second occurrence of a string is replaced by a
+pointer to the previous string, in the form of a pair (distance,
+length).  Distances are limited to 32K bytes, and lengths are limited
+to 258 bytes. When a string does not occur anywhere in the previous
+32K bytes, it is emitted as a sequence of literal bytes.  (In this
+description, `string' must be taken as an arbitrary sequence of bytes,
+and is not restricted to printable characters.)
+
+Literals or match lengths are compressed with one Huffman tree, and
+match distances are compressed with another tree. The trees are stored
+in a compact form at the start of each block. The blocks can have any
+size (except that the compressed data for one block must fit in
+available memory). A block is terminated when deflate() determines that
+it would be useful to start another block with fresh trees. (This is
+somewhat similar to the behavior of LZW-based _compress_.)
+
+Duplicated strings are found using a hash table. All input strings of
+length 3 are inserted in the hash table. A hash index is computed for
+the next 3 bytes. If the hash chain for this index is not empty, all
+strings in the chain are compared with the current input string, and
+the longest match is selected.
+
+The hash chains are searched starting with the most recent strings, to
+favor small distances and thus take advantage of the Huffman encoding.
+The hash chains are singly linked. There are no deletions from the
+hash chains, the algorithm simply discards matches that are too old.
+
+To avoid a worst-case situation, very long hash chains are arbitrarily
+truncated at a certain length, determined by a runtime option (level
+parameter of deflateInit). So deflate() does not always find the longest
+possible match but generally finds a match which is long enough.
+
+deflate() also defers the selection of matches with a lazy evaluation
+mechanism. After a match of length N has been found, deflate() searches for
+a longer match at the next input byte. If a longer match is found, the
+previous match is truncated to a length of one (thus producing a single
+literal byte) and the process of lazy evaluation begins again. Otherwise,
+the original match is kept, and the next match search is attempted only N
+steps later.
+
+The lazy match evaluation is also subject to a runtime parameter. If
+the current match is long enough, deflate() reduces the search for a longer
+match, thus speeding up the whole process. If compression ratio is more
+important than speed, deflate() attempts a complete second search even if
+the first match is already long enough.
+
+The lazy match evaluation is not performed for the fastest compression
+modes (level parameter 1 to 3). For these fast modes, new strings
+are inserted in the hash table only when no match was found, or
+when the match is not too long. This degrades the compression ratio
+but saves time since there are both fewer insertions and fewer searches.
+
+
+2. Decompression algorithm (inflate)
+
+2.1 Introduction
+
+The key question is how to represent a Huffman code (or any prefix code) so
+that you can decode fast.  The most important characteristic is that shorter
+codes are much more common than longer codes, so pay attention to decoding the
+short codes fast, and let the long codes take longer to decode.
+
+inflate() sets up a first level table that covers some number of bits of
+input less than the length of longest code.  It gets that many bits from the
+stream, and looks it up in the table.  The table will tell if the next
+code is that many bits or less and how many, and if it is, it will tell
+the value, else it will point to the next level table for which inflate()
+grabs more bits and tries to decode a longer code.
+
+How many bits to make the first lookup is a tradeoff between the time it
+takes to decode and the time it takes to build the table.  If building the
+table took no time (and if you had infinite memory), then there would only
+be a first level table to cover all the way to the longest code.  However,
+building the table ends up taking a lot longer for more bits since short
+codes are replicated many times in such a table.  What inflate() does is
+simply to make the number of bits in the first table a variable, and  then
+to set that variable for the maximum speed.
+
+For inflate, which has 286 possible codes for the literal/length tree, the size
+of the first table is nine bits.  Also the distance trees have 30 possible
+values, and the size of the first table is six bits.  Note that for each of
+those cases, the table ended up one bit longer than the ``average'' code
+length, i.e. the code length of an approximately flat code which would be a
+little more than eight bits for 286 symbols and a little less than five bits
+for 30 symbols.
+
+
+2.2 More details on the inflate table lookup
+
+Ok, you want to know what this cleverly obfuscated inflate tree actually
+looks like.  You are correct that it's not a Huffman tree.  It is simply a
+lookup table for the first, let's say, nine bits of a Huffman symbol.  The
+symbol could be as short as one bit or as long as 15 bits.  If a particular
+symbol is shorter than nine bits, then that symbol's translation is duplicated
+in all those entries that start with that symbol's bits.  For example, if the
+symbol is four bits, then it's duplicated 32 times in a nine-bit table.  If a
+symbol is nine bits long, it appears in the table once.
+
+If the symbol is longer than nine bits, then that entry in the table points
+to another similar table for the remaining bits.  Again, there are duplicated
+entries as needed.  The idea is that most of the time the symbol will be short
+and there will only be one table look up.  (That's whole idea behind data
+compression in the first place.)  For the less frequent long symbols, there
+will be two lookups.  If you had a compression method with really long
+symbols, you could have as many levels of lookups as is efficient.  For
+inflate, two is enough.
+
+So a table entry either points to another table (in which case nine bits in
+the above example are gobbled), or it contains the translation for the symbol
+and the number of bits to gobble.  Then you start again with the next
+ungobbled bit.
+
+You may wonder: why not just have one lookup table for how ever many bits the
+longest symbol is?  The reason is that if you do that, you end up spending
+more time filling in duplicate symbol entries than you do actually decoding.
+At least for deflate's output that generates new trees every several 10's of
+kbytes.  You can imagine that filling in a 2^15 entry table for a 15-bit code
+would take too long if you're only decoding several thousand symbols.  At the
+other extreme, you could make a new table for every bit in the code.  In fact,
+that's essentially a Huffman tree.  But then you spend too much time
+traversing the tree while decoding, even for short symbols.
+
+So the number of bits for the first lookup table is a trade of the time to
+fill out the table vs. the time spent looking at the second level and above of
+the table.
+
+Here is an example, scaled down:
+
+The code being decoded, with 10 symbols, from 1 to 6 bits long:
+
+A: 0
+B: 10
+C: 1100
+D: 11010
+E: 11011
+F: 11100
+G: 11101
+H: 11110
+I: 111110
+J: 111111
+
+Let's make the first table three bits long (eight entries):
+
+000: A,1
+001: A,1
+010: A,1
+011: A,1
+100: B,2
+101: B,2
+110: -> table X (gobble 3 bits)
+111: -> table Y (gobble 3 bits)
+
+Each entry is what the bits decode as and how many bits that is, i.e. how
+many bits to gobble.  Or the entry points to another table, with the number of
+bits to gobble implicit in the size of the table.
+
+Table X is two bits long since the longest code starting with 110 is five bits
+long:
+
+00: C,1
+01: C,1
+10: D,2
+11: E,2
+
+Table Y is three bits long since the longest code starting with 111 is six
+bits long:
+
+000: F,2
+001: F,2
+010: G,2
+011: G,2
+100: H,2
+101: H,2
+110: I,3
+111: J,3
+
+So what we have here are three tables with a total of 20 entries that had to
+be constructed.  That's compared to 64 entries for a single table.  Or
+compared to 16 entries for a Huffman tree (six two entry tables and one four
+entry table).  Assuming that the code ideally represents the probability of
+the symbols, it takes on the average 1.25 lookups per symbol.  That's compared
+to one lookup for the single table, or 1.66 lookups per symbol for the
+Huffman tree.
+
+There, I think that gives you a picture of what's going on.  For inflate, the
+meaning of a particular symbol is often more than just a letter.  It can be a
+byte (a "literal"), or it can be either a length or a distance which
+indicates a base value and a number of bits to fetch after the code that is
+added to the base value.  Or it might be the special end-of-block code.  The
+data structures created in inftrees.c try to encode all that information
+compactly in the tables.
+
+
+Jean-loup Gailly        Mark Adler
+jloup@gzip.org          madler@alumni.caltech.edu
+
+
+References:
+
+[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data
+Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3,
+pp. 337-343.
+
+``DEFLATE Compressed Data Format Specification'' available in
+http://tools.ietf.org/html/rfc1951
diff --git a/deps/libchdr/deps/zlib-1.2.11/doc/rfc1950.txt b/deps/libchdr/deps/zlib-1.2.11/doc/rfc1950.txt
new file mode 100644 (file)
index 0000000..ce6428a
--- /dev/null
@@ -0,0 +1,619 @@
+
+
+
+
+
+
+Network Working Group                                         P. Deutsch
+Request for Comments: 1950                           Aladdin Enterprises
+Category: Informational                                      J-L. Gailly
+                                                                Info-ZIP
+                                                                May 1996
+
+
+         ZLIB Compressed Data Format Specification version 3.3
+
+Status of This Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+IESG Note:
+
+   The IESG takes no position on the validity of any Intellectual
+   Property Rights statements contained in this document.
+
+Notices
+
+   Copyright (c) 1996 L. Peter Deutsch and Jean-Loup Gailly
+
+   Permission is granted to copy and distribute this document for any
+   purpose and without charge, including translations into other
+   languages and incorporation into compilations, provided that the
+   copyright notice and this notice are preserved, and that any
+   substantive changes or deletions from the original are clearly
+   marked.
+
+   A pointer to the latest version of this and related documentation in
+   HTML format can be found at the URL
+   <ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html>.
+
+Abstract
+
+   This specification defines a lossless compressed data format.  The
+   data can be produced or consumed, even for an arbitrarily long
+   sequentially presented input data stream, using only an a priori
+   bounded amount of intermediate storage.  The format presently uses
+   the DEFLATE compression method but can be easily extended to use
+   other compression methods.  It can be implemented readily in a manner
+   not covered by patents.  This specification also defines the ADLER-32
+   checksum (an extension and improvement of the Fletcher checksum),
+   used for detection of data corruption, and provides an algorithm for
+   computing it.
+
+
+
+
+Deutsch & Gailly             Informational                      [Page 1]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+Table of Contents
+
+   1. Introduction ................................................... 2
+      1.1. Purpose ................................................... 2
+      1.2. Intended audience ......................................... 3
+      1.3. Scope ..................................................... 3
+      1.4. Compliance ................................................ 3
+      1.5.  Definitions of terms and conventions used ................ 3
+      1.6. Changes from previous versions ............................ 3
+   2. Detailed specification ......................................... 3
+      2.1. Overall conventions ....................................... 3
+      2.2. Data format ............................................... 4
+      2.3. Compliance ................................................ 7
+   3. References ..................................................... 7
+   4. Source code .................................................... 8
+   5. Security Considerations ........................................ 8
+   6. Acknowledgements ............................................... 8
+   7. Authors' Addresses ............................................. 8
+   8. Appendix: Rationale ............................................ 9
+   9. Appendix: Sample code ..........................................10
+
+1. Introduction
+
+   1.1. Purpose
+
+      The purpose of this specification is to define a lossless
+      compressed data format that:
+
+          * Is independent of CPU type, operating system, file system,
+            and character set, and hence can be used for interchange;
+
+          * Can be produced or consumed, even for an arbitrarily long
+            sequentially presented input data stream, using only an a
+            priori bounded amount of intermediate storage, and hence can
+            be used in data communications or similar structures such as
+            Unix filters;
+
+          * Can use a number of different compression methods;
+
+          * Can be implemented readily in a manner not covered by
+            patents, and hence can be practiced freely.
+
+      The data format defined by this specification does not attempt to
+      allow random access to compressed data.
+
+
+
+
+
+
+
+Deutsch & Gailly             Informational                      [Page 2]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+   1.2. Intended audience
+
+      This specification is intended for use by implementors of software
+      to compress data into zlib format and/or decompress data from zlib
+      format.
+
+      The text of the specification assumes a basic background in
+      programming at the level of bits and other primitive data
+      representations.
+
+   1.3. Scope
+
+      The specification specifies a compressed data format that can be
+      used for in-memory compression of a sequence of arbitrary bytes.
+
+   1.4. Compliance
+
+      Unless otherwise indicated below, a compliant decompressor must be
+      able to accept and decompress any data set that conforms to all
+      the specifications presented here; a compliant compressor must
+      produce data sets that conform to all the specifications presented
+      here.
+
+   1.5.  Definitions of terms and conventions used
+
+      byte: 8 bits stored or transmitted as a unit (same as an octet).
+      (For this specification, a byte is exactly 8 bits, even on
+      machines which store a character on a number of bits different
+      from 8.) See below, for the numbering of bits within a byte.
+
+   1.6. Changes from previous versions
+
+      Version 3.1 was the first public release of this specification.
+      In version 3.2, some terminology was changed and the Adler-32
+      sample code was rewritten for clarity.  In version 3.3, the
+      support for a preset dictionary was introduced, and the
+      specification was converted to RFC style.
+
+2. Detailed specification
+
+   2.1. Overall conventions
+
+      In the diagrams below, a box like this:
+
+         +---+
+         |   | <-- the vertical bars might be missing
+         +---+
+
+
+
+
+Deutsch & Gailly             Informational                      [Page 3]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+      represents one byte; a box like this:
+
+         +==============+
+         |              |
+         +==============+
+
+      represents a variable number of bytes.
+
+      Bytes stored within a computer do not have a "bit order", since
+      they are always treated as a unit.  However, a byte considered as
+      an integer between 0 and 255 does have a most- and least-
+      significant bit, and since we write numbers with the most-
+      significant digit on the left, we also write bytes with the most-
+      significant bit on the left.  In the diagrams below, we number the
+      bits of a byte so that bit 0 is the least-significant bit, i.e.,
+      the bits are numbered:
+
+         +--------+
+         |76543210|
+         +--------+
+
+      Within a computer, a number may occupy multiple bytes.  All
+      multi-byte numbers in the format described here are stored with
+      the MOST-significant byte first (at the lower memory address).
+      For example, the decimal number 520 is stored as:
+
+             0     1
+         +--------+--------+
+         |00000010|00001000|
+         +--------+--------+
+          ^        ^
+          |        |
+          |        + less significant byte = 8
+          + more significant byte = 2 x 256
+
+   2.2. Data format
+
+      A zlib stream has the following structure:
+
+           0   1
+         +---+---+
+         |CMF|FLG|   (more-->)
+         +---+---+
+
+
+
+
+
+
+
+
+Deutsch & Gailly             Informational                      [Page 4]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+      (if FLG.FDICT set)
+
+           0   1   2   3
+         +---+---+---+---+
+         |     DICTID    |   (more-->)
+         +---+---+---+---+
+
+         +=====================+---+---+---+---+
+         |...compressed data...|    ADLER32    |
+         +=====================+---+---+---+---+
+
+      Any data which may appear after ADLER32 are not part of the zlib
+      stream.
+
+      CMF (Compression Method and flags)
+         This byte is divided into a 4-bit compression method and a 4-
+         bit information field depending on the compression method.
+
+            bits 0 to 3  CM     Compression method
+            bits 4 to 7  CINFO  Compression info
+
+      CM (Compression method)
+         This identifies the compression method used in the file. CM = 8
+         denotes the "deflate" compression method with a window size up
+         to 32K.  This is the method used by gzip and PNG (see
+         references [1] and [2] in Chapter 3, below, for the reference
+         documents).  CM = 15 is reserved.  It might be used in a future
+         version of this specification to indicate the presence of an
+         extra field before the compressed data.
+
+      CINFO (Compression info)
+         For CM = 8, CINFO is the base-2 logarithm of the LZ77 window
+         size, minus eight (CINFO=7 indicates a 32K window size). Values
+         of CINFO above 7 are not allowed in this version of the
+         specification.  CINFO is not defined in this specification for
+         CM not equal to 8.
+
+      FLG (FLaGs)
+         This flag byte is divided as follows:
+
+            bits 0 to 4  FCHECK  (check bits for CMF and FLG)
+            bit  5       FDICT   (preset dictionary)
+            bits 6 to 7  FLEVEL  (compression level)
+
+         The FCHECK value must be such that CMF and FLG, when viewed as
+         a 16-bit unsigned integer stored in MSB order (CMF*256 + FLG),
+         is a multiple of 31.
+
+
+
+
+Deutsch & Gailly             Informational                      [Page 5]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+      FDICT (Preset dictionary)
+         If FDICT is set, a DICT dictionary identifier is present
+         immediately after the FLG byte. The dictionary is a sequence of
+         bytes which are initially fed to the compressor without
+         producing any compressed output. DICT is the Adler-32 checksum
+         of this sequence of bytes (see the definition of ADLER32
+         below).  The decompressor can use this identifier to determine
+         which dictionary has been used by the compressor.
+
+      FLEVEL (Compression level)
+         These flags are available for use by specific compression
+         methods.  The "deflate" method (CM = 8) sets these flags as
+         follows:
+
+            0 - compressor used fastest algorithm
+            1 - compressor used fast algorithm
+            2 - compressor used default algorithm
+            3 - compressor used maximum compression, slowest algorithm
+
+         The information in FLEVEL is not needed for decompression; it
+         is there to indicate if recompression might be worthwhile.
+
+      compressed data
+         For compression method 8, the compressed data is stored in the
+         deflate compressed data format as described in the document
+         "DEFLATE Compressed Data Format Specification" by L. Peter
+         Deutsch. (See reference [3] in Chapter 3, below)
+
+         Other compressed data formats are not specified in this version
+         of the zlib specification.
+
+      ADLER32 (Adler-32 checksum)
+         This contains a checksum value of the uncompressed data
+         (excluding any dictionary data) computed according to Adler-32
+         algorithm. This algorithm is a 32-bit extension and improvement
+         of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
+         standard. See references [4] and [5] in Chapter 3, below)
+
+         Adler-32 is composed of two sums accumulated per byte: s1 is
+         the sum of all bytes, s2 is the sum of all s1 values. Both sums
+         are done modulo 65521. s1 is initialized to 1, s2 to zero.  The
+         Adler-32 checksum is stored as s2*65536 + s1 in most-
+         significant-byte first (network) order.
+
+
+
+
+
+
+
+
+Deutsch & Gailly             Informational                      [Page 6]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+   2.3. Compliance
+
+      A compliant compressor must produce streams with correct CMF, FLG
+      and ADLER32, but need not support preset dictionaries.  When the
+      zlib data format is used as part of another standard data format,
+      the compressor may use only preset dictionaries that are specified
+      by this other data format.  If this other format does not use the
+      preset dictionary feature, the compressor must not set the FDICT
+      flag.
+
+      A compliant decompressor must check CMF, FLG, and ADLER32, and
+      provide an error indication if any of these have incorrect values.
+      A compliant decompressor must give an error indication if CM is
+      not one of the values defined in this specification (only the
+      value 8 is permitted in this version), since another value could
+      indicate the presence of new features that would cause subsequent
+      data to be interpreted incorrectly.  A compliant decompressor must
+      give an error indication if FDICT is set and DICTID is not the
+      identifier of a known preset dictionary.  A decompressor may
+      ignore FLEVEL and still be compliant.  When the zlib data format
+      is being used as a part of another standard format, a compliant
+      decompressor must support all the preset dictionaries specified by
+      the other format. When the other format does not use the preset
+      dictionary feature, a compliant decompressor must reject any
+      stream in which the FDICT flag is set.
+
+3. References
+
+   [1] Deutsch, L.P.,"GZIP Compressed Data Format Specification",
+       available in ftp://ftp.uu.net/pub/archiving/zip/doc/
+
+   [2] Thomas Boutell, "PNG (Portable Network Graphics) specification",
+       available in ftp://ftp.uu.net/graphics/png/documents/
+
+   [3] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification",
+       available in ftp://ftp.uu.net/pub/archiving/zip/doc/
+
+   [4] Fletcher, J. G., "An Arithmetic Checksum for Serial
+       Transmissions," IEEE Transactions on Communications, Vol. COM-30,
+       No. 1, January 1982, pp. 247-252.
+
+   [5] ITU-T Recommendation X.224, Annex D, "Checksum Algorithms,"
+       November, 1993, pp. 144, 145. (Available from
+       gopher://info.itu.ch). ITU-T X.244 is also the same as ISO 8073.
+
+
+
+
+
+
+
+Deutsch & Gailly             Informational                      [Page 7]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+4. Source code
+
+   Source code for a C language implementation of a "zlib" compliant
+   library is available at ftp://ftp.uu.net/pub/archiving/zip/zlib/.
+
+5. Security Considerations
+
+   A decoder that fails to check the ADLER32 checksum value may be
+   subject to undetected data corruption.
+
+6. Acknowledgements
+
+   Trademarks cited in this document are the property of their
+   respective owners.
+
+   Jean-Loup Gailly and Mark Adler designed the zlib format and wrote
+   the related software described in this specification.  Glenn
+   Randers-Pehrson converted this document to RFC and HTML format.
+
+7. Authors' Addresses
+
+   L. Peter Deutsch
+   Aladdin Enterprises
+   203 Santa Margarita Ave.
+   Menlo Park, CA 94025
+
+   Phone: (415) 322-0103 (AM only)
+   FAX:   (415) 322-1734
+   EMail: <ghost@aladdin.com>
+
+
+   Jean-Loup Gailly
+
+   EMail: <gzip@prep.ai.mit.edu>
+
+   Questions about the technical content of this specification can be
+   sent by email to
+
+   Jean-Loup Gailly <gzip@prep.ai.mit.edu> and
+   Mark Adler <madler@alumni.caltech.edu>
+
+   Editorial comments on this specification can be sent by email to
+
+   L. Peter Deutsch <ghost@aladdin.com> and
+   Glenn Randers-Pehrson <randeg@alumni.rpi.edu>
+
+
+
+
+
+
+Deutsch & Gailly             Informational                      [Page 8]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+8. Appendix: Rationale
+
+   8.1. Preset dictionaries
+
+      A preset dictionary is specially useful to compress short input
+      sequences. The compressor can take advantage of the dictionary
+      context to encode the input in a more compact manner. The
+      decompressor can be initialized with the appropriate context by
+      virtually decompressing a compressed version of the dictionary
+      without producing any output. However for certain compression
+      algorithms such as the deflate algorithm this operation can be
+      achieved without actually performing any decompression.
+
+      The compressor and the decompressor must use exactly the same
+      dictionary. The dictionary may be fixed or may be chosen among a
+      certain number of predefined dictionaries, according to the kind
+      of input data. The decompressor can determine which dictionary has
+      been chosen by the compressor by checking the dictionary
+      identifier. This document does not specify the contents of
+      predefined dictionaries, since the optimal dictionaries are
+      application specific. Standard data formats using this feature of
+      the zlib specification must precisely define the allowed
+      dictionaries.
+
+   8.2. The Adler-32 algorithm
+
+      The Adler-32 algorithm is much faster than the CRC32 algorithm yet
+      still provides an extremely low probability of undetected errors.
+
+      The modulo on unsigned long accumulators can be delayed for 5552
+      bytes, so the modulo operation time is negligible.  If the bytes
+      are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
+      and order sensitive, unlike the first sum, which is just a
+      checksum.  That 65521 is prime is important to avoid a possible
+      large class of two-byte errors that leave the check unchanged.
+      (The Fletcher checksum uses 255, which is not prime and which also
+      makes the Fletcher check insensitive to single byte changes 0 <->
+      255.)
+
+      The sum s1 is initialized to 1 instead of zero to make the length
+      of the sequence part of s2, so that the length does not have to be
+      checked separately. (Any sequence of zeroes has a Fletcher
+      checksum of zero.)
+
+
+
+
+
+
+
+
+Deutsch & Gailly             Informational                      [Page 9]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+9. Appendix: Sample code
+
+   The following C code computes the Adler-32 checksum of a data buffer.
+   It is written for clarity, not for speed.  The sample code is in the
+   ANSI C programming language. Non C users may find it easier to read
+   with these hints:
+
+      &      Bitwise AND operator.
+      >>     Bitwise right shift operator. When applied to an
+             unsigned quantity, as here, right shift inserts zero bit(s)
+             at the left.
+      <<     Bitwise left shift operator. Left shift inserts zero
+             bit(s) at the right.
+      ++     "n++" increments the variable n.
+      %      modulo operator: a % b is the remainder of a divided by b.
+
+      #define BASE 65521 /* largest prime smaller than 65536 */
+
+      /*
+         Update a running Adler-32 checksum with the bytes buf[0..len-1]
+       and return the updated checksum. The Adler-32 checksum should be
+       initialized to 1.
+
+       Usage example:
+
+         unsigned long adler = 1L;
+
+         while (read_buffer(buffer, length) != EOF) {
+           adler = update_adler32(adler, buffer, length);
+         }
+         if (adler != original_adler) error();
+      */
+      unsigned long update_adler32(unsigned long adler,
+         unsigned char *buf, int len)
+      {
+        unsigned long s1 = adler & 0xffff;
+        unsigned long s2 = (adler >> 16) & 0xffff;
+        int n;
+
+        for (n = 0; n < len; n++) {
+          s1 = (s1 + buf[n]) % BASE;
+          s2 = (s2 + s1)     % BASE;
+        }
+        return (s2 << 16) + s1;
+      }
+
+      /* Return the adler32 of the bytes buf[0..len-1] */
+
+
+
+
+Deutsch & Gailly             Informational                     [Page 10]
+\f
+RFC 1950       ZLIB Compressed Data Format Specification        May 1996
+
+
+      unsigned long adler32(unsigned char *buf, int len)
+      {
+        return update_adler32(1L, buf, len);
+      }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Deutsch & Gailly             Informational                     [Page 11]
+\f
diff --git a/deps/libchdr/deps/zlib-1.2.11/doc/rfc1951.txt b/deps/libchdr/deps/zlib-1.2.11/doc/rfc1951.txt
new file mode 100644 (file)
index 0000000..403c8c7
--- /dev/null
@@ -0,0 +1,955 @@
+
+
+
+
+
+
+Network Working Group                                         P. Deutsch
+Request for Comments: 1951                           Aladdin Enterprises
+Category: Informational                                         May 1996
+
+
+        DEFLATE Compressed Data Format Specification version 1.3
+
+Status of This Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+IESG Note:
+
+   The IESG takes no position on the validity of any Intellectual
+   Property Rights statements contained in this document.
+
+Notices
+
+   Copyright (c) 1996 L. Peter Deutsch
+
+   Permission is granted to copy and distribute this document for any
+   purpose and without charge, including translations into other
+   languages and incorporation into compilations, provided that the
+   copyright notice and this notice are preserved, and that any
+   substantive changes or deletions from the original are clearly
+   marked.
+
+   A pointer to the latest version of this and related documentation in
+   HTML format can be found at the URL
+   <ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html>.
+
+Abstract
+
+   This specification defines a lossless compressed data format that
+   compresses data using a combination of the LZ77 algorithm and Huffman
+   coding, with efficiency comparable to the best currently available
+   general-purpose compression methods.  The data can be produced or
+   consumed, even for an arbitrarily long sequentially presented input
+   data stream, using only an a priori bounded amount of intermediate
+   storage.  The format can be implemented readily in a manner not
+   covered by patents.
+
+
+
+
+
+
+
+
+Deutsch                      Informational                      [Page 1]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+Table of Contents
+
+   1. Introduction ................................................... 2
+      1.1. Purpose ................................................... 2
+      1.2. Intended audience ......................................... 3
+      1.3. Scope ..................................................... 3
+      1.4. Compliance ................................................ 3
+      1.5.  Definitions of terms and conventions used ................ 3
+      1.6. Changes from previous versions ............................ 4
+   2. Compressed representation overview ............................. 4
+   3. Detailed specification ......................................... 5
+      3.1. Overall conventions ....................................... 5
+          3.1.1. Packing into bytes .................................. 5
+      3.2. Compressed block format ................................... 6
+          3.2.1. Synopsis of prefix and Huffman coding ............... 6
+          3.2.2. Use of Huffman coding in the "deflate" format ....... 7
+          3.2.3. Details of block format ............................. 9
+          3.2.4. Non-compressed blocks (BTYPE=00) ................... 11
+          3.2.5. Compressed blocks (length and distance codes) ...... 11
+          3.2.6. Compression with fixed Huffman codes (BTYPE=01) .... 12
+          3.2.7. Compression with dynamic Huffman codes (BTYPE=10) .. 13
+      3.3. Compliance ............................................... 14
+   4. Compression algorithm details ................................. 14
+   5. References .................................................... 16
+   6. Security Considerations ....................................... 16
+   7. Source code ................................................... 16
+   8. Acknowledgements .............................................. 16
+   9. Author's Address .............................................. 17
+
+1. Introduction
+
+   1.1. Purpose
+
+      The purpose of this specification is to define a lossless
+      compressed data format that:
+          * Is independent of CPU type, operating system, file system,
+            and character set, and hence can be used for interchange;
+          * Can be produced or consumed, even for an arbitrarily long
+            sequentially presented input data stream, using only an a
+            priori bounded amount of intermediate storage, and hence
+            can be used in data communications or similar structures
+            such as Unix filters;
+          * Compresses data with efficiency comparable to the best
+            currently available general-purpose compression methods,
+            and in particular considerably better than the "compress"
+            program;
+          * Can be implemented readily in a manner not covered by
+            patents, and hence can be practiced freely;
+
+
+
+Deutsch                      Informational                      [Page 2]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+          * Is compatible with the file format produced by the current
+            widely used gzip utility, in that conforming decompressors
+            will be able to read data produced by the existing gzip
+            compressor.
+
+      The data format defined by this specification does not attempt to:
+
+          * Allow random access to compressed data;
+          * Compress specialized data (e.g., raster graphics) as well
+            as the best currently available specialized algorithms.
+
+      A simple counting argument shows that no lossless compression
+      algorithm can compress every possible input data set.  For the
+      format defined here, the worst case expansion is 5 bytes per 32K-
+      byte block, i.e., a size increase of 0.015% for large data sets.
+      English text usually compresses by a factor of 2.5 to 3;
+      executable files usually compress somewhat less; graphical data
+      such as raster images may compress much more.
+
+   1.2. Intended audience
+
+      This specification is intended for use by implementors of software
+      to compress data into "deflate" format and/or decompress data from
+      "deflate" format.
+
+      The text of the specification assumes a basic background in
+      programming at the level of bits and other primitive data
+      representations.  Familiarity with the technique of Huffman coding
+      is helpful but not required.
+
+   1.3. Scope
+
+      The specification specifies a method for representing a sequence
+      of bytes as a (usually shorter) sequence of bits, and a method for
+      packing the latter bit sequence into bytes.
+
+   1.4. Compliance
+
+      Unless otherwise indicated below, a compliant decompressor must be
+      able to accept and decompress any data set that conforms to all
+      the specifications presented here; a compliant compressor must
+      produce data sets that conform to all the specifications presented
+      here.
+
+   1.5.  Definitions of terms and conventions used
+
+      Byte: 8 bits stored or transmitted as a unit (same as an octet).
+      For this specification, a byte is exactly 8 bits, even on machines
+
+
+
+Deutsch                      Informational                      [Page 3]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+      which store a character on a number of bits different from eight.
+      See below, for the numbering of bits within a byte.
+
+      String: a sequence of arbitrary bytes.
+
+   1.6. Changes from previous versions
+
+      There have been no technical changes to the deflate format since
+      version 1.1 of this specification.  In version 1.2, some
+      terminology was changed.  Version 1.3 is a conversion of the
+      specification to RFC style.
+
+2. Compressed representation overview
+
+   A compressed data set consists of a series of blocks, corresponding
+   to successive blocks of input data.  The block sizes are arbitrary,
+   except that non-compressible blocks are limited to 65,535 bytes.
+
+   Each block is compressed using a combination of the LZ77 algorithm
+   and Huffman coding. The Huffman trees for each block are independent
+   of those for previous or subsequent blocks; the LZ77 algorithm may
+   use a reference to a duplicated string occurring in a previous block,
+   up to 32K input bytes before.
+
+   Each block consists of two parts: a pair of Huffman code trees that
+   describe the representation of the compressed data part, and a
+   compressed data part.  (The Huffman trees themselves are compressed
+   using Huffman encoding.)  The compressed data consists of a series of
+   elements of two types: literal bytes (of strings that have not been
+   detected as duplicated within the previous 32K input bytes), and
+   pointers to duplicated strings, where a pointer is represented as a
+   pair <length, backward distance>.  The representation used in the
+   "deflate" format limits distances to 32K bytes and lengths to 258
+   bytes, but does not limit the size of a block, except for
+   uncompressible blocks, which are limited as noted above.
+
+   Each type of value (literals, distances, and lengths) in the
+   compressed data is represented using a Huffman code, using one code
+   tree for literals and lengths and a separate code tree for distances.
+   The code trees for each block appear in a compact form just before
+   the compressed data for that block.
+
+
+
+
+
+
+
+
+
+
+Deutsch                      Informational                      [Page 4]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+3. Detailed specification
+
+   3.1. Overall conventions In the diagrams below, a box like this:
+
+         +---+
+         |   | <-- the vertical bars might be missing
+         +---+
+
+      represents one byte; a box like this:
+
+         +==============+
+         |              |
+         +==============+
+
+      represents a variable number of bytes.
+
+      Bytes stored within a computer do not have a "bit order", since
+      they are always treated as a unit.  However, a byte considered as
+      an integer between 0 and 255 does have a most- and least-
+      significant bit, and since we write numbers with the most-
+      significant digit on the left, we also write bytes with the most-
+      significant bit on the left.  In the diagrams below, we number the
+      bits of a byte so that bit 0 is the least-significant bit, i.e.,
+      the bits are numbered:
+
+         +--------+
+         |76543210|
+         +--------+
+
+      Within a computer, a number may occupy multiple bytes.  All
+      multi-byte numbers in the format described here are stored with
+      the least-significant byte first (at the lower memory address).
+      For example, the decimal number 520 is stored as:
+
+             0        1
+         +--------+--------+
+         |00001000|00000010|
+         +--------+--------+
+          ^        ^
+          |        |
+          |        + more significant byte = 2 x 256
+          + less significant byte = 8
+
+      3.1.1. Packing into bytes
+
+         This document does not address the issue of the order in which
+         bits of a byte are transmitted on a bit-sequential medium,
+         since the final data format described here is byte- rather than
+
+
+
+Deutsch                      Informational                      [Page 5]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+         bit-oriented.  However, we describe the compressed block format
+         in below, as a sequence of data elements of various bit
+         lengths, not a sequence of bytes.  We must therefore specify
+         how to pack these data elements into bytes to form the final
+         compressed byte sequence:
+
+             * Data elements are packed into bytes in order of
+               increasing bit number within the byte, i.e., starting
+               with the least-significant bit of the byte.
+             * Data elements other than Huffman codes are packed
+               starting with the least-significant bit of the data
+               element.
+             * Huffman codes are packed starting with the most-
+               significant bit of the code.
+
+         In other words, if one were to print out the compressed data as
+         a sequence of bytes, starting with the first byte at the
+         *right* margin and proceeding to the *left*, with the most-
+         significant bit of each byte on the left as usual, one would be
+         able to parse the result from right to left, with fixed-width
+         elements in the correct MSB-to-LSB order and Huffman codes in
+         bit-reversed order (i.e., with the first bit of the code in the
+         relative LSB position).
+
+   3.2. Compressed block format
+
+      3.2.1. Synopsis of prefix and Huffman coding
+
+         Prefix coding represents symbols from an a priori known
+         alphabet by bit sequences (codes), one code for each symbol, in
+         a manner such that different symbols may be represented by bit
+         sequences of different lengths, but a parser can always parse
+         an encoded string unambiguously symbol-by-symbol.
+
+         We define a prefix code in terms of a binary tree in which the
+         two edges descending from each non-leaf node are labeled 0 and
+         1 and in which the leaf nodes correspond one-for-one with (are
+         labeled with) the symbols of the alphabet; then the code for a
+         symbol is the sequence of 0's and 1's on the edges leading from
+         the root to the leaf labeled with that symbol.  For example:
+
+
+
+
+
+
+
+
+
+
+
+Deutsch                      Informational                      [Page 6]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+                          /\              Symbol    Code
+                         0  1             ------    ----
+                        /    \                A      00
+                       /\     B               B       1
+                      0  1                    C     011
+                     /    \                   D     010
+                    A     /\
+                         0  1
+                        /    \
+                       D      C
+
+         A parser can decode the next symbol from an encoded input
+         stream by walking down the tree from the root, at each step
+         choosing the edge corresponding to the next input bit.
+
+         Given an alphabet with known symbol frequencies, the Huffman
+         algorithm allows the construction of an optimal prefix code
+         (one which represents strings with those symbol frequencies
+         using the fewest bits of any possible prefix codes for that
+         alphabet).  Such a code is called a Huffman code.  (See
+         reference [1] in Chapter 5, references for additional
+         information on Huffman codes.)
+
+         Note that in the "deflate" format, the Huffman codes for the
+         various alphabets must not exceed certain maximum code lengths.
+         This constraint complicates the algorithm for computing code
+         lengths from symbol frequencies.  Again, see Chapter 5,
+         references for details.
+
+      3.2.2. Use of Huffman coding in the "deflate" format
+
+         The Huffman codes used for each alphabet in the "deflate"
+         format have two additional rules:
+
+             * All codes of a given bit length have lexicographically
+               consecutive values, in the same order as the symbols
+               they represent;
+
+             * Shorter codes lexicographically precede longer codes.
+
+
+
+
+
+
+
+
+
+
+
+
+Deutsch                      Informational                      [Page 7]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+         We could recode the example above to follow this rule as
+         follows, assuming that the order of the alphabet is ABCD:
+
+            Symbol  Code
+            ------  ----
+            A       10
+            B       0
+            C       110
+            D       111
+
+         I.e., 0 precedes 10 which precedes 11x, and 110 and 111 are
+         lexicographically consecutive.
+
+         Given this rule, we can define the Huffman code for an alphabet
+         just by giving the bit lengths of the codes for each symbol of
+         the alphabet in order; this is sufficient to determine the
+         actual codes.  In our example, the code is completely defined
+         by the sequence of bit lengths (2, 1, 3, 3).  The following
+         algorithm generates the codes as integers, intended to be read
+         from most- to least-significant bit.  The code lengths are
+         initially in tree[I].Len; the codes are produced in
+         tree[I].Code.
+
+         1)  Count the number of codes for each code length.  Let
+             bl_count[N] be the number of codes of length N, N >= 1.
+
+         2)  Find the numerical value of the smallest code for each
+             code length:
+
+                code = 0;
+                bl_count[0] = 0;
+                for (bits = 1; bits <= MAX_BITS; bits++) {
+                    code = (code + bl_count[bits-1]) << 1;
+                    next_code[bits] = code;
+                }
+
+         3)  Assign numerical values to all codes, using consecutive
+             values for all codes of the same length with the base
+             values determined at step 2. Codes that are never used
+             (which have a bit length of zero) must not be assigned a
+             value.
+
+                for (n = 0;  n <= max_code; n++) {
+                    len = tree[n].Len;
+                    if (len != 0) {
+                        tree[n].Code = next_code[len];
+                        next_code[len]++;
+                    }
+
+
+
+Deutsch                      Informational                      [Page 8]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+                }
+
+         Example:
+
+         Consider the alphabet ABCDEFGH, with bit lengths (3, 3, 3, 3,
+         3, 2, 4, 4).  After step 1, we have:
+
+            N      bl_count[N]
+            -      -----------
+            2      1
+            3      5
+            4      2
+
+         Step 2 computes the following next_code values:
+
+            N      next_code[N]
+            -      ------------
+            1      0
+            2      0
+            3      2
+            4      14
+
+         Step 3 produces the following code values:
+
+            Symbol Length   Code
+            ------ ------   ----
+            A       3        010
+            B       3        011
+            C       3        100
+            D       3        101
+            E       3        110
+            F       2         00
+            G       4       1110
+            H       4       1111
+
+      3.2.3. Details of block format
+
+         Each block of compressed data begins with 3 header bits
+         containing the following data:
+
+            first bit       BFINAL
+            next 2 bits     BTYPE
+
+         Note that the header bits do not necessarily begin on a byte
+         boundary, since a block does not necessarily occupy an integral
+         number of bytes.
+
+
+
+
+
+Deutsch                      Informational                      [Page 9]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+         BFINAL is set if and only if this is the last block of the data
+         set.
+
+         BTYPE specifies how the data are compressed, as follows:
+
+            00 - no compression
+            01 - compressed with fixed Huffman codes
+            10 - compressed with dynamic Huffman codes
+            11 - reserved (error)
+
+         The only difference between the two compressed cases is how the
+         Huffman codes for the literal/length and distance alphabets are
+         defined.
+
+         In all cases, the decoding algorithm for the actual data is as
+         follows:
+
+            do
+               read block header from input stream.
+               if stored with no compression
+                  skip any remaining bits in current partially
+                     processed byte
+                  read LEN and NLEN (see next section)
+                  copy LEN bytes of data to output
+               otherwise
+                  if compressed with dynamic Huffman codes
+                     read representation of code trees (see
+                        subsection below)
+                  loop (until end of block code recognized)
+                     decode literal/length value from input stream
+                     if value < 256
+                        copy value (literal byte) to output stream
+                     otherwise
+                        if value = end of block (256)
+                           break from loop
+                        otherwise (value = 257..285)
+                           decode distance from input stream
+
+                           move backwards distance bytes in the output
+                           stream, and copy length bytes from this
+                           position to the output stream.
+                  end loop
+            while not last block
+
+         Note that a duplicated string reference may refer to a string
+         in a previous block; i.e., the backward distance may cross one
+         or more block boundaries.  However a distance cannot refer past
+         the beginning of the output stream.  (An application using a
+
+
+
+Deutsch                      Informational                     [Page 10]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+         preset dictionary might discard part of the output stream; a
+         distance can refer to that part of the output stream anyway)
+         Note also that the referenced string may overlap the current
+         position; for example, if the last 2 bytes decoded have values
+         X and Y, a string reference with <length = 5, distance = 2>
+         adds X,Y,X,Y,X to the output stream.
+
+         We now specify each compression method in turn.
+
+      3.2.4. Non-compressed blocks (BTYPE=00)
+
+         Any bits of input up to the next byte boundary are ignored.
+         The rest of the block consists of the following information:
+
+              0   1   2   3   4...
+            +---+---+---+---+================================+
+            |  LEN  | NLEN  |... LEN bytes of literal data...|
+            +---+---+---+---+================================+
+
+         LEN is the number of data bytes in the block.  NLEN is the
+         one's complement of LEN.
+
+      3.2.5. Compressed blocks (length and distance codes)
+
+         As noted above, encoded data blocks in the "deflate" format
+         consist of sequences of symbols drawn from three conceptually
+         distinct alphabets: either literal bytes, from the alphabet of
+         byte values (0..255), or <length, backward distance> pairs,
+         where the length is drawn from (3..258) and the distance is
+         drawn from (1..32,768).  In fact, the literal and length
+         alphabets are merged into a single alphabet (0..285), where
+         values 0..255 represent literal bytes, the value 256 indicates
+         end-of-block, and values 257..285 represent length codes
+         (possibly in conjunction with extra bits following the symbol
+         code) as follows:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Deutsch                      Informational                     [Page 11]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+                 Extra               Extra               Extra
+            Code Bits Length(s) Code Bits Lengths   Code Bits Length(s)
+            ---- ---- ------     ---- ---- -------   ---- ---- -------
+             257   0     3       267   1   15,16     277   4   67-82
+             258   0     4       268   1   17,18     278   4   83-98
+             259   0     5       269   2   19-22     279   4   99-114
+             260   0     6       270   2   23-26     280   4  115-130
+             261   0     7       271   2   27-30     281   5  131-162
+             262   0     8       272   2   31-34     282   5  163-194
+             263   0     9       273   3   35-42     283   5  195-226
+             264   0    10       274   3   43-50     284   5  227-257
+             265   1  11,12      275   3   51-58     285   0    258
+             266   1  13,14      276   3   59-66
+
+         The extra bits should be interpreted as a machine integer
+         stored with the most-significant bit first, e.g., bits 1110
+         represent the value 14.
+
+                  Extra           Extra               Extra
+             Code Bits Dist  Code Bits   Dist     Code Bits Distance
+             ---- ---- ----  ---- ----  ------    ---- ---- --------
+               0   0    1     10   4     33-48    20    9   1025-1536
+               1   0    2     11   4     49-64    21    9   1537-2048
+               2   0    3     12   5     65-96    22   10   2049-3072
+               3   0    4     13   5     97-128   23   10   3073-4096
+               4   1   5,6    14   6    129-192   24   11   4097-6144
+               5   1   7,8    15   6    193-256   25   11   6145-8192
+               6   2   9-12   16   7    257-384   26   12  8193-12288
+               7   2  13-16   17   7    385-512   27   12 12289-16384
+               8   3  17-24   18   8    513-768   28   13 16385-24576
+               9   3  25-32   19   8   769-1024   29   13 24577-32768
+
+      3.2.6. Compression with fixed Huffman codes (BTYPE=01)
+
+         The Huffman codes for the two alphabets are fixed, and are not
+         represented explicitly in the data.  The Huffman code lengths
+         for the literal/length alphabet are:
+
+                   Lit Value    Bits        Codes
+                   ---------    ----        -----
+                     0 - 143     8          00110000 through
+                                            10111111
+                   144 - 255     9          110010000 through
+                                            111111111
+                   256 - 279     7          0000000 through
+                                            0010111
+                   280 - 287     8          11000000 through
+                                            11000111
+
+
+
+Deutsch                      Informational                     [Page 12]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+         The code lengths are sufficient to generate the actual codes,
+         as described above; we show the codes in the table for added
+         clarity.  Literal/length values 286-287 will never actually
+         occur in the compressed data, but participate in the code
+         construction.
+
+         Distance codes 0-31 are represented by (fixed-length) 5-bit
+         codes, with possible additional bits as shown in the table
+         shown in Paragraph 3.2.5, above.  Note that distance codes 30-
+         31 will never actually occur in the compressed data.
+
+      3.2.7. Compression with dynamic Huffman codes (BTYPE=10)
+
+         The Huffman codes for the two alphabets appear in the block
+         immediately after the header bits and before the actual
+         compressed data, first the literal/length code and then the
+         distance code.  Each code is defined by a sequence of code
+         lengths, as discussed in Paragraph 3.2.2, above.  For even
+         greater compactness, the code length sequences themselves are
+         compressed using a Huffman code.  The alphabet for code lengths
+         is as follows:
+
+               0 - 15: Represent code lengths of 0 - 15
+                   16: Copy the previous code length 3 - 6 times.
+                       The next 2 bits indicate repeat length
+                             (0 = 3, ... , 3 = 6)
+                          Example:  Codes 8, 16 (+2 bits 11),
+                                    16 (+2 bits 10) will expand to
+                                    12 code lengths of 8 (1 + 6 + 5)
+                   17: Repeat a code length of 0 for 3 - 10 times.
+                       (3 bits of length)
+                   18: Repeat a code length of 0 for 11 - 138 times
+                       (7 bits of length)
+
+         A code length of 0 indicates that the corresponding symbol in
+         the literal/length or distance alphabet will not occur in the
+         block, and should not participate in the Huffman code
+         construction algorithm given earlier.  If only one distance
+         code is used, it is encoded using one bit, not zero bits; in
+         this case there is a single code length of one, with one unused
+         code.  One distance code of zero bits means that there are no
+         distance codes used at all (the data is all literals).
+
+         We can now define the format of the block:
+
+               5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286)
+               5 Bits: HDIST, # of Distance codes - 1        (1 - 32)
+               4 Bits: HCLEN, # of Code Length codes - 4     (4 - 19)
+
+
+
+Deutsch                      Informational                     [Page 13]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+               (HCLEN + 4) x 3 bits: code lengths for the code length
+                  alphabet given just above, in the order: 16, 17, 18,
+                  0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+
+                  These code lengths are interpreted as 3-bit integers
+                  (0-7); as above, a code length of 0 means the
+                  corresponding symbol (literal/length or distance code
+                  length) is not used.
+
+               HLIT + 257 code lengths for the literal/length alphabet,
+                  encoded using the code length Huffman code
+
+               HDIST + 1 code lengths for the distance alphabet,
+                  encoded using the code length Huffman code
+
+               The actual compressed data of the block,
+                  encoded using the literal/length and distance Huffman
+                  codes
+
+               The literal/length symbol 256 (end of data),
+                  encoded using the literal/length Huffman code
+
+         The code length repeat codes can cross from HLIT + 257 to the
+         HDIST + 1 code lengths.  In other words, all code lengths form
+         a single sequence of HLIT + HDIST + 258 values.
+
+   3.3. Compliance
+
+      A compressor may limit further the ranges of values specified in
+      the previous section and still be compliant; for example, it may
+      limit the range of backward pointers to some value smaller than
+      32K.  Similarly, a compressor may limit the size of blocks so that
+      a compressible block fits in memory.
+
+      A compliant decompressor must accept the full range of possible
+      values defined in the previous section, and must accept blocks of
+      arbitrary size.
+
+4. Compression algorithm details
+
+   While it is the intent of this document to define the "deflate"
+   compressed data format without reference to any particular
+   compression algorithm, the format is related to the compressed
+   formats produced by LZ77 (Lempel-Ziv 1977, see reference [2] below);
+   since many variations of LZ77 are patented, it is strongly
+   recommended that the implementor of a compressor follow the general
+   algorithm presented here, which is known not to be patented per se.
+   The material in this section is not part of the definition of the
+
+
+
+Deutsch                      Informational                     [Page 14]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+   specification per se, and a compressor need not follow it in order to
+   be compliant.
+
+   The compressor terminates a block when it determines that starting a
+   new block with fresh trees would be useful, or when the block size
+   fills up the compressor's block buffer.
+
+   The compressor uses a chained hash table to find duplicated strings,
+   using a hash function that operates on 3-byte sequences.  At any
+   given point during compression, let XYZ be the next 3 input bytes to
+   be examined (not necessarily all different, of course).  First, the
+   compressor examines the hash chain for XYZ.  If the chain is empty,
+   the compressor simply writes out X as a literal byte and advances one
+   byte in the input.  If the hash chain is not empty, indicating that
+   the sequence XYZ (or, if we are unlucky, some other 3 bytes with the
+   same hash function value) has occurred recently, the compressor
+   compares all strings on the XYZ hash chain with the actual input data
+   sequence starting at the current point, and selects the longest
+   match.
+
+   The compressor searches the hash chains starting with the most recent
+   strings, to favor small distances and thus take advantage of the
+   Huffman encoding.  The hash chains are singly linked. There are no
+   deletions from the hash chains; the algorithm simply discards matches
+   that are too old.  To avoid a worst-case situation, very long hash
+   chains are arbitrarily truncated at a certain length, determined by a
+   run-time parameter.
+
+   To improve overall compression, the compressor optionally defers the
+   selection of matches ("lazy matching"): after a match of length N has
+   been found, the compressor searches for a longer match starting at
+   the next input byte.  If it finds a longer match, it truncates the
+   previous match to a length of one (thus producing a single literal
+   byte) and then emits the longer match.  Otherwise, it emits the
+   original match, and, as described above, advances N bytes before
+   continuing.
+
+   Run-time parameters also control this "lazy match" procedure.  If
+   compression ratio is most important, the compressor attempts a
+   complete second search regardless of the length of the first match.
+   In the normal case, if the current match is "long enough", the
+   compressor reduces the search for a longer match, thus speeding up
+   the process.  If speed is most important, the compressor inserts new
+   strings in the hash table only when no match was found, or when the
+   match is not "too long".  This degrades the compression ratio but
+   saves time since there are both fewer insertions and fewer searches.
+
+
+
+
+
+Deutsch                      Informational                     [Page 15]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+5. References
+
+   [1] Huffman, D. A., "A Method for the Construction of Minimum
+       Redundancy Codes", Proceedings of the Institute of Radio
+       Engineers, September 1952, Volume 40, Number 9, pp. 1098-1101.
+
+   [2] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data
+       Compression", IEEE Transactions on Information Theory, Vol. 23,
+       No. 3, pp. 337-343.
+
+   [3] Gailly, J.-L., and Adler, M., ZLIB documentation and sources,
+       available in ftp://ftp.uu.net/pub/archiving/zip/doc/
+
+   [4] Gailly, J.-L., and Adler, M., GZIP documentation and sources,
+       available as gzip-*.tar in ftp://prep.ai.mit.edu/pub/gnu/
+
+   [5] Schwartz, E. S., and Kallick, B. "Generating a canonical prefix
+       encoding." Comm. ACM, 7,3 (Mar. 1964), pp. 166-169.
+
+   [6] Hirschberg and Lelewer, "Efficient decoding of prefix codes,"
+       Comm. ACM, 33,4, April 1990, pp. 449-459.
+
+6. Security Considerations
+
+   Any data compression method involves the reduction of redundancy in
+   the data.  Consequently, any corruption of the data is likely to have
+   severe effects and be difficult to correct.  Uncompressed text, on
+   the other hand, will probably still be readable despite the presence
+   of some corrupted bytes.
+
+   It is recommended that systems using this data format provide some
+   means of validating the integrity of the compressed data.  See
+   reference [3], for example.
+
+7. Source code
+
+   Source code for a C language implementation of a "deflate" compliant
+   compressor and decompressor is available within the zlib package at
+   ftp://ftp.uu.net/pub/archiving/zip/zlib/.
+
+8. Acknowledgements
+
+   Trademarks cited in this document are the property of their
+   respective owners.
+
+   Phil Katz designed the deflate format.  Jean-Loup Gailly and Mark
+   Adler wrote the related software described in this specification.
+   Glenn Randers-Pehrson converted this document to RFC and HTML format.
+
+
+
+Deutsch                      Informational                     [Page 16]
+\f
+RFC 1951      DEFLATE Compressed Data Format Specification      May 1996
+
+
+9. Author's Address
+
+   L. Peter Deutsch
+   Aladdin Enterprises
+   203 Santa Margarita Ave.
+   Menlo Park, CA 94025
+
+   Phone: (415) 322-0103 (AM only)
+   FAX:   (415) 322-1734
+   EMail: <ghost@aladdin.com>
+
+   Questions about the technical content of this specification can be
+   sent by email to:
+
+   Jean-Loup Gailly <gzip@prep.ai.mit.edu> and
+   Mark Adler <madler@alumni.caltech.edu>
+
+   Editorial comments on this specification can be sent by email to:
+
+   L. Peter Deutsch <ghost@aladdin.com> and
+   Glenn Randers-Pehrson <randeg@alumni.rpi.edu>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Deutsch                      Informational                     [Page 17]
+\f
diff --git a/deps/libchdr/deps/zlib-1.2.11/doc/rfc1952.txt b/deps/libchdr/deps/zlib-1.2.11/doc/rfc1952.txt
new file mode 100644 (file)
index 0000000..a8e51b4
--- /dev/null
@@ -0,0 +1,675 @@
+
+
+
+
+
+
+Network Working Group                                         P. Deutsch
+Request for Comments: 1952                           Aladdin Enterprises
+Category: Informational                                         May 1996
+
+
+               GZIP file format specification version 4.3
+
+Status of This Memo
+
+   This memo provides information for the Internet community.  This memo
+   does not specify an Internet standard of any kind.  Distribution of
+   this memo is unlimited.
+
+IESG Note:
+
+   The IESG takes no position on the validity of any Intellectual
+   Property Rights statements contained in this document.
+
+Notices
+
+   Copyright (c) 1996 L. Peter Deutsch
+
+   Permission is granted to copy and distribute this document for any
+   purpose and without charge, including translations into other
+   languages and incorporation into compilations, provided that the
+   copyright notice and this notice are preserved, and that any
+   substantive changes or deletions from the original are clearly
+   marked.
+
+   A pointer to the latest version of this and related documentation in
+   HTML format can be found at the URL
+   <ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html>.
+
+Abstract
+
+   This specification defines a lossless compressed data format that is
+   compatible with the widely used GZIP utility.  The format includes a
+   cyclic redundancy check value for detecting data corruption.  The
+   format presently uses the DEFLATE method of compression but can be
+   easily extended to use other compression methods.  The format can be
+   implemented readily in a manner not covered by patents.
+
+
+
+
+
+
+
+
+
+
+Deutsch                      Informational                      [Page 1]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+Table of Contents
+
+   1. Introduction ................................................... 2
+      1.1. Purpose ................................................... 2
+      1.2. Intended audience ......................................... 3
+      1.3. Scope ..................................................... 3
+      1.4. Compliance ................................................ 3
+      1.5. Definitions of terms and conventions used ................. 3
+      1.6. Changes from previous versions ............................ 3
+   2. Detailed specification ......................................... 4
+      2.1. Overall conventions ....................................... 4
+      2.2. File format ............................................... 5
+      2.3. Member format ............................................. 5
+          2.3.1. Member header and trailer ........................... 6
+              2.3.1.1. Extra field ................................... 8
+              2.3.1.2. Compliance .................................... 9
+      3. References .................................................. 9
+      4. Security Considerations .................................... 10
+      5. Acknowledgements ........................................... 10
+      6. Author's Address ........................................... 10
+      7. Appendix: Jean-Loup Gailly's gzip utility .................. 11
+      8. Appendix: Sample CRC Code .................................. 11
+
+1. Introduction
+
+   1.1. Purpose
+
+      The purpose of this specification is to define a lossless
+      compressed data format that:
+
+          * Is independent of CPU type, operating system, file system,
+            and character set, and hence can be used for interchange;
+          * Can compress or decompress a data stream (as opposed to a
+            randomly accessible file) to produce another data stream,
+            using only an a priori bounded amount of intermediate
+            storage, and hence can be used in data communications or
+            similar structures such as Unix filters;
+          * Compresses data with efficiency comparable to the best
+            currently available general-purpose compression methods,
+            and in particular considerably better than the "compress"
+            program;
+          * Can be implemented readily in a manner not covered by
+            patents, and hence can be practiced freely;
+          * Is compatible with the file format produced by the current
+            widely used gzip utility, in that conforming decompressors
+            will be able to read data produced by the existing gzip
+            compressor.
+
+
+
+
+Deutsch                      Informational                      [Page 2]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+      The data format defined by this specification does not attempt to:
+
+          * Provide random access to compressed data;
+          * Compress specialized data (e.g., raster graphics) as well as
+            the best currently available specialized algorithms.
+
+   1.2. Intended audience
+
+      This specification is intended for use by implementors of software
+      to compress data into gzip format and/or decompress data from gzip
+      format.
+
+      The text of the specification assumes a basic background in
+      programming at the level of bits and other primitive data
+      representations.
+
+   1.3. Scope
+
+      The specification specifies a compression method and a file format
+      (the latter assuming only that a file can store a sequence of
+      arbitrary bytes).  It does not specify any particular interface to
+      a file system or anything about character sets or encodings
+      (except for file names and comments, which are optional).
+
+   1.4. Compliance
+
+      Unless otherwise indicated below, a compliant decompressor must be
+      able to accept and decompress any file that conforms to all the
+      specifications presented here; a compliant compressor must produce
+      files that conform to all the specifications presented here.  The
+      material in the appendices is not part of the specification per se
+      and is not relevant to compliance.
+
+   1.5. Definitions of terms and conventions used
+
+      byte: 8 bits stored or transmitted as a unit (same as an octet).
+      (For this specification, a byte is exactly 8 bits, even on
+      machines which store a character on a number of bits different
+      from 8.)  See below for the numbering of bits within a byte.
+
+   1.6. Changes from previous versions
+
+      There have been no technical changes to the gzip format since
+      version 4.1 of this specification.  In version 4.2, some
+      terminology was changed, and the sample CRC code was rewritten for
+      clarity and to eliminate the requirement for the caller to do pre-
+      and post-conditioning.  Version 4.3 is a conversion of the
+      specification to RFC style.
+
+
+
+Deutsch                      Informational                      [Page 3]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+2. Detailed specification
+
+   2.1. Overall conventions
+
+      In the diagrams below, a box like this:
+
+         +---+
+         |   | <-- the vertical bars might be missing
+         +---+
+
+      represents one byte; a box like this:
+
+         +==============+
+         |              |
+         +==============+
+
+      represents a variable number of bytes.
+
+      Bytes stored within a computer do not have a "bit order", since
+      they are always treated as a unit.  However, a byte considered as
+      an integer between 0 and 255 does have a most- and least-
+      significant bit, and since we write numbers with the most-
+      significant digit on the left, we also write bytes with the most-
+      significant bit on the left.  In the diagrams below, we number the
+      bits of a byte so that bit 0 is the least-significant bit, i.e.,
+      the bits are numbered:
+
+         +--------+
+         |76543210|
+         +--------+
+
+      This document does not address the issue of the order in which
+      bits of a byte are transmitted on a bit-sequential medium, since
+      the data format described here is byte- rather than bit-oriented.
+
+      Within a computer, a number may occupy multiple bytes.  All
+      multi-byte numbers in the format described here are stored with
+      the least-significant byte first (at the lower memory address).
+      For example, the decimal number 520 is stored as:
+
+             0        1
+         +--------+--------+
+         |00001000|00000010|
+         +--------+--------+
+          ^        ^
+          |        |
+          |        + more significant byte = 2 x 256
+          + less significant byte = 8
+
+
+
+Deutsch                      Informational                      [Page 4]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+   2.2. File format
+
+      A gzip file consists of a series of "members" (compressed data
+      sets).  The format of each member is specified in the following
+      section.  The members simply appear one after another in the file,
+      with no additional information before, between, or after them.
+
+   2.3. Member format
+
+      Each member has the following structure:
+
+         +---+---+---+---+---+---+---+---+---+---+
+         |ID1|ID2|CM |FLG|     MTIME     |XFL|OS | (more-->)
+         +---+---+---+---+---+---+---+---+---+---+
+
+      (if FLG.FEXTRA set)
+
+         +---+---+=================================+
+         | XLEN  |...XLEN bytes of "extra field"...| (more-->)
+         +---+---+=================================+
+
+      (if FLG.FNAME set)
+
+         +=========================================+
+         |...original file name, zero-terminated...| (more-->)
+         +=========================================+
+
+      (if FLG.FCOMMENT set)
+
+         +===================================+
+         |...file comment, zero-terminated...| (more-->)
+         +===================================+
+
+      (if FLG.FHCRC set)
+
+         +---+---+
+         | CRC16 |
+         +---+---+
+
+         +=======================+
+         |...compressed blocks...| (more-->)
+         +=======================+
+
+           0   1   2   3   4   5   6   7
+         +---+---+---+---+---+---+---+---+
+         |     CRC32     |     ISIZE     |
+         +---+---+---+---+---+---+---+---+
+
+
+
+
+Deutsch                      Informational                      [Page 5]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+      2.3.1. Member header and trailer
+
+         ID1 (IDentification 1)
+         ID2 (IDentification 2)
+            These have the fixed values ID1 = 31 (0x1f, \037), ID2 = 139
+            (0x8b, \213), to identify the file as being in gzip format.
+
+         CM (Compression Method)
+            This identifies the compression method used in the file.  CM
+            = 0-7 are reserved.  CM = 8 denotes the "deflate"
+            compression method, which is the one customarily used by
+            gzip and which is documented elsewhere.
+
+         FLG (FLaGs)
+            This flag byte is divided into individual bits as follows:
+
+               bit 0   FTEXT
+               bit 1   FHCRC
+               bit 2   FEXTRA
+               bit 3   FNAME
+               bit 4   FCOMMENT
+               bit 5   reserved
+               bit 6   reserved
+               bit 7   reserved
+
+            If FTEXT is set, the file is probably ASCII text.  This is
+            an optional indication, which the compressor may set by
+            checking a small amount of the input data to see whether any
+            non-ASCII characters are present.  In case of doubt, FTEXT
+            is cleared, indicating binary data. For systems which have
+            different file formats for ascii text and binary data, the
+            decompressor can use FTEXT to choose the appropriate format.
+            We deliberately do not specify the algorithm used to set
+            this bit, since a compressor always has the option of
+            leaving it cleared and a decompressor always has the option
+            of ignoring it and letting some other program handle issues
+            of data conversion.
+
+            If FHCRC is set, a CRC16 for the gzip header is present,
+            immediately before the compressed data. The CRC16 consists
+            of the two least significant bytes of the CRC32 for all
+            bytes of the gzip header up to and not including the CRC16.
+            [The FHCRC bit was never set by versions of gzip up to
+            1.2.4, even though it was documented with a different
+            meaning in gzip 1.2.4.]
+
+            If FEXTRA is set, optional extra fields are present, as
+            described in a following section.
+
+
+
+Deutsch                      Informational                      [Page 6]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+            If FNAME is set, an original file name is present,
+            terminated by a zero byte.  The name must consist of ISO
+            8859-1 (LATIN-1) characters; on operating systems using
+            EBCDIC or any other character set for file names, the name
+            must be translated to the ISO LATIN-1 character set.  This
+            is the original name of the file being compressed, with any
+            directory components removed, and, if the file being
+            compressed is on a file system with case insensitive names,
+            forced to lower case. There is no original file name if the
+            data was compressed from a source other than a named file;
+            for example, if the source was stdin on a Unix system, there
+            is no file name.
+
+            If FCOMMENT is set, a zero-terminated file comment is
+            present.  This comment is not interpreted; it is only
+            intended for human consumption.  The comment must consist of
+            ISO 8859-1 (LATIN-1) characters.  Line breaks should be
+            denoted by a single line feed character (10 decimal).
+
+            Reserved FLG bits must be zero.
+
+         MTIME (Modification TIME)
+            This gives the most recent modification time of the original
+            file being compressed.  The time is in Unix format, i.e.,
+            seconds since 00:00:00 GMT, Jan.  1, 1970.  (Note that this
+            may cause problems for MS-DOS and other systems that use
+            local rather than Universal time.)  If the compressed data
+            did not come from a file, MTIME is set to the time at which
+            compression started.  MTIME = 0 means no time stamp is
+            available.
+
+         XFL (eXtra FLags)
+            These flags are available for use by specific compression
+            methods.  The "deflate" method (CM = 8) sets these flags as
+            follows:
+
+               XFL = 2 - compressor used maximum compression,
+                         slowest algorithm
+               XFL = 4 - compressor used fastest algorithm
+
+         OS (Operating System)
+            This identifies the type of file system on which compression
+            took place.  This may be useful in determining end-of-line
+            convention for text files.  The currently defined values are
+            as follows:
+
+
+
+
+
+
+Deutsch                      Informational                      [Page 7]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+                 0 - FAT filesystem (MS-DOS, OS/2, NT/Win32)
+                 1 - Amiga
+                 2 - VMS (or OpenVMS)
+                 3 - Unix
+                 4 - VM/CMS
+                 5 - Atari TOS
+                 6 - HPFS filesystem (OS/2, NT)
+                 7 - Macintosh
+                 8 - Z-System
+                 9 - CP/M
+                10 - TOPS-20
+                11 - NTFS filesystem (NT)
+                12 - QDOS
+                13 - Acorn RISCOS
+               255 - unknown
+
+         XLEN (eXtra LENgth)
+            If FLG.FEXTRA is set, this gives the length of the optional
+            extra field.  See below for details.
+
+         CRC32 (CRC-32)
+            This contains a Cyclic Redundancy Check value of the
+            uncompressed data computed according to CRC-32 algorithm
+            used in the ISO 3309 standard and in section 8.1.1.6.2 of
+            ITU-T recommendation V.42.  (See http://www.iso.ch for
+            ordering ISO documents. See gopher://info.itu.ch for an
+            online version of ITU-T V.42.)
+
+         ISIZE (Input SIZE)
+            This contains the size of the original (uncompressed) input
+            data modulo 2^32.
+
+      2.3.1.1. Extra field
+
+         If the FLG.FEXTRA bit is set, an "extra field" is present in
+         the header, with total length XLEN bytes.  It consists of a
+         series of subfields, each of the form:
+
+            +---+---+---+---+==================================+
+            |SI1|SI2|  LEN  |... LEN bytes of subfield data ...|
+            +---+---+---+---+==================================+
+
+         SI1 and SI2 provide a subfield ID, typically two ASCII letters
+         with some mnemonic value.  Jean-Loup Gailly
+         <gzip@prep.ai.mit.edu> is maintaining a registry of subfield
+         IDs; please send him any subfield ID you wish to use.  Subfield
+         IDs with SI2 = 0 are reserved for future use.  The following
+         IDs are currently defined:
+
+
+
+Deutsch                      Informational                      [Page 8]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+            SI1         SI2         Data
+            ----------  ----------  ----
+            0x41 ('A')  0x70 ('P')  Apollo file type information
+
+         LEN gives the length of the subfield data, excluding the 4
+         initial bytes.
+
+      2.3.1.2. Compliance
+
+         A compliant compressor must produce files with correct ID1,
+         ID2, CM, CRC32, and ISIZE, but may set all the other fields in
+         the fixed-length part of the header to default values (255 for
+         OS, 0 for all others).  The compressor must set all reserved
+         bits to zero.
+
+         A compliant decompressor must check ID1, ID2, and CM, and
+         provide an error indication if any of these have incorrect
+         values.  It must examine FEXTRA/XLEN, FNAME, FCOMMENT and FHCRC
+         at least so it can skip over the optional fields if they are
+         present.  It need not examine any other part of the header or
+         trailer; in particular, a decompressor may ignore FTEXT and OS
+         and always produce binary output, and still be compliant.  A
+         compliant decompressor must give an error indication if any
+         reserved bit is non-zero, since such a bit could indicate the
+         presence of a new field that would cause subsequent data to be
+         interpreted incorrectly.
+
+3. References
+
+   [1] "Information Processing - 8-bit single-byte coded graphic
+       character sets - Part 1: Latin alphabet No.1" (ISO 8859-1:1987).
+       The ISO 8859-1 (Latin-1) character set is a superset of 7-bit
+       ASCII. Files defining this character set are available as
+       iso_8859-1.* in ftp://ftp.uu.net/graphics/png/documents/
+
+   [2] ISO 3309
+
+   [3] ITU-T recommendation V.42
+
+   [4] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification",
+       available in ftp://ftp.uu.net/pub/archiving/zip/doc/
+
+   [5] Gailly, J.-L., GZIP documentation, available as gzip-*.tar in
+       ftp://prep.ai.mit.edu/pub/gnu/
+
+   [6] Sarwate, D.V., "Computation of Cyclic Redundancy Checks via Table
+       Look-Up", Communications of the ACM, 31(8), pp.1008-1013.
+
+
+
+
+Deutsch                      Informational                      [Page 9]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+   [7] Schwaderer, W.D., "CRC Calculation", April 85 PC Tech Journal,
+       pp.118-133.
+
+   [8] ftp://ftp.adelaide.edu.au/pub/rocksoft/papers/crc_v3.txt,
+       describing the CRC concept.
+
+4. Security Considerations
+
+   Any data compression method involves the reduction of redundancy in
+   the data.  Consequently, any corruption of the data is likely to have
+   severe effects and be difficult to correct.  Uncompressed text, on
+   the other hand, will probably still be readable despite the presence
+   of some corrupted bytes.
+
+   It is recommended that systems using this data format provide some
+   means of validating the integrity of the compressed data, such as by
+   setting and checking the CRC-32 check value.
+
+5. Acknowledgements
+
+   Trademarks cited in this document are the property of their
+   respective owners.
+
+   Jean-Loup Gailly designed the gzip format and wrote, with Mark Adler,
+   the related software described in this specification.  Glenn
+   Randers-Pehrson converted this document to RFC and HTML format.
+
+6. Author's Address
+
+   L. Peter Deutsch
+   Aladdin Enterprises
+   203 Santa Margarita Ave.
+   Menlo Park, CA 94025
+
+   Phone: (415) 322-0103 (AM only)
+   FAX:   (415) 322-1734
+   EMail: <ghost@aladdin.com>
+
+   Questions about the technical content of this specification can be
+   sent by email to:
+
+   Jean-Loup Gailly <gzip@prep.ai.mit.edu> and
+   Mark Adler <madler@alumni.caltech.edu>
+
+   Editorial comments on this specification can be sent by email to:
+
+   L. Peter Deutsch <ghost@aladdin.com> and
+   Glenn Randers-Pehrson <randeg@alumni.rpi.edu>
+
+
+
+Deutsch                      Informational                     [Page 10]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+7. Appendix: Jean-Loup Gailly's gzip utility
+
+   The most widely used implementation of gzip compression, and the
+   original documentation on which this specification is based, were
+   created by Jean-Loup Gailly <gzip@prep.ai.mit.edu>.  Since this
+   implementation is a de facto standard, we mention some more of its
+   features here.  Again, the material in this section is not part of
+   the specification per se, and implementations need not follow it to
+   be compliant.
+
+   When compressing or decompressing a file, gzip preserves the
+   protection, ownership, and modification time attributes on the local
+   file system, since there is no provision for representing protection
+   attributes in the gzip file format itself.  Since the file format
+   includes a modification time, the gzip decompressor provides a
+   command line switch that assigns the modification time from the file,
+   rather than the local modification time of the compressed input, to
+   the decompressed output.
+
+8. Appendix: Sample CRC Code
+
+   The following sample code represents a practical implementation of
+   the CRC (Cyclic Redundancy Check). (See also ISO 3309 and ITU-T V.42
+   for a formal specification.)
+
+   The sample code is in the ANSI C programming language. Non C users
+   may find it easier to read with these hints:
+
+      &      Bitwise AND operator.
+      ^      Bitwise exclusive-OR operator.
+      >>     Bitwise right shift operator. When applied to an
+             unsigned quantity, as here, right shift inserts zero
+             bit(s) at the left.
+      !      Logical NOT operator.
+      ++     "n++" increments the variable n.
+      0xNNN  0x introduces a hexadecimal (base 16) constant.
+             Suffix L indicates a long value (at least 32 bits).
+
+      /* Table of CRCs of all 8-bit messages. */
+      unsigned long crc_table[256];
+
+      /* Flag: has the table been computed? Initially false. */
+      int crc_table_computed = 0;
+
+      /* Make the table for a fast CRC. */
+      void make_crc_table(void)
+      {
+        unsigned long c;
+
+
+
+Deutsch                      Informational                     [Page 11]
+\f
+RFC 1952             GZIP File Format Specification             May 1996
+
+
+        int n, k;
+        for (n = 0; n < 256; n++) {
+          c = (unsigned long) n;
+          for (k = 0; k < 8; k++) {
+            if (c & 1) {
+              c = 0xedb88320L ^ (c >> 1);
+            } else {
+              c = c >> 1;
+            }
+          }
+          crc_table[n] = c;
+        }
+        crc_table_computed = 1;
+      }
+
+      /*
+         Update a running crc with the bytes buf[0..len-1] and return
+       the updated crc. The crc should be initialized to zero. Pre- and
+       post-conditioning (one's complement) is performed within this
+       function so it shouldn't be done by the caller. Usage example:
+
+         unsigned long crc = 0L;
+
+         while (read_buffer(buffer, length) != EOF) {
+           crc = update_crc(crc, buffer, length);
+         }
+         if (crc != original_crc) error();
+      */
+      unsigned long update_crc(unsigned long crc,
+                      unsigned char *buf, int len)
+      {
+        unsigned long c = crc ^ 0xffffffffL;
+        int n;
+
+        if (!crc_table_computed)
+          make_crc_table();
+        for (n = 0; n < len; n++) {
+          c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+        }
+        return c ^ 0xffffffffL;
+      }
+
+      /* Return the CRC of the bytes buf[0..len-1]. */
+      unsigned long crc(unsigned char *buf, int len)
+      {
+        return update_crc(0L, buf, len);
+      }
+
+
+
+
+Deutsch                      Informational                     [Page 12]
+\f
diff --git a/deps/libchdr/deps/zlib-1.2.11/doc/txtvsbin.txt b/deps/libchdr/deps/zlib-1.2.11/doc/txtvsbin.txt
new file mode 100644 (file)
index 0000000..3d0f063
--- /dev/null
@@ -0,0 +1,107 @@
+A Fast Method for Identifying Plain Text Files
+==============================================
+
+
+Introduction
+------------
+
+Given a file coming from an unknown source, it is sometimes desirable
+to find out whether the format of that file is plain text.  Although
+this may appear like a simple task, a fully accurate detection of the
+file type requires heavy-duty semantic analysis on the file contents.
+It is, however, possible to obtain satisfactory results by employing
+various heuristics.
+
+Previous versions of PKZip and other zip-compatible compression tools
+were using a crude detection scheme: if more than 80% (4/5) of the bytes
+found in a certain buffer are within the range [7..127], the file is
+labeled as plain text, otherwise it is labeled as binary.  A prominent
+limitation of this scheme is the restriction to Latin-based alphabets.
+Other alphabets, like Greek, Cyrillic or Asian, make extensive use of
+the bytes within the range [128..255], and texts using these alphabets
+are most often misidentified by this scheme; in other words, the rate
+of false negatives is sometimes too high, which means that the recall
+is low.  Another weakness of this scheme is a reduced precision, due to
+the false positives that may occur when binary files containing large
+amounts of textual characters are misidentified as plain text.
+
+In this article we propose a new, simple detection scheme that features
+a much increased precision and a near-100% recall.  This scheme is
+designed to work on ASCII, Unicode and other ASCII-derived alphabets,
+and it handles single-byte encodings (ISO-8859, MacRoman, KOI8, etc.)
+and variable-sized encodings (ISO-2022, UTF-8, etc.).  Wider encodings
+(UCS-2/UTF-16 and UCS-4/UTF-32) are not handled, however.
+
+
+The Algorithm
+-------------
+
+The algorithm works by dividing the set of bytecodes [0..255] into three
+categories:
+- The white list of textual bytecodes:
+  9 (TAB), 10 (LF), 13 (CR), 32 (SPACE) to 255.
+- The gray list of tolerated bytecodes:
+  7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), 27 (ESC).
+- The black list of undesired, non-textual bytecodes:
+  0 (NUL) to 6, 14 to 31.
+
+If a file contains at least one byte that belongs to the white list and
+no byte that belongs to the black list, then the file is categorized as
+plain text; otherwise, it is categorized as binary.  (The boundary case,
+when the file is empty, automatically falls into the latter category.)
+
+
+Rationale
+---------
+
+The idea behind this algorithm relies on two observations.
+
+The first observation is that, although the full range of 7-bit codes
+[0..127] is properly specified by the ASCII standard, most control
+characters in the range [0..31] are not used in practice.  The only
+widely-used, almost universally-portable control codes are 9 (TAB),
+10 (LF) and 13 (CR).  There are a few more control codes that are
+recognized on a reduced range of platforms and text viewers/editors:
+7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB) and 27 (ESC); but these
+codes are rarely (if ever) used alone, without being accompanied by
+some printable text.  Even the newer, portable text formats such as
+XML avoid using control characters outside the list mentioned here.
+
+The second observation is that most of the binary files tend to contain
+control characters, especially 0 (NUL).  Even though the older text
+detection schemes observe the presence of non-ASCII codes from the range
+[128..255], the precision rarely has to suffer if this upper range is
+labeled as textual, because the files that are genuinely binary tend to
+contain both control characters and codes from the upper range.  On the
+other hand, the upper range needs to be labeled as textual, because it
+is used by virtually all ASCII extensions.  In particular, this range is
+used for encoding non-Latin scripts.
+
+Since there is no counting involved, other than simply observing the
+presence or the absence of some byte values, the algorithm produces
+consistent results, regardless what alphabet encoding is being used.
+(If counting were involved, it could be possible to obtain different
+results on a text encoded, say, using ISO-8859-16 versus UTF-8.)
+
+There is an extra category of plain text files that are "polluted" with
+one or more black-listed codes, either by mistake or by peculiar design
+considerations.  In such cases, a scheme that tolerates a small fraction
+of black-listed codes would provide an increased recall (i.e. more true
+positives).  This, however, incurs a reduced precision overall, since
+false positives are more likely to appear in binary files that contain
+large chunks of textual data.  Furthermore, "polluted" plain text should
+be regarded as binary by general-purpose text detection schemes, because
+general-purpose text processing algorithms might not be applicable.
+Under this premise, it is safe to say that our detection method provides
+a near-100% recall.
+
+Experiments have been run on many files coming from various platforms
+and applications.  We tried plain text files, system logs, source code,
+formatted office documents, compiled object code, etc.  The results
+confirm the optimistic assumptions about the capabilities of this
+algorithm.
+
+
+--
+Cosmin Truta
+Last updated: 2006-May-28
diff --git a/deps/libchdr/deps/zlib-1.2.11/gzclose.c b/deps/libchdr/deps/zlib-1.2.11/gzclose.c
new file mode 100644 (file)
index 0000000..caeb99a
--- /dev/null
@@ -0,0 +1,25 @@
+/* gzclose.c -- zlib gzclose() function
+ * Copyright (C) 2004, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* gzclose() is in a separate file so that it is linked in only if it is used.
+   That way the other gzclose functions can be used instead to avoid linking in
+   unneeded compression or decompression routines. */
+int ZEXPORT gzclose(file)
+    gzFile file;
+{
+#ifndef NO_GZCOMPRESS
+    gz_statep state;
+
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file);
+#else
+    return gzclose_r(file);
+#endif
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/gzguts.h b/deps/libchdr/deps/zlib-1.2.11/gzguts.h
new file mode 100644 (file)
index 0000000..45be573
--- /dev/null
@@ -0,0 +1,222 @@
+/* gzguts.h -- zlib internal header definitions for gz* operations
+ * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#ifndef _WIN32
+#  include <unistd.h>
+#endif
+
+#ifdef _LARGEFILE64_SOURCE
+#  ifndef _LARGEFILE_SOURCE
+#    define _LARGEFILE_SOURCE 1
+#  endif
+#  ifdef _FILE_OFFSET_BITS
+#    undef _FILE_OFFSET_BITS
+#  endif
+#endif
+
+#ifdef HAVE_HIDDEN
+#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+#  define ZLIB_INTERNAL
+#endif
+
+#include <stdio.h>
+#include "zlib.h"
+#ifdef STDC
+#  include <string.h>
+#  include <stdlib.h>
+#  include <limits.h>
+#endif
+
+#ifndef _POSIX_SOURCE
+#  define _POSIX_SOURCE
+#endif
+#include <fcntl.h>
+
+#ifdef _WIN32
+#  include <stddef.h>
+#endif
+
+#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32)
+#  include <io.h>
+#endif
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+#  define WIDECHAR
+#endif
+
+#ifdef WINAPI_FAMILY
+#  define open _open
+#  define read _read
+#  define write _write
+#  define close _close
+#endif
+
+#ifdef NO_DEFLATE       /* for compatibility with old definition */
+#  define NO_GZCOMPRESS
+#endif
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+
+#if defined(__CYGWIN__)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+
+#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410)
+#  ifndef HAVE_VSNPRINTF
+#    define HAVE_VSNPRINTF
+#  endif
+#endif
+
+#ifndef HAVE_VSNPRINTF
+#  ifdef MSDOS
+/* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+   but for now we just assume it doesn't. */
+#    define NO_vsnprintf
+#  endif
+#  ifdef __TURBOC__
+#    define NO_vsnprintf
+#  endif
+#  ifdef WIN32
+/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+#    if !defined(vsnprintf) && !defined(NO_vsnprintf)
+#      if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )
+#         define vsnprintf _vsnprintf
+#      endif
+#    endif
+#  endif
+#  ifdef __SASC
+#    define NO_vsnprintf
+#  endif
+#  ifdef VMS
+#    define NO_vsnprintf
+#  endif
+#  ifdef __OS400__
+#    define NO_vsnprintf
+#  endif
+#  ifdef __MVS__
+#    define NO_vsnprintf
+#  endif
+#endif
+
+/* unlike snprintf (which is required in C99), _snprintf does not guarantee
+   null termination of the result -- however this is only used in gzlib.c where
+   the result is assured to fit in the space provided */
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#  define snprintf _snprintf
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* since "static" is used to mean two completely different things in C, we
+   define "local" for the non-static meaning of "static", for readability
+   (compile with -Dlocal if your debugger can't find static symbols) */
+
+/* gz* functions always use library allocation functions */
+#ifndef STDC
+  extern voidp  malloc OF((uInt size));
+  extern void   free   OF((voidpf ptr));
+#endif
+
+/* get errno and strerror definition */
+#if defined UNDER_CE
+#  include <windows.h>
+#  define zstrerror() gz_strwinerror((DWORD)GetLastError())
+#else
+#  ifndef NO_STRERROR
+#    include <errno.h>
+#    define zstrerror() strerror(errno)
+#  else
+#    define zstrerror() "stdio error (consult errno)"
+#  endif
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
+    ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+    ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+    ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+    ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+#endif
+
+/* default memLevel */
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+
+/* default i/o buffer size -- double this for output when reading (this and
+   twice this must be able to fit in an unsigned type) */
+#define GZBUFSIZE 8192
+
+/* gzip modes, also provide a little integrity check on the passed structure */
+#define GZ_NONE 0
+#define GZ_READ 7247
+#define GZ_WRITE 31153
+#define GZ_APPEND 1     /* mode set to GZ_WRITE after the file is opened */
+
+/* values for gz_state how */
+#define LOOK 0      /* look for a gzip header */
+#define COPY 1      /* copy input directly */
+#define GZIP 2      /* decompress a gzip stream */
+
+/* internal gzip file state data structure */
+typedef struct {
+        /* exposed contents for gzgetc() macro */
+    struct gzFile_s x;      /* "x" for exposed */
+                            /* x.have: number of bytes available at x.next */
+                            /* x.next: next output data to deliver or write */
+                            /* x.pos: current position in uncompressed data */
+        /* used for both reading and writing */
+    int mode;               /* see gzip modes above */
+    int fd;                 /* file descriptor */
+    char *path;             /* path or fd for error messages */
+    unsigned size;          /* buffer size, zero if not allocated yet */
+    unsigned want;          /* requested buffer size, default is GZBUFSIZE */
+    unsigned char *in;      /* input buffer (double-sized when writing) */
+    unsigned char *out;     /* output buffer (double-sized when reading) */
+    int direct;             /* 0 if processing gzip, 1 if transparent */
+        /* just for reading */
+    int how;                /* 0: get header, 1: copy, 2: decompress */
+    z_off64_t start;        /* where the gzip data started, for rewinding */
+    int eof;                /* true if end of input file reached */
+    int past;               /* true if read requested past end */
+        /* just for writing */
+    int level;              /* compression level */
+    int strategy;           /* compression strategy */
+        /* seek request */
+    z_off64_t skip;         /* amount to skip (already rewound if backwards) */
+    int seek;               /* true if seek request pending */
+        /* error information */
+    int err;                /* error code */
+    char *msg;              /* error message */
+        /* zlib inflate or deflate stream */
+    z_stream strm;          /* stream structure in-place (not a pointer) */
+} gz_state;
+typedef gz_state FAR *gz_statep;
+
+/* shared functions */
+void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
+#if defined UNDER_CE
+char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
+#endif
+
+/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
+   value -- needed when comparing unsigned to z_off64_t, which is signed
+   (possible z_off64_t types off_t, off64_t, and long are all signed) */
+#ifdef INT_MAX
+#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
+#else
+unsigned ZLIB_INTERNAL gz_intmax OF((void));
+#  define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
+#endif
diff --git a/deps/libchdr/deps/zlib-1.2.11/gzlib.c b/deps/libchdr/deps/zlib-1.2.11/gzlib.c
new file mode 100644 (file)
index 0000000..4105e6a
--- /dev/null
@@ -0,0 +1,637 @@
+/* gzlib.c -- zlib functions common to reading and writing gzip files
+ * Copyright (C) 2004-2017 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+#if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__)
+#  define LSEEK _lseeki64
+#else
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+#  define LSEEK lseek64
+#else
+#  define LSEEK lseek
+#endif
+#endif
+
+/* Local functions */
+local void gz_reset OF((gz_statep));
+local gzFile gz_open OF((const void *, int, const char *));
+
+#if defined UNDER_CE
+
+/* Map the Windows error number in ERROR to a locale-dependent error message
+   string and return a pointer to it.  Typically, the values for ERROR come
+   from GetLastError.
+
+   The string pointed to shall not be modified by the application, but may be
+   overwritten by a subsequent call to gz_strwinerror
+
+   The gz_strwinerror function does not change the current setting of
+   GetLastError. */
+char ZLIB_INTERNAL *gz_strwinerror (error)
+     DWORD error;
+{
+    static char buf[1024];
+
+    wchar_t *msgbuf;
+    DWORD lasterr = GetLastError();
+    DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
+        | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+        NULL,
+        error,
+        0, /* Default language */
+        (LPVOID)&msgbuf,
+        0,
+        NULL);
+    if (chars != 0) {
+        /* If there is an \r\n appended, zap it.  */
+        if (chars >= 2
+            && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') {
+            chars -= 2;
+            msgbuf[chars] = 0;
+        }
+
+        if (chars > sizeof (buf) - 1) {
+            chars = sizeof (buf) - 1;
+            msgbuf[chars] = 0;
+        }
+
+        wcstombs(buf, msgbuf, chars + 1);
+        LocalFree(msgbuf);
+    }
+    else {
+        sprintf(buf, "unknown win32 error (%ld)", error);
+    }
+
+    SetLastError(lasterr);
+    return buf;
+}
+
+#endif /* UNDER_CE */
+
+/* Reset gzip file state */
+local void gz_reset(state)
+    gz_statep state;
+{
+    state->x.have = 0;              /* no output data available */
+    if (state->mode == GZ_READ) {   /* for reading ... */
+        state->eof = 0;             /* not at end of file */
+        state->past = 0;            /* have not read past end yet */
+        state->how = LOOK;          /* look for gzip header */
+    }
+    state->seek = 0;                /* no seek request pending */
+    gz_error(state, Z_OK, NULL);    /* clear error */
+    state->x.pos = 0;               /* no uncompressed data yet */
+    state->strm.avail_in = 0;       /* no input data yet */
+}
+
+/* Open a gzip file either by name or file descriptor. */
+local gzFile gz_open(path, fd, mode)
+    const void *path;
+    int fd;
+    const char *mode;
+{
+    gz_statep state;
+    z_size_t len;
+    int oflag;
+#ifdef O_CLOEXEC
+    int cloexec = 0;
+#endif
+#ifdef O_EXCL
+    int exclusive = 0;
+#endif
+
+    /* check input */
+    if (path == NULL)
+        return NULL;
+
+    /* allocate gzFile structure to return */
+    state = (gz_statep)malloc(sizeof(gz_state));
+    if (state == NULL)
+        return NULL;
+    state->size = 0;            /* no buffers allocated yet */
+    state->want = GZBUFSIZE;    /* requested buffer size */
+    state->msg = NULL;          /* no error message yet */
+
+    /* interpret mode */
+    state->mode = GZ_NONE;
+    state->level = Z_DEFAULT_COMPRESSION;
+    state->strategy = Z_DEFAULT_STRATEGY;
+    state->direct = 0;
+    while (*mode) {
+        if (*mode >= '0' && *mode <= '9')
+            state->level = *mode - '0';
+        else
+            switch (*mode) {
+            case 'r':
+                state->mode = GZ_READ;
+                break;
+#ifndef NO_GZCOMPRESS
+            case 'w':
+                state->mode = GZ_WRITE;
+                break;
+            case 'a':
+                state->mode = GZ_APPEND;
+                break;
+#endif
+            case '+':       /* can't read and write at the same time */
+                free(state);
+                return NULL;
+            case 'b':       /* ignore -- will request binary anyway */
+                break;
+#ifdef O_CLOEXEC
+            case 'e':
+                cloexec = 1;
+                break;
+#endif
+#ifdef O_EXCL
+            case 'x':
+                exclusive = 1;
+                break;
+#endif
+            case 'f':
+                state->strategy = Z_FILTERED;
+                break;
+            case 'h':
+                state->strategy = Z_HUFFMAN_ONLY;
+                break;
+            case 'R':
+                state->strategy = Z_RLE;
+                break;
+            case 'F':
+                state->strategy = Z_FIXED;
+                break;
+            case 'T':
+                state->direct = 1;
+                break;
+            default:        /* could consider as an error, but just ignore */
+                ;
+            }
+        mode++;
+    }
+
+    /* must provide an "r", "w", or "a" */
+    if (state->mode == GZ_NONE) {
+        free(state);
+        return NULL;
+    }
+
+    /* can't force transparent read */
+    if (state->mode == GZ_READ) {
+        if (state->direct) {
+            free(state);
+            return NULL;
+        }
+        state->direct = 1;      /* for empty file */
+    }
+
+    /* save the path name for error messages */
+#ifdef WIDECHAR
+    if (fd == -2) {
+        len = wcstombs(NULL, path, 0);
+        if (len == (z_size_t)-1)
+            len = 0;
+    }
+    else
+#endif
+        len = strlen((const char *)path);
+    state->path = (char *)malloc(len + 1);
+    if (state->path == NULL) {
+        free(state);
+        return NULL;
+    }
+#ifdef WIDECHAR
+    if (fd == -2)
+        if (len)
+            wcstombs(state->path, path, len + 1);
+        else
+            *(state->path) = 0;
+    else
+#endif
+#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
+        (void)snprintf(state->path, len + 1, "%s", (const char *)path);
+#else
+        strcpy(state->path, path);
+#endif
+
+    /* compute the flags for open() */
+    oflag =
+#ifdef O_LARGEFILE
+        O_LARGEFILE |
+#endif
+#ifdef O_BINARY
+        O_BINARY |
+#endif
+#ifdef O_CLOEXEC
+        (cloexec ? O_CLOEXEC : 0) |
+#endif
+        (state->mode == GZ_READ ?
+         O_RDONLY :
+         (O_WRONLY | O_CREAT |
+#ifdef O_EXCL
+          (exclusive ? O_EXCL : 0) |
+#endif
+          (state->mode == GZ_WRITE ?
+           O_TRUNC :
+           O_APPEND)));
+
+    /* open the file with the appropriate flags (or just use fd) */
+    state->fd = fd > -1 ? fd : (
+#ifdef WIDECHAR
+        fd == -2 ? _wopen(path, oflag, 0666) :
+#endif
+        open((const char *)path, oflag, 0666));
+    if (state->fd == -1) {
+        free(state->path);
+        free(state);
+        return NULL;
+    }
+    if (state->mode == GZ_APPEND) {
+        LSEEK(state->fd, 0, SEEK_END);  /* so gzoffset() is correct */
+        state->mode = GZ_WRITE;         /* simplify later checks */
+    }
+
+    /* save the current position for rewinding (only if reading) */
+    if (state->mode == GZ_READ) {
+        state->start = LSEEK(state->fd, 0, SEEK_CUR);
+        if (state->start == -1) state->start = 0;
+    }
+
+    /* initialize stream */
+    gz_reset(state);
+
+    /* return stream */
+    return (gzFile)state;
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen(path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzopen64(path, mode)
+    const char *path;
+    const char *mode;
+{
+    return gz_open(path, -1, mode);
+}
+
+/* -- see zlib.h -- */
+gzFile ZEXPORT gzdopen(fd, mode)
+    int fd;
+    const char *mode;
+{
+    char *path;         /* identifier for error messages */
+    gzFile gz;
+
+    if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL)
+        return NULL;
+#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
+    (void)snprintf(path, 7 + 3 * sizeof(int), "<fd:%d>", fd);
+#else
+    sprintf(path, "<fd:%d>", fd);   /* for debugging */
+#endif
+    gz = gz_open(path, fd, mode);
+    free(path);
+    return gz;
+}
+
+/* -- see zlib.h -- */
+#ifdef WIDECHAR
+gzFile ZEXPORT gzopen_w(path, mode)
+    const wchar_t *path;
+    const char *mode;
+{
+    return gz_open(path, -2, mode);
+}
+#endif
+
+/* -- see zlib.h -- */
+int ZEXPORT gzbuffer(file, size)
+    gzFile file;
+    unsigned size;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* make sure we haven't already allocated memory */
+    if (state->size != 0)
+        return -1;
+
+    /* check and set requested size */
+    if ((size << 1) < size)
+        return -1;              /* need to be able to double it */
+    if (size < 2)
+        size = 2;               /* need two bytes to check magic header */
+    state->want = size;
+    return 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzrewind(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no error */
+    if (state->mode != GZ_READ ||
+            (state->err != Z_OK && state->err != Z_BUF_ERROR))
+        return -1;
+
+    /* back up and start over */
+    if (LSEEK(state->fd, state->start, SEEK_SET) == -1)
+        return -1;
+    gz_reset(state);
+    return 0;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzseek64(file, offset, whence)
+    gzFile file;
+    z_off64_t offset;
+    int whence;
+{
+    unsigned n;
+    z_off64_t ret;
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* check that there's no error */
+    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
+        return -1;
+
+    /* can only seek from start or relative to current position */
+    if (whence != SEEK_SET && whence != SEEK_CUR)
+        return -1;
+
+    /* normalize offset to a SEEK_CUR specification */
+    if (whence == SEEK_SET)
+        offset -= state->x.pos;
+    else if (state->seek)
+        offset += state->skip;
+    state->seek = 0;
+
+    /* if within raw area while reading, just go there */
+    if (state->mode == GZ_READ && state->how == COPY &&
+            state->x.pos + offset >= 0) {
+        ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
+        if (ret == -1)
+            return -1;
+        state->x.have = 0;
+        state->eof = 0;
+        state->past = 0;
+        state->seek = 0;
+        gz_error(state, Z_OK, NULL);
+        state->strm.avail_in = 0;
+        state->x.pos += offset;
+        return state->x.pos;
+    }
+
+    /* calculate skip amount, rewinding if needed for back seek when reading */
+    if (offset < 0) {
+        if (state->mode != GZ_READ)         /* writing -- can't go backwards */
+            return -1;
+        offset += state->x.pos;
+        if (offset < 0)                     /* before start of file! */
+            return -1;
+        if (gzrewind(file) == -1)           /* rewind, then skip to offset */
+            return -1;
+    }
+
+    /* if reading, skip what's in output buffer (one less gzgetc() check) */
+    if (state->mode == GZ_READ) {
+        n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ?
+            (unsigned)offset : state->x.have;
+        state->x.have -= n;
+        state->x.next += n;
+        state->x.pos += n;
+        offset -= n;
+    }
+
+    /* request skip (if not zero) */
+    if (offset) {
+        state->seek = 1;
+        state->skip = offset;
+    }
+    return state->x.pos + offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzseek(file, offset, whence)
+    gzFile file;
+    z_off_t offset;
+    int whence;
+{
+    z_off64_t ret;
+
+    ret = gzseek64(file, (z_off64_t)offset, whence);
+    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gztell64(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* return position */
+    return state->x.pos + (state->seek ? state->skip : 0);
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gztell(file)
+    gzFile file;
+{
+    z_off64_t ret;
+
+    ret = gztell64(file);
+    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+z_off64_t ZEXPORT gzoffset64(file)
+    gzFile file;
+{
+    z_off64_t offset;
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return -1;
+
+    /* compute and return effective offset in file */
+    offset = LSEEK(state->fd, 0, SEEK_CUR);
+    if (offset == -1)
+        return -1;
+    if (state->mode == GZ_READ)             /* reading */
+        offset -= state->strm.avail_in;     /* don't count buffered input */
+    return offset;
+}
+
+/* -- see zlib.h -- */
+z_off_t ZEXPORT gzoffset(file)
+    gzFile file;
+{
+    z_off64_t ret;
+
+    ret = gzoffset64(file);
+    return ret == (z_off_t)ret ? (z_off_t)ret : -1;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzeof(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return 0;
+
+    /* return end-of-file state */
+    return state->mode == GZ_READ ? state->past : 0;
+}
+
+/* -- see zlib.h -- */
+const char * ZEXPORT gzerror(file, errnum)
+    gzFile file;
+    int *errnum;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return NULL;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return NULL;
+
+    /* return error information */
+    if (errnum != NULL)
+        *errnum = state->err;
+    return state->err == Z_MEM_ERROR ? "out of memory" :
+                                       (state->msg == NULL ? "" : state->msg);
+}
+
+/* -- see zlib.h -- */
+void ZEXPORT gzclearerr(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure and check integrity */
+    if (file == NULL)
+        return;
+    state = (gz_statep)file;
+    if (state->mode != GZ_READ && state->mode != GZ_WRITE)
+        return;
+
+    /* clear error and end-of-file */
+    if (state->mode == GZ_READ) {
+        state->eof = 0;
+        state->past = 0;
+    }
+    gz_error(state, Z_OK, NULL);
+}
+
+/* Create an error message in allocated memory and set state->err and
+   state->msg accordingly.  Free any previous error message already there.  Do
+   not try to free or allocate space if the error is Z_MEM_ERROR (out of
+   memory).  Simply save the error message as a static string.  If there is an
+   allocation failure constructing the error message, then convert the error to
+   out of memory. */
+void ZLIB_INTERNAL gz_error(state, err, msg)
+    gz_statep state;
+    int err;
+    const char *msg;
+{
+    /* free previously allocated message and clear */
+    if (state->msg != NULL) {
+        if (state->err != Z_MEM_ERROR)
+            free(state->msg);
+        state->msg = NULL;
+    }
+
+    /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */
+    if (err != Z_OK && err != Z_BUF_ERROR)
+        state->x.have = 0;
+
+    /* set error code, and if no message, then done */
+    state->err = err;
+    if (msg == NULL)
+        return;
+
+    /* for an out of memory error, return literal string when requested */
+    if (err == Z_MEM_ERROR)
+        return;
+
+    /* construct error message with path */
+    if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) ==
+            NULL) {
+        state->err = Z_MEM_ERROR;
+        return;
+    }
+#if !defined(NO_snprintf) && !defined(NO_vsnprintf)
+    (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3,
+                   "%s%s%s", state->path, ": ", msg);
+#else
+    strcpy(state->msg, state->path);
+    strcat(state->msg, ": ");
+    strcat(state->msg, msg);
+#endif
+}
+
+#ifndef INT_MAX
+/* portably return maximum value for an int (when limits.h presumed not
+   available) -- we need to do this to cover cases where 2's complement not
+   used, since C standard permits 1's complement and sign-bit representations,
+   otherwise we could just use ((unsigned)-1) >> 1 */
+unsigned ZLIB_INTERNAL gz_intmax()
+{
+    unsigned p, q;
+
+    p = 1;
+    do {
+        q = p;
+        p <<= 1;
+        p++;
+    } while (p > q);
+    return q >> 1;
+}
+#endif
diff --git a/deps/libchdr/deps/zlib-1.2.11/gzread.c b/deps/libchdr/deps/zlib-1.2.11/gzread.c
new file mode 100644 (file)
index 0000000..956b91e
--- /dev/null
@@ -0,0 +1,654 @@
+/* gzread.c -- zlib functions for reading gzip files
+ * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
+local int gz_avail OF((gz_statep));
+local int gz_look OF((gz_statep));
+local int gz_decomp OF((gz_statep));
+local int gz_fetch OF((gz_statep));
+local int gz_skip OF((gz_statep, z_off64_t));
+local z_size_t gz_read OF((gz_statep, voidp, z_size_t));
+
+/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
+   state->fd, and update state->eof, state->err, and state->msg as appropriate.
+   This function needs to loop on read(), since read() is not guaranteed to
+   read the number of bytes requested, depending on the type of descriptor. */
+local int gz_load(state, buf, len, have)
+    gz_statep state;
+    unsigned char *buf;
+    unsigned len;
+    unsigned *have;
+{
+    int ret;
+    unsigned get, max = ((unsigned)-1 >> 2) + 1;
+
+    *have = 0;
+    do {
+        get = len - *have;
+        if (get > max)
+            get = max;
+        ret = read(state->fd, buf + *have, get);
+        if (ret <= 0)
+            break;
+        *have += (unsigned)ret;
+    } while (*have < len);
+    if (ret < 0) {
+        gz_error(state, Z_ERRNO, zstrerror());
+        return -1;
+    }
+    if (ret == 0)
+        state->eof = 1;
+    return 0;
+}
+
+/* Load up input buffer and set eof flag if last data loaded -- return -1 on
+   error, 0 otherwise.  Note that the eof flag is set when the end of the input
+   file is reached, even though there may be unused data in the buffer.  Once
+   that data has been used, no more attempts will be made to read the file.
+   If strm->avail_in != 0, then the current data is moved to the beginning of
+   the input buffer, and then the remainder of the buffer is loaded with the
+   available data from the input file. */
+local int gz_avail(state)
+    gz_statep state;
+{
+    unsigned got;
+    z_streamp strm = &(state->strm);
+
+    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
+        return -1;
+    if (state->eof == 0) {
+        if (strm->avail_in) {       /* copy what's there to the start */
+            unsigned char *p = state->in;
+            unsigned const char *q = strm->next_in;
+            unsigned n = strm->avail_in;
+            do {
+                *p++ = *q++;
+            } while (--n);
+        }
+        if (gz_load(state, state->in + strm->avail_in,
+                    state->size - strm->avail_in, &got) == -1)
+            return -1;
+        strm->avail_in += got;
+        strm->next_in = state->in;
+    }
+    return 0;
+}
+
+/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
+   If this is the first time in, allocate required memory.  state->how will be
+   left unchanged if there is no more input data available, will be set to COPY
+   if there is no gzip header and direct copying will be performed, or it will
+   be set to GZIP for decompression.  If direct copying, then leftover input
+   data from the input buffer will be copied to the output buffer.  In that
+   case, all further file reads will be directly to either the output buffer or
+   a user buffer.  If decompressing, the inflate state will be initialized.
+   gz_look() will return 0 on success or -1 on failure. */
+local int gz_look(state)
+    gz_statep state;
+{
+    z_streamp strm = &(state->strm);
+
+    /* allocate read buffers and inflate memory */
+    if (state->size == 0) {
+        /* allocate buffers */
+        state->in = (unsigned char *)malloc(state->want);
+        state->out = (unsigned char *)malloc(state->want << 1);
+        if (state->in == NULL || state->out == NULL) {
+            free(state->out);
+            free(state->in);
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+        state->size = state->want;
+
+        /* allocate inflate memory */
+        state->strm.zalloc = Z_NULL;
+        state->strm.zfree = Z_NULL;
+        state->strm.opaque = Z_NULL;
+        state->strm.avail_in = 0;
+        state->strm.next_in = Z_NULL;
+        if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
+            free(state->out);
+            free(state->in);
+            state->size = 0;
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+    }
+
+    /* get at least the magic bytes in the input buffer */
+    if (strm->avail_in < 2) {
+        if (gz_avail(state) == -1)
+            return -1;
+        if (strm->avail_in == 0)
+            return 0;
+    }
+
+    /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
+       a logical dilemma here when considering the case of a partially written
+       gzip file, to wit, if a single 31 byte is written, then we cannot tell
+       whether this is a single-byte file, or just a partially written gzip
+       file -- for here we assume that if a gzip file is being written, then
+       the header will be written in a single operation, so that reading a
+       single byte is sufficient indication that it is not a gzip file) */
+    if (strm->avail_in > 1 &&
+            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
+        inflateReset(strm);
+        state->how = GZIP;
+        state->direct = 0;
+        return 0;
+    }
+
+    /* no gzip header -- if we were decoding gzip before, then this is trailing
+       garbage.  Ignore the trailing garbage and finish. */
+    if (state->direct == 0) {
+        strm->avail_in = 0;
+        state->eof = 1;
+        state->x.have = 0;
+        return 0;
+    }
+
+    /* doing raw i/o, copy any leftover input to output -- this assumes that
+       the output buffer is larger than the input buffer, which also assures
+       space for gzungetc() */
+    state->x.next = state->out;
+    if (strm->avail_in) {
+        memcpy(state->x.next, strm->next_in, strm->avail_in);
+        state->x.have = strm->avail_in;
+        strm->avail_in = 0;
+    }
+    state->how = COPY;
+    state->direct = 1;
+    return 0;
+}
+
+/* Decompress from input to the provided next_out and avail_out in the state.
+   On return, state->x.have and state->x.next point to the just decompressed
+   data.  If the gzip stream completes, state->how is reset to LOOK to look for
+   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
+   on success, -1 on failure. */
+local int gz_decomp(state)
+    gz_statep state;
+{
+    int ret = Z_OK;
+    unsigned had;
+    z_streamp strm = &(state->strm);
+
+    /* fill output buffer up to end of deflate stream */
+    had = strm->avail_out;
+    do {
+        /* get more input for inflate() */
+        if (strm->avail_in == 0 && gz_avail(state) == -1)
+            return -1;
+        if (strm->avail_in == 0) {
+            gz_error(state, Z_BUF_ERROR, "unexpected end of file");
+            break;
+        }
+
+        /* decompress and handle errors */
+        ret = inflate(strm, Z_NO_FLUSH);
+        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
+            gz_error(state, Z_STREAM_ERROR,
+                     "internal error: inflate stream corrupt");
+            return -1;
+        }
+        if (ret == Z_MEM_ERROR) {
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
+            gz_error(state, Z_DATA_ERROR,
+                     strm->msg == NULL ? "compressed data error" : strm->msg);
+            return -1;
+        }
+    } while (strm->avail_out && ret != Z_STREAM_END);
+
+    /* update available output */
+    state->x.have = had - strm->avail_out;
+    state->x.next = strm->next_out - state->x.have;
+
+    /* if the gzip stream completed successfully, look for another */
+    if (ret == Z_STREAM_END)
+        state->how = LOOK;
+
+    /* good decompression */
+    return 0;
+}
+
+/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
+   Data is either copied from the input file or decompressed from the input
+   file depending on state->how.  If state->how is LOOK, then a gzip header is
+   looked for to determine whether to copy or decompress.  Returns -1 on error,
+   otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
+   end of the input file has been reached and all data has been processed.  */
+local int gz_fetch(state)
+    gz_statep state;
+{
+    z_streamp strm = &(state->strm);
+
+    do {
+        switch(state->how) {
+        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
+            if (gz_look(state) == -1)
+                return -1;
+            if (state->how == LOOK)
+                return 0;
+            break;
+        case COPY:      /* -> COPY */
+            if (gz_load(state, state->out, state->size << 1, &(state->x.have))
+                    == -1)
+                return -1;
+            state->x.next = state->out;
+            return 0;
+        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
+            strm->avail_out = state->size << 1;
+            strm->next_out = state->out;
+            if (gz_decomp(state) == -1)
+                return -1;
+        }
+    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
+    return 0;
+}
+
+/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
+local int gz_skip(state, len)
+    gz_statep state;
+    z_off64_t len;
+{
+    unsigned n;
+
+    /* skip over len bytes or reach end-of-file, whichever comes first */
+    while (len)
+        /* skip over whatever is in output buffer */
+        if (state->x.have) {
+            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
+                (unsigned)len : state->x.have;
+            state->x.have -= n;
+            state->x.next += n;
+            state->x.pos += n;
+            len -= n;
+        }
+
+        /* output buffer empty -- return if we're at the end of the input */
+        else if (state->eof && state->strm.avail_in == 0)
+            break;
+
+        /* need more data to skip -- load up output buffer */
+        else {
+            /* get more output, looking for header if required */
+            if (gz_fetch(state) == -1)
+                return -1;
+        }
+    return 0;
+}
+
+/* Read len bytes into buf from file, or less than len up to the end of the
+   input.  Return the number of bytes read.  If zero is returned, either the
+   end of file was reached, or there was an error.  state->err must be
+   consulted in that case to determine which. */
+local z_size_t gz_read(state, buf, len)
+    gz_statep state;
+    voidp buf;
+    z_size_t len;
+{
+    z_size_t got;
+    unsigned n;
+
+    /* if len is zero, avoid unnecessary operations */
+    if (len == 0)
+        return 0;
+
+    /* process a skip request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_skip(state, state->skip) == -1)
+            return 0;
+    }
+
+    /* get len bytes to buf, or less than len if at the end */
+    got = 0;
+    do {
+        /* set n to the maximum amount of len that fits in an unsigned int */
+        n = -1;
+        if (n > len)
+            n = len;
+
+        /* first just try copying data from the output buffer */
+        if (state->x.have) {
+            if (state->x.have < n)
+                n = state->x.have;
+            memcpy(buf, state->x.next, n);
+            state->x.next += n;
+            state->x.have -= n;
+        }
+
+        /* output buffer empty -- return if we're at the end of the input */
+        else if (state->eof && state->strm.avail_in == 0) {
+            state->past = 1;        /* tried to read past end */
+            break;
+        }
+
+        /* need output data -- for small len or new stream load up our output
+           buffer */
+        else if (state->how == LOOK || n < (state->size << 1)) {
+            /* get more output, looking for header if required */
+            if (gz_fetch(state) == -1)
+                return 0;
+            continue;       /* no progress yet -- go back to copy above */
+            /* the copy above assures that we will leave with space in the
+               output buffer, allowing at least one gzungetc() to succeed */
+        }
+
+        /* large len -- read directly into user buffer */
+        else if (state->how == COPY) {      /* read directly */
+            if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
+                return 0;
+        }
+
+        /* large len -- decompress directly into user buffer */
+        else {  /* state->how == GZIP */
+            state->strm.avail_out = n;
+            state->strm.next_out = (unsigned char *)buf;
+            if (gz_decomp(state) == -1)
+                return 0;
+            n = state->x.have;
+            state->x.have = 0;
+        }
+
+        /* update progress */
+        len -= n;
+        buf = (char *)buf + n;
+        got += n;
+        state->x.pos += n;
+    } while (len);
+
+    /* return number of bytes read into user buffer */
+    return got;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzread(file, buf, len)
+    gzFile file;
+    voidp buf;
+    unsigned len;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no (serious) error */
+    if (state->mode != GZ_READ ||
+            (state->err != Z_OK && state->err != Z_BUF_ERROR))
+        return -1;
+
+    /* since an int is returned, make sure len fits in one, otherwise return
+       with an error (this avoids a flaw in the interface) */
+    if ((int)len < 0) {
+        gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
+        return -1;
+    }
+
+    /* read len or fewer bytes to buf */
+    len = gz_read(state, buf, len);
+
+    /* check for an error */
+    if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
+        return -1;
+
+    /* return the number of bytes read (this is assured to fit in an int) */
+    return (int)len;
+}
+
+/* -- see zlib.h -- */
+z_size_t ZEXPORT gzfread(buf, size, nitems, file)
+    voidp buf;
+    z_size_t size;
+    z_size_t nitems;
+    gzFile file;
+{
+    z_size_t len;
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no (serious) error */
+    if (state->mode != GZ_READ ||
+            (state->err != Z_OK && state->err != Z_BUF_ERROR))
+        return 0;
+
+    /* compute bytes to read -- error on overflow */
+    len = nitems * size;
+    if (size && len / size != nitems) {
+        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
+        return 0;
+    }
+
+    /* read len or fewer bytes to buf, return the number of full items read */
+    return len ? gz_read(state, buf, len) / size : 0;
+}
+
+/* -- see zlib.h -- */
+#ifdef Z_PREFIX_SET
+#  undef z_gzgetc
+#else
+#  undef gzgetc
+#endif
+int ZEXPORT gzgetc(file)
+    gzFile file;
+{
+    int ret;
+    unsigned char buf[1];
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no (serious) error */
+    if (state->mode != GZ_READ ||
+        (state->err != Z_OK && state->err != Z_BUF_ERROR))
+        return -1;
+
+    /* try output buffer (no need to check for skip request) */
+    if (state->x.have) {
+        state->x.have--;
+        state->x.pos++;
+        return *(state->x.next)++;
+    }
+
+    /* nothing there -- try gz_read() */
+    ret = gz_read(state, buf, 1);
+    return ret < 1 ? -1 : buf[0];
+}
+
+int ZEXPORT gzgetc_(file)
+gzFile file;
+{
+    return gzgetc(file);
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzungetc(c, file)
+    int c;
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no (serious) error */
+    if (state->mode != GZ_READ ||
+        (state->err != Z_OK && state->err != Z_BUF_ERROR))
+        return -1;
+
+    /* process a skip request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_skip(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* can't push EOF */
+    if (c < 0)
+        return -1;
+
+    /* if output buffer empty, put byte at end (allows more pushing) */
+    if (state->x.have == 0) {
+        state->x.have = 1;
+        state->x.next = state->out + (state->size << 1) - 1;
+        state->x.next[0] = (unsigned char)c;
+        state->x.pos--;
+        state->past = 0;
+        return c;
+    }
+
+    /* if no room, give up (must have already done a gzungetc()) */
+    if (state->x.have == (state->size << 1)) {
+        gz_error(state, Z_DATA_ERROR, "out of room to push characters");
+        return -1;
+    }
+
+    /* slide output data if needed and insert byte before existing data */
+    if (state->x.next == state->out) {
+        unsigned char *src = state->out + state->x.have;
+        unsigned char *dest = state->out + (state->size << 1);
+        while (src > state->out)
+            *--dest = *--src;
+        state->x.next = dest;
+    }
+    state->x.have++;
+    state->x.next--;
+    state->x.next[0] = (unsigned char)c;
+    state->x.pos--;
+    state->past = 0;
+    return c;
+}
+
+/* -- see zlib.h -- */
+char * ZEXPORT gzgets(file, buf, len)
+    gzFile file;
+    char *buf;
+    int len;
+{
+    unsigned left, n;
+    char *str;
+    unsigned char *eol;
+    gz_statep state;
+
+    /* check parameters and get internal structure */
+    if (file == NULL || buf == NULL || len < 1)
+        return NULL;
+    state = (gz_statep)file;
+
+    /* check that we're reading and that there's no (serious) error */
+    if (state->mode != GZ_READ ||
+        (state->err != Z_OK && state->err != Z_BUF_ERROR))
+        return NULL;
+
+    /* process a skip request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_skip(state, state->skip) == -1)
+            return NULL;
+    }
+
+    /* copy output bytes up to new line or len - 1, whichever comes first --
+       append a terminating zero to the string (we don't check for a zero in
+       the contents, let the user worry about that) */
+    str = buf;
+    left = (unsigned)len - 1;
+    if (left) do {
+        /* assure that something is in the output buffer */
+        if (state->x.have == 0 && gz_fetch(state) == -1)
+            return NULL;                /* error */
+        if (state->x.have == 0) {       /* end of file */
+            state->past = 1;            /* read past end */
+            break;                      /* return what we have */
+        }
+
+        /* look for end-of-line in current output buffer */
+        n = state->x.have > left ? left : state->x.have;
+        eol = (unsigned char *)memchr(state->x.next, '\n', n);
+        if (eol != NULL)
+            n = (unsigned)(eol - state->x.next) + 1;
+
+        /* copy through end-of-line, or remainder if not found */
+        memcpy(buf, state->x.next, n);
+        state->x.have -= n;
+        state->x.next += n;
+        state->x.pos += n;
+        left -= n;
+        buf += n;
+    } while (left && eol == NULL);
+
+    /* return terminated string, or if nothing, end of file */
+    if (buf == str)
+        return NULL;
+    buf[0] = 0;
+    return str;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzdirect(file)
+    gzFile file;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+
+    /* if the state is not known, but we can find out, then do so (this is
+       mainly for right after a gzopen() or gzdopen()) */
+    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
+        (void)gz_look(state);
+
+    /* return 1 if transparent, 0 if processing a gzip stream */
+    return state->direct;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_r(file)
+    gzFile file;
+{
+    int ret, err;
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    /* check that we're reading */
+    if (state->mode != GZ_READ)
+        return Z_STREAM_ERROR;
+
+    /* free memory and close file */
+    if (state->size) {
+        inflateEnd(&(state->strm));
+        free(state->out);
+        free(state->in);
+    }
+    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
+    gz_error(state, Z_OK, NULL);
+    free(state->path);
+    ret = close(state->fd);
+    free(state);
+    return ret ? Z_ERRNO : err;
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/gzwrite.c b/deps/libchdr/deps/zlib-1.2.11/gzwrite.c
new file mode 100644 (file)
index 0000000..c7b5651
--- /dev/null
@@ -0,0 +1,665 @@
+/* gzwrite.c -- zlib functions for writing gzip files
+ * Copyright (C) 2004-2017 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "gzguts.h"
+
+/* Local functions */
+local int gz_init OF((gz_statep));
+local int gz_comp OF((gz_statep, int));
+local int gz_zero OF((gz_statep, z_off64_t));
+local z_size_t gz_write OF((gz_statep, voidpc, z_size_t));
+
+/* Initialize state for writing a gzip file.  Mark initialization by setting
+   state->size to non-zero.  Return -1 on a memory allocation failure, or 0 on
+   success. */
+local int gz_init(state)
+    gz_statep state;
+{
+    int ret;
+    z_streamp strm = &(state->strm);
+
+    /* allocate input buffer (double size for gzprintf) */
+    state->in = (unsigned char *)malloc(state->want << 1);
+    if (state->in == NULL) {
+        gz_error(state, Z_MEM_ERROR, "out of memory");
+        return -1;
+    }
+
+    /* only need output buffer and deflate state if compressing */
+    if (!state->direct) {
+        /* allocate output buffer */
+        state->out = (unsigned char *)malloc(state->want);
+        if (state->out == NULL) {
+            free(state->in);
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+
+        /* allocate deflate memory, set up for gzip compression */
+        strm->zalloc = Z_NULL;
+        strm->zfree = Z_NULL;
+        strm->opaque = Z_NULL;
+        ret = deflateInit2(strm, state->level, Z_DEFLATED,
+                           MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
+        if (ret != Z_OK) {
+            free(state->out);
+            free(state->in);
+            gz_error(state, Z_MEM_ERROR, "out of memory");
+            return -1;
+        }
+        strm->next_in = NULL;
+    }
+
+    /* mark state as initialized */
+    state->size = state->want;
+
+    /* initialize write buffer if compressing */
+    if (!state->direct) {
+        strm->avail_out = state->size;
+        strm->next_out = state->out;
+        state->x.next = strm->next_out;
+    }
+    return 0;
+}
+
+/* Compress whatever is at avail_in and next_in and write to the output file.
+   Return -1 if there is an error writing to the output file or if gz_init()
+   fails to allocate memory, otherwise 0.  flush is assumed to be a valid
+   deflate() flush value.  If flush is Z_FINISH, then the deflate() state is
+   reset to start a new gzip stream.  If gz->direct is true, then simply write
+   to the output file without compressing, and ignore flush. */
+local int gz_comp(state, flush)
+    gz_statep state;
+    int flush;
+{
+    int ret, writ;
+    unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
+    z_streamp strm = &(state->strm);
+
+    /* allocate memory if this is the first time through */
+    if (state->size == 0 && gz_init(state) == -1)
+        return -1;
+
+    /* write directly if requested */
+    if (state->direct) {
+        while (strm->avail_in) {
+            put = strm->avail_in > max ? max : strm->avail_in;
+            writ = write(state->fd, strm->next_in, put);
+            if (writ < 0) {
+                gz_error(state, Z_ERRNO, zstrerror());
+                return -1;
+            }
+            strm->avail_in -= (unsigned)writ;
+            strm->next_in += writ;
+        }
+        return 0;
+    }
+
+    /* run deflate() on provided input until it produces no more output */
+    ret = Z_OK;
+    do {
+        /* write out current buffer contents if full, or if flushing, but if
+           doing Z_FINISH then don't write until we get to Z_STREAM_END */
+        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
+            (flush != Z_FINISH || ret == Z_STREAM_END))) {
+            while (strm->next_out > state->x.next) {
+                put = strm->next_out - state->x.next > (int)max ? max :
+                      (unsigned)(strm->next_out - state->x.next);
+                writ = write(state->fd, state->x.next, put);
+                if (writ < 0) {
+                    gz_error(state, Z_ERRNO, zstrerror());
+                    return -1;
+                }
+                state->x.next += writ;
+            }
+            if (strm->avail_out == 0) {
+                strm->avail_out = state->size;
+                strm->next_out = state->out;
+                state->x.next = state->out;
+            }
+        }
+
+        /* compress */
+        have = strm->avail_out;
+        ret = deflate(strm, flush);
+        if (ret == Z_STREAM_ERROR) {
+            gz_error(state, Z_STREAM_ERROR,
+                      "internal error: deflate stream corrupt");
+            return -1;
+        }
+        have -= strm->avail_out;
+    } while (have);
+
+    /* if that completed a deflate stream, allow another to start */
+    if (flush == Z_FINISH)
+        deflateReset(strm);
+
+    /* all done, no errors */
+    return 0;
+}
+
+/* Compress len zeros to output.  Return -1 on a write error or memory
+   allocation failure by gz_comp(), or 0 on success. */
+local int gz_zero(state, len)
+    gz_statep state;
+    z_off64_t len;
+{
+    int first;
+    unsigned n;
+    z_streamp strm = &(state->strm);
+
+    /* consume whatever's left in the input buffer */
+    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+        return -1;
+
+    /* compress len zeros (len guaranteed > 0) */
+    first = 1;
+    while (len) {
+        n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
+            (unsigned)len : state->size;
+        if (first) {
+            memset(state->in, 0, n);
+            first = 0;
+        }
+        strm->avail_in = n;
+        strm->next_in = state->in;
+        state->x.pos += n;
+        if (gz_comp(state, Z_NO_FLUSH) == -1)
+            return -1;
+        len -= n;
+    }
+    return 0;
+}
+
+/* Write len bytes from buf to file.  Return the number of bytes written.  If
+   the returned value is less than len, then there was an error. */
+local z_size_t gz_write(state, buf, len)
+    gz_statep state;
+    voidpc buf;
+    z_size_t len;
+{
+    z_size_t put = len;
+
+    /* if len is zero, avoid unnecessary operations */
+    if (len == 0)
+        return 0;
+
+    /* allocate memory if this is the first time through */
+    if (state->size == 0 && gz_init(state) == -1)
+        return 0;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return 0;
+    }
+
+    /* for small len, copy to input buffer, otherwise compress directly */
+    if (len < state->size) {
+        /* copy to input buffer, compress when full */
+        do {
+            unsigned have, copy;
+
+            if (state->strm.avail_in == 0)
+                state->strm.next_in = state->in;
+            have = (unsigned)((state->strm.next_in + state->strm.avail_in) -
+                              state->in);
+            copy = state->size - have;
+            if (copy > len)
+                copy = len;
+            memcpy(state->in + have, buf, copy);
+            state->strm.avail_in += copy;
+            state->x.pos += copy;
+            buf = (const char *)buf + copy;
+            len -= copy;
+            if (len && gz_comp(state, Z_NO_FLUSH) == -1)
+                return 0;
+        } while (len);
+    }
+    else {
+        /* consume whatever's left in the input buffer */
+        if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
+            return 0;
+
+        /* directly compress user buffer to file */
+        state->strm.next_in = (z_const Bytef *)buf;
+        do {
+            unsigned n = (unsigned)-1;
+            if (n > len)
+                n = len;
+            state->strm.avail_in = n;
+            state->x.pos += n;
+            if (gz_comp(state, Z_NO_FLUSH) == -1)
+                return 0;
+            len -= n;
+        } while (len);
+    }
+
+    /* input was all buffered or compressed */
+    return put;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzwrite(file, buf, len)
+    gzFile file;
+    voidpc buf;
+    unsigned len;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return 0;
+
+    /* since an int is returned, make sure len fits in one, otherwise return
+       with an error (this avoids a flaw in the interface) */
+    if ((int)len < 0) {
+        gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
+        return 0;
+    }
+
+    /* write len bytes from buf (the return value will fit in an int) */
+    return (int)gz_write(state, buf, len);
+}
+
+/* -- see zlib.h -- */
+z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
+    voidpc buf;
+    z_size_t size;
+    z_size_t nitems;
+    gzFile file;
+{
+    z_size_t len;
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return 0;
+    state = (gz_statep)file;
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return 0;
+
+    /* compute bytes to read -- error on overflow */
+    len = nitems * size;
+    if (size && len / size != nitems) {
+        gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
+        return 0;
+    }
+
+    /* write len bytes to buf, return the number of full items written */
+    return len ? gz_write(state, buf, len) / size : 0;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputc(file, c)
+    gzFile file;
+    int c;
+{
+    unsigned have;
+    unsigned char buf[1];
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return -1;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return -1;
+    }
+
+    /* try writing to input buffer for speed (state->size == 0 if buffer not
+       initialized) */
+    if (state->size) {
+        if (strm->avail_in == 0)
+            strm->next_in = state->in;
+        have = (unsigned)((strm->next_in + strm->avail_in) - state->in);
+        if (have < state->size) {
+            state->in[have] = (unsigned char)c;
+            strm->avail_in++;
+            state->x.pos++;
+            return c & 0xff;
+        }
+    }
+
+    /* no room in buffer or not initialized, use gz_write() */
+    buf[0] = (unsigned char)c;
+    if (gz_write(state, buf, 1) != 1)
+        return -1;
+    return c & 0xff;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzputs(file, str)
+    gzFile file;
+    const char *str;
+{
+    int ret;
+    z_size_t len;
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return -1;
+    state = (gz_statep)file;
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return -1;
+
+    /* write string */
+    len = strlen(str);
+    ret = gz_write(state, str, len);
+    return ret == 0 && len != 0 ? -1 : ret;
+}
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#include <stdarg.h>
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
+{
+    int len;
+    unsigned left;
+    char *next;
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return Z_STREAM_ERROR;
+
+    /* make sure we have some buffer space */
+    if (state->size == 0 && gz_init(state) == -1)
+        return state->err;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return state->err;
+    }
+
+    /* do the printf() into the input buffer, put length in len -- the input
+       buffer is double-sized just for this function, so there is guaranteed to
+       be state->size bytes available after the current contents */
+    if (strm->avail_in == 0)
+        strm->next_in = state->in;
+    next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in);
+    next[state->size - 1] = 0;
+#ifdef NO_vsnprintf
+#  ifdef HAS_vsprintf_void
+    (void)vsprintf(next, format, va);
+    for (len = 0; len < state->size; len++)
+        if (next[len] == 0) break;
+#  else
+    len = vsprintf(next, format, va);
+#  endif
+#else
+#  ifdef HAS_vsnprintf_void
+    (void)vsnprintf(next, state->size, format, va);
+    len = strlen(next);
+#  else
+    len = vsnprintf(next, state->size, format, va);
+#  endif
+#endif
+
+    /* check that printf() results fit in buffer */
+    if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0)
+        return 0;
+
+    /* update buffer and position, compress first half if past that */
+    strm->avail_in += (unsigned)len;
+    state->x.pos += len;
+    if (strm->avail_in >= state->size) {
+        left = strm->avail_in - state->size;
+        strm->avail_in = state->size;
+        if (gz_comp(state, Z_NO_FLUSH) == -1)
+            return state->err;
+        memcpy(state->in, state->in + state->size, left);
+        strm->next_in = state->in;
+        strm->avail_in = left;
+    }
+    return len;
+}
+
+int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
+{
+    va_list va;
+    int ret;
+
+    va_start(va, format);
+    ret = gzvprintf(file, format, va);
+    va_end(va);
+    return ret;
+}
+
+#else /* !STDC && !Z_HAVE_STDARG_H */
+
+/* -- see zlib.h -- */
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+    gzFile file;
+    const char *format;
+    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+    unsigned len, left;
+    char *next;
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that can really pass pointer in ints */
+    if (sizeof(int) != sizeof(void *))
+        return Z_STREAM_ERROR;
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return Z_STREAM_ERROR;
+
+    /* make sure we have some buffer space */
+    if (state->size == 0 && gz_init(state) == -1)
+        return state->error;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return state->error;
+    }
+
+    /* do the printf() into the input buffer, put length in len -- the input
+       buffer is double-sized just for this function, so there is guaranteed to
+       be state->size bytes available after the current contents */
+    if (strm->avail_in == 0)
+        strm->next_in = state->in;
+    next = (char *)(strm->next_in + strm->avail_in);
+    next[state->size - 1] = 0;
+#ifdef NO_snprintf
+#  ifdef HAS_sprintf_void
+    sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12,
+            a13, a14, a15, a16, a17, a18, a19, a20);
+    for (len = 0; len < size; len++)
+        if (next[len] == 0)
+            break;
+#  else
+    len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
+                  a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#else
+#  ifdef HAS_snprintf_void
+    snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9,
+             a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+    len = strlen(next);
+#  else
+    len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8,
+                   a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+#  endif
+#endif
+
+    /* check that printf() results fit in buffer */
+    if (len == 0 || len >= state->size || next[state->size - 1] != 0)
+        return 0;
+
+    /* update buffer and position, compress first half if past that */
+    strm->avail_in += len;
+    state->x.pos += len;
+    if (strm->avail_in >= state->size) {
+        left = strm->avail_in - state->size;
+        strm->avail_in = state->size;
+        if (gz_comp(state, Z_NO_FLUSH) == -1)
+            return state->err;
+        memcpy(state->in, state->in + state->size, left);
+        strm->next_in = state->in;
+        strm->avail_in = left;
+    }
+    return (int)len;
+}
+
+#endif
+
+/* -- see zlib.h -- */
+int ZEXPORT gzflush(file, flush)
+    gzFile file;
+    int flush;
+{
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return Z_STREAM_ERROR;
+
+    /* check flush parameter */
+    if (flush < 0 || flush > Z_FINISH)
+        return Z_STREAM_ERROR;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return state->err;
+    }
+
+    /* compress remaining data with requested flush */
+    (void)gz_comp(state, flush);
+    return state->err;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzsetparams(file, level, strategy)
+    gzFile file;
+    int level;
+    int strategy;
+{
+    gz_statep state;
+    z_streamp strm;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+    strm = &(state->strm);
+
+    /* check that we're writing and that there's no error */
+    if (state->mode != GZ_WRITE || state->err != Z_OK)
+        return Z_STREAM_ERROR;
+
+    /* if no change is requested, then do nothing */
+    if (level == state->level && strategy == state->strategy)
+        return Z_OK;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            return state->err;
+    }
+
+    /* change compression parameters for subsequent input */
+    if (state->size) {
+        /* flush previous input with previous parameters before changing */
+        if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1)
+            return state->err;
+        deflateParams(strm, level, strategy);
+    }
+    state->level = level;
+    state->strategy = strategy;
+    return Z_OK;
+}
+
+/* -- see zlib.h -- */
+int ZEXPORT gzclose_w(file)
+    gzFile file;
+{
+    int ret = Z_OK;
+    gz_statep state;
+
+    /* get internal structure */
+    if (file == NULL)
+        return Z_STREAM_ERROR;
+    state = (gz_statep)file;
+
+    /* check that we're writing */
+    if (state->mode != GZ_WRITE)
+        return Z_STREAM_ERROR;
+
+    /* check for seek request */
+    if (state->seek) {
+        state->seek = 0;
+        if (gz_zero(state, state->skip) == -1)
+            ret = state->err;
+    }
+
+    /* flush, free memory, and close file */
+    if (gz_comp(state, Z_FINISH) == -1)
+        ret = state->err;
+    if (state->size) {
+        if (!state->direct) {
+            (void)deflateEnd(&(state->strm));
+            free(state->out);
+        }
+        free(state->in);
+    }
+    gz_error(state, Z_OK, NULL);
+    free(state->path);
+    if (close(state->fd) == -1)
+        ret = Z_ERRNO;
+    free(state);
+    return ret;
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/infback.c b/deps/libchdr/deps/zlib-1.2.11/infback.c
new file mode 100644 (file)
index 0000000..59679ec
--- /dev/null
@@ -0,0 +1,640 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+   This code is largely copied from inflate.c.  Normally either infback.o or
+   inflate.o would be linked into an application--not both.  The interface
+   with inffast.c is retained so that optimized assembler-coded versions of
+   inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+   strm provides memory allocation functions in zalloc and zfree, or
+   Z_NULL to use the library memory allocation functions.
+
+   windowBits is in the range 8..15, and window is a user-supplied
+   window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL || window == Z_NULL ||
+        windowBits < 8 || windowBits > 15)
+        return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+#endif
+    }
+    if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+    strm->zfree = zcfree;
+#endif
+    state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+                                               sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->dmax = 32768U;
+    state->wbits = (uInt)windowBits;
+    state->wsize = 1U << windowBits;
+    state->window = window;
+    state->wnext = 0;
+    state->whave = 0;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Assure that some input is available.  If input is requested, but denied,
+   then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+    do { \
+        if (have == 0) { \
+            have = in(in_desc, &next); \
+            if (have == 0) { \
+                next = Z_NULL; \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+   with an error if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        PULL(); \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflateBack() with
+   an error. */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/* Assure that some output space is available, by writing out the window
+   if it's full.  If the write fails, return from inflateBack() with a
+   Z_BUF_ERROR. */
+#define ROOM() \
+    do { \
+        if (left == 0) { \
+            put = state->window; \
+            left = state->wsize; \
+            state->whave = left; \
+            if (out(out_desc, put, left)) { \
+                ret = Z_BUF_ERROR; \
+                goto inf_leave; \
+            } \
+        } \
+    } while (0)
+
+/*
+   strm provides the memory allocation functions and window buffer on input,
+   and provides information on the unused input on return.  For Z_DATA_ERROR
+   returns, strm will also provide an error message.
+
+   in() and out() are the call-back input and output functions.  When
+   inflateBack() needs more input, it calls in().  When inflateBack() has
+   filled the window with output, or when it completes with data in the
+   window, it calls out() to write out the data.  The application must not
+   change the provided input until in() is called again or inflateBack()
+   returns.  The application must not change the window/output buffer until
+   inflateBack() returns.
+
+   in() and out() are called with a descriptor parameter provided in the
+   inflateBack() call.  This parameter can be a structure that provides the
+   information required to do the read or write, as well as accumulated
+   information on the input and output such as totals and check values.
+
+   in() should return zero on failure.  out() should return non-zero on
+   failure.  If either in() or out() fails, than inflateBack() returns a
+   Z_BUF_ERROR.  strm->next_in can be checked for Z_NULL to see whether it
+   was in() or out() that caused in the error.  Otherwise,  inflateBack()
+   returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+   error, or Z_MEM_ERROR if it could not allocate memory for the state.
+   inflateBack() can also return Z_STREAM_ERROR if the input parameters
+   are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+    struct inflate_state FAR *state;
+    z_const unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code here;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    /* Check that the strm exists and that the state was initialized */
+    if (strm == Z_NULL || strm->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* Reset the state */
+    strm->msg = Z_NULL;
+    state->mode = TYPE;
+    state->last = 0;
+    state->whave = 0;
+    next = strm->next_in;
+    have = next != Z_NULL ? strm->avail_in : 0;
+    hold = 0;
+    bits = 0;
+    put = state->window;
+    left = state->wsize;
+
+    /* Inflate until end of block marked as last */
+    for (;;)
+        switch (state->mode) {
+        case TYPE:
+            /* determine and dispatch block type */
+            if (state->last) {
+                BYTEBITS();
+                state->mode = DONE;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN;              /* decode codes */
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+
+        case STORED:
+            /* get and verify stored block length */
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+
+            /* copy stored block from input to output */
+            while (state->length != 0) {
+                copy = state->length;
+                PULL();
+                ROOM();
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+
+        case TABLE:
+            /* get dynamic table entries descriptor */
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+
+            /* get code length code lengths (not a typo) */
+            state->have = 0;
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+
+            /* get length and distance code code lengths */
+            state->have = 0;
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    here = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (here.val < 16) {
+                    DROPBITS(here.bits);
+                    state->lens[state->have++] = here.val;
+                }
+                else {
+                    if (here.val == 16) {
+                        NEEDBITS(here.bits + 2);
+                        DROPBITS(here.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = (unsigned)(state->lens[state->have - 1]);
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (here.val == 17) {
+                        NEEDBITS(here.bits + 3);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(here.bits + 7);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* check for end-of-block code (better have one) */
+            if (state->lens[256] == 0) {
+                strm->msg = (char *)"invalid code -- missing end-of-block";
+                state->mode = BAD;
+                break;
+            }
+
+            /* build code tables -- note: do not change the lenbits or distbits
+               values here (9 and 6) without reading the comments in inftrees.h
+               concerning the ENOUGH constants, which depend on those values */
+            state->next = state->codes;
+            state->lencode = (code const FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (code const FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN;
+
+        case LEN:
+            /* use inflate_fast() if we have enough input and output */
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                if (state->whave < state->wsize)
+                    state->whave = state->wsize - left;
+                inflate_fast(strm, state->wsize);
+                LOAD();
+                break;
+            }
+
+            /* get a literal, length, or end-of-block code */
+            for (;;) {
+                here = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (here.op && (here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(here.bits);
+            state->length = (unsigned)here.val;
+
+            /* process literal */
+            if (here.op == 0) {
+                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", here.val));
+                ROOM();
+                *put++ = (unsigned char)(state->length);
+                left--;
+                state->mode = LEN;
+                break;
+            }
+
+            /* process end of block */
+            if (here.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->mode = TYPE;
+                break;
+            }
+
+            /* invalid code */
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+
+            /* length code -- get extra bits, if any */
+            state->extra = (unsigned)(here.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+
+            /* get distance code */
+            for (;;) {
+                here = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+            }
+            DROPBITS(here.bits);
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)here.val;
+
+            /* get distance extra bits, if any */
+            state->extra = (unsigned)(here.op) & 15;
+            if (state->extra != 0) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+            }
+            if (state->offset > state->wsize - (state->whave < state->wsize ?
+                                                left : 0)) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+
+            /* copy match from window to output */
+            do {
+                ROOM();
+                copy = state->wsize - state->offset;
+                if (copy < left) {
+                    from = put + copy;
+                    copy = left - copy;
+                }
+                else {
+                    from = put - state->offset;
+                    copy = left;
+                }
+                if (copy > state->length) copy = state->length;
+                state->length -= copy;
+                left -= copy;
+                do {
+                    *put++ = *from++;
+                } while (--copy);
+            } while (state->length != 0);
+            break;
+
+        case DONE:
+            /* inflate stream terminated properly -- write leftover output */
+            ret = Z_STREAM_END;
+            if (left < state->wsize) {
+                if (out(out_desc, state->window, state->wsize - left))
+                    ret = Z_BUF_ERROR;
+            }
+            goto inf_leave;
+
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+
+        default:                /* can't happen, but makes compilers happy */
+            ret = Z_STREAM_ERROR;
+            goto inf_leave;
+        }
+
+    /* Return unused input */
+  inf_leave:
+    strm->next_in = next;
+    strm->avail_in = have;
+    return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+        return Z_STREAM_ERROR;
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/inffast.c b/deps/libchdr/deps/zlib-1.2.11/inffast.c
new file mode 100644 (file)
index 0000000..0dbd1db
--- /dev/null
@@ -0,0 +1,323 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2017 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef ASMINF
+#  pragma message("Assembler code may have bugs -- use at your own risk")
+#else
+
+/*
+   Decode literal, length, and distance codes and write out the resulting
+   literal and match bytes until either not enough input or output is
+   available, an end-of-block is encountered, or a data error is encountered.
+   When large enough input and output buffers are supplied to inflate(), for
+   example, a 16K input buffer and a 64K output buffer, more than 95% of the
+   inflate execution time is spent in this routine.
+
+   Entry assumptions:
+
+        state->mode == LEN
+        strm->avail_in >= 6
+        strm->avail_out >= 258
+        start >= strm->avail_out
+        state->bits < 8
+
+   On return, state->mode is one of:
+
+        LEN -- ran out of enough output space or enough available input
+        TYPE -- reached end of block code, inflate() to interpret next block
+        BAD -- error in block data
+
+   Notes:
+
+    - The maximum input bits used by a length/distance pair is 15 bits for the
+      length code, 5 bits for the length extra, 15 bits for the distance code,
+      and 13 bits for the distance extra.  This totals 48 bits, or six bytes.
+      Therefore if strm->avail_in >= 6, then there is enough input to avoid
+      checking for available input while decoding.
+
+    - The maximum bytes that a single length/distance pair can output is 258
+      bytes, which is the maximum length that can be coded.  inflate_fast()
+      requires strm->avail_out >= 258 for each loop to avoid checking for
+      output space.
+ */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start;         /* inflate()'s starting value for strm->avail_out */
+{
+    struct inflate_state FAR *state;
+    z_const unsigned char FAR *in;      /* local strm->next_in */
+    z_const unsigned char FAR *last;    /* have enough input while in < last */
+    unsigned char FAR *out;     /* local strm->next_out */
+    unsigned char FAR *beg;     /* inflate()'s initial strm->next_out */
+    unsigned char FAR *end;     /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+    unsigned dmax;              /* maximum distance from zlib header */
+#endif
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned wnext;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if wsize != 0 */
+    unsigned long hold;         /* local strm->hold */
+    unsigned bits;              /* local strm->bits */
+    code const FAR *lcode;      /* local strm->lencode */
+    code const FAR *dcode;      /* local strm->distcode */
+    unsigned lmask;             /* mask for first level of length codes */
+    unsigned dmask;             /* mask for first level of distance codes */
+    code here;                  /* retrieved table entry */
+    unsigned op;                /* code bits, operation, extra bits, or */
+                                /*  window position, window bytes to copy */
+    unsigned len;               /* match length, unused bytes */
+    unsigned dist;              /* match distance */
+    unsigned char FAR *from;    /* where to copy match from */
+
+    /* copy state to local variables */
+    state = (struct inflate_state FAR *)strm->state;
+    in = strm->next_in;
+    last = in + (strm->avail_in - 5);
+    out = strm->next_out;
+    beg = out - (start - strm->avail_out);
+    end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+    dmax = state->dmax;
+#endif
+    wsize = state->wsize;
+    whave = state->whave;
+    wnext = state->wnext;
+    window = state->window;
+    hold = state->hold;
+    bits = state->bits;
+    lcode = state->lencode;
+    dcode = state->distcode;
+    lmask = (1U << state->lenbits) - 1;
+    dmask = (1U << state->distbits) - 1;
+
+    /* decode literals and length/distances until end-of-block or not enough
+       input data or output space */
+    do {
+        if (bits < 15) {
+            hold += (unsigned long)(*in++) << bits;
+            bits += 8;
+            hold += (unsigned long)(*in++) << bits;
+            bits += 8;
+        }
+        here = lcode[hold & lmask];
+      dolen:
+        op = (unsigned)(here.bits);
+        hold >>= op;
+        bits -= op;
+        op = (unsigned)(here.op);
+        if (op == 0) {                          /* literal */
+            Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                    "inflate:         literal '%c'\n" :
+                    "inflate:         literal 0x%02x\n", here.val));
+            *out++ = (unsigned char)(here.val);
+        }
+        else if (op & 16) {                     /* length base */
+            len = (unsigned)(here.val);
+            op &= 15;                           /* number of extra bits */
+            if (op) {
+                if (bits < op) {
+                    hold += (unsigned long)(*in++) << bits;
+                    bits += 8;
+                }
+                len += (unsigned)hold & ((1U << op) - 1);
+                hold >>= op;
+                bits -= op;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", len));
+            if (bits < 15) {
+                hold += (unsigned long)(*in++) << bits;
+                bits += 8;
+                hold += (unsigned long)(*in++) << bits;
+                bits += 8;
+            }
+            here = dcode[hold & dmask];
+          dodist:
+            op = (unsigned)(here.bits);
+            hold >>= op;
+            bits -= op;
+            op = (unsigned)(here.op);
+            if (op & 16) {                      /* distance base */
+                dist = (unsigned)(here.val);
+                op &= 15;                       /* number of extra bits */
+                if (bits < op) {
+                    hold += (unsigned long)(*in++) << bits;
+                    bits += 8;
+                    if (bits < op) {
+                        hold += (unsigned long)(*in++) << bits;
+                        bits += 8;
+                    }
+                }
+                dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+                if (dist > dmax) {
+                    strm->msg = (char *)"invalid distance too far back";
+                    state->mode = BAD;
+                    break;
+                }
+#endif
+                hold >>= op;
+                bits -= op;
+                Tracevv((stderr, "inflate:         distance %u\n", dist));
+                op = (unsigned)(out - beg);     /* max distance in output */
+                if (dist > op) {                /* see if copy from window */
+                    op = dist - op;             /* distance back in window */
+                    if (op > whave) {
+                        if (state->sane) {
+                            strm->msg =
+                                (char *)"invalid distance too far back";
+                            state->mode = BAD;
+                            break;
+                        }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+                        if (len <= op - whave) {
+                            do {
+                                *out++ = 0;
+                            } while (--len);
+                            continue;
+                        }
+                        len -= op - whave;
+                        do {
+                            *out++ = 0;
+                        } while (--op > whave);
+                        if (op == 0) {
+                            from = out - dist;
+                            do {
+                                *out++ = *from++;
+                            } while (--len);
+                            continue;
+                        }
+#endif
+                    }
+                    from = window;
+                    if (wnext == 0) {           /* very common case */
+                        from += wsize - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                *out++ = *from++;
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    else if (wnext < op) {      /* wrap around window */
+                        from += wsize + wnext - op;
+                        op -= wnext;
+                        if (op < len) {         /* some from end of window */
+                            len -= op;
+                            do {
+                                *out++ = *from++;
+                            } while (--op);
+                            from = window;
+                            if (wnext < len) {  /* some from start of window */
+                                op = wnext;
+                                len -= op;
+                                do {
+                                    *out++ = *from++;
+                                } while (--op);
+                                from = out - dist;      /* rest from output */
+                            }
+                        }
+                    }
+                    else {                      /* contiguous in window */
+                        from += wnext - op;
+                        if (op < len) {         /* some from window */
+                            len -= op;
+                            do {
+                                *out++ = *from++;
+                            } while (--op);
+                            from = out - dist;  /* rest from output */
+                        }
+                    }
+                    while (len > 2) {
+                        *out++ = *from++;
+                        *out++ = *from++;
+                        *out++ = *from++;
+                        len -= 3;
+                    }
+                    if (len) {
+                        *out++ = *from++;
+                        if (len > 1)
+                            *out++ = *from++;
+                    }
+                }
+                else {
+                    from = out - dist;          /* copy direct from output */
+                    do {                        /* minimum length is three */
+                        *out++ = *from++;
+                        *out++ = *from++;
+                        *out++ = *from++;
+                        len -= 3;
+                    } while (len > 2);
+                    if (len) {
+                        *out++ = *from++;
+                        if (len > 1)
+                            *out++ = *from++;
+                    }
+                }
+            }
+            else if ((op & 64) == 0) {          /* 2nd level distance code */
+                here = dcode[here.val + (hold & ((1U << op) - 1))];
+                goto dodist;
+            }
+            else {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+        }
+        else if ((op & 64) == 0) {              /* 2nd level length code */
+            here = lcode[here.val + (hold & ((1U << op) - 1))];
+            goto dolen;
+        }
+        else if (op & 32) {                     /* end-of-block */
+            Tracevv((stderr, "inflate:         end of block\n"));
+            state->mode = TYPE;
+            break;
+        }
+        else {
+            strm->msg = (char *)"invalid literal/length code";
+            state->mode = BAD;
+            break;
+        }
+    } while (in < last && out < end);
+
+    /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+    len = bits >> 3;
+    in -= len;
+    bits -= len << 3;
+    hold &= (1U << bits) - 1;
+
+    /* update state and return */
+    strm->next_in = in;
+    strm->next_out = out;
+    strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+    strm->avail_out = (unsigned)(out < end ?
+                                 257 + (end - out) : 257 - (out - end));
+    state->hold = hold;
+    state->bits = bits;
+    return;
+}
+
+/*
+   inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+   - Using bit fields for code structure
+   - Different op definition to avoid & for extra bits (do & for table bits)
+   - Three separate decoding do-loops for direct, window, and wnext == 0
+   - Special case for distance > 1 copies to do overlapped load and store copy
+   - Explicit branch predictions (based on measured branch probabilities)
+   - Deferring match copy and interspersed it with decoding subsequent codes
+   - Swapping literal/length else
+   - Swapping window/direct else
+   - Larger unrolled copy loops (three is about right)
+   - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/deps/libchdr/deps/zlib-1.2.11/inffast.h b/deps/libchdr/deps/zlib-1.2.11/inffast.h
new file mode 100644 (file)
index 0000000..e5c1aa4
--- /dev/null
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/deps/libchdr/deps/zlib-1.2.11/inffixed.h b/deps/libchdr/deps/zlib-1.2.11/inffixed.h
new file mode 100644 (file)
index 0000000..d628327
--- /dev/null
@@ -0,0 +1,94 @@
+    /* inffixed.h -- table for decoding fixed codes
+     * Generated automatically by makefixed().
+     */
+
+    /* WARNING: this file should *not* be used by applications.
+       It is part of the implementation of this library and is
+       subject to change. Applications should only use zlib.h.
+     */
+
+    static const code lenfix[512] = {
+        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+        {0,9,255}
+    };
+
+    static const code distfix[32] = {
+        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+        {22,5,193},{64,5,0}
+    };
diff --git a/deps/libchdr/deps/zlib-1.2.11/inflate.c b/deps/libchdr/deps/zlib-1.2.11/inflate.c
new file mode 100644 (file)
index 0000000..ac333e8
--- /dev/null
@@ -0,0 +1,1561 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0    24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ *   creation of window when not needed, minimize use of window when it is
+ *   needed, make inffast.c even faster, implement gzip decoding, and to
+ *   improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1    25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2    4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ *   to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3    22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ *   buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4    1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common wnext == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ *   source file infback.c to provide a call-back interface to inflate for
+ *   programs like gzip and unzip -- uses window as output buffer to avoid
+ *   window copying
+ *
+ * 1.2.beta5    1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ *   input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6    4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ *   make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7    27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0        9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ *   for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ *   and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+#  ifndef BUILDFIXED
+#    define BUILDFIXED
+#  endif
+#endif
+
+/* function prototypes */
+local int inflateStateCheck OF((z_streamp strm));
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
+                           unsigned copy));
+#ifdef BUILDFIXED
+   void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
+                              unsigned len));
+
+local int inflateStateCheck(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+    if (strm == Z_NULL ||
+        strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
+        return 1;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state == Z_NULL || state->strm != strm ||
+        state->mode < HEAD || state->mode > SYNC)
+        return 1;
+    return 0;
+}
+
+int ZEXPORT inflateResetKeep(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    strm->total_in = strm->total_out = state->total = 0;
+    strm->msg = Z_NULL;
+    if (state->wrap)        /* to support ill-conceived Java test suite */
+        strm->adler = state->wrap & 1;
+    state->mode = HEAD;
+    state->last = 0;
+    state->havedict = 0;
+    state->dmax = 32768U;
+    state->head = Z_NULL;
+    state->hold = 0;
+    state->bits = 0;
+    state->lencode = state->distcode = state->next = state->codes;
+    state->sane = 1;
+    state->back = -1;
+    Tracev((stderr, "inflate: reset\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    state->wsize = 0;
+    state->whave = 0;
+    state->wnext = 0;
+    return inflateResetKeep(strm);
+}
+
+int ZEXPORT inflateReset2(strm, windowBits)
+z_streamp strm;
+int windowBits;
+{
+    int wrap;
+    struct inflate_state FAR *state;
+
+    /* get the state */
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* extract wrap request from windowBits parameter */
+    if (windowBits < 0) {
+        wrap = 0;
+        windowBits = -windowBits;
+    }
+    else {
+        wrap = (windowBits >> 4) + 5;
+#ifdef GUNZIP
+        if (windowBits < 48)
+            windowBits &= 15;
+#endif
+    }
+
+    /* set number of window bits, free window if different */
+    if (windowBits && (windowBits < 8 || windowBits > 15))
+        return Z_STREAM_ERROR;
+    if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
+        ZFREE(strm, state->window);
+        state->window = Z_NULL;
+    }
+
+    /* update state and reset the rest of it */
+    state->wrap = wrap;
+    state->wbits = (unsigned)windowBits;
+    return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+    int ret;
+    struct inflate_state FAR *state;
+
+    if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+        stream_size != (int)(sizeof(z_stream)))
+        return Z_VERSION_ERROR;
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+    strm->msg = Z_NULL;                 /* in case we return an error */
+    if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+        strm->zalloc = zcalloc;
+        strm->opaque = (voidpf)0;
+#endif
+    }
+    if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+        return Z_STREAM_ERROR;
+#else
+        strm->zfree = zcfree;
+#endif
+    state = (struct inflate_state FAR *)
+            ZALLOC(strm, 1, sizeof(struct inflate_state));
+    if (state == Z_NULL) return Z_MEM_ERROR;
+    Tracev((stderr, "inflate: allocated\n"));
+    strm->state = (struct internal_state FAR *)state;
+    state->strm = strm;
+    state->window = Z_NULL;
+    state->mode = HEAD;     /* to pass state test in inflateReset2() */
+    ret = inflateReset2(strm, windowBits);
+    if (ret != Z_OK) {
+        ZFREE(strm, state);
+        strm->state = Z_NULL;
+    }
+    return ret;
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+    return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+    struct inflate_state FAR *state;
+
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (bits < 0) {
+        state->hold = 0;
+        state->bits = 0;
+        return Z_OK;
+    }
+    if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;
+    value &= (1L << bits) - 1;
+    state->hold += (unsigned)value << state->bits;
+    state->bits += (uInt)bits;
+    return Z_OK;
+}
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications, since the rewriting of the tables and virgin
+   may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+    static int virgin = 1;
+    static code *lenfix, *distfix;
+    static code fixed[544];
+
+    /* build fixed huffman tables if first call (may not be thread safe) */
+    if (virgin) {
+        unsigned sym, bits;
+        static code *next;
+
+        /* literal/length table */
+        sym = 0;
+        while (sym < 144) state->lens[sym++] = 8;
+        while (sym < 256) state->lens[sym++] = 9;
+        while (sym < 280) state->lens[sym++] = 7;
+        while (sym < 288) state->lens[sym++] = 8;
+        next = fixed;
+        lenfix = next;
+        bits = 9;
+        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+        /* distance table */
+        sym = 0;
+        while (sym < 32) state->lens[sym++] = 5;
+        distfix = next;
+        bits = 5;
+        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+        /* do this just once */
+        virgin = 0;
+    }
+#else /* !BUILDFIXED */
+#   include "inffixed.h"
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
+   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
+   those tables to stdout, which would be piped to inffixed.h.  A small program
+   can simply call makefixed to do this:
+
+    void makefixed(void);
+
+    int main(void)
+    {
+        makefixed();
+        return 0;
+    }
+
+   Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+    a.out > inffixed.h
+ */
+void makefixed()
+{
+    unsigned low, size;
+    struct inflate_state state;
+
+    fixedtables(&state);
+    puts("    /* inffixed.h -- table for decoding fixed codes");
+    puts("     * Generated automatically by makefixed().");
+    puts("     */");
+    puts("");
+    puts("    /* WARNING: this file should *not* be used by applications.");
+    puts("       It is part of the implementation of this library and is");
+    puts("       subject to change. Applications should only use zlib.h.");
+    puts("     */");
+    puts("");
+    size = 1U << 9;
+    printf("    static const code lenfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 7) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
+               state.lencode[low].bits, state.lencode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+    size = 1U << 5;
+    printf("\n    static const code distfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 6) == 0) printf("\n        ");
+        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+               state.distcode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n    };");
+}
+#endif /* MAKEFIXED */
+
+/*
+   Update the window with the last wsize (normally 32K) bytes written before
+   returning.  If window does not exist yet, create it.  This is only called
+   when a window is already in use, or when output has been written during this
+   inflate call, but the end of the deflate stream has not been reached yet.
+   It is also called to create a window for dictionary data when a dictionary
+   is loaded.
+
+   Providing output buffers larger than 32K to inflate() should provide a speed
+   advantage, since only the last 32K of output is copied to the sliding window
+   upon return from inflate(), and since all distances after the first 32K of
+   output will fall in the output data, making match copies simpler and faster.
+   The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, end, copy)
+z_streamp strm;
+const Bytef *end;
+unsigned copy;
+{
+    struct inflate_state FAR *state;
+    unsigned dist;
+
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* if it hasn't been done already, allocate space for the window */
+    if (state->window == Z_NULL) {
+        state->window = (unsigned char FAR *)
+                        ZALLOC(strm, 1U << state->wbits,
+                               sizeof(unsigned char));
+        if (state->window == Z_NULL) return 1;
+    }
+
+    /* if window not in use yet, initialize */
+    if (state->wsize == 0) {
+        state->wsize = 1U << state->wbits;
+        state->wnext = 0;
+        state->whave = 0;
+    }
+
+    /* copy state->wsize or less output bytes into the circular window */
+    if (copy >= state->wsize) {
+        zmemcpy(state->window, end - state->wsize, state->wsize);
+        state->wnext = 0;
+        state->whave = state->wsize;
+    }
+    else {
+        dist = state->wsize - state->wnext;
+        if (dist > copy) dist = copy;
+        zmemcpy(state->window + state->wnext, end - copy, dist);
+        copy -= dist;
+        if (copy) {
+            zmemcpy(state->window, end - copy, copy);
+            state->wnext = copy;
+            state->whave = state->wsize;
+        }
+        else {
+            state->wnext += dist;
+            if (state->wnext == state->wsize) state->wnext = 0;
+            if (state->whave < state->wsize) state->whave += dist;
+        }
+    }
+    return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+#  define UPDATE(check, buf, len) \
+    (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+#  define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+#  define CRC2(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        check = crc32(check, hbuf, 2); \
+    } while (0)
+
+#  define CRC4(check, word) \
+    do { \
+        hbuf[0] = (unsigned char)(word); \
+        hbuf[1] = (unsigned char)((word) >> 8); \
+        hbuf[2] = (unsigned char)((word) >> 16); \
+        hbuf[3] = (unsigned char)((word) >> 24); \
+        check = crc32(check, hbuf, 4); \
+    } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+    do { \
+        put = strm->next_out; \
+        left = strm->avail_out; \
+        next = strm->next_in; \
+        have = strm->avail_in; \
+        hold = state->hold; \
+        bits = state->bits; \
+    } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+    do { \
+        strm->next_out = put; \
+        strm->avail_out = left; \
+        strm->next_in = next; \
+        strm->avail_in = have; \
+        state->hold = hold; \
+        state->bits = bits; \
+    } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+    do { \
+        hold = 0; \
+        bits = 0; \
+    } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+   if there is no input available. */
+#define PULLBYTE() \
+    do { \
+        if (have == 0) goto inf_leave; \
+        have--; \
+        hold += (unsigned long)(*next++) << bits; \
+        bits += 8; \
+    } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator.  If there is
+   not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+    do { \
+        while (bits < (unsigned)(n)) \
+            PULLBYTE(); \
+    } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+    ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+    do { \
+        hold >>= (n); \
+        bits -= (unsigned)(n); \
+    } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+    do { \
+        hold >>= bits & 7; \
+        bits -= bits & 7; \
+    } while (0)
+
+/*
+   inflate() uses a state machine to process as much input data and generate as
+   much output data as possible before returning.  The state machine is
+   structured roughly as follows:
+
+    for (;;) switch (state) {
+    ...
+    case STATEn:
+        if (not enough input data or output space to make progress)
+            return;
+        ... make progress ...
+        state = STATEm;
+        break;
+    ...
+    }
+
+   so when inflate() is called again, the same case is attempted again, and
+   if the appropriate resources are provided, the machine proceeds to the
+   next state.  The NEEDBITS() macro is usually the way the state evaluates
+   whether it can proceed or should return.  NEEDBITS() does the return if
+   the requested bits are not available.  The typical use of the BITS macros
+   is:
+
+        NEEDBITS(n);
+        ... do something with BITS(n) ...
+        DROPBITS(n);
+
+   where NEEDBITS(n) either returns from inflate() if there isn't enough
+   input left to load n bits into the accumulator, or it continues.  BITS(n)
+   gives the low n bits in the accumulator.  When done, DROPBITS(n) drops
+   the low n bits off the accumulator.  INITBITS() clears the accumulator
+   and sets the number of available bits to zero.  BYTEBITS() discards just
+   enough bits to put the accumulator on a byte boundary.  After BYTEBITS()
+   and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+   NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+   if there is no input available.  The decoding of variable length codes uses
+   PULLBYTE() directly in order to pull just enough bytes to decode the next
+   code, and no more.
+
+   Some states loop until they get enough input, making sure that enough
+   state information is maintained to continue the loop where it left off
+   if NEEDBITS() returns in the loop.  For example, want, need, and keep
+   would all have to actually be part of the saved state in case NEEDBITS()
+   returns:
+
+    case STATEw:
+        while (want < need) {
+            NEEDBITS(n);
+            keep[want++] = BITS(n);
+            DROPBITS(n);
+        }
+        state = STATEx;
+    case STATEx:
+
+   As shown above, if the next state is also the next case, then the break
+   is omitted.
+
+   A state may also return if there is not enough output space available to
+   complete that state.  Those states are copying stored data, writing a
+   literal byte, and copying a matching string.
+
+   When returning, a "goto inf_leave" is used to update the total counters,
+   update the check value, and determine whether any progress has been made
+   during that inflate() call in order to return the proper return code.
+   Progress is defined as a change in either strm->avail_in or strm->avail_out.
+   When there is a window, goto inf_leave will update the window with the last
+   output written.  If a goto inf_leave occurs in the middle of decompression
+   and there is no window currently, goto inf_leave will create one and copy
+   output to the window for the next call of inflate().
+
+   In this implementation, the flush parameter of inflate() only affects the
+   return code (per zlib.h).  inflate() always writes as much as possible to
+   strm->next_out, given the space available and the provided input--the effect
+   documented in zlib.h of Z_SYNC_FLUSH.  Furthermore, inflate() always defers
+   the allocation of and copying into a sliding window until necessary, which
+   provides the effect documented in zlib.h for Z_FINISH when the entire input
+   stream available.  So the only thing the flush parameter actually does is:
+   when flush is set to Z_FINISH, inflate() cannot return Z_OK.  Instead it
+   will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+    struct inflate_state FAR *state;
+    z_const unsigned char FAR *next;    /* next input */
+    unsigned char FAR *put;     /* next output */
+    unsigned have, left;        /* available input and output */
+    unsigned long hold;         /* bit buffer */
+    unsigned bits;              /* bits in bit buffer */
+    unsigned in, out;           /* save starting available input and output */
+    unsigned copy;              /* number of stored or match bytes to copy */
+    unsigned char FAR *from;    /* where to copy match bytes from */
+    code here;                  /* current decoding table entry */
+    code last;                  /* parent table entry */
+    unsigned len;               /* length to copy for repeats, bits to drop */
+    int ret;                    /* return code */
+#ifdef GUNZIP
+    unsigned char hbuf[4];      /* buffer for gzip header crc calculation */
+#endif
+    static const unsigned short order[19] = /* permutation of code lengths */
+        {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+    if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||
+        (strm->next_in == Z_NULL && strm->avail_in != 0))
+        return Z_STREAM_ERROR;
+
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->mode == TYPE) state->mode = TYPEDO;      /* skip check */
+    LOAD();
+    in = have;
+    out = left;
+    ret = Z_OK;
+    for (;;)
+        switch (state->mode) {
+        case HEAD:
+            if (state->wrap == 0) {
+                state->mode = TYPEDO;
+                break;
+            }
+            NEEDBITS(16);
+#ifdef GUNZIP
+            if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */
+                if (state->wbits == 0)
+                    state->wbits = 15;
+                state->check = crc32(0L, Z_NULL, 0);
+                CRC2(state->check, hold);
+                INITBITS();
+                state->mode = FLAGS;
+                break;
+            }
+            state->flags = 0;           /* expect zlib header */
+            if (state->head != Z_NULL)
+                state->head->done = -1;
+            if (!(state->wrap & 1) ||   /* check if zlib header allowed */
+#else
+            if (
+#endif
+                ((BITS(8) << 8) + (hold >> 8)) % 31) {
+                strm->msg = (char *)"incorrect header check";
+                state->mode = BAD;
+                break;
+            }
+            if (BITS(4) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            DROPBITS(4);
+            len = BITS(4) + 8;
+            if (state->wbits == 0)
+                state->wbits = len;
+            if (len > 15 || len > state->wbits) {
+                strm->msg = (char *)"invalid window size";
+                state->mode = BAD;
+                break;
+            }
+            state->dmax = 1U << len;
+            Tracev((stderr, "inflate:   zlib header ok\n"));
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = hold & 0x200 ? DICTID : TYPE;
+            INITBITS();
+            break;
+#ifdef GUNZIP
+        case FLAGS:
+            NEEDBITS(16);
+            state->flags = (int)(hold);
+            if ((state->flags & 0xff) != Z_DEFLATED) {
+                strm->msg = (char *)"unknown compression method";
+                state->mode = BAD;
+                break;
+            }
+            if (state->flags & 0xe000) {
+                strm->msg = (char *)"unknown header flags set";
+                state->mode = BAD;
+                break;
+            }
+            if (state->head != Z_NULL)
+                state->head->text = (int)((hold >> 8) & 1);
+            if ((state->flags & 0x0200) && (state->wrap & 4))
+                CRC2(state->check, hold);
+            INITBITS();
+            state->mode = TIME;
+        case TIME:
+            NEEDBITS(32);
+            if (state->head != Z_NULL)
+                state->head->time = hold;
+            if ((state->flags & 0x0200) && (state->wrap & 4))
+                CRC4(state->check, hold);
+            INITBITS();
+            state->mode = OS;
+        case OS:
+            NEEDBITS(16);
+            if (state->head != Z_NULL) {
+                state->head->xflags = (int)(hold & 0xff);
+                state->head->os = (int)(hold >> 8);
+            }
+            if ((state->flags & 0x0200) && (state->wrap & 4))
+                CRC2(state->check, hold);
+            INITBITS();
+            state->mode = EXLEN;
+        case EXLEN:
+            if (state->flags & 0x0400) {
+                NEEDBITS(16);
+                state->length = (unsigned)(hold);
+                if (state->head != Z_NULL)
+                    state->head->extra_len = (unsigned)hold;
+                if ((state->flags & 0x0200) && (state->wrap & 4))
+                    CRC2(state->check, hold);
+                INITBITS();
+            }
+            else if (state->head != Z_NULL)
+                state->head->extra = Z_NULL;
+            state->mode = EXTRA;
+        case EXTRA:
+            if (state->flags & 0x0400) {
+                copy = state->length;
+                if (copy > have) copy = have;
+                if (copy) {
+                    if (state->head != Z_NULL &&
+                        state->head->extra != Z_NULL) {
+                        len = state->head->extra_len - state->length;
+                        zmemcpy(state->head->extra + len, next,
+                                len + copy > state->head->extra_max ?
+                                state->head->extra_max - len : copy);
+                    }
+                    if ((state->flags & 0x0200) && (state->wrap & 4))
+                        state->check = crc32(state->check, next, copy);
+                    have -= copy;
+                    next += copy;
+                    state->length -= copy;
+                }
+                if (state->length) goto inf_leave;
+            }
+            state->length = 0;
+            state->mode = NAME;
+        case NAME:
+            if (state->flags & 0x0800) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->name != Z_NULL &&
+                            state->length < state->head->name_max)
+                        state->head->name[state->length++] = (Bytef)len;
+                } while (len && copy < have);
+                if ((state->flags & 0x0200) && (state->wrap & 4))
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->name = Z_NULL;
+            state->length = 0;
+            state->mode = COMMENT;
+        case COMMENT:
+            if (state->flags & 0x1000) {
+                if (have == 0) goto inf_leave;
+                copy = 0;
+                do {
+                    len = (unsigned)(next[copy++]);
+                    if (state->head != Z_NULL &&
+                            state->head->comment != Z_NULL &&
+                            state->length < state->head->comm_max)
+                        state->head->comment[state->length++] = (Bytef)len;
+                } while (len && copy < have);
+                if ((state->flags & 0x0200) && (state->wrap & 4))
+                    state->check = crc32(state->check, next, copy);
+                have -= copy;
+                next += copy;
+                if (len) goto inf_leave;
+            }
+            else if (state->head != Z_NULL)
+                state->head->comment = Z_NULL;
+            state->mode = HCRC;
+        case HCRC:
+            if (state->flags & 0x0200) {
+                NEEDBITS(16);
+                if ((state->wrap & 4) && hold != (state->check & 0xffff)) {
+                    strm->msg = (char *)"header crc mismatch";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+            }
+            if (state->head != Z_NULL) {
+                state->head->hcrc = (int)((state->flags >> 9) & 1);
+                state->head->done = 1;
+            }
+            strm->adler = state->check = crc32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+            break;
+#endif
+        case DICTID:
+            NEEDBITS(32);
+            strm->adler = state->check = ZSWAP32(hold);
+            INITBITS();
+            state->mode = DICT;
+        case DICT:
+            if (state->havedict == 0) {
+                RESTORE();
+                return Z_NEED_DICT;
+            }
+            strm->adler = state->check = adler32(0L, Z_NULL, 0);
+            state->mode = TYPE;
+        case TYPE:
+            if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+        case TYPEDO:
+            if (state->last) {
+                BYTEBITS();
+                state->mode = CHECK;
+                break;
+            }
+            NEEDBITS(3);
+            state->last = BITS(1);
+            DROPBITS(1);
+            switch (BITS(2)) {
+            case 0:                             /* stored block */
+                Tracev((stderr, "inflate:     stored block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = STORED;
+                break;
+            case 1:                             /* fixed block */
+                fixedtables(state);
+                Tracev((stderr, "inflate:     fixed codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = LEN_;             /* decode codes */
+                if (flush == Z_TREES) {
+                    DROPBITS(2);
+                    goto inf_leave;
+                }
+                break;
+            case 2:                             /* dynamic block */
+                Tracev((stderr, "inflate:     dynamic codes block%s\n",
+                        state->last ? " (last)" : ""));
+                state->mode = TABLE;
+                break;
+            case 3:
+                strm->msg = (char *)"invalid block type";
+                state->mode = BAD;
+            }
+            DROPBITS(2);
+            break;
+        case STORED:
+            BYTEBITS();                         /* go to byte boundary */
+            NEEDBITS(32);
+            if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+                strm->msg = (char *)"invalid stored block lengths";
+                state->mode = BAD;
+                break;
+            }
+            state->length = (unsigned)hold & 0xffff;
+            Tracev((stderr, "inflate:       stored length %u\n",
+                    state->length));
+            INITBITS();
+            state->mode = COPY_;
+            if (flush == Z_TREES) goto inf_leave;
+        case COPY_:
+            state->mode = COPY;
+        case COPY:
+            copy = state->length;
+            if (copy) {
+                if (copy > have) copy = have;
+                if (copy > left) copy = left;
+                if (copy == 0) goto inf_leave;
+                zmemcpy(put, next, copy);
+                have -= copy;
+                next += copy;
+                left -= copy;
+                put += copy;
+                state->length -= copy;
+                break;
+            }
+            Tracev((stderr, "inflate:       stored end\n"));
+            state->mode = TYPE;
+            break;
+        case TABLE:
+            NEEDBITS(14);
+            state->nlen = BITS(5) + 257;
+            DROPBITS(5);
+            state->ndist = BITS(5) + 1;
+            DROPBITS(5);
+            state->ncode = BITS(4) + 4;
+            DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+            if (state->nlen > 286 || state->ndist > 30) {
+                strm->msg = (char *)"too many length or distance symbols";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracev((stderr, "inflate:       table sizes ok\n"));
+            state->have = 0;
+            state->mode = LENLENS;
+        case LENLENS:
+            while (state->have < state->ncode) {
+                NEEDBITS(3);
+                state->lens[order[state->have++]] = (unsigned short)BITS(3);
+                DROPBITS(3);
+            }
+            while (state->have < 19)
+                state->lens[order[state->have++]] = 0;
+            state->next = state->codes;
+            state->lencode = (const code FAR *)(state->next);
+            state->lenbits = 7;
+            ret = inflate_table(CODES, state->lens, 19, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid code lengths set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       code lengths ok\n"));
+            state->have = 0;
+            state->mode = CODELENS;
+        case CODELENS:
+            while (state->have < state->nlen + state->ndist) {
+                for (;;) {
+                    here = state->lencode[BITS(state->lenbits)];
+                    if ((unsigned)(here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                if (here.val < 16) {
+                    DROPBITS(here.bits);
+                    state->lens[state->have++] = here.val;
+                }
+                else {
+                    if (here.val == 16) {
+                        NEEDBITS(here.bits + 2);
+                        DROPBITS(here.bits);
+                        if (state->have == 0) {
+                            strm->msg = (char *)"invalid bit length repeat";
+                            state->mode = BAD;
+                            break;
+                        }
+                        len = state->lens[state->have - 1];
+                        copy = 3 + BITS(2);
+                        DROPBITS(2);
+                    }
+                    else if (here.val == 17) {
+                        NEEDBITS(here.bits + 3);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 3 + BITS(3);
+                        DROPBITS(3);
+                    }
+                    else {
+                        NEEDBITS(here.bits + 7);
+                        DROPBITS(here.bits);
+                        len = 0;
+                        copy = 11 + BITS(7);
+                        DROPBITS(7);
+                    }
+                    if (state->have + copy > state->nlen + state->ndist) {
+                        strm->msg = (char *)"invalid bit length repeat";
+                        state->mode = BAD;
+                        break;
+                    }
+                    while (copy--)
+                        state->lens[state->have++] = (unsigned short)len;
+                }
+            }
+
+            /* handle error breaks in while */
+            if (state->mode == BAD) break;
+
+            /* check for end-of-block code (better have one) */
+            if (state->lens[256] == 0) {
+                strm->msg = (char *)"invalid code -- missing end-of-block";
+                state->mode = BAD;
+                break;
+            }
+
+            /* build code tables -- note: do not change the lenbits or distbits
+               values here (9 and 6) without reading the comments in inftrees.h
+               concerning the ENOUGH constants, which depend on those values */
+            state->next = state->codes;
+            state->lencode = (const code FAR *)(state->next);
+            state->lenbits = 9;
+            ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+                                &(state->lenbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid literal/lengths set";
+                state->mode = BAD;
+                break;
+            }
+            state->distcode = (const code FAR *)(state->next);
+            state->distbits = 6;
+            ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+                            &(state->next), &(state->distbits), state->work);
+            if (ret) {
+                strm->msg = (char *)"invalid distances set";
+                state->mode = BAD;
+                break;
+            }
+            Tracev((stderr, "inflate:       codes ok\n"));
+            state->mode = LEN_;
+            if (flush == Z_TREES) goto inf_leave;
+        case LEN_:
+            state->mode = LEN;
+        case LEN:
+            if (have >= 6 && left >= 258) {
+                RESTORE();
+                inflate_fast(strm, out);
+                LOAD();
+                if (state->mode == TYPE)
+                    state->back = -1;
+                break;
+            }
+            state->back = 0;
+            for (;;) {
+                here = state->lencode[BITS(state->lenbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if (here.op && (here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->lencode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+                state->back += last.bits;
+            }
+            DROPBITS(here.bits);
+            state->back += here.bits;
+            state->length = (unsigned)here.val;
+            if ((int)(here.op) == 0) {
+                Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+                        "inflate:         literal '%c'\n" :
+                        "inflate:         literal 0x%02x\n", here.val));
+                state->mode = LIT;
+                break;
+            }
+            if (here.op & 32) {
+                Tracevv((stderr, "inflate:         end of block\n"));
+                state->back = -1;
+                state->mode = TYPE;
+                break;
+            }
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid literal/length code";
+                state->mode = BAD;
+                break;
+            }
+            state->extra = (unsigned)(here.op) & 15;
+            state->mode = LENEXT;
+        case LENEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->length += BITS(state->extra);
+                DROPBITS(state->extra);
+                state->back += state->extra;
+            }
+            Tracevv((stderr, "inflate:         length %u\n", state->length));
+            state->was = state->length;
+            state->mode = DIST;
+        case DIST:
+            for (;;) {
+                here = state->distcode[BITS(state->distbits)];
+                if ((unsigned)(here.bits) <= bits) break;
+                PULLBYTE();
+            }
+            if ((here.op & 0xf0) == 0) {
+                last = here;
+                for (;;) {
+                    here = state->distcode[last.val +
+                            (BITS(last.bits + last.op) >> last.bits)];
+                    if ((unsigned)(last.bits + here.bits) <= bits) break;
+                    PULLBYTE();
+                }
+                DROPBITS(last.bits);
+                state->back += last.bits;
+            }
+            DROPBITS(here.bits);
+            state->back += here.bits;
+            if (here.op & 64) {
+                strm->msg = (char *)"invalid distance code";
+                state->mode = BAD;
+                break;
+            }
+            state->offset = (unsigned)here.val;
+            state->extra = (unsigned)(here.op) & 15;
+            state->mode = DISTEXT;
+        case DISTEXT:
+            if (state->extra) {
+                NEEDBITS(state->extra);
+                state->offset += BITS(state->extra);
+                DROPBITS(state->extra);
+                state->back += state->extra;
+            }
+#ifdef INFLATE_STRICT
+            if (state->offset > state->dmax) {
+                strm->msg = (char *)"invalid distance too far back";
+                state->mode = BAD;
+                break;
+            }
+#endif
+            Tracevv((stderr, "inflate:         distance %u\n", state->offset));
+            state->mode = MATCH;
+        case MATCH:
+            if (left == 0) goto inf_leave;
+            copy = out - left;
+            if (state->offset > copy) {         /* copy from window */
+                copy = state->offset - copy;
+                if (copy > state->whave) {
+                    if (state->sane) {
+                        strm->msg = (char *)"invalid distance too far back";
+                        state->mode = BAD;
+                        break;
+                    }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+                    Trace((stderr, "inflate.c too far\n"));
+                    copy -= state->whave;
+                    if (copy > state->length) copy = state->length;
+                    if (copy > left) copy = left;
+                    left -= copy;
+                    state->length -= copy;
+                    do {
+                        *put++ = 0;
+                    } while (--copy);
+                    if (state->length == 0) state->mode = LEN;
+                    break;
+#endif
+                }
+                if (copy > state->wnext) {
+                    copy -= state->wnext;
+                    from = state->window + (state->wsize - copy);
+                }
+                else
+                    from = state->window + (state->wnext - copy);
+                if (copy > state->length) copy = state->length;
+            }
+            else {                              /* copy from output */
+                from = put - state->offset;
+                copy = state->length;
+            }
+            if (copy > left) copy = left;
+            left -= copy;
+            state->length -= copy;
+            do {
+                *put++ = *from++;
+            } while (--copy);
+            if (state->length == 0) state->mode = LEN;
+            break;
+        case LIT:
+            if (left == 0) goto inf_leave;
+            *put++ = (unsigned char)(state->length);
+            left--;
+            state->mode = LEN;
+            break;
+        case CHECK:
+            if (state->wrap) {
+                NEEDBITS(32);
+                out -= left;
+                strm->total_out += out;
+                state->total += out;
+                if ((state->wrap & 4) && out)
+                    strm->adler = state->check =
+                        UPDATE(state->check, put - out, out);
+                out = left;
+                if ((state->wrap & 4) && (
+#ifdef GUNZIP
+                     state->flags ? hold :
+#endif
+                     ZSWAP32(hold)) != state->check) {
+                    strm->msg = (char *)"incorrect data check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   check matches trailer\n"));
+            }
+#ifdef GUNZIP
+            state->mode = LENGTH;
+        case LENGTH:
+            if (state->wrap && state->flags) {
+                NEEDBITS(32);
+                if (hold != (state->total & 0xffffffffUL)) {
+                    strm->msg = (char *)"incorrect length check";
+                    state->mode = BAD;
+                    break;
+                }
+                INITBITS();
+                Tracev((stderr, "inflate:   length matches trailer\n"));
+            }
+#endif
+            state->mode = DONE;
+        case DONE:
+            ret = Z_STREAM_END;
+            goto inf_leave;
+        case BAD:
+            ret = Z_DATA_ERROR;
+            goto inf_leave;
+        case MEM:
+            return Z_MEM_ERROR;
+        case SYNC:
+        default:
+            return Z_STREAM_ERROR;
+        }
+
+    /*
+       Return from inflate(), updating the total counts and the check value.
+       If there was no progress during the inflate() call, return a buffer
+       error.  Call updatewindow() to create and/or update the window state.
+       Note: a memory error from inflate() is non-recoverable.
+     */
+  inf_leave:
+    RESTORE();
+    if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
+            (state->mode < CHECK || flush != Z_FINISH)))
+        if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
+            state->mode = MEM;
+            return Z_MEM_ERROR;
+        }
+    in -= strm->avail_in;
+    out -= strm->avail_out;
+    strm->total_in += in;
+    strm->total_out += out;
+    state->total += out;
+    if ((state->wrap & 4) && out)
+        strm->adler = state->check =
+            UPDATE(state->check, strm->next_out - out, out);
+    strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
+                      (state->mode == TYPE ? 128 : 0) +
+                      (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
+    if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+        ret = Z_BUF_ERROR;
+    return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+    if (inflateStateCheck(strm))
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->window != Z_NULL) ZFREE(strm, state->window);
+    ZFREE(strm, strm->state);
+    strm->state = Z_NULL;
+    Tracev((stderr, "inflate: end\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+Bytef *dictionary;
+uInt *dictLength;
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+
+    /* copy dictionary */
+    if (state->whave && dictionary != Z_NULL) {
+        zmemcpy(dictionary, state->window + state->wnext,
+                state->whave - state->wnext);
+        zmemcpy(dictionary + state->whave - state->wnext,
+                state->window, state->wnext);
+    }
+    if (dictLength != Z_NULL)
+        *dictLength = state->whave;
+    return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+    struct inflate_state FAR *state;
+    unsigned long dictid;
+    int ret;
+
+    /* check state */
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (state->wrap != 0 && state->mode != DICT)
+        return Z_STREAM_ERROR;
+
+    /* check for correct dictionary identifier */
+    if (state->mode == DICT) {
+        dictid = adler32(0L, Z_NULL, 0);
+        dictid = adler32(dictid, dictionary, dictLength);
+        if (dictid != state->check)
+            return Z_DATA_ERROR;
+    }
+
+    /* copy dictionary to window using updatewindow(), which will amend the
+       existing dictionary if appropriate */
+    ret = updatewindow(strm, dictionary + dictLength, dictLength);
+    if (ret) {
+        state->mode = MEM;
+        return Z_MEM_ERROR;
+    }
+    state->havedict = 1;
+    Tracev((stderr, "inflate:   dictionary set\n"));
+    return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+    struct inflate_state FAR *state;
+
+    /* check state */
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+    /* save header structure */
+    state->head = head;
+    head->done = 0;
+    return Z_OK;
+}
+
+/*
+   Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff.  Return when found
+   or when out of input.  When called, *have is the number of pattern bytes
+   found in order so far, in 0..3.  On return *have is updated to the new
+   state.  If on return *have equals four, then the pattern was found and the
+   return value is how many bytes were read including the last byte of the
+   pattern.  If *have is less than four, then the pattern has not been found
+   yet and the return value is len.  In the latter case, syncsearch() can be
+   called again with more data and the *have state.  *have is initialized to
+   zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+const unsigned char FAR *buf;
+unsigned len;
+{
+    unsigned got;
+    unsigned next;
+
+    got = *have;
+    next = 0;
+    while (next < len && got < 4) {
+        if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+            got++;
+        else if (buf[next])
+            got = 0;
+        else
+            got = 4 - got;
+        next++;
+    }
+    *have = got;
+    return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+    unsigned len;               /* number of bytes to look at or looked at */
+    unsigned long in, out;      /* temporary to save total_in and total_out */
+    unsigned char buf[4];       /* to restore bit buffer to byte string */
+    struct inflate_state FAR *state;
+
+    /* check parameters */
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+    /* if first time, start search in bit buffer */
+    if (state->mode != SYNC) {
+        state->mode = SYNC;
+        state->hold <<= state->bits & 7;
+        state->bits -= state->bits & 7;
+        len = 0;
+        while (state->bits >= 8) {
+            buf[len++] = (unsigned char)(state->hold);
+            state->hold >>= 8;
+            state->bits -= 8;
+        }
+        state->have = 0;
+        syncsearch(&(state->have), buf, len);
+    }
+
+    /* search available input */
+    len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+    strm->avail_in -= len;
+    strm->next_in += len;
+    strm->total_in += len;
+
+    /* return no joy or set up to restart inflate() on a new block */
+    if (state->have != 4) return Z_DATA_ERROR;
+    in = strm->total_in;  out = strm->total_out;
+    inflateReset(strm);
+    strm->total_in = in;  strm->total_out = out;
+    state->mode = TYPE;
+    return Z_OK;
+}
+
+/*
+   Returns true if inflate is currently at the end of a block generated by
+   Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+   implementation to provide an additional safety check. PPP uses
+   Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+   block. When decompressing, PPP checks that at the end of input packet,
+   inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+    struct inflate_state FAR *state;
+    struct inflate_state FAR *copy;
+    unsigned char FAR *window;
+    unsigned wsize;
+
+    /* check input */
+    if (inflateStateCheck(source) || dest == Z_NULL)
+        return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)source->state;
+
+    /* allocate space */
+    copy = (struct inflate_state FAR *)
+           ZALLOC(source, 1, sizeof(struct inflate_state));
+    if (copy == Z_NULL) return Z_MEM_ERROR;
+    window = Z_NULL;
+    if (state->window != Z_NULL) {
+        window = (unsigned char FAR *)
+                 ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+        if (window == Z_NULL) {
+            ZFREE(source, copy);
+            return Z_MEM_ERROR;
+        }
+    }
+
+    /* copy state */
+    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+    zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
+    copy->strm = dest;
+    if (state->lencode >= state->codes &&
+        state->lencode <= state->codes + ENOUGH - 1) {
+        copy->lencode = copy->codes + (state->lencode - state->codes);
+        copy->distcode = copy->codes + (state->distcode - state->codes);
+    }
+    copy->next = copy->codes + (state->next - state->codes);
+    if (window != Z_NULL) {
+        wsize = 1U << state->wbits;
+        zmemcpy(window, state->window, wsize);
+    }
+    copy->window = window;
+    dest->state = (struct internal_state FAR *)copy;
+    return Z_OK;
+}
+
+int ZEXPORT inflateUndermine(strm, subvert)
+z_streamp strm;
+int subvert;
+{
+    struct inflate_state FAR *state;
+
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+    state->sane = !subvert;
+    return Z_OK;
+#else
+    (void)subvert;
+    state->sane = 1;
+    return Z_DATA_ERROR;
+#endif
+}
+
+int ZEXPORT inflateValidate(strm, check)
+z_streamp strm;
+int check;
+{
+    struct inflate_state FAR *state;
+
+    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+    state = (struct inflate_state FAR *)strm->state;
+    if (check)
+        state->wrap |= 4;
+    else
+        state->wrap &= ~4;
+    return Z_OK;
+}
+
+long ZEXPORT inflateMark(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+
+    if (inflateStateCheck(strm))
+        return -(1L << 16);
+    state = (struct inflate_state FAR *)strm->state;
+    return (long)(((unsigned long)((long)state->back)) << 16) +
+        (state->mode == COPY ? state->length :
+            (state->mode == MATCH ? state->was - state->length : 0));
+}
+
+unsigned long ZEXPORT inflateCodesUsed(strm)
+z_streamp strm;
+{
+    struct inflate_state FAR *state;
+    if (inflateStateCheck(strm)) return (unsigned long)-1;
+    state = (struct inflate_state FAR *)strm->state;
+    return (unsigned long)(state->next - state->codes);
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/inflate.h b/deps/libchdr/deps/zlib-1.2.11/inflate.h
new file mode 100644 (file)
index 0000000..a46cce6
--- /dev/null
@@ -0,0 +1,125 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+   trailer decoding by inflate().  NO_GZIP would be used to avoid linking in
+   the crc code when it is not needed.  For shared libraries, gzip decoding
+   should be left enabled. */
+#ifndef NO_GZIP
+#  define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+    HEAD = 16180,   /* i: waiting for magic header */
+    FLAGS,      /* i: waiting for method and flags (gzip) */
+    TIME,       /* i: waiting for modification time (gzip) */
+    OS,         /* i: waiting for extra flags and operating system (gzip) */
+    EXLEN,      /* i: waiting for extra length (gzip) */
+    EXTRA,      /* i: waiting for extra bytes (gzip) */
+    NAME,       /* i: waiting for end of file name (gzip) */
+    COMMENT,    /* i: waiting for end of comment (gzip) */
+    HCRC,       /* i: waiting for header crc (gzip) */
+    DICTID,     /* i: waiting for dictionary check value */
+    DICT,       /* waiting for inflateSetDictionary() call */
+        TYPE,       /* i: waiting for type bits, including last-flag bit */
+        TYPEDO,     /* i: same, but skip check to exit inflate on new block */
+        STORED,     /* i: waiting for stored size (length and complement) */
+        COPY_,      /* i/o: same as COPY below, but only first time in */
+        COPY,       /* i/o: waiting for input or output to copy stored block */
+        TABLE,      /* i: waiting for dynamic block table lengths */
+        LENLENS,    /* i: waiting for code length code lengths */
+        CODELENS,   /* i: waiting for length/lit and distance code lengths */
+            LEN_,       /* i: same as LEN below, but only first time in */
+            LEN,        /* i: waiting for length/lit/eob code */
+            LENEXT,     /* i: waiting for length extra bits */
+            DIST,       /* i: waiting for distance code */
+            DISTEXT,    /* i: waiting for distance extra bits */
+            MATCH,      /* o: waiting for output space to copy string */
+            LIT,        /* o: waiting for output space to write literal */
+    CHECK,      /* i: waiting for 32-bit check value */
+    LENGTH,     /* i: waiting for 32-bit length (gzip) */
+    DONE,       /* finished check, done -- remain here until reset */
+    BAD,        /* got a data error -- remain here until reset */
+    MEM,        /* got an inflate() memory error -- remain here until reset */
+    SYNC        /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+    State transitions between above modes -
+
+    (most modes can go to BAD or MEM on error -- not shown for clarity)
+
+    Process header:
+        HEAD -> (gzip) or (zlib) or (raw)
+        (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
+                  HCRC -> TYPE
+        (zlib) -> DICTID or TYPE
+        DICTID -> DICT -> TYPE
+        (raw) -> TYPEDO
+    Read deflate blocks:
+            TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
+            STORED -> COPY_ -> COPY -> TYPE
+            TABLE -> LENLENS -> CODELENS -> LEN_
+            LEN_ -> LEN
+    Read deflate codes in fixed or dynamic block:
+                LEN -> LENEXT or LIT or TYPE
+                LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+                LIT -> LEN
+    Process trailer:
+        CHECK -> LENGTH -> DONE
+ */
+
+/* State maintained between inflate() calls -- approximately 7K bytes, not
+   including the allocated sliding window, which is up to 32K bytes. */
+struct inflate_state {
+    z_streamp strm;             /* pointer back to this zlib stream */
+    inflate_mode mode;          /* current inflate mode */
+    int last;                   /* true if processing last block */
+    int wrap;                   /* bit 0 true for zlib, bit 1 true for gzip,
+                                   bit 2 true to validate check value */
+    int havedict;               /* true if dictionary provided */
+    int flags;                  /* gzip header method and flags (0 if zlib) */
+    unsigned dmax;              /* zlib header max distance (INFLATE_STRICT) */
+    unsigned long check;        /* protected copy of check value */
+    unsigned long total;        /* protected copy of output count */
+    gz_headerp head;            /* where to save gzip header information */
+        /* sliding window */
+    unsigned wbits;             /* log base 2 of requested window size */
+    unsigned wsize;             /* window size or zero if not using window */
+    unsigned whave;             /* valid bytes in the window */
+    unsigned wnext;             /* window write index */
+    unsigned char FAR *window;  /* allocated sliding window, if needed */
+        /* bit accumulator */
+    unsigned long hold;         /* input bit accumulator */
+    unsigned bits;              /* number of bits in "in" */
+        /* for string and stored block copying */
+    unsigned length;            /* literal or length of data to copy */
+    unsigned offset;            /* distance back to copy string from */
+        /* for table and code decoding */
+    unsigned extra;             /* extra bits needed */
+        /* fixed and dynamic code tables */
+    code const FAR *lencode;    /* starting table for length/literal codes */
+    code const FAR *distcode;   /* starting table for distance codes */
+    unsigned lenbits;           /* index bits for lencode */
+    unsigned distbits;          /* index bits for distcode */
+        /* dynamic table building */
+    unsigned ncode;             /* number of code length code lengths */
+    unsigned nlen;              /* number of length code lengths */
+    unsigned ndist;             /* number of distance code lengths */
+    unsigned have;              /* number of code lengths in lens[] */
+    code FAR *next;             /* next available space in codes[] */
+    unsigned short lens[320];   /* temporary storage for code lengths */
+    unsigned short work[288];   /* work area for code table building */
+    code codes[ENOUGH];         /* space for code tables */
+    int sane;                   /* if false, allow invalid distance too far */
+    int back;                   /* bits back of last unprocessed length/lit */
+    unsigned was;               /* initial length of match */
+};
diff --git a/deps/libchdr/deps/zlib-1.2.11/inftrees.c b/deps/libchdr/deps/zlib-1.2.11/inftrees.c
new file mode 100644 (file)
index 0000000..2ea08fc
--- /dev/null
@@ -0,0 +1,304 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2017 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+   " inflate 1.2.11 Copyright 1995-2017 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/*
+   Build a set of tables to decode the provided canonical Huffman code.
+   The code lengths are lens[0..codes-1].  The result starts at *table,
+   whose indices are 0..2^bits-1.  work is a writable array of at least
+   lens shorts, which is used as a work area.  type is the type of code
+   to be generated, CODES, LENS, or DISTS.  On return, zero is success,
+   -1 is an invalid code, and +1 means that ENOUGH isn't enough.  table
+   on return points to the next available entry's address.  bits is the
+   requested root table index bits, and on return it is the actual root
+   table index bits.  It will differ if the request is greater than the
+   longest code or if it is less than the shortest code.
+ */
+int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+    unsigned len;               /* a code's length in bits */
+    unsigned sym;               /* index of code symbols */
+    unsigned min, max;          /* minimum and maximum code lengths */
+    unsigned root;              /* number of index bits for root table */
+    unsigned curr;              /* number of index bits for current table */
+    unsigned drop;              /* code bits to drop for sub-table */
+    int left;                   /* number of prefix codes available */
+    unsigned used;              /* code entries in table used */
+    unsigned huff;              /* Huffman code */
+    unsigned incr;              /* for incrementing code, index */
+    unsigned fill;              /* index for replicating entries */
+    unsigned low;               /* low bits for current root entry */
+    unsigned mask;              /* mask for low root bits */
+    code here;                  /* table entry for duplication */
+    code FAR *next;             /* next available space in table */
+    const unsigned short FAR *base;     /* base value table to use */
+    const unsigned short FAR *extra;    /* extra bits table to use */
+    unsigned match;             /* use base and extra for symbol >= match */
+    unsigned short count[MAXBITS+1];    /* number of codes of each length */
+    unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
+    static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+    static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+        16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202};
+    static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577, 0, 0};
+    static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+        16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+        23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+        28, 28, 29, 29, 64, 64};
+
+    /*
+       Process a set of code lengths to create a canonical Huffman code.  The
+       code lengths are lens[0..codes-1].  Each length corresponds to the
+       symbols 0..codes-1.  The Huffman code is generated by first sorting the
+       symbols by length from short to long, and retaining the symbol order
+       for codes with equal lengths.  Then the code starts with all zero bits
+       for the first code of the shortest length, and the codes are integer
+       increments for the same length, and zeros are appended as the length
+       increases.  For the deflate format, these bits are stored backwards
+       from their more natural integer increment ordering, and so when the
+       decoding tables are built in the large loop below, the integer codes
+       are incremented backwards.
+
+       This routine assumes, but does not check, that all of the entries in
+       lens[] are in the range 0..MAXBITS.  The caller must assure this.
+       1..MAXBITS is interpreted as that code length.  zero means that that
+       symbol does not occur in this code.
+
+       The codes are sorted by computing a count of codes for each length,
+       creating from that a table of starting indices for each length in the
+       sorted table, and then entering the symbols in order in the sorted
+       table.  The sorted table is work[], with that space being provided by
+       the caller.
+
+       The length counts are used for other purposes as well, i.e. finding
+       the minimum and maximum length codes, determining if there are any
+       codes at all, checking for a valid set of lengths, and looking ahead
+       at length counts to determine sub-table sizes when building the
+       decoding tables.
+     */
+
+    /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+    for (len = 0; len <= MAXBITS; len++)
+        count[len] = 0;
+    for (sym = 0; sym < codes; sym++)
+        count[lens[sym]]++;
+
+    /* bound code lengths, force root to be within code lengths */
+    root = *bits;
+    for (max = MAXBITS; max >= 1; max--)
+        if (count[max] != 0) break;
+    if (root > max) root = max;
+    if (max == 0) {                     /* no symbols to code at all */
+        here.op = (unsigned char)64;    /* invalid code marker */
+        here.bits = (unsigned char)1;
+        here.val = (unsigned short)0;
+        *(*table)++ = here;             /* make a table to force an error */
+        *(*table)++ = here;
+        *bits = 1;
+        return 0;     /* no symbols, but wait for decoding to report error */
+    }
+    for (min = 1; min < max; min++)
+        if (count[min] != 0) break;
+    if (root < min) root = min;
+
+    /* check for an over-subscribed or incomplete set of lengths */
+    left = 1;
+    for (len = 1; len <= MAXBITS; len++) {
+        left <<= 1;
+        left -= count[len];
+        if (left < 0) return -1;        /* over-subscribed */
+    }
+    if (left > 0 && (type == CODES || max != 1))
+        return -1;                      /* incomplete set */
+
+    /* generate offsets into symbol table for each length for sorting */
+    offs[1] = 0;
+    for (len = 1; len < MAXBITS; len++)
+        offs[len + 1] = offs[len] + count[len];
+
+    /* sort symbols by length, by symbol order within each length */
+    for (sym = 0; sym < codes; sym++)
+        if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+    /*
+       Create and fill in decoding tables.  In this loop, the table being
+       filled is at next and has curr index bits.  The code being used is huff
+       with length len.  That code is converted to an index by dropping drop
+       bits off of the bottom.  For codes where len is less than drop + curr,
+       those top drop + curr - len bits are incremented through all values to
+       fill the table with replicated entries.
+
+       root is the number of index bits for the root table.  When len exceeds
+       root, sub-tables are created pointed to by the root entry with an index
+       of the low root bits of huff.  This is saved in low to check for when a
+       new sub-table should be started.  drop is zero when the root table is
+       being filled, and drop is root when sub-tables are being filled.
+
+       When a new sub-table is needed, it is necessary to look ahead in the
+       code lengths to determine what size sub-table is needed.  The length
+       counts are used for this, and so count[] is decremented as codes are
+       entered in the tables.
+
+       used keeps track of how many table entries have been allocated from the
+       provided *table space.  It is checked for LENS and DIST tables against
+       the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+       the initial root table size constants.  See the comments in inftrees.h
+       for more information.
+
+       sym increments through all symbols, and the loop terminates when
+       all codes of length max, i.e. all codes, have been processed.  This
+       routine permits incomplete codes, so another loop after this one fills
+       in the rest of the decoding tables with invalid code markers.
+     */
+
+    /* set up for code type */
+    switch (type) {
+    case CODES:
+        base = extra = work;    /* dummy value--not used */
+        match = 20;
+        break;
+    case LENS:
+        base = lbase;
+        extra = lext;
+        match = 257;
+        break;
+    default:    /* DISTS */
+        base = dbase;
+        extra = dext;
+        match = 0;
+    }
+
+    /* initialize state for loop */
+    huff = 0;                   /* starting code */
+    sym = 0;                    /* starting code symbol */
+    len = min;                  /* starting code length */
+    next = *table;              /* current table to fill in */
+    curr = root;                /* current table index bits */
+    drop = 0;                   /* current bits to drop from code for index */
+    low = (unsigned)(-1);       /* trigger new sub-table when len > root */
+    used = 1U << root;          /* use root table entries */
+    mask = used - 1;            /* mask for comparing low */
+
+    /* check available table space */
+    if ((type == LENS && used > ENOUGH_LENS) ||
+        (type == DISTS && used > ENOUGH_DISTS))
+        return 1;
+
+    /* process all codes and make table entries */
+    for (;;) {
+        /* create table entry */
+        here.bits = (unsigned char)(len - drop);
+        if (work[sym] + 1U < match) {
+            here.op = (unsigned char)0;
+            here.val = work[sym];
+        }
+        else if (work[sym] >= match) {
+            here.op = (unsigned char)(extra[work[sym] - match]);
+            here.val = base[work[sym] - match];
+        }
+        else {
+            here.op = (unsigned char)(32 + 64);         /* end of block */
+            here.val = 0;
+        }
+
+        /* replicate for those indices with low len bits equal to huff */
+        incr = 1U << (len - drop);
+        fill = 1U << curr;
+        min = fill;                 /* save offset to next table */
+        do {
+            fill -= incr;
+            next[(huff >> drop) + fill] = here;
+        } while (fill != 0);
+
+        /* backwards increment the len-bit code huff */
+        incr = 1U << (len - 1);
+        while (huff & incr)
+            incr >>= 1;
+        if (incr != 0) {
+            huff &= incr - 1;
+            huff += incr;
+        }
+        else
+            huff = 0;
+
+        /* go to next symbol, update count, len */
+        sym++;
+        if (--(count[len]) == 0) {
+            if (len == max) break;
+            len = lens[work[sym]];
+        }
+
+        /* create new sub-table if needed */
+        if (len > root && (huff & mask) != low) {
+            /* if first time, transition to sub-tables */
+            if (drop == 0)
+                drop = root;
+
+            /* increment past last table */
+            next += min;            /* here min is 1 << curr */
+
+            /* determine length of next table */
+            curr = len - drop;
+            left = (int)(1 << curr);
+            while (curr + drop < max) {
+                left -= count[curr + drop];
+                if (left <= 0) break;
+                curr++;
+                left <<= 1;
+            }
+
+            /* check for enough space */
+            used += 1U << curr;
+            if ((type == LENS && used > ENOUGH_LENS) ||
+                (type == DISTS && used > ENOUGH_DISTS))
+                return 1;
+
+            /* point entry in root table to sub-table */
+            low = huff & mask;
+            (*table)[low].op = (unsigned char)curr;
+            (*table)[low].bits = (unsigned char)root;
+            (*table)[low].val = (unsigned short)(next - *table);
+        }
+    }
+
+    /* fill in remaining table entry if code is incomplete (guaranteed to have
+       at most one remaining entry, since if the code is incomplete, the
+       maximum code length that was allowed to get this far is one bit) */
+    if (huff != 0) {
+        here.op = (unsigned char)64;            /* invalid code marker */
+        here.bits = (unsigned char)(len - drop);
+        here.val = (unsigned short)0;
+        next[huff] = here;
+    }
+
+    /* set return parameters */
+    *table += used;
+    *bits = root;
+    return 0;
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/inftrees.h b/deps/libchdr/deps/zlib-1.2.11/inftrees.h
new file mode 100644 (file)
index 0000000..baa53a0
--- /dev/null
@@ -0,0 +1,62 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables.  Each entry provides either the
+   information needed to do the operation requested by the code that
+   indexed that table entry, or it provides a pointer to another
+   table that indexes more bits of the code.  op indicates whether
+   the entry is a pointer to another table, a literal, a length or
+   distance, an end-of-block, or an invalid code.  For a table
+   pointer, the low four bits of op is the number of index bits of
+   that table.  For a length or distance, the low four bits of op
+   is the number of extra bits to get after the code.  bits is
+   the number of bits in this code or part of the code to drop off
+   of the bit buffer.  val is the actual byte to output in the case
+   of a literal, the base length or distance, or the offset from
+   the current table to the next table.  Each entry is four bytes. */
+typedef struct {
+    unsigned char op;           /* operation, extra bits, table bits */
+    unsigned char bits;         /* bits in this part of the code */
+    unsigned short val;         /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+    00000000 - literal
+    0000tttt - table link, tttt != 0 is the number of table index bits
+    0001eeee - length or distance, eeee is the number of extra bits
+    01100000 - end of block
+    01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table.  The maximum number of code structures is
+   1444, which is the sum of 852 for literal/length codes and 592 for distance
+   codes.  These values were found by exhaustive searches using the program
+   examples/enough.c found in the zlib distribtution.  The arguments to that
+   program are the number of symbols, the initial root table size, and the
+   maximum bit length of a code.  "enough 286 9 15" for literal/length codes
+   returns returns 852, and "enough 30 6 15" for distance codes returns 592.
+   The initial root table size (9 or 6) is found in the fifth argument of the
+   inflate_table() calls in inflate.c and infback.c.  If the root table size is
+   changed, then these maximum sizes would be need to be recalculated and
+   updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 592
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table() */
+typedef enum {
+    CODES,
+    LENS,
+    DISTS
+} codetype;
+
+int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
+                             unsigned codes, code FAR * FAR *table,
+                             unsigned FAR *bits, unsigned short FAR *work));
diff --git a/deps/libchdr/deps/zlib-1.2.11/make_vms.com b/deps/libchdr/deps/zlib-1.2.11/make_vms.com
new file mode 100644 (file)
index 0000000..65e9d0c
--- /dev/null
@@ -0,0 +1,867 @@
+$! make libz under VMS written by
+$! Martin P.J. Zinser
+$!
+$! In case of problems with the install you might contact me at
+$! zinser@zinser.no-ip.info(preferred) or
+$! martin.zinser@eurexchange.com (work)
+$!
+$! Make procedure history for Zlib
+$!
+$!------------------------------------------------------------------------------
+$! Version history
+$! 0.01 20060120 First version to receive a number
+$! 0.02 20061008 Adapt to new Makefile.in
+$! 0.03 20091224 Add support for large file check
+$! 0.04 20100110 Add new gzclose, gzlib, gzread, gzwrite
+$! 0.05 20100221 Exchange zlibdefs.h by zconf.h.in
+$! 0.06 20120111 Fix missing amiss_err, update zconf_h.in, fix new exmples
+$!               subdir path, update module search in makefile.in
+$! 0.07 20120115 Triggered by work done by Alexey Chupahin completly redesigned
+$!               shared image creation
+$! 0.08 20120219 Make it work on VAX again, pre-load missing symbols to shared
+$!               image
+$! 0.09 20120305 SMS.  P1 sets builder ("MMK", "MMS", " " (built-in)).
+$!               "" -> automatic, preference: MMK, MMS, built-in.
+$!
+$ on error then goto err_exit
+$!
+$ true  = 1
+$ false = 0
+$ tmpnam = "temp_" + f$getjpi("","pid")
+$ tt = tmpnam + ".txt"
+$ tc = tmpnam + ".c"
+$ th = tmpnam + ".h"
+$ define/nolog tconfig 'th'
+$ its_decc = false
+$ its_vaxc = false
+$ its_gnuc = false
+$ s_case   = False
+$!
+$! Setup variables holding "config" information
+$!
+$ Make    = "''p1'"
+$ name     = "Zlib"
+$ version  = "?.?.?"
+$ v_string = "ZLIB_VERSION"
+$ v_file   = "zlib.h"
+$ ccopt   = "/include = []"
+$ lopts   = ""
+$ dnsrl   = ""
+$ aconf_in_file = "zconf.h.in#zconf.h_in#zconf_h.in"
+$ conf_check_string = ""
+$ linkonly = false
+$ optfile  = name + ".opt"
+$ mapfile  = name + ".map"
+$ libdefs  = ""
+$ vax      = f$getsyi("HW_MODEL").lt.1024
+$ axp      = f$getsyi("HW_MODEL").ge.1024 .and. f$getsyi("HW_MODEL").lt.4096
+$ ia64     = f$getsyi("HW_MODEL").ge.4096
+$!
+$! 2012-03-05 SMS.
+$! Why is this needed?  And if it is needed, why not simply ".not. vax"?
+$!
+$!!! if axp .or. ia64 then  set proc/parse=extended
+$!
+$ whoami = f$parse(f$environment("Procedure"),,,,"NO_CONCEAL")
+$ mydef  = F$parse(whoami,,,"DEVICE")
+$ mydir  = f$parse(whoami,,,"DIRECTORY") - "]["
+$ myproc = f$parse(whoami,,,"Name") + f$parse(whoami,,,"type")
+$!
+$! Check for MMK/MMS
+$!
+$ if (Make .eqs. "")
+$ then
+$   If F$Search ("Sys$System:MMS.EXE") .nes. "" Then Make = "MMS"
+$   If F$Type (MMK) .eqs. "STRING" Then Make = "MMK"
+$ else
+$   Make = f$edit( Make, "trim")
+$ endif
+$!
+$ gosub find_version
+$!
+$  open/write topt tmp.opt
+$  open/write optf 'optfile'
+$!
+$ gosub check_opts
+$!
+$! Look for the compiler used
+$!
+$ gosub check_compiler
+$ close topt
+$ close optf
+$!
+$ if its_decc
+$ then
+$   ccopt = "/prefix=all" + ccopt
+$   if f$trnlnm("SYS") .eqs. ""
+$   then
+$     if axp
+$     then
+$       define sys sys$library:
+$     else
+$       ccopt = "/decc" + ccopt
+$       define sys decc$library_include:
+$     endif
+$   endif
+$!
+$! 2012-03-05 SMS.
+$! Why /NAMES = AS_IS?  Why not simply ".not. vax"?  And why not on VAX?
+$!
+$   if axp .or. ia64
+$   then
+$       ccopt = ccopt + "/name=as_is/opt=(inline=speed)"
+$       s_case = true
+$   endif
+$ endif
+$ if its_vaxc .or. its_gnuc
+$ then
+$    if f$trnlnm("SYS").eqs."" then define sys sys$library:
+$ endif
+$!
+$! Build a fake configure input header
+$!
+$ open/write conf_hin config.hin
+$ write conf_hin "#undef _LARGEFILE64_SOURCE"
+$ close conf_hin
+$!
+$!
+$ i = 0
+$FIND_ACONF:
+$ fname = f$element(i,"#",aconf_in_file)
+$ if fname .eqs. "#" then goto AMISS_ERR
+$ if f$search(fname) .eqs. ""
+$ then
+$   i = i + 1
+$   goto find_aconf
+$ endif
+$ open/read/err=aconf_err aconf_in 'fname'
+$ open/write aconf zconf.h
+$ACONF_LOOP:
+$ read/end_of_file=aconf_exit aconf_in line
+$ work = f$edit(line, "compress,trim")
+$ if f$extract(0,6,work) .nes. "#undef"
+$ then
+$   if f$extract(0,12,work) .nes. "#cmakedefine"
+$   then
+$       write aconf line
+$   endif
+$ else
+$   cdef = f$element(1," ",work)
+$   gosub check_config
+$ endif
+$ goto aconf_loop
+$ACONF_EXIT:
+$ write aconf ""
+$ write aconf "/* VMS specifics added by make_vms.com: */"
+$ write aconf "#define VMS 1"
+$ write aconf "#include <unistd.h>"
+$ write aconf "#include <unixio.h>"
+$ write aconf "#ifdef _LARGEFILE"
+$ write aconf "# define off64_t __off64_t"
+$ write aconf "# define fopen64 fopen"
+$ write aconf "# define fseeko64 fseeko"
+$ write aconf "# define lseek64 lseek"
+$ write aconf "# define ftello64 ftell"
+$ write aconf "#endif"
+$ write aconf "#if !defined( __VAX) && (__CRTL_VER >= 70312000)"
+$ write aconf "# define HAVE_VSNPRINTF"
+$ write aconf "#endif"
+$ close aconf_in
+$ close aconf
+$ if f$search("''th'") .nes. "" then delete 'th';*
+$! Build the thing plain or with mms
+$!
+$ write sys$output "Compiling Zlib sources ..."
+$ if make.eqs.""
+$ then
+$   if (f$search( "example.obj;*") .nes. "") then delete example.obj;*
+$   if (f$search( "minigzip.obj;*") .nes. "") then delete minigzip.obj;*
+$   CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" -
+                adler32.c zlib.h zconf.h
+$   CALL MAKE compress.OBJ "CC ''CCOPT' compress" -
+                compress.c zlib.h zconf.h
+$   CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" -
+                crc32.c zlib.h zconf.h
+$   CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" -
+                deflate.c deflate.h zutil.h zlib.h zconf.h
+$   CALL MAKE gzclose.OBJ "CC ''CCOPT' gzclose" -
+                gzclose.c zutil.h zlib.h zconf.h
+$   CALL MAKE gzlib.OBJ "CC ''CCOPT' gzlib" -
+                gzlib.c zutil.h zlib.h zconf.h
+$   CALL MAKE gzread.OBJ "CC ''CCOPT' gzread" -
+                gzread.c zutil.h zlib.h zconf.h
+$   CALL MAKE gzwrite.OBJ "CC ''CCOPT' gzwrite" -
+                gzwrite.c zutil.h zlib.h zconf.h
+$   CALL MAKE infback.OBJ "CC ''CCOPT' infback" -
+                infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h
+$   CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" -
+                inffast.c zutil.h zlib.h zconf.h inffast.h
+$   CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" -
+                inflate.c zutil.h zlib.h zconf.h infblock.h
+$   CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" -
+                inftrees.c zutil.h zlib.h zconf.h inftrees.h
+$   CALL MAKE trees.OBJ "CC ''CCOPT' trees" -
+                trees.c deflate.h zutil.h zlib.h zconf.h
+$   CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" -
+                uncompr.c zlib.h zconf.h
+$   CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" -
+                zutil.c zutil.h zlib.h zconf.h
+$   write sys$output "Building Zlib ..."
+$   CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ
+$   write sys$output "Building example..."
+$   CALL MAKE example.OBJ "CC ''CCOPT' [.test]example" -
+                [.test]example.c zlib.h zconf.h
+$   call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb
+$   write sys$output "Building minigzip..."
+$   CALL MAKE minigzip.OBJ "CC ''CCOPT' [.test]minigzip" -
+              [.test]minigzip.c zlib.h zconf.h
+$   call make minigzip.exe -
+              "LINK minigzip,libz.olb/lib" -
+              minigzip.obj libz.olb
+$ else
+$   gosub crea_mms
+$   write sys$output "Make ''name' ''version' with ''Make' "
+$   'make'
+$ endif
+$!
+$! Create shareable image
+$!
+$ gosub crea_olist
+$ write sys$output "Creating libzshr.exe"
+$ call map_2_shopt 'mapfile' 'optfile'
+$ LINK_'lopts'/SHARE=libzshr.exe modules.opt/opt,'optfile'/opt
+$ write sys$output "Zlib build completed"
+$ delete/nolog tmp.opt;*
+$ exit
+$AMISS_ERR:
+$ write sys$output "No source for config.hin found."
+$ write sys$output "Tried any of ''aconf_in_file'"
+$ goto err_exit
+$CC_ERR:
+$ write sys$output "C compiler required to build ''name'"
+$ goto err_exit
+$ERR_EXIT:
+$ set message/facil/ident/sever/text
+$ close/nolog optf
+$ close/nolog topt
+$ close/nolog aconf_in
+$ close/nolog aconf
+$ close/nolog out
+$ close/nolog min
+$ close/nolog mod
+$ close/nolog h_in
+$ write sys$output "Exiting..."
+$ exit 2
+$!
+$!
+$MAKE: SUBROUTINE   !SUBROUTINE TO CHECK DEPENDENCIES
+$ V = 'F$Verify(0)
+$! P1 = What we are trying to make
+$! P2 = Command to make it
+$! P3 - P8  What it depends on
+$
+$ If F$Search(P1) .Eqs. "" Then Goto Makeit
+$ Time = F$CvTime(F$File(P1,"RDT"))
+$arg=3
+$Loop:
+$       Argument = P'arg
+$       If Argument .Eqs. "" Then Goto Exit
+$       El=0
+$Loop2:
+$       File = F$Element(El," ",Argument)
+$       If File .Eqs. " " Then Goto Endl
+$       AFile = ""
+$Loop3:
+$       OFile = AFile
+$       AFile = F$Search(File)
+$       If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl
+$       If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit
+$       Goto Loop3
+$NextEL:
+$       El = El + 1
+$       Goto Loop2
+$EndL:
+$ arg=arg+1
+$ If arg .Le. 8 Then Goto Loop
+$ Goto Exit
+$
+$Makeit:
+$ VV=F$VERIFY(0)
+$ write sys$output P2
+$ 'P2
+$ VV='F$Verify(VV)
+$Exit:
+$ If V Then Set Verify
+$ENDSUBROUTINE
+$!------------------------------------------------------------------------------
+$!
+$! Check command line options and set symbols accordingly
+$!
+$!------------------------------------------------------------------------------
+$! Version history
+$! 0.01 20041206 First version to receive a number
+$! 0.02 20060126 Add new "HELP" target
+$ CHECK_OPTS:
+$ i = 1
+$ OPT_LOOP:
+$ if i .lt. 9
+$ then
+$   cparm = f$edit(p'i',"upcase")
+$!
+$! Check if parameter actually contains something
+$!
+$   if f$edit(cparm,"trim") .nes. ""
+$   then
+$     if cparm .eqs. "DEBUG"
+$     then
+$       ccopt = ccopt + "/noopt/deb"
+$       lopts = lopts + "/deb"
+$     endif
+$     if f$locate("CCOPT=",cparm) .lt. f$length(cparm)
+$     then
+$       start = f$locate("=",cparm) + 1
+$       len   = f$length(cparm) - start
+$       ccopt = ccopt + f$extract(start,len,cparm)
+$       if f$locate("AS_IS",f$edit(ccopt,"UPCASE")) .lt. f$length(ccopt) -
+          then s_case = true
+$     endif
+$     if cparm .eqs. "LINK" then linkonly = true
+$     if f$locate("LOPTS=",cparm) .lt. f$length(cparm)
+$     then
+$       start = f$locate("=",cparm) + 1
+$       len   = f$length(cparm) - start
+$       lopts = lopts + f$extract(start,len,cparm)
+$     endif
+$     if f$locate("CC=",cparm) .lt. f$length(cparm)
+$     then
+$       start  = f$locate("=",cparm) + 1
+$       len    = f$length(cparm) - start
+$       cc_com = f$extract(start,len,cparm)
+        if (cc_com .nes. "DECC") .and. -
+           (cc_com .nes. "VAXC") .and. -
+           (cc_com .nes. "GNUC")
+$       then
+$         write sys$output "Unsupported compiler choice ''cc_com' ignored"
+$         write sys$output "Use DECC, VAXC, or GNUC instead"
+$       else
+$         if cc_com .eqs. "DECC" then its_decc = true
+$         if cc_com .eqs. "VAXC" then its_vaxc = true
+$         if cc_com .eqs. "GNUC" then its_gnuc = true
+$       endif
+$     endif
+$     if f$locate("MAKE=",cparm) .lt. f$length(cparm)
+$     then
+$       start  = f$locate("=",cparm) + 1
+$       len    = f$length(cparm) - start
+$       mmks = f$extract(start,len,cparm)
+$       if (mmks .eqs. "MMK") .or. (mmks .eqs. "MMS")
+$       then
+$         make = mmks
+$       else
+$         write sys$output "Unsupported make choice ''mmks' ignored"
+$         write sys$output "Use MMK or MMS instead"
+$       endif
+$     endif
+$     if cparm .eqs. "HELP" then gosub bhelp
+$   endif
+$   i = i + 1
+$   goto opt_loop
+$ endif
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Look for the compiler used
+$!
+$! Version history
+$! 0.01 20040223 First version to receive a number
+$! 0.02 20040229 Save/set value of decc$no_rooted_search_lists
+$! 0.03 20060202 Extend handling of GNU C
+$! 0.04 20090402 Compaq -> hp
+$CHECK_COMPILER:
+$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc))
+$ then
+$   its_decc = (f$search("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. "")
+$   its_vaxc = .not. its_decc .and. (F$Search("SYS$System:VAXC.Exe") .nes. "")
+$   its_gnuc = .not. (its_decc .or. its_vaxc) .and. (f$trnlnm("gnu_cc") .nes. "")
+$ endif
+$!
+$! Exit if no compiler available
+$!
+$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc))
+$ then goto CC_ERR
+$ else
+$   if its_decc
+$   then
+$     write sys$output "CC compiler check ... hp C"
+$     if f$trnlnm("decc$no_rooted_search_lists") .nes. ""
+$     then
+$       dnrsl = f$trnlnm("decc$no_rooted_search_lists")
+$     endif
+$     define/nolog decc$no_rooted_search_lists 1
+$   else
+$     if its_vaxc then write sys$output "CC compiler check ... VAX C"
+$     if its_gnuc
+$     then
+$         write sys$output "CC compiler check ... GNU C"
+$         if f$trnlnm(topt) then write topt "gnu_cc:[000000]gcclib.olb/lib"
+$         if f$trnlnm(optf) then write optf "gnu_cc:[000000]gcclib.olb/lib"
+$         cc = "gcc"
+$     endif
+$     if f$trnlnm(topt) then write topt "sys$share:vaxcrtl.exe/share"
+$     if f$trnlnm(optf) then write optf "sys$share:vaxcrtl.exe/share"
+$   endif
+$ endif
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! If MMS/MMK are available dump out the descrip.mms if required
+$!
+$CREA_MMS:
+$ write sys$output "Creating descrip.mms..."
+$ create descrip.mms
+$ open/append out descrip.mms
+$ copy sys$input: out
+$ deck
+# descrip.mms: MMS description file for building zlib on VMS
+# written by Martin P.J. Zinser
+# <zinser@zinser.no-ip.info or martin.zinser@eurexchange.com>
+
+OBJS = adler32.obj, compress.obj, crc32.obj, gzclose.obj, gzlib.obj\
+       gzread.obj, gzwrite.obj, uncompr.obj, infback.obj\
+       deflate.obj, trees.obj, zutil.obj, inflate.obj, \
+       inftrees.obj, inffast.obj
+
+$ eod
+$ write out "CFLAGS=", ccopt
+$ write out "LOPTS=", lopts
+$ write out "all : example.exe minigzip.exe libz.olb"
+$ copy sys$input: out
+$ deck
+        @ write sys$output " Example applications available"
+
+libz.olb : libz.olb($(OBJS))
+       @ write sys$output " libz available"
+
+example.exe : example.obj libz.olb
+              link $(LOPTS) example,libz.olb/lib
+
+minigzip.exe : minigzip.obj libz.olb
+              link $(LOPTS) minigzip,libz.olb/lib
+
+clean :
+       delete *.obj;*,libz.olb;*,*.opt;*,*.exe;*
+
+
+# Other dependencies.
+adler32.obj  : adler32.c zutil.h zlib.h zconf.h
+compress.obj : compress.c zlib.h zconf.h
+crc32.obj    : crc32.c zutil.h zlib.h zconf.h
+deflate.obj  : deflate.c deflate.h zutil.h zlib.h zconf.h
+example.obj  : [.test]example.c zlib.h zconf.h
+gzclose.obj  : gzclose.c zutil.h zlib.h zconf.h
+gzlib.obj    : gzlib.c zutil.h zlib.h zconf.h
+gzread.obj   : gzread.c zutil.h zlib.h zconf.h
+gzwrite.obj  : gzwrite.c zutil.h zlib.h zconf.h
+inffast.obj  : inffast.c zutil.h zlib.h zconf.h inftrees.h inffast.h
+inflate.obj  : inflate.c zutil.h zlib.h zconf.h
+inftrees.obj : inftrees.c zutil.h zlib.h zconf.h inftrees.h
+minigzip.obj : [.test]minigzip.c zlib.h zconf.h
+trees.obj    : trees.c deflate.h zutil.h zlib.h zconf.h
+uncompr.obj  : uncompr.c zlib.h zconf.h
+zutil.obj    : zutil.c zutil.h zlib.h zconf.h
+infback.obj  : infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h
+$ eod
+$ close out
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Read list of core library sources from makefile.in and create options
+$! needed to build shareable image
+$!
+$CREA_OLIST:
+$ open/read min makefile.in
+$ open/write mod modules.opt
+$ src_check_list = "OBJZ =#OBJG ="
+$MRLOOP:
+$ read/end=mrdone min rec
+$ i = 0
+$SRC_CHECK_LOOP:
+$ src_check = f$element(i, "#", src_check_list)
+$ i = i+1
+$ if src_check .eqs. "#" then goto mrloop
+$ if (f$extract(0,6,rec) .nes. src_check) then goto src_check_loop
+$ rec = rec - src_check
+$ gosub extra_filnam
+$ if (f$element(1,"\",rec) .eqs. "\") then goto mrloop
+$MRSLOOP:
+$ read/end=mrdone min rec
+$ gosub extra_filnam
+$ if (f$element(1,"\",rec) .nes. "\") then goto mrsloop
+$MRDONE:
+$ close min
+$ close mod
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Take record extracted in crea_olist and split it into single filenames
+$!
+$EXTRA_FILNAM:
+$ myrec = f$edit(rec - "\", "trim,compress")
+$ i = 0
+$FELOOP:
+$ srcfil = f$element(i," ", myrec)
+$ if (srcfil .nes. " ")
+$ then
+$   write mod f$parse(srcfil,,,"NAME"), ".obj"
+$   i = i + 1
+$   goto feloop
+$ endif
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Find current Zlib version number
+$!
+$FIND_VERSION:
+$ open/read h_in 'v_file'
+$hloop:
+$ read/end=hdone h_in rec
+$ rec = f$edit(rec,"TRIM")
+$ if (f$extract(0,1,rec) .nes. "#") then goto hloop
+$ rec = f$edit(rec - "#", "TRIM")
+$ if f$element(0," ",rec) .nes. "define" then goto hloop
+$ if f$element(1," ",rec) .eqs. v_string
+$ then
+$   version = 'f$element(2," ",rec)'
+$   goto hdone
+$ endif
+$ goto hloop
+$hdone:
+$ close h_in
+$ return
+$!------------------------------------------------------------------------------
+$!
+$CHECK_CONFIG:
+$!
+$ in_ldef = f$locate(cdef,libdefs)
+$ if (in_ldef .lt. f$length(libdefs))
+$ then
+$   write aconf "#define ''cdef' 1"
+$   libdefs = f$extract(0,in_ldef,libdefs) + -
+              f$extract(in_ldef + f$length(cdef) + 1, -
+                        f$length(libdefs) - in_ldef - f$length(cdef) - 1, -
+                        libdefs)
+$ else
+$   if (f$type('cdef') .eqs. "INTEGER")
+$   then
+$     write aconf "#define ''cdef' ", 'cdef'
+$   else
+$     if (f$type('cdef') .eqs. "STRING")
+$     then
+$       write aconf "#define ''cdef' ", """", '''cdef'', """"
+$     else
+$       gosub check_cc_def
+$     endif
+$   endif
+$ endif
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Check if this is a define relating to the properties of the C/C++
+$! compiler
+$!
+$ CHECK_CC_DEF:
+$ if (cdef .eqs. "_LARGEFILE64_SOURCE")
+$ then
+$   copy sys$input: 'tc'
+$   deck
+#include "tconfig"
+#define _LARGEFILE
+#include <stdio.h>
+
+int main(){
+FILE *fp;
+  fp = fopen("temp.txt","r");
+  fseeko(fp,1,SEEK_SET);
+  fclose(fp);
+}
+
+$   eod
+$   test_inv = false
+$   comm_h = false
+$   gosub cc_prop_check
+$   return
+$ endif
+$ write aconf "/* ", line, " */"
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Check for properties of C/C++ compiler
+$!
+$! Version history
+$! 0.01 20031020 First version to receive a number
+$! 0.02 20031022 Added logic for defines with value
+$! 0.03 20040309 Make sure local config file gets not deleted
+$! 0.04 20041230 Also write include for configure run
+$! 0.05 20050103 Add processing of "comment defines"
+$CC_PROP_CHECK:
+$ cc_prop = true
+$ is_need = false
+$ is_need = (f$extract(0,4,cdef) .eqs. "NEED") .or. (test_inv .eq. true)
+$ if f$search(th) .eqs. "" then create 'th'
+$ set message/nofac/noident/nosever/notext
+$ on error then continue
+$ cc 'tmpnam'
+$ if .not. ($status)  then cc_prop = false
+$ on error then continue
+$! The headers might lie about the capabilities of the RTL
+$ link 'tmpnam',tmp.opt/opt
+$ if .not. ($status)  then cc_prop = false
+$ set message/fac/ident/sever/text
+$ on error then goto err_exit
+$ delete/nolog 'tmpnam'.*;*/exclude='th'
+$ if (cc_prop .and. .not. is_need) .or. -
+     (.not. cc_prop .and. is_need)
+$ then
+$   write sys$output "Checking for ''cdef'... yes"
+$   if f$type('cdef_val'_yes) .nes. ""
+$   then
+$     if f$type('cdef_val'_yes) .eqs. "INTEGER" -
+         then call write_config f$fao("#define !AS !UL",cdef,'cdef_val'_yes)
+$     if f$type('cdef_val'_yes) .eqs. "STRING" -
+         then call write_config f$fao("#define !AS !AS",cdef,'cdef_val'_yes)
+$   else
+$     call write_config f$fao("#define !AS 1",cdef)
+$   endif
+$   if (cdef .eqs. "HAVE_FSEEKO") .or. (cdef .eqs. "_LARGE_FILES") .or. -
+       (cdef .eqs. "_LARGEFILE64_SOURCE") then -
+      call write_config f$string("#define _LARGEFILE 1")
+$ else
+$   write sys$output "Checking for ''cdef'... no"
+$   if (comm_h)
+$   then
+      call write_config f$fao("/* !AS */",line)
+$   else
+$     if f$type('cdef_val'_no) .nes. ""
+$     then
+$       if f$type('cdef_val'_no) .eqs. "INTEGER" -
+           then call write_config f$fao("#define !AS !UL",cdef,'cdef_val'_no)
+$       if f$type('cdef_val'_no) .eqs. "STRING" -
+           then call write_config f$fao("#define !AS !AS",cdef,'cdef_val'_no)
+$     else
+$       call write_config f$fao("#undef !AS",cdef)
+$     endif
+$   endif
+$ endif
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Check for properties of C/C++ compiler with multiple result values
+$!
+$! Version history
+$! 0.01 20040127 First version
+$! 0.02 20050103 Reconcile changes from cc_prop up to version 0.05
+$CC_MPROP_CHECK:
+$ cc_prop = true
+$ i    = 1
+$ idel = 1
+$ MT_LOOP:
+$ if f$type(result_'i') .eqs. "STRING"
+$ then
+$   set message/nofac/noident/nosever/notext
+$   on error then continue
+$   cc 'tmpnam'_'i'
+$   if .not. ($status)  then cc_prop = false
+$   on error then continue
+$! The headers might lie about the capabilities of the RTL
+$   link 'tmpnam'_'i',tmp.opt/opt
+$   if .not. ($status)  then cc_prop = false
+$   set message/fac/ident/sever/text
+$   on error then goto err_exit
+$   delete/nolog 'tmpnam'_'i'.*;*
+$   if (cc_prop)
+$   then
+$     write sys$output "Checking for ''cdef'... ", mdef_'i'
+$     if f$type(mdef_'i') .eqs. "INTEGER" -
+         then call write_config f$fao("#define !AS !UL",cdef,mdef_'i')
+$     if f$type('cdef_val'_yes) .eqs. "STRING" -
+         then call write_config f$fao("#define !AS !AS",cdef,mdef_'i')
+$     goto msym_clean
+$   else
+$     i = i + 1
+$     goto mt_loop
+$   endif
+$ endif
+$ write sys$output "Checking for ''cdef'... no"
+$ call write_config f$fao("#undef !AS",cdef)
+$ MSYM_CLEAN:
+$ if (idel .le. msym_max)
+$ then
+$   delete/sym mdef_'idel'
+$   idel = idel + 1
+$   goto msym_clean
+$ endif
+$ return
+$!------------------------------------------------------------------------------
+$!
+$! Write configuration to both permanent and temporary config file
+$!
+$! Version history
+$! 0.01 20031029 First version to receive a number
+$!
+$WRITE_CONFIG: SUBROUTINE
+$  write aconf 'p1'
+$  open/append confh 'th'
+$  write confh 'p1'
+$  close confh
+$ENDSUBROUTINE
+$!------------------------------------------------------------------------------
+$!
+$! Analyze the project map file and create the symbol vector for a shareable
+$! image from it
+$!
+$! Version history
+$! 0.01 20120128 First version
+$! 0.02 20120226 Add pre-load logic
+$!
+$ MAP_2_SHOPT: Subroutine
+$!
+$ SAY := "WRITE_ SYS$OUTPUT"
+$!
+$ IF F$SEARCH("''P1'") .EQS. ""
+$ THEN
+$    SAY "MAP_2_SHOPT-E-NOSUCHFILE:  Error, inputfile ''p1' not available"
+$    goto exit_m2s
+$ ENDIF
+$ IF "''P2'" .EQS. ""
+$ THEN
+$    SAY "MAP_2_SHOPT:  Error, no output file provided"
+$    goto exit_m2s
+$ ENDIF
+$!
+$ module1 = "deflate#deflateEnd#deflateInit_#deflateParams#deflateSetDictionary"
+$ module2 = "gzclose#gzerror#gzgetc#gzgets#gzopen#gzprintf#gzputc#gzputs#gzread"
+$ module3 = "gzseek#gztell#inflate#inflateEnd#inflateInit_#inflateSetDictionary"
+$ module4 = "inflateSync#uncompress#zlibVersion#compress"
+$ open/read map 'p1
+$ if axp .or. ia64
+$ then
+$     open/write aopt a.opt
+$     open/write bopt b.opt
+$     write aopt " CASE_SENSITIVE=YES"
+$     write bopt "SYMBOL_VECTOR= (-"
+$     mod_sym_num = 1
+$ MOD_SYM_LOOP:
+$     if f$type(module'mod_sym_num') .nes. ""
+$     then
+$         mod_in = 0
+$ MOD_SYM_IN:
+$         shared_proc = f$element(mod_in, "#", module'mod_sym_num')
+$         if shared_proc .nes. "#"
+$         then
+$             write aopt f$fao(" symbol_vector=(!AS/!AS=PROCEDURE)",-
+                              f$edit(shared_proc,"upcase"),shared_proc)
+$             write bopt f$fao("!AS=PROCEDURE,-",shared_proc)
+$             mod_in = mod_in + 1
+$             goto mod_sym_in
+$         endif
+$         mod_sym_num = mod_sym_num + 1
+$         goto mod_sym_loop
+$     endif
+$MAP_LOOP:
+$     read/end=map_end map line
+$     if (f$locate("{",line).lt. f$length(line)) .or. -
+         (f$locate("global:", line) .lt. f$length(line))
+$     then
+$         proc = true
+$         goto map_loop
+$     endif
+$     if f$locate("}",line).lt. f$length(line) then proc = false
+$     if f$locate("local:", line) .lt. f$length(line) then proc = false
+$     if proc
+$     then
+$         shared_proc = f$edit(line,"collapse")
+$         chop_semi = f$locate(";", shared_proc)
+$         if chop_semi .lt. f$length(shared_proc) then -
+              shared_proc = f$extract(0, chop_semi, shared_proc)
+$         write aopt f$fao(" symbol_vector=(!AS/!AS=PROCEDURE)",-
+                                f$edit(shared_proc,"upcase"),shared_proc)
+$         write bopt f$fao("!AS=PROCEDURE,-",shared_proc)
+$     endif
+$     goto map_loop
+$MAP_END:
+$     close/nolog aopt
+$     close/nolog bopt
+$     open/append libopt 'p2'
+$     open/read aopt a.opt
+$     open/read bopt b.opt
+$ALOOP:
+$     read/end=aloop_end aopt line
+$     write libopt line
+$     goto aloop
+$ALOOP_END:
+$     close/nolog aopt
+$     sv = ""
+$BLOOP:
+$     read/end=bloop_end bopt svn
+$     if (svn.nes."")
+$     then
+$        if (sv.nes."") then write libopt sv
+$        sv = svn
+$     endif
+$     goto bloop
+$BLOOP_END:
+$     write libopt f$extract(0,f$length(sv)-2,sv), "-"
+$     write libopt ")"
+$     close/nolog bopt
+$     delete/nolog/noconf a.opt;*,b.opt;*
+$ else
+$     if vax
+$     then
+$     open/append libopt 'p2'
+$     mod_sym_num = 1
+$ VMOD_SYM_LOOP:
+$     if f$type(module'mod_sym_num') .nes. ""
+$     then
+$         mod_in = 0
+$ VMOD_SYM_IN:
+$         shared_proc = f$element(mod_in, "#", module'mod_sym_num')
+$         if shared_proc .nes. "#"
+$         then
+$            write libopt f$fao("UNIVERSAL=!AS",-
+                                    f$edit(shared_proc,"upcase"))
+$             mod_in = mod_in + 1
+$             goto vmod_sym_in
+$         endif
+$         mod_sym_num = mod_sym_num + 1
+$         goto vmod_sym_loop
+$     endif
+$VMAP_LOOP:
+$        read/end=vmap_end map line
+$        if (f$locate("{",line).lt. f$length(line)) .or. -
+             (f$locate("global:", line) .lt. f$length(line))
+$        then
+$            proc = true
+$            goto vmap_loop
+$        endif
+$        if f$locate("}",line).lt. f$length(line) then proc = false
+$        if f$locate("local:", line) .lt. f$length(line) then proc = false
+$        if proc
+$        then
+$            shared_proc = f$edit(line,"collapse")
+$            chop_semi = f$locate(";", shared_proc)
+$            if chop_semi .lt. f$length(shared_proc) then -
+                 shared_proc = f$extract(0, chop_semi, shared_proc)
+$            write libopt f$fao("UNIVERSAL=!AS",-
+                                    f$edit(shared_proc,"upcase"))
+$        endif
+$        goto vmap_loop
+$VMAP_END:
+$     else
+$         write sys$output "Unknown Architecture (Not VAX, AXP, or IA64)"
+$         write sys$output "No options file created"
+$     endif
+$ endif
+$ EXIT_M2S:
+$ close/nolog map
+$ close/nolog libopt
+$ endsubroutine
diff --git a/deps/libchdr/deps/zlib-1.2.11/treebuild.xml b/deps/libchdr/deps/zlib-1.2.11/treebuild.xml
new file mode 100644 (file)
index 0000000..fd75525
--- /dev/null
@@ -0,0 +1,116 @@
+<?xml version="1.0" ?>
+<package name="zlib" version="1.2.11">
+    <library name="zlib" dlversion="1.2.11" dlname="z">
+       <property name="description"> zip compression library </property>
+       <property name="include-target-dir" value="$(@PACKAGE/install-includedir)" />
+
+       <!-- fixme: not implemented yet -->
+       <property name="compiler/c/inline" value="yes" />
+
+       <include-file name="zlib.h" scope="public" mode="644" />
+       <include-file name="zconf.h" scope="public" mode="644" />
+
+       <source name="adler32.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+       </source>
+       <source name="compress.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+       </source>
+       <source name="crc32.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="crc32.h" />
+       </source>
+       <source name="gzclose.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="gzguts.h" />
+       </source>
+       <source name="gzlib.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="gzguts.h" />
+       </source>
+       <source name="gzread.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="gzguts.h" />
+       </source>
+       <source name="gzwrite.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="gzguts.h" />
+       </source>
+       <source name="uncompr.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+       </source>
+       <source name="deflate.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="zutil.h" />
+           <depend name="deflate.h" />
+       </source>
+       <source name="trees.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="zutil.h" />
+           <depend name="deflate.h" />
+           <depend name="trees.h" />
+       </source>
+       <source name="zutil.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="zutil.h" />
+       </source>
+       <source name="inflate.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="zutil.h" />
+           <depend name="inftrees.h" />
+           <depend name="inflate.h" />
+           <depend name="inffast.h" />
+       </source>
+       <source name="infback.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="zutil.h" />
+           <depend name="inftrees.h" />
+           <depend name="inflate.h" />
+           <depend name="inffast.h" />
+       </source>
+       <source name="inftrees.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="zutil.h" />
+           <depend name="inftrees.h" />
+       </source>
+       <source name="inffast.c">
+           <depend name="zlib.h" />
+           <depend name="zconf.h" />
+           <depend name="zutil.h" />
+           <depend name="inftrees.h" />
+           <depend name="inflate.h" />
+           <depend name="inffast.h" />
+       </source>
+    </library>
+</package>
+
+<!--
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DZLIB_DEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+#           -Wstrict-prototypes -Wmissing-prototypes
+
+# OBJA =
+# to use the asm code: make OBJA=match.o
+#
+match.o: match.S
+       $(CPP) match.S > _match.s
+       $(CC) -c _match.s
+       mv _match.o match.o
+       rm -f _match.s
+-->
diff --git a/deps/libchdr/deps/zlib-1.2.11/trees.c b/deps/libchdr/deps/zlib-1.2.11/trees.c
new file mode 100644 (file)
index 0000000..50cf4b4
--- /dev/null
@@ -0,0 +1,1203 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2017 Jean-loup Gailly
+ * detect_data_type() function provided freely by Cosmin Truta, 2006
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef ZLIB_DEBUG
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN  512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+#  include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+    const ct_data *static_tree;  /* static tree or NULL */
+    const intf *extra_bits;      /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local const static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local const static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local const static_tree_desc  static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0,   BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, const ct_data *ltree,
+                              const ct_data *dtree));
+local int  detect_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef ZLIB_DEBUG
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* !ZLIB_DEBUG */
+#  define send_code(s, c, tree) \
+     { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef ZLIB_DEBUG
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (ush)value << s->bi_valid;
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= (ush)value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !ZLIB_DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = (int)value;\
+    s->bi_buf |= (ush)val << s->bi_valid;\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (ush)(value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* ZLIB_DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* For some embedded targets, global variables are not initialized: */
+#ifdef NO_INIT_GLOBAL_POINTERS
+    static_l_desc.static_tree = static_ltree;
+    static_l_desc.extra_bits = extra_lbits;
+    static_d_desc.static_tree = static_dtree;
+    static_d_desc.extra_bits = extra_dbits;
+    static_bl_desc.extra_bits = extra_blbits;
+#endif
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            _length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    _length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            _dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            _dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+
+#  ifdef GEN_TREES_H
+    gen_trees_header();
+#  endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+#  ifndef ZLIB_DEBUG
+#    include <stdio.h>
+#  endif
+
+#  define SEPARATOR(i, last, width) \
+      ((i) == (last)? "\n};\n\n" :    \
+       ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+    FILE *header = fopen("trees.h", "w");
+    int i;
+
+    Assert (header != NULL, "Can't open trees.h");
+    fprintf(header,
+            "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+    fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+    for (i = 0; i < L_CODES+2; i++) {
+        fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+                static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+    }
+
+    fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+                static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+    }
+
+    fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
+    for (i = 0; i < DIST_CODE_LEN; i++) {
+        fprintf(header, "%2u%s", _dist_code[i],
+                SEPARATOR(i, DIST_CODE_LEN-1, 20));
+    }
+
+    fprintf(header,
+        "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+    for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+        fprintf(header, "%2u%s", _length_code[i],
+                SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+    }
+
+    fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+    for (i = 0; i < LENGTH_CODES; i++) {
+        fprintf(header, "%1u%s", base_length[i],
+                SEPARATOR(i, LENGTH_CODES-1, 20));
+    }
+
+    fprintf(header, "local const int base_dist[D_CODES] = {\n");
+    for (i = 0; i < D_CODES; i++) {
+        fprintf(header, "%5u%s", base_dist[i],
+                SEPARATOR(i, D_CODES-1, 10));
+    }
+
+    fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void ZLIB_INTERNAL _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef ZLIB_DEBUG
+    s->compressed_len = 0L;
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree        = desc->dyn_tree;
+    int max_code         = desc->max_code;
+    const ct_data *stree = desc->stat_desc->static_tree;
+    const intf *extra    = desc->stat_desc->extra_bits;
+    int base             = desc->stat_desc->extra_base;
+    int max_length       = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (unsigned)(bits + xbits);
+        if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Tracev((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if ((unsigned) tree[m].Len != (unsigned) bits) {
+                Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    unsigned code = 0;         /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        code = (code + bl_count[bits-1]) << 1;
+        next_code[bits] = (ush)code;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree         = desc->dyn_tree;
+    const ct_data *stree  = desc->stat_desc->static_tree;
+    int elems             = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+                                s->depth[n] : s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int last;         /* one if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+last, 3);    /* send block type */
+    bi_windup(s);        /* align on byte boundary */
+    put_short(s, (ush)stored_len);
+    put_short(s, (ush)~stored_len);
+    zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);
+    s->pending += stored_len;
+#ifdef ZLIB_DEBUG
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+    s->bits_sent += 2*16;
+    s->bits_sent += stored_len<<3;
+#endif
+}
+
+/* ===========================================================================
+ * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
+ */
+void ZLIB_INTERNAL _tr_flush_bits(s)
+    deflate_state *s;
+{
+    bi_flush(s);
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ */
+void ZLIB_INTERNAL _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+#ifdef ZLIB_DEBUG
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+    bi_flush(s);
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and write out the encoded block.
+ */
+void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int last;         /* one if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+        /* Check if the file is binary or text */
+        if (s->strm->data_type == Z_UNKNOWN)
+            s->strm->data_type = detect_data_type(s);
+
+        /* Construct the literal and distance trees */
+        build_tree(s, (tree_desc *)(&(s->l_desc)));
+        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+
+        build_tree(s, (tree_desc *)(&(s->d_desc)));
+        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+                s->static_len));
+        /* At this point, opt_len and static_len are the total bit lengths of
+         * the compressed block data, excluding the tree representations.
+         */
+
+        /* Build the bit length tree for the above two trees, and get the index
+         * in bl_order of the last bit length code to send.
+         */
+        max_blindex = build_bl_tree(s);
+
+        /* Determine the best encoding. Compute the block lengths in bytes. */
+        opt_lenb = (s->opt_len+3+7)>>3;
+        static_lenb = (s->static_len+3+7)>>3;
+
+        Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+                opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+                s->last_lit));
+
+        if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+        opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, last);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+last, 3);
+        compress_block(s, (const ct_data *)static_ltree,
+                       (const ct_data *)static_dtree);
+#ifdef ZLIB_DEBUG
+        s->compressed_len += 3 + s->static_len;
+#endif
+    } else {
+        send_bits(s, (DYN_TREES<<1)+last, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (const ct_data *)s->dyn_ltree,
+                       (const ct_data *)s->dyn_dtree);
+#ifdef ZLIB_DEBUG
+        s->compressed_len += 3 + s->opt_len;
+#endif
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    /* The above check is made mod 2^32, for files larger than 512 MB
+     * and uLong implemented on 32 bits.
+     */
+    init_block(s);
+
+    if (last) {
+        bi_windup(s);
+#ifdef ZLIB_DEBUG
+        s->compressed_len += 7;  /* align on byte boundary */
+#endif
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ZLIB_INTERNAL _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+#ifdef TRUNCATE_BLOCK
+    /* Try to guess if it is profitable to stop the current block here */
+    if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+#endif
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    const ct_data *ltree; /* literal tree */
+    const ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = _length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= (unsigned)base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+               "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ *    a) There are no non-portable control characters belonging to the
+ *       "black list" (0..6, 14..25, 28..31).
+ *    b) There is at least one printable character belonging to the
+ *       "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ *   "gray list" that is ignored in this detection algorithm:
+ *   (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(s)
+    deflate_state *s;
+{
+    /* black_mask is the bit mask of black-listed bytes
+     * set bits 0..6, 14..25, and 28..31
+     * 0xf3ffc07f = binary 11110011111111111100000001111111
+     */
+    unsigned long black_mask = 0xf3ffc07fUL;
+    int n;
+
+    /* Check for non-textual ("black-listed") bytes. */
+    for (n = 0; n <= 31; n++, black_mask >>= 1)
+        if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+            return Z_BINARY;
+
+    /* Check for textual ("white-listed") bytes. */
+    if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+            || s->dyn_ltree[13].Freq != 0)
+        return Z_TEXT;
+    for (n = 32; n < LITERALS; n++)
+        if (s->dyn_ltree[n].Freq != 0)
+            return Z_TEXT;
+
+    /* There are no "black-listed" or "white-listed" bytes:
+     * this stream either is empty or has tolerated ("gray-listed") bytes only.
+     */
+    return Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef ZLIB_DEBUG
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/trees.h b/deps/libchdr/deps/zlib-1.2.11/trees.h
new file mode 100644 (file)
index 0000000..d35639d
--- /dev/null
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{  8}}, {{140},{  8}}, {{ 76},{  8}}, {{204},{  8}}, {{ 44},{  8}},
+{{172},{  8}}, {{108},{  8}}, {{236},{  8}}, {{ 28},{  8}}, {{156},{  8}},
+{{ 92},{  8}}, {{220},{  8}}, {{ 60},{  8}}, {{188},{  8}}, {{124},{  8}},
+{{252},{  8}}, {{  2},{  8}}, {{130},{  8}}, {{ 66},{  8}}, {{194},{  8}},
+{{ 34},{  8}}, {{162},{  8}}, {{ 98},{  8}}, {{226},{  8}}, {{ 18},{  8}},
+{{146},{  8}}, {{ 82},{  8}}, {{210},{  8}}, {{ 50},{  8}}, {{178},{  8}},
+{{114},{  8}}, {{242},{  8}}, {{ 10},{  8}}, {{138},{  8}}, {{ 74},{  8}},
+{{202},{  8}}, {{ 42},{  8}}, {{170},{  8}}, {{106},{  8}}, {{234},{  8}},
+{{ 26},{  8}}, {{154},{  8}}, {{ 90},{  8}}, {{218},{  8}}, {{ 58},{  8}},
+{{186},{  8}}, {{122},{  8}}, {{250},{  8}}, {{  6},{  8}}, {{134},{  8}},
+{{ 70},{  8}}, {{198},{  8}}, {{ 38},{  8}}, {{166},{  8}}, {{102},{  8}},
+{{230},{  8}}, {{ 22},{  8}}, {{150},{  8}}, {{ 86},{  8}}, {{214},{  8}},
+{{ 54},{  8}}, {{182},{  8}}, {{118},{  8}}, {{246},{  8}}, {{ 14},{  8}},
+{{142},{  8}}, {{ 78},{  8}}, {{206},{  8}}, {{ 46},{  8}}, {{174},{  8}},
+{{110},{  8}}, {{238},{  8}}, {{ 30},{  8}}, {{158},{  8}}, {{ 94},{  8}},
+{{222},{  8}}, {{ 62},{  8}}, {{190},{  8}}, {{126},{  8}}, {{254},{  8}},
+{{  1},{  8}}, {{129},{  8}}, {{ 65},{  8}}, {{193},{  8}}, {{ 33},{  8}},
+{{161},{  8}}, {{ 97},{  8}}, {{225},{  8}}, {{ 17},{  8}}, {{145},{  8}},
+{{ 81},{  8}}, {{209},{  8}}, {{ 49},{  8}}, {{177},{  8}}, {{113},{  8}},
+{{241},{  8}}, {{  9},{  8}}, {{137},{  8}}, {{ 73},{  8}}, {{201},{  8}},
+{{ 41},{  8}}, {{169},{  8}}, {{105},{  8}}, {{233},{  8}}, {{ 25},{  8}},
+{{153},{  8}}, {{ 89},{  8}}, {{217},{  8}}, {{ 57},{  8}}, {{185},{  8}},
+{{121},{  8}}, {{249},{  8}}, {{  5},{  8}}, {{133},{  8}}, {{ 69},{  8}},
+{{197},{  8}}, {{ 37},{  8}}, {{165},{  8}}, {{101},{  8}}, {{229},{  8}},
+{{ 21},{  8}}, {{149},{  8}}, {{ 85},{  8}}, {{213},{  8}}, {{ 53},{  8}},
+{{181},{  8}}, {{117},{  8}}, {{245},{  8}}, {{ 13},{  8}}, {{141},{  8}},
+{{ 77},{  8}}, {{205},{  8}}, {{ 45},{  8}}, {{173},{  8}}, {{109},{  8}},
+{{237},{  8}}, {{ 29},{  8}}, {{157},{  8}}, {{ 93},{  8}}, {{221},{  8}},
+{{ 61},{  8}}, {{189},{  8}}, {{125},{  8}}, {{253},{  8}}, {{ 19},{  9}},
+{{275},{  9}}, {{147},{  9}}, {{403},{  9}}, {{ 83},{  9}}, {{339},{  9}},
+{{211},{  9}}, {{467},{  9}}, {{ 51},{  9}}, {{307},{  9}}, {{179},{  9}},
+{{435},{  9}}, {{115},{  9}}, {{371},{  9}}, {{243},{  9}}, {{499},{  9}},
+{{ 11},{  9}}, {{267},{  9}}, {{139},{  9}}, {{395},{  9}}, {{ 75},{  9}},
+{{331},{  9}}, {{203},{  9}}, {{459},{  9}}, {{ 43},{  9}}, {{299},{  9}},
+{{171},{  9}}, {{427},{  9}}, {{107},{  9}}, {{363},{  9}}, {{235},{  9}},
+{{491},{  9}}, {{ 27},{  9}}, {{283},{  9}}, {{155},{  9}}, {{411},{  9}},
+{{ 91},{  9}}, {{347},{  9}}, {{219},{  9}}, {{475},{  9}}, {{ 59},{  9}},
+{{315},{  9}}, {{187},{  9}}, {{443},{  9}}, {{123},{  9}}, {{379},{  9}},
+{{251},{  9}}, {{507},{  9}}, {{  7},{  9}}, {{263},{  9}}, {{135},{  9}},
+{{391},{  9}}, {{ 71},{  9}}, {{327},{  9}}, {{199},{  9}}, {{455},{  9}},
+{{ 39},{  9}}, {{295},{  9}}, {{167},{  9}}, {{423},{  9}}, {{103},{  9}},
+{{359},{  9}}, {{231},{  9}}, {{487},{  9}}, {{ 23},{  9}}, {{279},{  9}},
+{{151},{  9}}, {{407},{  9}}, {{ 87},{  9}}, {{343},{  9}}, {{215},{  9}},
+{{471},{  9}}, {{ 55},{  9}}, {{311},{  9}}, {{183},{  9}}, {{439},{  9}},
+{{119},{  9}}, {{375},{  9}}, {{247},{  9}}, {{503},{  9}}, {{ 15},{  9}},
+{{271},{  9}}, {{143},{  9}}, {{399},{  9}}, {{ 79},{  9}}, {{335},{  9}},
+{{207},{  9}}, {{463},{  9}}, {{ 47},{  9}}, {{303},{  9}}, {{175},{  9}},
+{{431},{  9}}, {{111},{  9}}, {{367},{  9}}, {{239},{  9}}, {{495},{  9}},
+{{ 31},{  9}}, {{287},{  9}}, {{159},{  9}}, {{415},{  9}}, {{ 95},{  9}},
+{{351},{  9}}, {{223},{  9}}, {{479},{  9}}, {{ 63},{  9}}, {{319},{  9}},
+{{191},{  9}}, {{447},{  9}}, {{127},{  9}}, {{383},{  9}}, {{255},{  9}},
+{{511},{  9}}, {{  0},{  7}}, {{ 64},{  7}}, {{ 32},{  7}}, {{ 96},{  7}},
+{{ 16},{  7}}, {{ 80},{  7}}, {{ 48},{  7}}, {{112},{  7}}, {{  8},{  7}},
+{{ 72},{  7}}, {{ 40},{  7}}, {{104},{  7}}, {{ 24},{  7}}, {{ 88},{  7}},
+{{ 56},{  7}}, {{120},{  7}}, {{  4},{  7}}, {{ 68},{  7}}, {{ 36},{  7}},
+{{100},{  7}}, {{ 20},{  7}}, {{ 84},{  7}}, {{ 52},{  7}}, {{116},{  7}},
+{{  3},{  8}}, {{131},{  8}}, {{ 67},{  8}}, {{195},{  8}}, {{ 35},{  8}},
+{{163},{  8}}, {{ 99},{  8}}, {{227},{  8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
+ 0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,  8,  8,
+ 8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,  0,  0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0,  1,  2,  3,  4,  5,  6,  7,  8,  8,  9,  9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+    0,     1,     2,     3,     4,     6,     8,    12,    16,    24,
+   32,    48,    64,    96,   128,   192,   256,   384,   512,   768,
+ 1024,  1536,  2048,  3072,  4096,  6144,  8192, 12288, 16384, 24576
+};
+
diff --git a/deps/libchdr/deps/zlib-1.2.11/uncompr.c b/deps/libchdr/deps/zlib-1.2.11/uncompr.c
new file mode 100644 (file)
index 0000000..f03a1a8
--- /dev/null
@@ -0,0 +1,93 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+     Decompresses the source buffer into the destination buffer.  *sourceLen is
+   the byte length of the source buffer. Upon entry, *destLen is the total size
+   of the destination buffer, which must be large enough to hold the entire
+   uncompressed data. (The size of the uncompressed data must have been saved
+   previously by the compressor and transmitted to the decompressor by some
+   mechanism outside the scope of this compression library.) Upon exit,
+   *destLen is the size of the decompressed data and *sourceLen is the number
+   of source bytes consumed. Upon return, source + *sourceLen points to the
+   first unused input byte.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
+   Z_DATA_ERROR if the input data was corrupted, including if the input data is
+   an incomplete zlib stream.
+*/
+int ZEXPORT uncompress2 (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong *sourceLen;
+{
+    z_stream stream;
+    int err;
+    const uInt max = (uInt)-1;
+    uLong len, left;
+    Byte buf[1];    /* for detection of incomplete stream when *destLen == 0 */
+
+    len = *sourceLen;
+    if (*destLen) {
+        left = *destLen;
+        *destLen = 0;
+    }
+    else {
+        left = 1;
+        dest = buf;
+    }
+
+    stream.next_in = (z_const Bytef *)source;
+    stream.avail_in = 0;
+    stream.zalloc = (alloc_func)0;
+    stream.zfree = (free_func)0;
+    stream.opaque = (voidpf)0;
+
+    err = inflateInit(&stream);
+    if (err != Z_OK) return err;
+
+    stream.next_out = dest;
+    stream.avail_out = 0;
+
+    do {
+        if (stream.avail_out == 0) {
+            stream.avail_out = left > (uLong)max ? max : (uInt)left;
+            left -= stream.avail_out;
+        }
+        if (stream.avail_in == 0) {
+            stream.avail_in = len > (uLong)max ? max : (uInt)len;
+            len -= stream.avail_in;
+        }
+        err = inflate(&stream, Z_NO_FLUSH);
+    } while (err == Z_OK);
+
+    *sourceLen -= len + stream.avail_in;
+    if (dest != buf)
+        *destLen = stream.total_out;
+    else if (stream.total_out && err == Z_BUF_ERROR)
+        left = 1;
+
+    inflateEnd(&stream);
+    return err == Z_STREAM_END ? Z_OK :
+           err == Z_NEED_DICT ? Z_DATA_ERROR  :
+           err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
+           err;
+}
+
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+    Bytef *dest;
+    uLongf *destLen;
+    const Bytef *source;
+    uLong sourceLen;
+{
+    return uncompress2(dest, destLen, source, &sourceLen);
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/zconf.h b/deps/libchdr/deps/zlib-1.2.11/zconf.h
new file mode 100644 (file)
index 0000000..5e1d68a
--- /dev/null
@@ -0,0 +1,534 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
+#  define Z_PREFIX_SET
+
+/* all linked symbols and init macros */
+#  define _dist_code            z__dist_code
+#  define _length_code          z__length_code
+#  define _tr_align             z__tr_align
+#  define _tr_flush_bits        z__tr_flush_bits
+#  define _tr_flush_block       z__tr_flush_block
+#  define _tr_init              z__tr_init
+#  define _tr_stored_block      z__tr_stored_block
+#  define _tr_tally             z__tr_tally
+#  define adler32               z_adler32
+#  define adler32_combine       z_adler32_combine
+#  define adler32_combine64     z_adler32_combine64
+#  define adler32_z             z_adler32_z
+#  ifndef Z_SOLO
+#    define compress              z_compress
+#    define compress2             z_compress2
+#    define compressBound         z_compressBound
+#  endif
+#  define crc32                 z_crc32
+#  define crc32_combine         z_crc32_combine
+#  define crc32_combine64       z_crc32_combine64
+#  define crc32_z               z_crc32_z
+#  define deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  define deflateGetDictionary  z_deflateGetDictionary
+#  define deflateInit           z_deflateInit
+#  define deflateInit2          z_deflateInit2
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateInit_          z_deflateInit_
+#  define deflateParams         z_deflateParams
+#  define deflatePending        z_deflatePending
+#  define deflatePrime          z_deflatePrime
+#  define deflateReset          z_deflateReset
+#  define deflateResetKeep      z_deflateResetKeep
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateSetHeader      z_deflateSetHeader
+#  define deflateTune           z_deflateTune
+#  define deflate_copyright     z_deflate_copyright
+#  define get_crc_table         z_get_crc_table
+#  ifndef Z_SOLO
+#    define gz_error              z_gz_error
+#    define gz_intmax             z_gz_intmax
+#    define gz_strwinerror        z_gz_strwinerror
+#    define gzbuffer              z_gzbuffer
+#    define gzclearerr            z_gzclearerr
+#    define gzclose               z_gzclose
+#    define gzclose_r             z_gzclose_r
+#    define gzclose_w             z_gzclose_w
+#    define gzdirect              z_gzdirect
+#    define gzdopen               z_gzdopen
+#    define gzeof                 z_gzeof
+#    define gzerror               z_gzerror
+#    define gzflush               z_gzflush
+#    define gzfread               z_gzfread
+#    define gzfwrite              z_gzfwrite
+#    define gzgetc                z_gzgetc
+#    define gzgetc_               z_gzgetc_
+#    define gzgets                z_gzgets
+#    define gzoffset              z_gzoffset
+#    define gzoffset64            z_gzoffset64
+#    define gzopen                z_gzopen
+#    define gzopen64              z_gzopen64
+#    ifdef _WIN32
+#      define gzopen_w              z_gzopen_w
+#    endif
+#    define gzprintf              z_gzprintf
+#    define gzputc                z_gzputc
+#    define gzputs                z_gzputs
+#    define gzread                z_gzread
+#    define gzrewind              z_gzrewind
+#    define gzseek                z_gzseek
+#    define gzseek64              z_gzseek64
+#    define gzsetparams           z_gzsetparams
+#    define gztell                z_gztell
+#    define gztell64              z_gztell64
+#    define gzungetc              z_gzungetc
+#    define gzvprintf             z_gzvprintf
+#    define gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit       z_inflateBackInit
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCodesUsed      z_inflateCodesUsed
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateGetHeader      z_inflateGetHeader
+#  define inflateInit           z_inflateInit
+#  define inflateInit2          z_inflateInit2
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateInit_          z_inflateInit_
+#  define inflateMark           z_inflateMark
+#  define inflatePrime          z_inflatePrime
+#  define inflateReset          z_inflateReset
+#  define inflateReset2         z_inflateReset2
+#  define inflateResetKeep      z_inflateResetKeep
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateValidate       z_inflateValidate
+#  define inflate_copyright     z_inflate_copyright
+#  define inflate_fast          z_inflate_fast
+#  define inflate_table         z_inflate_table
+#  ifndef Z_SOLO
+#    define uncompress            z_uncompress
+#    define uncompress2           z_uncompress2
+#  endif
+#  define zError                z_zError
+#  ifndef Z_SOLO
+#    define zcalloc               z_zcalloc
+#    define zcfree                z_zcfree
+#  endif
+#  define zlibCompileFlags      z_zlibCompileFlags
+#  define zlibVersion           z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+#  define Byte                  z_Byte
+#  define Bytef                 z_Bytef
+#  define alloc_func            z_alloc_func
+#  define charf                 z_charf
+#  define free_func             z_free_func
+#  ifndef Z_SOLO
+#    define gzFile                z_gzFile
+#  endif
+#  define gz_header             z_gz_header
+#  define gz_headerp            z_gz_headerp
+#  define in_func               z_in_func
+#  define intf                  z_intf
+#  define out_func              z_out_func
+#  define uInt                  z_uInt
+#  define uIntf                 z_uIntf
+#  define uLong                 z_uLong
+#  define uLongf                z_uLongf
+#  define voidp                 z_voidp
+#  define voidpc                z_voidpc
+#  define voidpf                z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+#  define gz_header_s           z_gz_header_s
+#  define internal_state        z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+#  define z_const const
+#else
+#  define z_const
+#endif
+
+#ifdef Z_SOLO
+   typedef unsigned long z_size_t;
+#else
+#  define z_longlong long long
+#  if defined(NO_SIZE_T)
+     typedef unsigned NO_SIZE_T z_size_t;
+#  elif defined(STDC)
+#    include <stddef.h>
+     typedef size_t z_size_t;
+#  else
+     typedef unsigned long z_size_t;
+#  endif
+#  undef z_longlong
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus about 7 kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#    define Z_ARG(args)  args
+#  else
+#    define Z_ARG(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+#  include <limits.h>
+#  if (UINT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned
+#  elif (ULONG_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned long
+#  elif (USHRT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned short
+#  endif
+#endif
+
+#ifdef Z_U4
+   typedef Z_U4 z_crc_t;
+#else
+   typedef unsigned long z_crc_t;
+#endif
+
+#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+#  ifndef Z_SOLO
+#    include <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* for wchar_t */
+#  endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+#  undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* for off_t */
+#    endif
+#    ifndef z_off_t
+#      define z_off_t off_t
+#    endif
+#  endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+#  define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+#  define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+#  define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+#  define z_off64_t off64_t
+#else
+#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+#    define z_off64_t __int64
+#  else
+#    define z_off64_t z_off_t
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+  #pragma map(deflateInit_,"DEIN")
+  #pragma map(deflateInit2_,"DEIN2")
+  #pragma map(deflateEnd,"DEEND")
+  #pragma map(deflateBound,"DEBND")
+  #pragma map(inflateInit_,"ININ")
+  #pragma map(inflateInit2_,"ININ2")
+  #pragma map(inflateEnd,"INEND")
+  #pragma map(inflateSync,"INSY")
+  #pragma map(inflateSetDictionary,"INSEDI")
+  #pragma map(compressBound,"CMBND")
+  #pragma map(inflate_table,"INTABL")
+  #pragma map(inflate_fast,"INFA")
+  #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/deps/libchdr/deps/zlib-1.2.11/zconf.h.cmakein b/deps/libchdr/deps/zlib-1.2.11/zconf.h.cmakein
new file mode 100644 (file)
index 0000000..a7f24cc
--- /dev/null
@@ -0,0 +1,536 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+#cmakedefine Z_PREFIX
+#cmakedefine Z_HAVE_UNISTD_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
+#  define Z_PREFIX_SET
+
+/* all linked symbols and init macros */
+#  define _dist_code            z__dist_code
+#  define _length_code          z__length_code
+#  define _tr_align             z__tr_align
+#  define _tr_flush_bits        z__tr_flush_bits
+#  define _tr_flush_block       z__tr_flush_block
+#  define _tr_init              z__tr_init
+#  define _tr_stored_block      z__tr_stored_block
+#  define _tr_tally             z__tr_tally
+#  define adler32               z_adler32
+#  define adler32_combine       z_adler32_combine
+#  define adler32_combine64     z_adler32_combine64
+#  define adler32_z             z_adler32_z
+#  ifndef Z_SOLO
+#    define compress              z_compress
+#    define compress2             z_compress2
+#    define compressBound         z_compressBound
+#  endif
+#  define crc32                 z_crc32
+#  define crc32_combine         z_crc32_combine
+#  define crc32_combine64       z_crc32_combine64
+#  define crc32_z               z_crc32_z
+#  define deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  define deflateGetDictionary  z_deflateGetDictionary
+#  define deflateInit           z_deflateInit
+#  define deflateInit2          z_deflateInit2
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateInit_          z_deflateInit_
+#  define deflateParams         z_deflateParams
+#  define deflatePending        z_deflatePending
+#  define deflatePrime          z_deflatePrime
+#  define deflateReset          z_deflateReset
+#  define deflateResetKeep      z_deflateResetKeep
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateSetHeader      z_deflateSetHeader
+#  define deflateTune           z_deflateTune
+#  define deflate_copyright     z_deflate_copyright
+#  define get_crc_table         z_get_crc_table
+#  ifndef Z_SOLO
+#    define gz_error              z_gz_error
+#    define gz_intmax             z_gz_intmax
+#    define gz_strwinerror        z_gz_strwinerror
+#    define gzbuffer              z_gzbuffer
+#    define gzclearerr            z_gzclearerr
+#    define gzclose               z_gzclose
+#    define gzclose_r             z_gzclose_r
+#    define gzclose_w             z_gzclose_w
+#    define gzdirect              z_gzdirect
+#    define gzdopen               z_gzdopen
+#    define gzeof                 z_gzeof
+#    define gzerror               z_gzerror
+#    define gzflush               z_gzflush
+#    define gzfread               z_gzfread
+#    define gzfwrite              z_gzfwrite
+#    define gzgetc                z_gzgetc
+#    define gzgetc_               z_gzgetc_
+#    define gzgets                z_gzgets
+#    define gzoffset              z_gzoffset
+#    define gzoffset64            z_gzoffset64
+#    define gzopen                z_gzopen
+#    define gzopen64              z_gzopen64
+#    ifdef _WIN32
+#      define gzopen_w              z_gzopen_w
+#    endif
+#    define gzprintf              z_gzprintf
+#    define gzputc                z_gzputc
+#    define gzputs                z_gzputs
+#    define gzread                z_gzread
+#    define gzrewind              z_gzrewind
+#    define gzseek                z_gzseek
+#    define gzseek64              z_gzseek64
+#    define gzsetparams           z_gzsetparams
+#    define gztell                z_gztell
+#    define gztell64              z_gztell64
+#    define gzungetc              z_gzungetc
+#    define gzvprintf             z_gzvprintf
+#    define gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit       z_inflateBackInit
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCodesUsed      z_inflateCodesUsed
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateGetHeader      z_inflateGetHeader
+#  define inflateInit           z_inflateInit
+#  define inflateInit2          z_inflateInit2
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateInit_          z_inflateInit_
+#  define inflateMark           z_inflateMark
+#  define inflatePrime          z_inflatePrime
+#  define inflateReset          z_inflateReset
+#  define inflateReset2         z_inflateReset2
+#  define inflateResetKeep      z_inflateResetKeep
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateValidate       z_inflateValidate
+#  define inflate_copyright     z_inflate_copyright
+#  define inflate_fast          z_inflate_fast
+#  define inflate_table         z_inflate_table
+#  ifndef Z_SOLO
+#    define uncompress            z_uncompress
+#    define uncompress2           z_uncompress2
+#  endif
+#  define zError                z_zError
+#  ifndef Z_SOLO
+#    define zcalloc               z_zcalloc
+#    define zcfree                z_zcfree
+#  endif
+#  define zlibCompileFlags      z_zlibCompileFlags
+#  define zlibVersion           z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+#  define Byte                  z_Byte
+#  define Bytef                 z_Bytef
+#  define alloc_func            z_alloc_func
+#  define charf                 z_charf
+#  define free_func             z_free_func
+#  ifndef Z_SOLO
+#    define gzFile                z_gzFile
+#  endif
+#  define gz_header             z_gz_header
+#  define gz_headerp            z_gz_headerp
+#  define in_func               z_in_func
+#  define intf                  z_intf
+#  define out_func              z_out_func
+#  define uInt                  z_uInt
+#  define uIntf                 z_uIntf
+#  define uLong                 z_uLong
+#  define uLongf                z_uLongf
+#  define voidp                 z_voidp
+#  define voidpc                z_voidpc
+#  define voidpf                z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+#  define gz_header_s           z_gz_header_s
+#  define internal_state        z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+#  define z_const const
+#else
+#  define z_const
+#endif
+
+#ifdef Z_SOLO
+   typedef unsigned long z_size_t;
+#else
+#  define z_longlong long long
+#  if defined(NO_SIZE_T)
+     typedef unsigned NO_SIZE_T z_size_t;
+#  elif defined(STDC)
+#    include <stddef.h>
+     typedef size_t z_size_t;
+#  else
+     typedef unsigned long z_size_t;
+#  endif
+#  undef z_longlong
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus about 7 kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#    define Z_ARG(args)  args
+#  else
+#    define Z_ARG(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+#  include <limits.h>
+#  if (UINT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned
+#  elif (ULONG_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned long
+#  elif (USHRT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned short
+#  endif
+#endif
+
+#ifdef Z_U4
+   typedef Z_U4 z_crc_t;
+#else
+   typedef unsigned long z_crc_t;
+#endif
+
+#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+#  ifndef Z_SOLO
+#    include <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* for wchar_t */
+#  endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+#  undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* for off_t */
+#    endif
+#    ifndef z_off_t
+#      define z_off_t off_t
+#    endif
+#  endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+#  define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+#  define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+#  define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+#  define z_off64_t off64_t
+#else
+#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+#    define z_off64_t __int64
+#  else
+#    define z_off64_t z_off_t
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+  #pragma map(deflateInit_,"DEIN")
+  #pragma map(deflateInit2_,"DEIN2")
+  #pragma map(deflateEnd,"DEEND")
+  #pragma map(deflateBound,"DEBND")
+  #pragma map(inflateInit_,"ININ")
+  #pragma map(inflateInit2_,"ININ2")
+  #pragma map(inflateEnd,"INEND")
+  #pragma map(inflateSync,"INSY")
+  #pragma map(inflateSetDictionary,"INSEDI")
+  #pragma map(compressBound,"CMBND")
+  #pragma map(inflate_table,"INTABL")
+  #pragma map(inflate_fast,"INFA")
+  #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/deps/libchdr/deps/zlib-1.2.11/zconf.h.in b/deps/libchdr/deps/zlib-1.2.11/zconf.h.in
new file mode 100644 (file)
index 0000000..5e1d68a
--- /dev/null
@@ -0,0 +1,534 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
+#  define Z_PREFIX_SET
+
+/* all linked symbols and init macros */
+#  define _dist_code            z__dist_code
+#  define _length_code          z__length_code
+#  define _tr_align             z__tr_align
+#  define _tr_flush_bits        z__tr_flush_bits
+#  define _tr_flush_block       z__tr_flush_block
+#  define _tr_init              z__tr_init
+#  define _tr_stored_block      z__tr_stored_block
+#  define _tr_tally             z__tr_tally
+#  define adler32               z_adler32
+#  define adler32_combine       z_adler32_combine
+#  define adler32_combine64     z_adler32_combine64
+#  define adler32_z             z_adler32_z
+#  ifndef Z_SOLO
+#    define compress              z_compress
+#    define compress2             z_compress2
+#    define compressBound         z_compressBound
+#  endif
+#  define crc32                 z_crc32
+#  define crc32_combine         z_crc32_combine
+#  define crc32_combine64       z_crc32_combine64
+#  define crc32_z               z_crc32_z
+#  define deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  define deflateGetDictionary  z_deflateGetDictionary
+#  define deflateInit           z_deflateInit
+#  define deflateInit2          z_deflateInit2
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateInit_          z_deflateInit_
+#  define deflateParams         z_deflateParams
+#  define deflatePending        z_deflatePending
+#  define deflatePrime          z_deflatePrime
+#  define deflateReset          z_deflateReset
+#  define deflateResetKeep      z_deflateResetKeep
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateSetHeader      z_deflateSetHeader
+#  define deflateTune           z_deflateTune
+#  define deflate_copyright     z_deflate_copyright
+#  define get_crc_table         z_get_crc_table
+#  ifndef Z_SOLO
+#    define gz_error              z_gz_error
+#    define gz_intmax             z_gz_intmax
+#    define gz_strwinerror        z_gz_strwinerror
+#    define gzbuffer              z_gzbuffer
+#    define gzclearerr            z_gzclearerr
+#    define gzclose               z_gzclose
+#    define gzclose_r             z_gzclose_r
+#    define gzclose_w             z_gzclose_w
+#    define gzdirect              z_gzdirect
+#    define gzdopen               z_gzdopen
+#    define gzeof                 z_gzeof
+#    define gzerror               z_gzerror
+#    define gzflush               z_gzflush
+#    define gzfread               z_gzfread
+#    define gzfwrite              z_gzfwrite
+#    define gzgetc                z_gzgetc
+#    define gzgetc_               z_gzgetc_
+#    define gzgets                z_gzgets
+#    define gzoffset              z_gzoffset
+#    define gzoffset64            z_gzoffset64
+#    define gzopen                z_gzopen
+#    define gzopen64              z_gzopen64
+#    ifdef _WIN32
+#      define gzopen_w              z_gzopen_w
+#    endif
+#    define gzprintf              z_gzprintf
+#    define gzputc                z_gzputc
+#    define gzputs                z_gzputs
+#    define gzread                z_gzread
+#    define gzrewind              z_gzrewind
+#    define gzseek                z_gzseek
+#    define gzseek64              z_gzseek64
+#    define gzsetparams           z_gzsetparams
+#    define gztell                z_gztell
+#    define gztell64              z_gztell64
+#    define gzungetc              z_gzungetc
+#    define gzvprintf             z_gzvprintf
+#    define gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit       z_inflateBackInit
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCodesUsed      z_inflateCodesUsed
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateGetHeader      z_inflateGetHeader
+#  define inflateInit           z_inflateInit
+#  define inflateInit2          z_inflateInit2
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateInit_          z_inflateInit_
+#  define inflateMark           z_inflateMark
+#  define inflatePrime          z_inflatePrime
+#  define inflateReset          z_inflateReset
+#  define inflateReset2         z_inflateReset2
+#  define inflateResetKeep      z_inflateResetKeep
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateValidate       z_inflateValidate
+#  define inflate_copyright     z_inflate_copyright
+#  define inflate_fast          z_inflate_fast
+#  define inflate_table         z_inflate_table
+#  ifndef Z_SOLO
+#    define uncompress            z_uncompress
+#    define uncompress2           z_uncompress2
+#  endif
+#  define zError                z_zError
+#  ifndef Z_SOLO
+#    define zcalloc               z_zcalloc
+#    define zcfree                z_zcfree
+#  endif
+#  define zlibCompileFlags      z_zlibCompileFlags
+#  define zlibVersion           z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+#  define Byte                  z_Byte
+#  define Bytef                 z_Bytef
+#  define alloc_func            z_alloc_func
+#  define charf                 z_charf
+#  define free_func             z_free_func
+#  ifndef Z_SOLO
+#    define gzFile                z_gzFile
+#  endif
+#  define gz_header             z_gz_header
+#  define gz_headerp            z_gz_headerp
+#  define in_func               z_in_func
+#  define intf                  z_intf
+#  define out_func              z_out_func
+#  define uInt                  z_uInt
+#  define uIntf                 z_uIntf
+#  define uLong                 z_uLong
+#  define uLongf                z_uLongf
+#  define voidp                 z_voidp
+#  define voidpc                z_voidpc
+#  define voidpf                z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+#  define gz_header_s           z_gz_header_s
+#  define internal_state        z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+#  define z_const const
+#else
+#  define z_const
+#endif
+
+#ifdef Z_SOLO
+   typedef unsigned long z_size_t;
+#else
+#  define z_longlong long long
+#  if defined(NO_SIZE_T)
+     typedef unsigned NO_SIZE_T z_size_t;
+#  elif defined(STDC)
+#    include <stddef.h>
+     typedef size_t z_size_t;
+#  else
+     typedef unsigned long z_size_t;
+#  endif
+#  undef z_longlong
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus about 7 kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#    define Z_ARG(args)  args
+#  else
+#    define Z_ARG(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+#  include <limits.h>
+#  if (UINT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned
+#  elif (ULONG_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned long
+#  elif (USHRT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned short
+#  endif
+#endif
+
+#ifdef Z_U4
+   typedef Z_U4 z_crc_t;
+#else
+   typedef unsigned long z_crc_t;
+#endif
+
+#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
+#  define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+#  ifndef Z_SOLO
+#    include <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* for wchar_t */
+#  endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+#  undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* for off_t */
+#    endif
+#    ifndef z_off_t
+#      define z_off_t off_t
+#    endif
+#  endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+#  define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+#  define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+#  define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+#  define z_off64_t off64_t
+#else
+#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+#    define z_off64_t __int64
+#  else
+#    define z_off64_t z_off_t
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+  #pragma map(deflateInit_,"DEIN")
+  #pragma map(deflateInit2_,"DEIN2")
+  #pragma map(deflateEnd,"DEEND")
+  #pragma map(deflateBound,"DEBND")
+  #pragma map(inflateInit_,"ININ")
+  #pragma map(inflateInit2_,"ININ2")
+  #pragma map(inflateEnd,"INEND")
+  #pragma map(inflateSync,"INSY")
+  #pragma map(inflateSetDictionary,"INSEDI")
+  #pragma map(compressBound,"CMBND")
+  #pragma map(inflate_table,"INTABL")
+  #pragma map(inflate_fast,"INFA")
+  #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/deps/libchdr/deps/zlib-1.2.11/zlib.3 b/deps/libchdr/deps/zlib-1.2.11/zlib.3
new file mode 100644 (file)
index 0000000..bda4eb0
--- /dev/null
@@ -0,0 +1,149 @@
+.TH ZLIB 3 "15 Jan 2017"
+.SH NAME
+zlib \- compression/decompression library
+.SH SYNOPSIS
+[see
+.I zlib.h
+for full description]
+.SH DESCRIPTION
+The
+.I zlib
+library is a general purpose data compression library.
+The code is thread safe, assuming that the standard library functions
+used are thread safe, such as memory allocation routines.
+It provides in-memory compression and decompression functions,
+including integrity checks of the uncompressed data.
+This version of the library supports only one compression method (deflation)
+but other algorithms may be added later
+with the same stream interface.
+.LP
+Compression can be done in a single step if the buffers are large enough
+or can be done by repeated calls of the compression function.
+In the latter case,
+the application must provide more input and/or consume the output
+(providing more output space) before each call.
+.LP
+The library also supports reading and writing files in
+.IR gzip (1)
+(.gz) format
+with an interface similar to that of stdio.
+.LP
+The library does not install any signal handler.
+The decoder checks the consistency of the compressed data,
+so the library should never crash even in the case of corrupted input.
+.LP
+All functions of the compression library are documented in the file
+.IR zlib.h .
+The distribution source includes examples of use of the library
+in the files
+.I test/example.c
+and
+.IR test/minigzip.c,
+as well as other examples in the
+.IR examples/
+directory.
+.LP
+Changes to this version are documented in the file
+.I ChangeLog
+that accompanies the source.
+.LP
+.I zlib
+is built in to many languages and operating systems, including but not limited to
+Java, Python, .NET, PHP, Perl, Ruby, Swift, and Go.
+.LP
+An experimental package to read and write files in the .zip format,
+written on top of
+.I zlib
+by Gilles Vollant (info@winimage.com),
+is available at:
+.IP
+http://www.winimage.com/zLibDll/minizip.html
+and also in the
+.I contrib/minizip
+directory of the main
+.I zlib
+source distribution.
+.SH "SEE ALSO"
+The
+.I zlib
+web site can be found at:
+.IP
+http://zlib.net/
+.LP
+The data format used by the
+.I zlib
+library is described by RFC
+(Request for Comments) 1950 to 1952 in the files:
+.IP
+http://tools.ietf.org/html/rfc1950 (for the zlib header and trailer format)
+.br
+http://tools.ietf.org/html/rfc1951 (for the deflate compressed data format)
+.br
+http://tools.ietf.org/html/rfc1952 (for the gzip header and trailer format)
+.LP
+Mark Nelson wrote an article about
+.I zlib
+for the Jan. 1997 issue of  Dr. Dobb's Journal;
+a copy of the article is available at:
+.IP
+http://marknelson.us/1997/01/01/zlib-engine/
+.SH "REPORTING PROBLEMS"
+Before reporting a problem,
+please check the
+.I zlib
+web site to verify that you have the latest version of
+.IR zlib ;
+otherwise,
+obtain the latest version and see if the problem still exists.
+Please read the
+.I zlib
+FAQ at:
+.IP
+http://zlib.net/zlib_faq.html
+.LP
+before asking for help.
+Send questions and/or comments to zlib@gzip.org,
+or (for the Windows DLL version) to Gilles Vollant (info@winimage.com).
+.SH AUTHORS AND LICENSE
+Version 1.2.11
+.LP
+Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
+.LP
+This software is provided 'as-is', without any express or implied
+warranty.  In no event will the authors be held liable for any damages
+arising from the use of this software.
+.LP
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+.LP
+.nr step 1 1
+.IP \n[step]. 3
+The origin of this software must not be misrepresented; you must not
+claim that you wrote the original software. If you use this software
+in a product, an acknowledgment in the product documentation would be
+appreciated but is not required.
+.IP \n+[step].
+Altered source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+.IP \n+[step].
+This notice may not be removed or altered from any source distribution.
+.LP
+Jean-loup Gailly        Mark Adler
+.br
+jloup@gzip.org          madler@alumni.caltech.edu
+.LP
+The deflate format used by
+.I zlib
+was defined by Phil Katz.
+The deflate and
+.I zlib
+specifications were written by L. Peter Deutsch.
+Thanks to all the people who reported problems and suggested various
+improvements in
+.IR zlib ;
+who are too numerous to cite here.
+.LP
+UNIX manual page by R. P. C. Rodgers,
+U.S. National Library of Medicine (rodgers@nlm.nih.gov).
+.\" end of man page
diff --git a/deps/libchdr/deps/zlib-1.2.11/zlib.3.pdf b/deps/libchdr/deps/zlib-1.2.11/zlib.3.pdf
new file mode 100644 (file)
index 0000000..6fa519c
Binary files /dev/null and b/deps/libchdr/deps/zlib-1.2.11/zlib.3.pdf differ
diff --git a/deps/libchdr/deps/zlib-1.2.11/zlib.h b/deps/libchdr/deps/zlib-1.2.11/zlib.h
new file mode 100644 (file)
index 0000000..f09cdaf
--- /dev/null
@@ -0,0 +1,1912 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.11, January 15th, 2017
+
+  Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.11"
+#define ZLIB_VERNUM 0x12b0
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 11
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+    The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed data.
+  This version of the library supports only one compression method (deflation)
+  but other algorithms will be added later and will have the same stream
+  interface.
+
+    Compression can be done in a single step if the buffers are large enough,
+  or can be done by repeated calls of the compression function.  In the latter
+  case, the application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+    The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+    The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+    This library can optionally read and write gzip and raw deflate streams in
+  memory as well.
+
+    The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+    The library does not install any signal handler.  The decoder checks
+  the consistency of the compressed data, so the library should never crash
+  even in the case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    z_const Bytef *next_in;     /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total number of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte will go here */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total number of bytes output so far */
+
+    z_const char *msg;  /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text
+                           for deflate, or the decoding state for inflate */
+    uLong   adler;      /* Adler-32 or CRC-32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+     The application must update next_in and avail_in when avail_in has dropped
+   to zero.  It must update next_out and avail_out when avail_out has dropped
+   to zero.  The application must initialize zalloc, zfree and opaque before
+   calling the init function.  All other fields are set by the compression
+   library and must not be updated by the application.
+
+     The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree.  This can be useful for custom
+   memory management.  The compression library attaches no meaning to the
+   opaque value.
+
+     zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.  In that case, zlib is thread-safe.  When zalloc and zfree are
+   Z_NULL on entry to the initialization function, they are set to internal
+   routines that use the standard library functions malloc() and free().
+
+     On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this if
+   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
+   returned by zalloc for objects of exactly 65536 bytes *must* have their
+   offset normalized to zero.  The default allocation function provided by this
+   library ensures this (see zutil.c).  To reduce memory requirements and avoid
+   any allocation of 64K objects, at the expense of compression ratio, compile
+   the library with -DMAX_WBITS=14 (see zconf.h).
+
+     The fields total_in and total_out can be used for statistics or progress
+   reports.  After compression, total_in holds the total size of the
+   uncompressed data and may be saved for use by the decompressor (particularly
+   if the decompressor wants to decompress everything in a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+#define Z_TREES         6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field for deflate() */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is not
+   compatible with the zlib.h header file used by the application.  This check
+   is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression.  The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+   allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at all
+   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
+   requests a default compromise between speed and compression (currently
+   equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if level is not a valid compression level, or
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
+   if there is no error message.  deflateInit does not perform any compression:
+   this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows.  deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Generate more output starting at next_out and update next_out and avail_out
+    accordingly.  This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary.  Some output may be provided even if
+    flush is zero.
+
+    Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating avail_in or avail_out accordingly; avail_out should
+  never be zero before the call.  The application can consume the compressed
+  output when it wants, for example when the output buffer is full (avail_out
+  == 0), or after each call of deflate().  If deflate returns Z_OK and with
+  zero avail_out, it must be called again after making room in the output
+  buffer because there might be more output pending. See deflatePending(),
+  which can be used if desired to determine whether or not there is more ouput
+  in that case.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumulate before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far.  (In
+  particular avail_in is zero after the call if enough output space has been
+  provided before the call.) Flushing may degrade compression for some
+  compression algorithms and so it should be used only when necessary.  This
+  completes the current deflate block and follows it with an empty stored block
+  that is three bits plus filler bits to the next byte, followed by four bytes
+  (00 00 ff ff).
+
+    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+  output buffer, but the output is not aligned to a byte boundary.  All of the
+  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+  This completes the current deflate block and follows it with an empty fixed
+  codes block that is 10 bits long.  This assures that enough bytes are output
+  in order for the decompressor to finish the block before the empty fixed
+  codes block.
+
+    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+  seven bits of the current block are held to be written as the next byte after
+  the next deflate block is completed.  In this case, the decompressor may not
+  be provided enough bits at this point in order to complete decompression of
+  the data provided so far to the compressor.  It may need to wait for the next
+  block to be emitted.  This is for advanced applications that need to control
+  the emission of deflate blocks.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there was
+  enough output space.  If deflate returns with Z_OK or Z_BUF_ERROR, this
+  function must be called again with Z_FINISH and more output space (updated
+  avail_out) but no more input data, until it returns with Z_STREAM_END or an
+  error.  After deflate has returned Z_STREAM_END, the only possible operations
+  on the stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used in the first deflate call after deflateInit if all the
+  compression is to be done in a single step.  In order to complete in one
+  call, avail_out must be at least the value returned by deflateBound (see
+  below).  Then deflate is guaranteed to return Z_STREAM_END.  If not enough
+  output space is provided, deflate will not return Z_STREAM_END, and it must
+  be called again as described above.
+
+    deflate() sets strm->adler to the Adler-32 checksum of all input read
+  so far (that is, total_in bytes).  If a gzip stream is being generated, then
+  strm->adler will be the CRC-32 checksum of the input read so far.  (See
+  deflateInit2 below.)
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT).  If in doubt, the data is
+  considered binary.  This field is only for information purposes and does not
+  affect the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was Z_NULL or the state was inadvertently written over
+  by the application), or Z_BUF_ERROR if no progress is possible (for example
+  avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not fatal, and
+  deflate() can be called again with more input and more output space to
+  continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded).  In the error case, msg
+   may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression.  The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller.  In the current version of inflate, the provided input is not
+   read or consumed.  The allocation of a sliding window will be deferred to
+   the first call of inflate (if the decompression does not complete on the
+   first call).  If zalloc and zfree are set to Z_NULL, inflateInit updates
+   them to use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit does not perform any decompression.
+   Actual decompression will be done by inflate().  So next_in, and avail_in,
+   next_out, and avail_out are unused and unchanged.  The current
+   implementation of inflateInit() does not process any header information --
+   that is deferred until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows.  inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), then next_in and avail_in are updated
+    accordingly, and processing will resume at this point for the next call of
+    inflate().
+
+  - Generate more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there is
+    no more input data or no more space in the output buffer (see below about
+    the flush parameter).
+
+    Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating the next_* and avail_* values accordingly.  If the
+  caller of inflate() does not provide both available input and available
+  output space, it is possible that there will be no progress made.  The
+  application can consume the uncompressed output when it wants, for example
+  when the output buffer is full (avail_out == 0), or after each call of
+  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
+  called again after making room in the output buffer because there might be
+  more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer.  Z_BLOCK requests that inflate()
+  stop if and when it gets to the next deflate block boundary.  When decoding
+  the zlib or gzip format, this will cause inflate() to return immediately
+  after the header and before the first block.  When doing a raw inflate,
+  inflate() will go ahead and process the first block, and will return when it
+  gets to the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  To assist in this, on return inflate() always sets strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64 if
+  inflate() is currently decoding the last block in the deflate stream, plus
+  128 if inflate() returned immediately after decoding an end-of-block code or
+  decoding the complete header up to just before the first byte of the deflate
+  stream.  The end-of-block will not be indicated until all of the uncompressed
+  data from that block has been written to strm->next_out.  The number of
+  unused bits may in general be greater than seven, except when bit 7 of
+  data_type is set, in which case the number of unused bits will be less than
+  eight.  data_type is set as noted here every time inflate() returns for all
+  flush options, and so can be used to determine the amount of currently
+  consumed input in bits.
+
+    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+  end of each deflate block header is reached, before any actual data in that
+  block is decoded.  This allows the caller to determine the length of the
+  deflate block header for later use in random access within a deflate block.
+  256 is added to the value of strm->data_type when inflate() returns
+  immediately after reaching the end of the deflate block header.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error.  However if all decompression is to be performed in a single step (a
+  single call of inflate), the parameter flush should be set to Z_FINISH.  In
+  this case all pending input is processed and all pending output is flushed;
+  avail_out must be large enough to hold all of the uncompressed data for the
+  operation to complete.  (The size of the uncompressed data may have been
+  saved by the compressor for this purpose.)  The use of Z_FINISH is not
+  required to perform an inflation in one step.  However it may be used to
+  inform inflate that a faster approach can be used for the single inflate()
+  call.  Z_FINISH also informs inflate to not maintain a sliding window if the
+  stream completes, which reduces inflate's memory footprint.  If the stream
+  does not complete, either because not all of the stream is provided or not
+  enough output space is provided, then a sliding window will be allocated and
+  inflate() can be called again to continue the operation as if Z_NO_FLUSH had
+  been used.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call.  So the effects of the flush parameter in this implementation are
+  on the return value of inflate() as noted below, when inflate() returns early
+  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
+  memory for a sliding window when Z_FINISH is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the Adler-32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below.  At the end of the stream, inflate() checks that its computed Adler-32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically, if requested when
+  initializing with inflateInit2().  Any information contained in the gzip
+  header is not retained unless inflateGetHeader() is used.  When processing
+  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
+  produced so far.  The CRC-32 is checked against the gzip trailer, as is the
+  uncompressed length, modulo 2^32.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value, in which case strm->msg points to a string with a more specific
+  error), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  next_in or next_out was Z_NULL, or the state was inadvertently written over
+  by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR
+  if no progress was possible or if there was not enough room in the output
+  buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing.  If Z_DATA_ERROR is returned, the application may
+  then call inflateSync() to look for a good compression block if a partial
+  recovery of the data is to be attempted.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state
+   was inconsistent.
+*/
+
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options.  The
+   fields next_in, zalloc, zfree and opaque must be initialized before by the
+   caller.
+
+     The method parameter is the compression method.  It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library.  Larger values of this parameter result in better
+   compression at the expense of memory usage.  The default value is 15 if
+   deflateInit is used instead.
+
+     For the current implementation of deflate(), a windowBits value of 8 (a
+   window size of 256 bytes) is not supported.  As a result, a request for 8
+   will result in 9 (a 512-byte window).  In that case, providing 8 to
+   inflateInit2() will result in an error when the zlib header with 9 is
+   checked against the initialization of inflate().  The remedy is to not use 8
+   with deflateInit2() with this initialization, or at least in that case use 9
+   with inflateInit2().
+
+     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
+   determines the window size.  deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute a check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding.  Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper.  The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero), no
+   header crc, and the operating system will be set to the appropriate value,
+   if the operating system was determined at compile time.  If a gzip stream is
+   being written, strm->adler is a CRC-32 instead of an Adler-32.
+
+     For raw deflate or gzip encoding, a request for a 256-byte window is
+   rejected as invalid, since only the zlib header provides a means of
+   transmitting the window size to the decompressor.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state.  memLevel=1 uses minimum memory but is
+   slow and reduces compression ratio; memLevel=9 uses maximum memory for
+   optimal speed.  The default value is 8.  See zconf.h for total memory usage
+   as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm.  Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding).  Filtered data consists mostly of small values with a somewhat
+   random distribution.  In this case, the compression algorithm is tuned to
+   compress them better.  The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
+   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
+   strategy parameter only affects the compression ratio but not the
+   correctness of the compressed output even if it is not set appropriately.
+   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+   decoder for special applications.
+
+     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
+   set to null if there is no error message.  deflateInit2 does not perform any
+   compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output.  When using the zlib format, this
+   function must be called immediately after deflateInit, deflateInit2 or
+   deflateReset, and before any call of deflate.  When doing raw deflate, this
+   function must be called either before any call of deflate, or immediately
+   after the completion of a deflate block, i.e. after all input has been
+   consumed and all output has been delivered when using any of the flush
+   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
+   compressor and decompressor must use exactly the same dictionary (see
+   inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary.  Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size
+   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
+   useful should be put at the end of the dictionary, not at the front.  In
+   addition, the current implementation of deflate will use at most the window
+   size minus 262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the Adler-32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor.  (The Adler-32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   Adler-32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if not at a block boundary for raw deflate).  deflateSetDictionary does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm,
+                                             Bytef *dictionary,
+                                             uInt  *dictLength));
+/*
+     Returns the sliding dictionary being maintained by deflate.  dictLength is
+   set to the number of bytes in the dictionary, and that many bytes are copied
+   to dictionary.  dictionary must have enough space, where 32768 bytes is
+   always enough.  If deflateGetDictionary() is called with dictionary equal to
+   Z_NULL, then only the dictionary length is returned, and nothing is copied.
+   Similary, if dictLength is Z_NULL, then it is not set.
+
+     deflateGetDictionary() may return a length less than the window size, even
+   when more than the window size in input has been provided. It may return up
+   to 258 bytes less in that case, due to how zlib's implementation of deflate
+   manages the sliding window and lookahead for matches, where matches can be
+   up to 258 bytes long. If the application needs the last window-size bytes of
+   input, then that would need to be saved by the application outside of zlib.
+
+     deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
+   stream state is inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter.  The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and can
+   consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit, but
+   does not free and reallocate the internal compression state.  The stream
+   will leave the compression level and any other attributes that may have been
+   set unchanged.
+
+     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2().  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different strategy.
+   If the compression approach (which is a function of the level) or the
+   strategy is changed, and if any input has been consumed in a previous
+   deflate() call, then the input available so far is compressed with the old
+   level and strategy using deflate(strm, Z_BLOCK).  There are three approaches
+   for the compression levels 0, 1..3, and 4..9 respectively.  The new level
+   and strategy will take effect at the next call of deflate().
+
+     If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does
+   not have enough output space to complete, then the parameter change will not
+   take effect.  In this case, deflateParams() can be called again with the
+   same parameters and more output space to try again.
+
+     In order to assure a change in the parameters on the first try, the
+   deflate stream should be flushed using deflate() with Z_BLOCK or other flush
+   request until strm.avail_out is not zero, before calling deflateParams().
+   Then no more input data should be provided before the deflateParams() call.
+   If this is done, the old level and strategy will be applied to the data
+   compressed before deflateParams(), and the new level and strategy will be
+   applied to the the data compressed after deflateParams().
+
+     deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream
+   state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if
+   there was not enough output space to complete the compression of the
+   available input data before a change in the strategy or approach.  Note that
+   in the case of a Z_BUF_ERROR, the parameters are not changed.  A return
+   value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be
+   retried with more output space.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit() or
+   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
+   to allocate an output buffer for deflation in a single pass, and so would be
+   called before deflate().  If that first deflate() call is provided the
+   sourceLen input bytes, an output buffer allocated to the size returned by
+   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
+   to return Z_STREAM_END.  Note that it is possible for the compressed size to
+   be larger than the value returned by deflateBound() if flush options other
+   than Z_FINISH or Z_NO_FLUSH are used.
+*/
+
+ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
+                                       unsigned *pending,
+                                       int *bits));
+/*
+     deflatePending() returns the number of bytes and bits of output that have
+   been generated, but not yet provided in the available output.  The bytes not
+   provided would be due to the available output space having being consumed.
+   The number of bits of output not provided are between 0 and 7, where they
+   await more bits to join them in order to fill out a full byte.  If pending
+   or bits are Z_NULL, then those values are not set.
+
+     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+ */
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+   is that this function is used to start off the deflate output with the bits
+   leftover from a previous deflate stream when appending to it.  As such, this
+   function can only be used for raw deflate, and must be used before the first
+   deflate() call after a deflateInit2() or deflateReset().  bits must be less
+   than or equal to 16, and that many of the least significant bits of value
+   will be inserted in the output.
+
+     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
+   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+     If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter.  The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library.  The default value is 15 if inflateInit is used
+   instead.  windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used.  If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be zero to request that inflate use the window size in
+   the zlib header of the compressed stream.
+
+     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
+   determines the window size.  inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream.  This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values.  If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an Adler-32 or a CRC-32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is.  Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding.  Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
+   CRC-32 instead of an Adler-32.  Unlike the gunzip utility and gzread() (see
+   below), inflate() will not automatically decode concatenated gzip streams.
+   inflate() will return Z_STREAM_END at the end of the gzip stream.  The state
+   would need to be reset to continue decoding a subsequent gzip stream.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit2 does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit2() does not process any header information -- that is
+   deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence.  This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
+   can be determined from the Adler-32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called at any
+   time to set the dictionary.  If the provided dictionary is smaller than the
+   window and there is already data in the window, then the provided dictionary
+   will amend what's there.  The application must insure that the dictionary
+   that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler-32 value).  inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
+                                             Bytef *dictionary,
+                                             uInt  *dictLength));
+/*
+     Returns the sliding dictionary being maintained by inflate.  dictLength is
+   set to the number of bytes in the dictionary, and that many bytes are copied
+   to dictionary.  dictionary must have enough space, where 32768 bytes is
+   always enough.  If inflateGetDictionary() is called with dictionary equal to
+   Z_NULL, then only the dictionary length is returned, and nothing is copied.
+   Similary, if dictLength is Z_NULL, then it is not set.
+
+     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
+   stream state is inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+     Skips invalid compressed data until a possible full flush point (see above
+   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
+   available input is skipped.  No output is provided.
+
+     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
+   All full flush points have this pattern, but not all occurrences of this
+   pattern are full flush points.
+
+     inflateSync returns Z_OK if a possible full flush point has been found,
+   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
+   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
+   In the success case, the application may save the current current value of
+   total_in which indicates where valid compressed data was found.  In the
+   error case, the application may repeatedly call inflateSync, providing more
+   input each time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate the internal decompression state.  The
+   stream will keep attributes that may have been set by inflateInit2.
+
+     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+                                      int windowBits));
+/*
+     This function is the same as inflateReset, but it also permits changing
+   the wrap and window size requests.  The windowBits parameter is interpreted
+   the same as it is for inflateInit2.  If the window size is changed, then the
+   memory allocated for the window is freed, and the window will be reallocated
+   by inflate() if needed.
+
+     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+   the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+   that this function is used to start inflating at a bit position in the
+   middle of a byte.  The provided bits will be used before any bytes are used
+   from next_in.  This function should only be used with raw inflate, and
+   should be used before the first inflate() call after inflateInit2() or
+   inflateReset().  bits must be less than or equal to 16, and that many of the
+   least significant bits of value will be inserted in the input.
+
+     If bits is negative, then the input stream bit buffer is emptied.  Then
+   inflatePrime() can be called again to put bits in the buffer.  This is used
+   to clear out bits leftover after feeding inflate a block description prior
+   to feeding inflate codes.
+
+     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+     This function returns two values, one in the lower 16 bits of the return
+   value, and the other in the remaining upper bits, obtained by shifting the
+   return value down 16 bits.  If the upper value is -1 and the lower value is
+   zero, then inflate() is currently decoding information outside of a block.
+   If the upper value is -1 and the lower value is non-zero, then inflate is in
+   the middle of a stored block, with the lower value equaling the number of
+   bytes from the input remaining to copy.  If the upper value is not -1, then
+   it is the number of bits back from the current bit position in the input of
+   the code (literal or length/distance pair) currently being processed.  In
+   that case the lower value is the number of bytes already emitted for that
+   code.
+
+     A code is being processed if inflate is waiting for more input to complete
+   decoding of the code, or if it has completed decoding but is waiting for
+   more output space to write the literal or match data.
+
+     inflateMark() is used to mark locations in the input data for random
+   access, which may be at bit positions, and to note those cases where the
+   output of a code may span boundaries of random access blocks.  The current
+   location in the input stream can be determined from avail_in and data_type
+   as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+     inflateMark returns the value noted above, or -65536 if the provided
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
+   used to force inflate() to return immediately after header processing is
+   complete and before any actual data is decompressed.
+
+     The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When any
+   of extra, name, or comment are not Z_NULL and the respective field is not
+   present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+     If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
+   allocated, or Z_VERSION_ERROR if the version of the library does not match
+   the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *,
+                                z_const unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is potentially more efficient than
+   inflate() for file i/o applications, in that it avoids copying between the
+   output and the sliding window by simply making the window itself the output
+   buffer.  inflate() can be faster on modern CPUs when used with large
+   buffers.  inflateBack() trusts the application to not change the output
+   buffer passed by the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free the
+   allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects only
+   the raw deflate stream to decompress.  This is different from the default
+   behavior of inflate(), which expects a zlib header and trailer around the
+   deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero -- buf is ignored in that
+   case -- and inflateBack() will return a buffer error.  inflateBack() will
+   call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].
+   out() should return zero on success, or non-zero on failure.  If out()
+   returns non-zero, inflateBack() will return with an error.  Neither in() nor
+   out() are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+   in the deflate stream (in which case strm->msg is set to indicate the nature
+   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+   In the case of Z_BUF_ERROR, an input or output error can be distinguished
+   using strm->next_in which will be Z_NULL only if in() returned an error.  If
+   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+   non-zero.  (in() will always be called before out(), so strm->next_in is
+   assured to be defined if out() returns non-zero.)  Note that inflateBack()
+   cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: ZLIB_DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+#ifndef Z_SOLO
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the basic
+   stream-oriented functions.  To simplify the interface, some default options
+   are assumed (compression level and memory usage, standard memory allocation
+   functions).  The source code of these utility functions can be modified if
+   you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed data.  compress() is equivalent to compress2() with a level
+   parameter of Z_DEFAULT_COMPRESSION.
+
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer.  The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer.  Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed data.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before a
+   compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be large enough to hold the entire
+   uncompressed data.  (The size of the uncompressed data must have been saved
+   previously by the compressor and transmitted to the decompressor by some
+   mechanism outside the scope of this compression library.) Upon exit, destLen
+   is the actual size of the uncompressed data.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
+   the case where there is not enough room, uncompress() will fill the output
+   buffer with the uncompressed data up to that point.
+*/
+
+ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest,   uLongf *destLen,
+                                    const Bytef *source, uLong *sourceLen));
+/*
+     Same as uncompress, except that sourceLen is a pointer, where the
+   length of the source is *sourceLen.  On return, *sourceLen is the number of
+   source bytes consumed.
+*/
+
+                        /* gzip file access functions */
+
+/*
+     This library supports reading and writing files in gzip (.gz) format with
+   an interface similar to that of stdio, using the functions that start with
+   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
+   wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
+   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+   for fixed code compression as in "wb9F".  (See the description of
+   deflateInit2 for more information about the strategy parameter.)  'T' will
+   request transparent writing or appending with no compression and not using
+   the gzip format.
+
+     "a" can be used instead of "w" to request that the gzip stream that will
+   be written be appended to the file.  "+" will result in an error, since
+   reading and writing to the same gzip file is not supported.  The addition of
+   "x" when writing will create the file exclusively, which fails if the file
+   already exists.  On systems that support it, the addition of "e" when
+   reading or writing will set the flag to close the file on an execve() call.
+
+     These functions, as well as gzip, will read and decode a sequence of gzip
+   streams in a file.  The append function of gzopen() can be used to create
+   such a file.  (Also see gzflush() for another way to do this.)  When
+   appending, gzopen does not test whether the file begins with a gzip stream,
+   nor does it look for the end of the gzip streams to begin appending.  gzopen
+   will simply append a gzip stream to the existing file.
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.  When
+   reading, this will be detected automatically by looking for the magic two-
+   byte gzip header.
+
+     gzopen returns NULL if the file could not be opened, if there was
+   insufficient memory to allocate the gzFile state, or if an invalid mode was
+   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+   errno can be checked to determine if the reason gzopen failed was that the
+   file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
+   are obtained from calls like open, dup, creat, pipe or fileno (if the file
+   has been previously opened with fopen).  The mode parameter is as in gzopen.
+
+     The next call of gzclose on the returned gzFile will also close the file
+   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+   mode);.  The duplicated descriptor should be saved to avoid a leak, since
+   gzdopen does not close fd if it fails.  If you are using fileno() to get the
+   file descriptor from a FILE *, then you will have to use dup() to avoid
+   double-close()ing the file descriptor.  Both gzclose() and fclose() will
+   close the associated file descriptor, so they need to have different file
+   descriptors.
+
+     gzdopen returns NULL if there was insufficient memory to allocate the
+   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
+   used until the next gz* read, write, seek, or close operation, so gzdopen
+   will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+     Set the internal buffer size used by this library's functions.  The
+   default buffer size is 8192 bytes.  This function must be called after
+   gzopen() or gzdopen(), and before any other calls that read or write the
+   file.  The buffer memory allocation is always deferred to the first read or
+   write.  Three times that size in buffer space is allocated.  A larger buffer
+   size of, for example, 64K or 128K bytes will noticeably increase the speed
+   of decompression (reading).
+
+     The new buffer size also affects the maximum length for gzprintf().
+
+     gzbuffer() returns 0 on success, or -1 on failure, such as being called
+   too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy.  See the description
+   of deflateInit2 for the meaning of these parameters.  Previously provided
+   data is flushed before the parameter change.
+
+     gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not
+   opened for writing, Z_ERRNO if there is an error writing the flushed data,
+   or Z_MEM_ERROR if there is a memory allocation error.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.  If
+   the input file is not in gzip format, gzread copies the given number of
+   bytes into the buffer directly from the file.
+
+     After reaching the end of a gzip stream in the input, gzread will continue
+   to read, looking for another gzip stream.  Any number of gzip streams may be
+   concatenated in the input file, and will all be decompressed by gzread().
+   If something other than a gzip stream is encountered after a gzip stream,
+   that remaining trailing garbage is ignored (and no error is returned).
+
+     gzread can be used to read a gzip file that is being concurrently written.
+   Upon reaching the end of the input, gzread will return with the available
+   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
+   gzclearerr can be used to clear the end of file indicator in order to permit
+   gzread to be tried again.  Z_OK indicates that a gzip stream was completed
+   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the
+   middle of a gzip stream.  Note that gzread does not return -1 in the event
+   of an incomplete gzip stream.  This error is deferred until gzclose(), which
+   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
+   stream.  Alternatively, gzerror can be used before gzclose to detect this
+   case.
+
+     gzread returns the number of uncompressed bytes actually read, less than
+   len for end of file, or -1 for error.  If len is too large to fit in an int,
+   then nothing is read, -1 is returned, and the error state is set to
+   Z_STREAM_ERROR.
+*/
+
+ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,
+                                     gzFile file));
+/*
+     Read up to nitems items of size size from file to buf, otherwise operating
+   as gzread() does.  This duplicates the interface of stdio's fread(), with
+   size_t request and return types.  If the library defines size_t, then
+   z_size_t is identical to size_t.  If not, then z_size_t is an unsigned
+   integer type that can contain a pointer.
+
+     gzfread() returns the number of full items read of size size, or zero if
+   the end of the file was reached and a full item could not be read, or if
+   there was an error.  gzerror() must be consulted if zero is returned in
+   order to determine if there was an error.  If the multiplication of size and
+   nitems overflows, i.e. the product does not fit in a z_size_t, then nothing
+   is read, zero is returned, and the error state is set to Z_STREAM_ERROR.
+
+     In the event that the end of file is reached and only a partial item is
+   available at the end, i.e. the remaining uncompressed data length is not a
+   multiple of size, then the final partial item is nevetheless read into buf
+   and the end-of-file flag is set.  The length of the partial item read is not
+   provided, but could be inferred from the result of gztell().  This behavior
+   is the same as the behavior of fread() implementations in common libraries,
+   but it prevents the direct use of gzfread() to read a concurrently written
+   file, reseting and retrying on end-of-file, when size is not 1.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+                                voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes written or 0 in case of
+   error.
+*/
+
+ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size,
+                                      z_size_t nitems, gzFile file));
+/*
+     gzfwrite() writes nitems items of size size from buf to file, duplicating
+   the interface of stdio's fwrite(), with size_t request and return types.  If
+   the library defines size_t, then z_size_t is identical to size_t.  If not,
+   then z_size_t is an unsigned integer type that can contain a pointer.
+
+     gzfwrite() returns the number of full items written of size size, or zero
+   if there was an error.  If the multiplication of size and nitems overflows,
+   i.e. the product does not fit in a z_size_t, then nothing is written, zero
+   is returned, and the error state is set to Z_STREAM_ERROR.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the arguments to the compressed file under
+   control of the format string, as in fprintf.  gzprintf returns the number of
+   uncompressed bytes actually written, or a negative zlib error code in case
+   of error.  The number of uncompressed bytes written is limited to 8191, or
+   one less than the buffer size given to gzbuffer().  The caller should assure
+   that this limit is not exceeded.  If it is exceeded, then gzprintf() will
+   return an error (0) with nothing written.  In this case, there may also be a
+   buffer overflow with unpredictable consequences, which is possible only if
+   zlib was compiled with the insecure functions sprintf() or vsprintf()
+   because the secure snprintf() or vsnprintf() functions were not available.
+   This can be determined using zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+     Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+
+     gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+     Reads bytes from the compressed file until len-1 characters are read, or a
+   newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  If any characters are read or if len == 1, the
+   string is terminated with a null character.  If no characters are read due
+   to an end-of-file or len < 1, then the buffer is left untouched.
+
+     gzgets returns buf which is a null-terminated string, or it returns NULL
+   for end-of-file or in case of error.  If there was an error, the contents at
+   buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+     Writes c, converted to an unsigned char, into the compressed file.  gzputc
+   returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+     Reads one byte from the compressed file.  gzgetc returns this byte or -1
+   in case of end of file or error.  This is implemented as a macro for speed.
+   As such, it does not do all of the checking the other functions do.  I.e.
+   it does not check to see if file is NULL, nor whether the structure file
+   points to has been clobbered or not.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+     Push one character back onto the stream to be read as the first character
+   on the next read.  At least one character of push-back is allowed.
+   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
+   fail if c is -1, and may fail if a character has been pushed but not read
+   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
+   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
+   The pushed character will be discarded if the stream is repositioned with
+   gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file.  The parameter flush
+   is as in the deflate() function.  The return value is the zlib error number
+   (see function gzerror below).  gzflush is only permitted when writing.
+
+     If the flush parameter is Z_FINISH, the remaining data is written and the
+   gzip stream is completed in the output.  If gzwrite() is called again, a new
+   gzip stream will be started in the output.  gzread() is able to read such
+   concatenated gzip streams.
+
+     gzflush should be called only when strictly necessary because it will
+   degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+                                   z_off_t offset, int whence));
+
+     Sets the starting position for the next gzread or gzwrite on the given
+   compressed file.  The offset represents a number of bytes in the
+   uncompressed data stream.  The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow.  If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+     gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+
+     Returns the starting position for the next gzread or gzwrite on the given
+   compressed file.  This position represents a number of bytes in the
+   uncompressed data stream, and is zero when starting, even if appending or
+   reading a gzip stream from the middle of a file using gzdopen().
+
+     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+     Returns the current offset in the file being read or written.  This offset
+   includes the count of bytes that precede the gzip stream, for example when
+   appending or when using gzdopen() for reading.  When reading, the offset
+   does not include as yet unused buffered input.  This information can be used
+   for a progress indicator.  On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns true (1) if the end-of-file indicator has been set while reading,
+   false (0) otherwise.  Note that the end-of-file indicator is set only if the
+   read tried to go past the end of the input, but came up short.  Therefore,
+   just like feof(), gzeof() may return false even if there is no more data to
+   read, in the event that the last read request was for the exact number of
+   bytes remaining in the input file.  This will happen if the input file size
+   is an exact multiple of the buffer size.
+
+     If gzeof() returns true, then the read functions will return no more data,
+   unless the end-of-file indicator is reset by gzclearerr() and the input file
+   has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns true (1) if file is being copied directly while reading, or false
+   (0) if file is a gzip stream being decompressed.
+
+     If the input file is empty, gzdirect() will return true, since the input
+   does not contain a gzip stream.
+
+     If gzdirect() is used immediately after gzopen() or gzdopen() it will
+   cause buffers to be allocated to allow reading the file to determine if it
+   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
+   gzdirect().
+
+     When writing, gzdirect() returns true (1) if transparent writing was
+   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
+   gzdirect() is not needed when writing.  Transparent writing must be
+   explicitly requested, so the application already knows the answer.  When
+   linking statically, using gzdirect() will include all of the zlib code for
+   gzip file reading and decompression, which may not be desired.)
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file and
+   deallocates the (de)compression state.  Note that once file is closed, you
+   cannot call gzerror with file, since its structures have been deallocated.
+   gzclose must not be called more than once on the same file, just as free
+   must not be called more than once on the same allocation.
+
+     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
+   last read ended in the middle of a gzip stream, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+     Same as gzclose(), but gzclose_r() is only for use when reading, and
+   gzclose_w() is only for use when writing or appending.  The advantage to
+   using these instead of gzclose() is that they avoid linking in zlib
+   compression or decompression code that is not used when only reading or only
+   writing respectively.  If gzclose() is used, then both compression and
+   decompression code will be included the application when linking to a static
+   zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the given
+   compressed file.  errnum is set to zlib error number.  If an error occurred
+   in the file system and not in the compression library, errnum is set to
+   Z_ERRNO and the application may consult errno to get the exact error code.
+
+     The application must not modify the returned string.  Future calls to
+   this function may invalidate the previously returned string.  If file is
+   closed, then the string previously returned by gzerror will no longer be
+   available.
+
+     gzerror() should be used to distinguish errors from end-of-file for those
+   functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file.  This is analogous to the
+   clearerr() function in stdio.  This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+#endif /* !Z_SOLO */
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the compression
+   library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum.  If buf is Z_NULL, this function returns the
+   required initial value for the checksum.
+
+     An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed
+   much faster.
+
+   Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf,
+                                    z_size_t len));
+/*
+     Same as adler32(), but with a size_t length.
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
+   that the z_off_t type (like off_t) is a signed integer.  If len2 is
+   negative, the result has no meaning or utility.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32.  If buf is Z_NULL, this function returns the required
+   initial value for the crc.  Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf,
+                                  z_size_t len));
+/*
+     Same as crc32(), but with a size_t length.
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#ifdef Z_PREFIX_SET
+#  define z_deflateInit(strm, level) \
+          deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+#  define z_inflateInit(strm) \
+          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+#  define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+          deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                        (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+#  define z_inflateInit2(strm, windowBits) \
+          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+                        (int)sizeof(z_stream))
+#  define z_inflateBackInit(strm, windowBits, window) \
+          inflateBackInit_((strm), (windowBits), (window), \
+                           ZLIB_VERSION, (int)sizeof(z_stream))
+#else
+#  define deflateInit(strm, level) \
+          deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+#  define inflateInit(strm) \
+          inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+#  define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+          deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                        (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+#  define inflateInit2(strm, windowBits) \
+          inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+                        (int)sizeof(z_stream))
+#  define inflateBackInit(strm, windowBits, window) \
+          inflateBackInit_((strm), (windowBits), (window), \
+                           ZLIB_VERSION, (int)sizeof(z_stream))
+#endif
+
+#ifndef Z_SOLO
+
+/* gzgetc() macro and its supporting function and exposed data structure.  Note
+ * that the real internal state is much larger than the exposed structure.
+ * This abbreviated structure exposes just enough for the gzgetc() macro.  The
+ * user should not mess with these exposed elements, since their names or
+ * behavior could change in the future, perhaps even capriciously.  They can
+ * only be used by the gzgetc() macro.  You have been warned.
+ */
+struct gzFile_s {
+    unsigned have;
+    unsigned char *next;
+    z_off64_t pos;
+};
+ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));  /* backward compatibility */
+#ifdef Z_PREFIX_SET
+#  undef z_gzgetc
+#  define z_gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))
+#else
+#  define gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))
+#endif
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#ifdef Z_LARGE64
+   ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+   ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+   ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+   ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+   ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
+#  ifdef Z_PREFIX_SET
+#    define z_gzopen z_gzopen64
+#    define z_gzseek z_gzseek64
+#    define z_gztell z_gztell64
+#    define z_gzoffset z_gzoffset64
+#    define z_adler32_combine z_adler32_combine64
+#    define z_crc32_combine z_crc32_combine64
+#  else
+#    define gzopen gzopen64
+#    define gzseek gzseek64
+#    define gztell gztell64
+#    define gzoffset gzoffset64
+#    define adler32_combine adler32_combine64
+#    define crc32_combine crc32_combine64
+#  endif
+#  ifndef Z_LARGE64
+     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#  endif
+#else
+   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+#else /* Z_SOLO */
+
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+
+#endif /* !Z_SOLO */
+
+/* undocumented functions */
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table    OF((void));
+ZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));
+ZEXTERN int            ZEXPORT inflateValidate OF((z_streamp, int));
+ZEXTERN unsigned long  ZEXPORT inflateCodesUsed OF ((z_streamp));
+ZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));
+ZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));
+#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO)
+ZEXTERN gzFile         ZEXPORT gzopen_w OF((const wchar_t *path,
+                                            const char *mode));
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+ZEXTERN int            ZEXPORTVA gzvprintf Z_ARG((gzFile file,
+                                                  const char *format,
+                                                  va_list va));
+#  endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/deps/libchdr/deps/zlib-1.2.11/zlib.map b/deps/libchdr/deps/zlib-1.2.11/zlib.map
new file mode 100644 (file)
index 0000000..40fa9db
--- /dev/null
@@ -0,0 +1,94 @@
+ZLIB_1.2.0 {\r
+  global:\r
+    compressBound;\r
+    deflateBound;\r
+    inflateBack;\r
+    inflateBackEnd;\r
+    inflateBackInit_;\r
+    inflateCopy;\r
+  local:\r
+    deflate_copyright;\r
+    inflate_copyright;\r
+    inflate_fast;\r
+    inflate_table;\r
+    zcalloc;\r
+    zcfree;\r
+    z_errmsg;\r
+    gz_error;\r
+    gz_intmax;\r
+    _*;\r
+};\r
+\r
+ZLIB_1.2.0.2 {\r
+    gzclearerr;\r
+    gzungetc;\r
+    zlibCompileFlags;\r
+} ZLIB_1.2.0;\r
+\r
+ZLIB_1.2.0.8 {\r
+    deflatePrime;\r
+} ZLIB_1.2.0.2;\r
+\r
+ZLIB_1.2.2 {\r
+    adler32_combine;\r
+    crc32_combine;\r
+    deflateSetHeader;\r
+    inflateGetHeader;\r
+} ZLIB_1.2.0.8;\r
+\r
+ZLIB_1.2.2.3 {\r
+    deflateTune;\r
+    gzdirect;\r
+} ZLIB_1.2.2;\r
+\r
+ZLIB_1.2.2.4 {\r
+    inflatePrime;\r
+} ZLIB_1.2.2.3;\r
+\r
+ZLIB_1.2.3.3 {\r
+    adler32_combine64;\r
+    crc32_combine64;\r
+    gzopen64;\r
+    gzseek64;\r
+    gztell64;\r
+    inflateUndermine;\r
+} ZLIB_1.2.2.4;\r
+\r
+ZLIB_1.2.3.4 {\r
+    inflateReset2;\r
+    inflateMark;\r
+} ZLIB_1.2.3.3;\r
+\r
+ZLIB_1.2.3.5 {\r
+    gzbuffer;\r
+    gzoffset;\r
+    gzoffset64;\r
+    gzclose_r;\r
+    gzclose_w;\r
+} ZLIB_1.2.3.4;\r
+\r
+ZLIB_1.2.5.1 {\r
+    deflatePending;\r
+} ZLIB_1.2.3.5;\r
+\r
+ZLIB_1.2.5.2 {\r
+    deflateResetKeep;\r
+    gzgetc_;\r
+    inflateResetKeep;\r
+} ZLIB_1.2.5.1;\r
+\r
+ZLIB_1.2.7.1 {\r
+    inflateGetDictionary;\r
+    gzvprintf;\r
+} ZLIB_1.2.5.2;\r
+\r
+ZLIB_1.2.9 {\r
+    inflateCodesUsed;\r
+    inflateValidate;\r
+    uncompress2;\r
+    gzfread;\r
+    gzfwrite;\r
+    deflateGetDictionary;\r
+    adler32_z;\r
+    crc32_z;\r
+} ZLIB_1.2.7.1;\r
diff --git a/deps/libchdr/deps/zlib-1.2.11/zlib.pc.cmakein b/deps/libchdr/deps/zlib-1.2.11/zlib.pc.cmakein
new file mode 100644 (file)
index 0000000..a5e6429
--- /dev/null
@@ -0,0 +1,13 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@CMAKE_INSTALL_PREFIX@
+libdir=@INSTALL_LIB_DIR@
+sharedlibdir=@INSTALL_LIB_DIR@
+includedir=@INSTALL_INC_DIR@
+
+Name: zlib
+Description: zlib compression library
+Version: @VERSION@
+
+Requires:
+Libs: -L${libdir} -L${sharedlibdir} -lz
+Cflags: -I${includedir}
diff --git a/deps/libchdr/deps/zlib-1.2.11/zlib.pc.in b/deps/libchdr/deps/zlib-1.2.11/zlib.pc.in
new file mode 100644 (file)
index 0000000..7e5acf9
--- /dev/null
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+sharedlibdir=@sharedlibdir@
+includedir=@includedir@
+
+Name: zlib
+Description: zlib compression library
+Version: @VERSION@
+
+Requires:
+Libs: -L${libdir} -L${sharedlibdir} -lz
+Cflags: -I${includedir}
diff --git a/deps/libchdr/deps/zlib-1.2.11/zlib2ansi b/deps/libchdr/deps/zlib-1.2.11/zlib2ansi
new file mode 100755 (executable)
index 0000000..15e3e16
--- /dev/null
@@ -0,0 +1,152 @@
+#!/usr/bin/perl
+
+# Transform K&R C function definitions into ANSI equivalent.
+#
+# Author: Paul Marquess
+# Version: 1.0
+# Date: 3 October 2006
+
+# TODO
+#
+# Asumes no function pointer parameters. unless they are typedefed.
+# Assumes no literal strings that look like function definitions
+# Assumes functions start at the beginning of a line
+
+use strict;
+use warnings;
+
+local $/;
+$_ = <>;
+
+my $sp = qr{ \s* (?: /\* .*? \*/ )? \s* }x; # assume no nested comments
+
+my $d1    = qr{ $sp (?: [\w\*\s]+ $sp)* $sp \w+ $sp [\[\]\s]* $sp }x ;
+my $decl  = qr{ $sp (?: \w+ $sp )+ $d1 }xo ;
+my $dList = qr{ $sp $decl (?: $sp , $d1 )* $sp ; $sp }xo ;
+
+
+while (s/^
+            (                  # Start $1
+                (              #   Start $2
+                    .*?        #     Minimal eat content
+                    ( ^ \w [\w\s\*]+ )    #     $3 -- function name
+                    \s*        #     optional whitespace
+                )              # $2 - Matched up to before parameter list
+
+                \( \s*         # Literal "(" + optional whitespace
+                ( [^\)]+ )     # $4 - one or more anythings except ")"
+                \s* \)         # optional whitespace surrounding a Literal ")"
+
+                ( (?: $dList )+ ) # $5
+
+                $sp ^ {        # literal "{" at start of line
+            )                  # Remember to $1
+        //xsom
+      )
+{
+    my $all = $1 ;
+    my $prefix = $2;
+    my $param_list = $4 ;
+    my $params = $5;
+
+    StripComments($params);
+    StripComments($param_list);
+    $param_list =~ s/^\s+//;
+    $param_list =~ s/\s+$//;
+
+    my $i = 0 ;
+    my %pList = map { $_ => $i++ }
+                split /\s*,\s*/, $param_list;
+    my $pMatch = '(\b' . join('|', keys %pList) . '\b)\W*$' ;
+
+    my @params = split /\s*;\s*/, $params;
+    my @outParams = ();
+    foreach my $p (@params)
+    {
+        if ($p =~ /,/)
+        {
+            my @bits = split /\s*,\s*/, $p;
+            my $first = shift @bits;
+            $first =~ s/^\s*//;
+            push @outParams, $first;
+            $first =~ /^(\w+\s*)/;
+            my $type = $1 ;
+            push @outParams, map { $type . $_ } @bits;
+        }
+        else
+        {
+            $p =~ s/^\s+//;
+            push @outParams, $p;
+        }
+    }
+
+
+    my %tmp = map { /$pMatch/;  $_ => $pList{$1}  }
+              @outParams ;
+
+    @outParams = map  { "    $_" }
+                 sort { $tmp{$a} <=> $tmp{$b} }
+                 @outParams ;
+
+    print $prefix ;
+    print "(\n" . join(",\n", @outParams) . ")\n";
+    print "{" ;
+
+}
+
+# Output any trailing code.
+print ;
+exit 0;
+
+
+sub StripComments
+{
+
+  no warnings;
+
+  # Strip C & C++ coments
+  # From the perlfaq
+  $_[0] =~
+
+    s{
+       /\*         ##  Start of /* ... */ comment
+       [^*]*\*+    ##  Non-* followed by 1-or-more *'s
+       (
+         [^/*][^*]*\*+
+       )*          ##  0-or-more things which don't start with /
+                   ##    but do end with '*'
+       /           ##  End of /* ... */ comment
+
+     |         ##     OR  C++ Comment
+       //          ## Start of C++ comment //
+       [^\n]*      ## followed by 0-or-more non end of line characters
+
+     |         ##     OR  various things which aren't comments:
+
+       (
+         "           ##  Start of " ... " string
+         (
+           \\.           ##  Escaped char
+         |               ##    OR
+           [^"\\]        ##  Non "\
+         )*
+         "           ##  End of " ... " string
+
+       |         ##     OR
+
+         '           ##  Start of ' ... ' string
+         (
+           \\.           ##  Escaped char
+         |               ##    OR
+           [^'\\]        ##  Non '\
+         )*
+         '           ##  End of ' ... ' string
+
+       |         ##     OR
+
+         .           ##  Anything other char
+         [^/"'\\]*   ##  Chars which doesn't start a comment, string or escape
+       )
+     }{$2}gxs;
+
+}
diff --git a/deps/libchdr/deps/zlib-1.2.11/zutil.c b/deps/libchdr/deps/zlib-1.2.11/zutil.c
new file mode 100644 (file)
index 0000000..a76c6b0
--- /dev/null
@@ -0,0 +1,325 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2017 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+#ifndef Z_SOLO
+#  include "gzguts.h"
+#endif
+
+z_const char * const z_errmsg[10] = {
+    (z_const char *)"need dictionary",     /* Z_NEED_DICT       2  */
+    (z_const char *)"stream end",          /* Z_STREAM_END      1  */
+    (z_const char *)"",                    /* Z_OK              0  */
+    (z_const char *)"file error",          /* Z_ERRNO         (-1) */
+    (z_const char *)"stream error",        /* Z_STREAM_ERROR  (-2) */
+    (z_const char *)"data error",          /* Z_DATA_ERROR    (-3) */
+    (z_const char *)"insufficient memory", /* Z_MEM_ERROR     (-4) */
+    (z_const char *)"buffer error",        /* Z_BUF_ERROR     (-5) */
+    (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */
+    (z_const char *)""
+};
+
+
+const char * ZEXPORT zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+    uLong flags;
+
+    flags = 0;
+    switch ((int)(sizeof(uInt))) {
+    case 2:     break;
+    case 4:     flags += 1;     break;
+    case 8:     flags += 2;     break;
+    default:    flags += 3;
+    }
+    switch ((int)(sizeof(uLong))) {
+    case 2:     break;
+    case 4:     flags += 1 << 2;        break;
+    case 8:     flags += 2 << 2;        break;
+    default:    flags += 3 << 2;
+    }
+    switch ((int)(sizeof(voidpf))) {
+    case 2:     break;
+    case 4:     flags += 1 << 4;        break;
+    case 8:     flags += 2 << 4;        break;
+    default:    flags += 3 << 4;
+    }
+    switch ((int)(sizeof(z_off_t))) {
+    case 2:     break;
+    case 4:     flags += 1 << 6;        break;
+    case 8:     flags += 2 << 6;        break;
+    default:    flags += 3 << 6;
+    }
+#ifdef ZLIB_DEBUG
+    flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+    flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+    flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+    flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+    flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+    flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+    flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+    flags += 1L << 20;
+#endif
+#ifdef FASTEST
+    flags += 1L << 21;
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifdef NO_vsnprintf
+    flags += 1L << 25;
+#    ifdef HAS_vsprintf_void
+    flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_vsnprintf_void
+    flags += 1L << 26;
+#    endif
+#  endif
+#else
+    flags += 1L << 24;
+#  ifdef NO_snprintf
+    flags += 1L << 25;
+#    ifdef HAS_sprintf_void
+    flags += 1L << 26;
+#    endif
+#  else
+#    ifdef HAS_snprintf_void
+    flags += 1L << 26;
+#    endif
+#  endif
+#endif
+    return flags;
+}
+
+#ifdef ZLIB_DEBUG
+#include <stdlib.h>
+#  ifndef verbose
+#    define verbose 0
+#  endif
+int ZLIB_INTERNAL z_verbose = verbose;
+
+void ZLIB_INTERNAL z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+    int err;
+{
+    return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+    /* The Microsoft C Run-Time Library for Windows CE doesn't have
+     * errno.  We define it as a global variable to simplify porting.
+     * Its value is always 0 and should not be used.
+     */
+    int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void ZLIB_INTERNAL zmemcpy(dest, source, len)
+    Bytef* dest;
+    const Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int ZLIB_INTERNAL zmemcmp(s1, s2, len)
+    const Bytef* s1;
+    const Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void ZLIB_INTERNAL zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+#ifndef Z_SOLO
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf;
+    ulg bsize = (ulg)items*size;
+
+    (void)opaque;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+
+    (void)opaque;
+
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
+{
+    (void)opaque;
+    return _halloc((long)items, size);
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+    (void)opaque;
+    _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  malloc OF((uInt size));
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    (void)opaque;
+    return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+                              (voidpf)calloc(items, size);
+}
+
+void ZLIB_INTERNAL zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    (void)opaque;
+    free(ptr);
+}
+
+#endif /* MY_ZCALLOC */
+
+#endif /* !Z_SOLO */
diff --git a/deps/libchdr/deps/zlib-1.2.11/zutil.h b/deps/libchdr/deps/zlib-1.2.11/zutil.h
new file mode 100644 (file)
index 0000000..b079ea6
--- /dev/null
@@ -0,0 +1,271 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#ifdef HAVE_HIDDEN
+#  define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+#  define ZLIB_INTERNAL
+#endif
+
+#include "zlib.h"
+
+#if defined(STDC) && !defined(Z_SOLO)
+#  if !(defined(_WIN32_WCE) && defined(_MSC_VER))
+#    include <stddef.h>
+#  endif
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+
+#ifdef Z_SOLO
+   typedef long ptrdiff_t;  /* guess -- will be caught if guess is wrong */
+#endif
+
+#ifndef local
+#  define local static
+#endif
+/* since "static" is used to mean two completely different things in C, we
+   define "local" for the non-static meaning of "static", for readability
+   (compile with -Dlocal if your debugger can't find static symbols) */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+#  define OS_CODE  0x00
+#  ifndef Z_SOLO
+#    if defined(__TURBOC__) || defined(__BORLANDC__)
+#      if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+         /* Allow compilation with ANSI keywords only enabled */
+         void _Cdecl farfree( void *block );
+         void *_Cdecl farmalloc( unsigned long nbytes );
+#      else
+#        include <alloc.h>
+#      endif
+#    else /* MSC or DJGPP */
+#      include <malloc.h>
+#    endif
+#  endif
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  1
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  2
+#  define F_OPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef __370__
+#  if __TARGET_LIB__ < 0x20000000
+#    define OS_CODE 4
+#  elif __TARGET_LIB__ < 0x40000000
+#    define OS_CODE 11
+#  else
+#    define OS_CODE 8
+#  endif
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  5
+#endif
+
+#ifdef OS2
+#  define OS_CODE  6
+#  if defined(M_I86) && !defined(Z_SOLO)
+#    include <malloc.h>
+#  endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+#  define OS_CODE  7
+#  ifndef Z_SOLO
+#    if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+#      include <unix.h> /* for fdopen */
+#    else
+#      ifndef fdopen
+#        define fdopen(fd,mode) NULL /* No fdopen() */
+#      endif
+#    endif
+#  endif
+#endif
+
+#ifdef __acorn
+#  define OS_CODE 13
+#endif
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+#  define OS_CODE  10
+#endif
+
+#ifdef _BEOS_
+#  define OS_CODE  16
+#endif
+
+#ifdef __TOS_OS400__
+#  define OS_CODE 18
+#endif
+
+#ifdef __APPLE__
+#  define OS_CODE 19
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
+#  if defined(_WIN32_WCE)
+#    define fdopen(fd,mode) NULL /* No fdopen() */
+#    ifndef _PTRDIFF_T_DEFINED
+       typedef int ptrdiff_t;
+#      define _PTRDIFF_T_DEFINED
+#    endif
+#  else
+#    define fdopen(fd,type)  _fdopen(fd,type)
+#  endif
+#endif
+
+#if defined(__BORLANDC__) && !defined(MSDOS)
+  #pragma warn -8004
+  #pragma warn -8008
+  #pragma warn -8066
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_WIN32) && \
+    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
+    ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+    ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#endif
+
+        /* common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  3     /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+#  define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#if defined(pyr) || defined(Z_SOLO)
+#  define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  * The __SC__ check is for Symantec.
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+   int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+   void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef ZLIB_DEBUG
+#  include <stdio.h>
+   extern int ZLIB_INTERNAL z_verbose;
+   extern void ZLIB_INTERNAL z_error OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
+#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
+#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+#ifndef Z_SOLO
+   voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
+                                    unsigned size));
+   void ZLIB_INTERNAL zcfree  OF((voidpf opaque, voidpf ptr));
+#endif
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+/* Reverse the bytes in a 32-bit value */
+#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+                    (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+#endif /* ZUTIL_H */
diff --git a/deps/libchdr/include/dr_libs/dr_flac.h b/deps/libchdr/include/dr_libs/dr_flac.h
new file mode 100644 (file)
index 0000000..2dcddb5
--- /dev/null
@@ -0,0 +1,12214 @@
+/*
+FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
+dr_flac - v0.12.28 - 2021-02-21
+
+David Reid - mackron@gmail.com
+
+GitHub: https://github.com/mackron/dr_libs
+*/
+
+/*
+RELEASE NOTES - v0.12.0
+=======================
+Version 0.12.0 has breaking API changes including changes to the existing API and the removal of deprecated APIs.
+
+
+Improved Client-Defined Memory Allocation
+-----------------------------------------
+The main change with this release is the addition of a more flexible way of implementing custom memory allocation routines. The
+existing system of DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE are still in place and will be used by default when no custom
+allocation callbacks are specified.
+
+To use the new system, you pass in a pointer to a drflac_allocation_callbacks object to drflac_open() and family, like this:
+
+    void* my_malloc(size_t sz, void* pUserData)
+    {
+        return malloc(sz);
+    }
+    void* my_realloc(void* p, size_t sz, void* pUserData)
+    {
+        return realloc(p, sz);
+    }
+    void my_free(void* p, void* pUserData)
+    {
+        free(p);
+    }
+
+    ...
+
+    drflac_allocation_callbacks allocationCallbacks;
+    allocationCallbacks.pUserData = &myData;
+    allocationCallbacks.onMalloc  = my_malloc;
+    allocationCallbacks.onRealloc = my_realloc;
+    allocationCallbacks.onFree    = my_free;
+    drflac* pFlac = drflac_open_file("my_file.flac", &allocationCallbacks);
+
+The advantage of this new system is that it allows you to specify user data which will be passed in to the allocation routines.
+
+Passing in null for the allocation callbacks object will cause dr_flac to use defaults which is the same as DRFLAC_MALLOC,
+DRFLAC_REALLOC and DRFLAC_FREE and the equivalent of how it worked in previous versions.
+
+Every API that opens a drflac object now takes this extra parameter. These include the following:
+
+    drflac_open()
+    drflac_open_relaxed()
+    drflac_open_with_metadata()
+    drflac_open_with_metadata_relaxed()
+    drflac_open_file()
+    drflac_open_file_with_metadata()
+    drflac_open_memory()
+    drflac_open_memory_with_metadata()
+    drflac_open_and_read_pcm_frames_s32()
+    drflac_open_and_read_pcm_frames_s16()
+    drflac_open_and_read_pcm_frames_f32()
+    drflac_open_file_and_read_pcm_frames_s32()
+    drflac_open_file_and_read_pcm_frames_s16()
+    drflac_open_file_and_read_pcm_frames_f32()
+    drflac_open_memory_and_read_pcm_frames_s32()
+    drflac_open_memory_and_read_pcm_frames_s16()
+    drflac_open_memory_and_read_pcm_frames_f32()
+
+
+
+Optimizations
+-------------
+Seeking performance has been greatly improved. A new binary search based seeking algorithm has been introduced which significantly
+improves performance over the brute force method which was used when no seek table was present. Seek table based seeking also takes
+advantage of the new binary search seeking system to further improve performance there as well. Note that this depends on CRC which
+means it will be disabled when DR_FLAC_NO_CRC is used.
+
+The SSE4.1 pipeline has been cleaned up and optimized. You should see some improvements with decoding speed of 24-bit files in
+particular. 16-bit streams should also see some improvement.
+
+drflac_read_pcm_frames_s16() has been optimized. Previously this sat on top of drflac_read_pcm_frames_s32() and performed it's s32
+to s16 conversion in a second pass. This is now all done in a single pass. This includes SSE2 and ARM NEON optimized paths.
+
+A minor optimization has been implemented for drflac_read_pcm_frames_s32(). This will now use an SSE2 optimized pipeline for stereo
+channel reconstruction which is the last part of the decoding process.
+
+The ARM build has seen a few improvements. The CLZ (count leading zeroes) and REV (byte swap) instructions are now used when
+compiling with GCC and Clang which is achieved using inline assembly. The CLZ instruction requires ARM architecture version 5 at
+compile time and the REV instruction requires ARM architecture version 6.
+
+An ARM NEON optimized pipeline has been implemented. To enable this you'll need to add -mfpu=neon to the command line when compiling.
+
+
+Removed APIs
+------------
+The following APIs were deprecated in version 0.11.0 and have been completely removed in version 0.12.0:
+
+    drflac_read_s32()                   -> drflac_read_pcm_frames_s32()
+    drflac_read_s16()                   -> drflac_read_pcm_frames_s16()
+    drflac_read_f32()                   -> drflac_read_pcm_frames_f32()
+    drflac_seek_to_sample()             -> drflac_seek_to_pcm_frame()
+    drflac_open_and_decode_s32()        -> drflac_open_and_read_pcm_frames_s32()
+    drflac_open_and_decode_s16()        -> drflac_open_and_read_pcm_frames_s16()
+    drflac_open_and_decode_f32()        -> drflac_open_and_read_pcm_frames_f32()
+    drflac_open_and_decode_file_s32()   -> drflac_open_file_and_read_pcm_frames_s32()
+    drflac_open_and_decode_file_s16()   -> drflac_open_file_and_read_pcm_frames_s16()
+    drflac_open_and_decode_file_f32()   -> drflac_open_file_and_read_pcm_frames_f32()
+    drflac_open_and_decode_memory_s32() -> drflac_open_memory_and_read_pcm_frames_s32()
+    drflac_open_and_decode_memory_s16() -> drflac_open_memory_and_read_pcm_frames_s16()
+    drflac_open_and_decode_memory_f32() -> drflac_open_memroy_and_read_pcm_frames_f32()
+
+Prior versions of dr_flac operated on a per-sample basis whereas now it operates on PCM frames. The removed APIs all relate
+to the old per-sample APIs. You now need to use the "pcm_frame" versions.
+*/
+
+
+/*
+Introduction
+============
+dr_flac is a single file library. To use it, do something like the following in one .c file.
+
+    ```c
+    #define DR_FLAC_IMPLEMENTATION
+    #include "dr_flac.h"
+    ```
+
+You can then #include this file in other parts of the program as you would with any other header file. To decode audio data, do something like the following:
+
+    ```c
+    drflac* pFlac = drflac_open_file("MySong.flac", NULL);
+    if (pFlac == NULL) {
+        // Failed to open FLAC file
+    }
+
+    drflac_int32* pSamples = malloc(pFlac->totalPCMFrameCount * pFlac->channels * sizeof(drflac_int32));
+    drflac_uint64 numberOfInterleavedSamplesActuallyRead = drflac_read_pcm_frames_s32(pFlac, pFlac->totalPCMFrameCount, pSamples);
+    ```
+
+The drflac object represents the decoder. It is a transparent type so all the information you need, such as the number of channels and the bits per sample,
+should be directly accessible - just make sure you don't change their values. Samples are always output as interleaved signed 32-bit PCM. In the example above
+a native FLAC stream was opened, however dr_flac has seamless support for Ogg encapsulated FLAC streams as well.
+
+You do not need to decode the entire stream in one go - you just specify how many samples you'd like at any given time and the decoder will give you as many
+samples as it can, up to the amount requested. Later on when you need the next batch of samples, just call it again. Example:
+
+    ```c
+    while (drflac_read_pcm_frames_s32(pFlac, chunkSizeInPCMFrames, pChunkSamples) > 0) {
+        do_something();
+    }
+    ```
+
+You can seek to a specific PCM frame with `drflac_seek_to_pcm_frame()`.
+
+If you just want to quickly decode an entire FLAC file in one go you can do something like this:
+
+    ```c
+    unsigned int channels;
+    unsigned int sampleRate;
+    drflac_uint64 totalPCMFrameCount;
+    drflac_int32* pSampleData = drflac_open_file_and_read_pcm_frames_s32("MySong.flac", &channels, &sampleRate, &totalPCMFrameCount, NULL);
+    if (pSampleData == NULL) {
+        // Failed to open and decode FLAC file.
+    }
+
+    ...
+
+    drflac_free(pSampleData, NULL);
+    ```
+
+You can read samples as signed 16-bit integer and 32-bit floating-point PCM with the *_s16() and *_f32() family of APIs respectively, but note that these
+should be considered lossy.
+
+
+If you need access to metadata (album art, etc.), use `drflac_open_with_metadata()`, `drflac_open_file_with_metdata()` or `drflac_open_memory_with_metadata()`.
+The rationale for keeping these APIs separate is that they're slightly slower than the normal versions and also just a little bit harder to use. dr_flac
+reports metadata to the application through the use of a callback, and every metadata block is reported before `drflac_open_with_metdata()` returns.
+
+The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style
+streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs:
+    
+    `drflac_open_relaxed()`
+    `drflac_open_with_metadata_relaxed()`
+
+It is not recommended to use these APIs for file based streams because a missing header would usually indicate a corrupt or perverse file. In addition, these
+APIs can take a long time to initialize because they may need to spend a lot of time finding the first frame.
+
+
+
+Build Options
+=============
+#define these options before including this file.
+
+#define DR_FLAC_NO_STDIO
+  Disable `drflac_open_file()` and family.
+
+#define DR_FLAC_NO_OGG
+  Disables support for Ogg/FLAC streams.
+
+#define DR_FLAC_BUFFER_SIZE <number>
+  Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls back to the client for more data.
+  Larger values means more memory, but better performance. My tests show diminishing returns after about 4KB (which is the default). Consider reducing this if
+  you have a very efficient implementation of onRead(), or increase it if it's very inefficient. Must be a multiple of 8.
+
+#define DR_FLAC_NO_CRC
+  Disables CRC checks. This will offer a performance boost when CRC is unnecessary. This will disable binary search seeking. When seeking, the seek table will
+  be used if available. Otherwise the seek will be performed using brute force.
+
+#define DR_FLAC_NO_SIMD
+  Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler.
+
+
+
+Notes
+=====
+- dr_flac does not support changing the sample rate nor channel count mid stream.
+- dr_flac is not thread-safe, but its APIs can be called from any thread so long as you do your own synchronization.
+- When using Ogg encapsulation, a corrupted metadata block will result in `drflac_open_with_metadata()` and `drflac_open()` returning inconsistent samples due
+  to differences in corrupted stream recorvery logic between the two APIs.
+*/
+
+#ifndef dr_flac_h
+#define dr_flac_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DRFLAC_STRINGIFY(x)      #x
+#define DRFLAC_XSTRINGIFY(x)     DRFLAC_STRINGIFY(x)
+
+#define DRFLAC_VERSION_MAJOR     0
+#define DRFLAC_VERSION_MINOR     12
+#define DRFLAC_VERSION_REVISION  28
+#define DRFLAC_VERSION_STRING    DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION)
+
+#include <stddef.h> /* For size_t. */
+
+/* Sized types. */
+typedef   signed char           drflac_int8;
+typedef unsigned char           drflac_uint8;
+typedef   signed short          drflac_int16;
+typedef unsigned short          drflac_uint16;
+typedef   signed int            drflac_int32;
+typedef unsigned int            drflac_uint32;
+#if defined(_MSC_VER)
+    typedef   signed __int64    drflac_int64;
+    typedef unsigned __int64    drflac_uint64;
+#else
+    #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
+        #pragma GCC diagnostic push
+        #pragma GCC diagnostic ignored "-Wlong-long"
+        #if defined(__clang__)
+            #pragma GCC diagnostic ignored "-Wc++11-long-long"
+        #endif
+    #endif
+    typedef   signed long long  drflac_int64;
+    typedef unsigned long long  drflac_uint64;
+    #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
+        #pragma GCC diagnostic pop
+    #endif
+#endif
+#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
+    typedef drflac_uint64       drflac_uintptr;
+#else
+    typedef drflac_uint32       drflac_uintptr;
+#endif
+typedef drflac_uint8            drflac_bool8;
+typedef drflac_uint32           drflac_bool32;
+#define DRFLAC_TRUE             1
+#define DRFLAC_FALSE            0
+
+#if !defined(DRFLAC_API)
+    #if defined(DRFLAC_DLL)
+        #if defined(_WIN32)
+            #define DRFLAC_DLL_IMPORT  __declspec(dllimport)
+            #define DRFLAC_DLL_EXPORT  __declspec(dllexport)
+            #define DRFLAC_DLL_PRIVATE static
+        #else
+            #if defined(__GNUC__) && __GNUC__ >= 4
+                #define DRFLAC_DLL_IMPORT  __attribute__((visibility("default")))
+                #define DRFLAC_DLL_EXPORT  __attribute__((visibility("default")))
+                #define DRFLAC_DLL_PRIVATE __attribute__((visibility("hidden")))
+            #else
+                #define DRFLAC_DLL_IMPORT
+                #define DRFLAC_DLL_EXPORT
+                #define DRFLAC_DLL_PRIVATE static
+            #endif
+        #endif
+
+        #if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION)
+            #define DRFLAC_API  DRFLAC_DLL_EXPORT
+        #else
+            #define DRFLAC_API  DRFLAC_DLL_IMPORT
+        #endif
+        #define DRFLAC_PRIVATE DRFLAC_DLL_PRIVATE
+    #else
+        #define DRFLAC_API extern
+        #define DRFLAC_PRIVATE static
+    #endif
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1700   /* Visual Studio 2012 */
+    #define DRFLAC_DEPRECATED       __declspec(deprecated)
+#elif (defined(__GNUC__) && __GNUC__ >= 4)  /* GCC 4 */
+    #define DRFLAC_DEPRECATED       __attribute__((deprecated))
+#elif defined(__has_feature)                /* Clang */
+    #if __has_feature(attribute_deprecated)
+        #define DRFLAC_DEPRECATED   __attribute__((deprecated))
+    #else
+        #define DRFLAC_DEPRECATED
+    #endif
+#else
+    #define DRFLAC_DEPRECATED
+#endif
+
+DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision);
+DRFLAC_API const char* drflac_version_string(void);
+
+/*
+As data is read from the client it is placed into an internal buffer for fast access. This controls the size of that buffer. Larger values means more speed,
+but also more memory. In my testing there is diminishing returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8.
+*/
+#ifndef DR_FLAC_BUFFER_SIZE
+#define DR_FLAC_BUFFER_SIZE   4096
+#endif
+
+/* Check if we can enable 64-bit optimizations. */
+#if defined(_WIN64) || defined(_LP64) || defined(__LP64__)
+#define DRFLAC_64BIT
+#endif
+
+#ifdef DRFLAC_64BIT
+typedef drflac_uint64 drflac_cache_t;
+#else
+typedef drflac_uint32 drflac_cache_t;
+#endif
+
+/* The various metadata block types. */
+#define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO       0
+#define DRFLAC_METADATA_BLOCK_TYPE_PADDING          1
+#define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION      2
+#define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE        3
+#define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT   4
+#define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET         5
+#define DRFLAC_METADATA_BLOCK_TYPE_PICTURE          6
+#define DRFLAC_METADATA_BLOCK_TYPE_INVALID          127
+
+/* The various picture types specified in the PICTURE block. */
+#define DRFLAC_PICTURE_TYPE_OTHER                   0
+#define DRFLAC_PICTURE_TYPE_FILE_ICON               1
+#define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON         2
+#define DRFLAC_PICTURE_TYPE_COVER_FRONT             3
+#define DRFLAC_PICTURE_TYPE_COVER_BACK              4
+#define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE            5
+#define DRFLAC_PICTURE_TYPE_MEDIA                   6
+#define DRFLAC_PICTURE_TYPE_LEAD_ARTIST             7
+#define DRFLAC_PICTURE_TYPE_ARTIST                  8
+#define DRFLAC_PICTURE_TYPE_CONDUCTOR               9
+#define DRFLAC_PICTURE_TYPE_BAND                    10
+#define DRFLAC_PICTURE_TYPE_COMPOSER                11
+#define DRFLAC_PICTURE_TYPE_LYRICIST                12
+#define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION      13
+#define DRFLAC_PICTURE_TYPE_DURING_RECORDING        14
+#define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE      15
+#define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE          16
+#define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH     17
+#define DRFLAC_PICTURE_TYPE_ILLUSTRATION            18
+#define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE           19
+#define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE      20
+
+typedef enum
+{
+    drflac_container_native,
+    drflac_container_ogg,
+    drflac_container_unknown
+} drflac_container;
+
+typedef enum
+{
+    drflac_seek_origin_start,
+    drflac_seek_origin_current
+} drflac_seek_origin;
+
+/* Packing is important on this structure because we map this directly to the raw data within the SEEKTABLE metadata block. */
+#pragma pack(2)
+typedef struct
+{
+    drflac_uint64 firstPCMFrame;
+    drflac_uint64 flacFrameOffset;   /* The offset from the first byte of the header of the first frame. */
+    drflac_uint16 pcmFrameCount;
+} drflac_seekpoint;
+#pragma pack()
+
+typedef struct
+{
+    drflac_uint16 minBlockSizeInPCMFrames;
+    drflac_uint16 maxBlockSizeInPCMFrames;
+    drflac_uint32 minFrameSizeInPCMFrames;
+    drflac_uint32 maxFrameSizeInPCMFrames;
+    drflac_uint32 sampleRate;
+    drflac_uint8  channels;
+    drflac_uint8  bitsPerSample;
+    drflac_uint64 totalPCMFrameCount;
+    drflac_uint8  md5[16];
+} drflac_streaminfo;
+
+typedef struct
+{
+    /*
+    The metadata type. Use this to know how to interpret the data below. Will be set to one of the
+    DRFLAC_METADATA_BLOCK_TYPE_* tokens.
+    */
+    drflac_uint32 type;
+
+    /*
+    A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to
+    not modify the contents of this buffer. Use the structures below for more meaningful and structured
+    information about the metadata. It's possible for this to be null.
+    */
+    const void* pRawData;
+
+    /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */
+    drflac_uint32 rawDataSize;
+
+    union
+    {
+        drflac_streaminfo streaminfo;
+
+        struct
+        {
+            int unused;
+        } padding;
+
+        struct
+        {
+            drflac_uint32 id;
+            const void* pData;
+            drflac_uint32 dataSize;
+        } application;
+
+        struct
+        {
+            drflac_uint32 seekpointCount;
+            const drflac_seekpoint* pSeekpoints;
+        } seektable;
+
+        struct
+        {
+            drflac_uint32 vendorLength;
+            const char* vendor;
+            drflac_uint32 commentCount;
+            const void* pComments;
+        } vorbis_comment;
+
+        struct
+        {
+            char catalog[128];
+            drflac_uint64 leadInSampleCount;
+            drflac_bool32 isCD;
+            drflac_uint8 trackCount;
+            const void* pTrackData;
+        } cuesheet;
+
+        struct
+        {
+            drflac_uint32 type;
+            drflac_uint32 mimeLength;
+            const char* mime;
+            drflac_uint32 descriptionLength;
+            const char* description;
+            drflac_uint32 width;
+            drflac_uint32 height;
+            drflac_uint32 colorDepth;
+            drflac_uint32 indexColorCount;
+            drflac_uint32 pictureDataSize;
+            const drflac_uint8* pPictureData;
+        } picture;
+    } data;
+} drflac_metadata;
+
+
+/*
+Callback for when data needs to be read from the client.
+
+
+Parameters
+----------
+pUserData (in)
+    The user data that was passed to drflac_open() and family.
+
+pBufferOut (out)
+    The output buffer.
+
+bytesToRead (in)
+    The number of bytes to read.
+
+
+Return Value
+------------
+The number of bytes actually read.
+
+
+Remarks
+-------
+A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until either the entire bytesToRead is filled or
+you have reached the end of the stream.
+*/
+typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead);
+
+/*
+Callback for when data needs to be seeked.
+
+
+Parameters
+----------
+pUserData (in)
+    The user data that was passed to drflac_open() and family.
+
+offset (in)
+    The number of bytes to move, relative to the origin. Will never be negative.
+
+origin (in)
+    The origin of the seek - the current position or the start of the stream.
+
+
+Return Value
+------------
+Whether or not the seek was successful.
+
+
+Remarks
+-------
+The offset will never be negative. Whether or not it is relative to the beginning or current position is determined by the "origin" parameter which will be
+either drflac_seek_origin_start or drflac_seek_origin_current.
+
+When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected
+and handled by returning DRFLAC_FALSE.
+*/
+typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin);
+
+/*
+Callback for when a metadata block is read.
+
+
+Parameters
+----------
+pUserData (in)
+    The user data that was passed to drflac_open() and family.
+
+pMetadata (in)
+    A pointer to a structure containing the data of the metadata block.
+
+
+Remarks
+-------
+Use pMetadata->type to determine which metadata block is being handled and how to read the data. This
+will be set to one of the DRFLAC_METADATA_BLOCK_TYPE_* tokens.
+*/
+typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata);
+
+
+typedef struct
+{
+    void* pUserData;
+    void* (* onMalloc)(size_t sz, void* pUserData);
+    void* (* onRealloc)(void* p, size_t sz, void* pUserData);
+    void  (* onFree)(void* p, void* pUserData);
+} drflac_allocation_callbacks;
+
+/* Structure for internal use. Only used for decoders opened with drflac_open_memory. */
+typedef struct
+{
+    const drflac_uint8* data;
+    size_t dataSize;
+    size_t currentReadPos;
+} drflac__memory_stream;
+
+/* Structure for internal use. Used for bit streaming. */
+typedef struct
+{
+    /* The function to call when more data needs to be read. */
+    drflac_read_proc onRead;
+
+    /* The function to call when the current read position needs to be moved. */
+    drflac_seek_proc onSeek;
+
+    /* The user data to pass around to onRead and onSeek. */
+    void* pUserData;
+
+
+    /*
+    The number of unaligned bytes in the L2 cache. This will always be 0 until the end of the stream is hit. At the end of the
+    stream there will be a number of bytes that don't cleanly fit in an L1 cache line, so we use this variable to know whether
+    or not the bistreamer needs to run on a slower path to read those last bytes. This will never be more than sizeof(drflac_cache_t).
+    */
+    size_t unalignedByteCount;
+
+    /* The content of the unaligned bytes. */
+    drflac_cache_t unalignedCache;
+
+    /* The index of the next valid cache line in the "L2" cache. */
+    drflac_uint32 nextL2Line;
+
+    /* The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining. */
+    drflac_uint32 consumedBits;
+
+    /*
+    The cached data which was most recently read from the client. There are two levels of cache. Data flows as such:
+    Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions.
+    */
+    drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)];
+    drflac_cache_t cache;
+
+    /*
+    CRC-16. This is updated whenever bits are read from the bit stream. Manually set this to 0 to reset the CRC. For FLAC, this
+    is reset to 0 at the beginning of each frame.
+    */
+    drflac_uint16 crc16;
+    drflac_cache_t crc16Cache;              /* A cache for optimizing CRC calculations. This is filled when when the L1 cache is reloaded. */
+    drflac_uint32 crc16CacheIgnoredBytes;   /* The number of bytes to ignore when updating the CRC-16 from the CRC-16 cache. */
+} drflac_bs;
+
+typedef struct
+{
+    /* The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC. */
+    drflac_uint8 subframeType;
+
+    /* The number of wasted bits per sample as specified by the sub-frame header. */
+    drflac_uint8 wastedBitsPerSample;
+
+    /* The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC. */
+    drflac_uint8 lpcOrder;
+
+    /* A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. */
+    drflac_int32* pSamplesS32;
+} drflac_subframe;
+
+typedef struct
+{
+    /*
+    If the stream uses variable block sizes, this will be set to the index of the first PCM frame. If fixed block sizes are used, this will
+    always be set to 0. This is 64-bit because the decoded PCM frame number will be 36 bits.
+    */
+    drflac_uint64 pcmFrameNumber;
+
+    /*
+    If the stream uses fixed block sizes, this will be set to the frame number. If variable block sizes are used, this will always be 0. This
+    is 32-bit because in fixed block sizes, the maximum frame number will be 31 bits.
+    */
+    drflac_uint32 flacFrameNumber;
+
+    /* The sample rate of this frame. */
+    drflac_uint32 sampleRate;
+
+    /* The number of PCM frames in each sub-frame within this frame. */
+    drflac_uint16 blockSizeInPCMFrames;
+
+    /*
+    The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this
+    will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE.
+    */
+    drflac_uint8 channelAssignment;
+
+    /* The number of bits per sample within this frame. */
+    drflac_uint8 bitsPerSample;
+
+    /* The frame's CRC. */
+    drflac_uint8 crc8;
+} drflac_frame_header;
+
+typedef struct
+{
+    /* The header. */
+    drflac_frame_header header;
+
+    /*
+    The number of PCM frames left to be read in this FLAC frame. This is initially set to the block size. As PCM frames are read,
+    this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame.
+    */
+    drflac_uint32 pcmFramesRemaining;
+
+    /* The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels. */
+    drflac_subframe subframes[8];
+} drflac_frame;
+
+typedef struct
+{
+    /* The function to call when a metadata block is read. */
+    drflac_meta_proc onMeta;
+
+    /* The user data posted to the metadata callback function. */
+    void* pUserDataMD;
+
+    /* Memory allocation callbacks. */
+    drflac_allocation_callbacks allocationCallbacks;
+
+
+    /* The sample rate. Will be set to something like 44100. */
+    drflac_uint32 sampleRate;
+
+    /*
+    The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. Maximum 8. This is set based on the
+    value specified in the STREAMINFO block.
+    */
+    drflac_uint8 channels;
+
+    /* The bits per sample. Will be set to something like 16, 24, etc. */
+    drflac_uint8 bitsPerSample;
+
+    /* The maximum block size, in samples. This number represents the number of samples in each channel (not combined). */
+    drflac_uint16 maxBlockSizeInPCMFrames;
+
+    /*
+    The total number of PCM Frames making up the stream. Can be 0 in which case it's still a valid stream, but just means
+    the total PCM frame count is unknown. Likely the case with streams like internet radio.
+    */
+    drflac_uint64 totalPCMFrameCount;
+
+
+    /* The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream. */
+    drflac_container container;
+
+    /* The number of seekpoints in the seektable. */
+    drflac_uint32 seekpointCount;
+
+
+    /* Information about the frame the decoder is currently sitting on. */
+    drflac_frame currentFLACFrame;
+
+
+    /* The index of the PCM frame the decoder is currently sitting on. This is only used for seeking. */
+    drflac_uint64 currentPCMFrame;
+
+    /* The position of the first FLAC frame in the stream. This is only ever used for seeking. */
+    drflac_uint64 firstFLACFramePosInBytes;
+
+
+    /* A hack to avoid a malloc() when opening a decoder with drflac_open_memory(). */
+    drflac__memory_stream memoryStream;
+
+
+    /* A pointer to the decoded sample data. This is an offset of pExtraData. */
+    drflac_int32* pDecodedSamples;
+
+    /* A pointer to the seek table. This is an offset of pExtraData, or NULL if there is no seek table. */
+    drflac_seekpoint* pSeekpoints;
+
+    /* Internal use only. Only used with Ogg containers. Points to a drflac_oggbs object. This is an offset of pExtraData. */
+    void* _oggbs;
+
+    /* Internal use only. Used for profiling and testing different seeking modes. */
+    drflac_bool32 _noSeekTableSeek    : 1;
+    drflac_bool32 _noBinarySearchSeek : 1;
+    drflac_bool32 _noBruteForceSeek   : 1;
+
+    /* The bit streamer. The raw FLAC data is fed through this object. */
+    drflac_bs bs;
+
+    /* Variable length extra data. We attach this to the end of the object so we can avoid unnecessary mallocs. */
+    drflac_uint8 pExtraData[1];
+} drflac;
+
+
+/*
+Opens a FLAC decoder.
+
+
+Parameters
+----------
+onRead (in)
+    The function to call when data needs to be read from the client.
+
+onSeek (in)
+    The function to call when the read position of the client data needs to move.
+
+pUserData (in, optional)
+    A pointer to application defined data that will be passed to onRead and onSeek.
+
+pAllocationCallbacks (in, optional)
+    A pointer to application defined callbacks for managing memory allocations.
+
+
+Return Value
+------------
+Returns a pointer to an object representing the decoder.
+
+
+Remarks
+-------
+Close the decoder with `drflac_close()`.
+
+`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`.
+
+This function will automatically detect whether or not you are attempting to open a native or Ogg encapsulated FLAC, both of which should work seamlessly
+without any manual intervention. Ogg encapsulation also works with multiplexed streams which basically means it can play FLAC encoded audio tracks in videos.
+
+This is the lowest level function for opening a FLAC stream. You can also use `drflac_open_file()` and `drflac_open_memory()` to open the stream from a file or
+from a block of memory respectively.
+
+The STREAMINFO block must be present for this to succeed. Use `drflac_open_relaxed()` to open a FLAC stream where the header may not be present.
+
+Use `drflac_open_with_metadata()` if you need access to metadata.
+
+
+Seek Also
+---------
+drflac_open_file()
+drflac_open_memory()
+drflac_open_with_metadata()
+drflac_close()
+*/
+DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/*
+Opens a FLAC stream with relaxed validation of the header block.
+
+
+Parameters
+----------
+onRead (in)
+    The function to call when data needs to be read from the client.
+
+onSeek (in)
+    The function to call when the read position of the client data needs to move.
+
+container (in)
+    Whether or not the FLAC stream is encapsulated using standard FLAC encapsulation or Ogg encapsulation.
+
+pUserData (in, optional)
+    A pointer to application defined data that will be passed to onRead and onSeek.
+
+pAllocationCallbacks (in, optional)
+    A pointer to application defined callbacks for managing memory allocations.
+
+
+Return Value
+------------
+A pointer to an object representing the decoder.
+
+
+Remarks
+-------
+The same as drflac_open(), except attempts to open the stream even when a header block is not present.
+
+Because the header is not necessarily available, the caller must explicitly define the container (Native or Ogg). Do not set this to `drflac_container_unknown`
+as that is for internal use only.
+
+Opening in relaxed mode will continue reading data from onRead until it finds a valid frame. If a frame is never found it will continue forever. To abort,
+force your `onRead` callback to return 0, which dr_flac will use as an indicator that the end of the stream was found.
+
+Use `drflac_open_with_metadata_relaxed()` if you need access to metadata.
+*/
+DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/*
+Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.).
+
+
+Parameters
+----------
+onRead (in)
+    The function to call when data needs to be read from the client.
+
+onSeek (in)
+    The function to call when the read position of the client data needs to move.
+
+onMeta (in)
+    The function to call for every metadata block.
+
+pUserData (in, optional)
+    A pointer to application defined data that will be passed to onRead, onSeek and onMeta.
+
+pAllocationCallbacks (in, optional)
+    A pointer to application defined callbacks for managing memory allocations.
+
+
+Return Value
+------------
+A pointer to an object representing the decoder.
+
+
+Remarks
+-------
+Close the decoder with `drflac_close()`.
+
+`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`.
+
+This is slower than `drflac_open()`, so avoid this one if you don't need metadata. Internally, this will allocate and free memory on the heap for every
+metadata block except for STREAMINFO and PADDING blocks.
+
+The caller is notified of the metadata via the `onMeta` callback. All metadata blocks will be handled before the function returns. This callback takes a
+pointer to a `drflac_metadata` object which is a union containing the data of all relevant metadata blocks. Use the `type` member to discriminate against
+the different metadata types.
+
+The STREAMINFO block must be present for this to succeed. Use `drflac_open_with_metadata_relaxed()` to open a FLAC stream where the header may not be present.
+
+Note that this will behave inconsistently with `drflac_open()` if the stream is an Ogg encapsulated stream and a metadata block is corrupted. This is due to
+the way the Ogg stream recovers from corrupted pages. When `drflac_open_with_metadata()` is being used, the open routine will try to read the contents of the
+metadata block, whereas `drflac_open()` will simply seek past it (for the sake of efficiency). This inconsistency can result in different samples being
+returned depending on whether or not the stream is being opened with metadata.
+
+
+Seek Also
+---------
+drflac_open_file_with_metadata()
+drflac_open_memory_with_metadata()
+drflac_open()
+drflac_close()
+*/
+DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/*
+The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present.
+
+See Also
+--------
+drflac_open_with_metadata()
+drflac_open_relaxed()
+*/
+DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/*
+Closes the given FLAC decoder.
+
+
+Parameters
+----------
+pFlac (in)
+    The decoder to close.
+
+
+Remarks
+-------
+This will destroy the decoder object.
+
+
+See Also
+--------
+drflac_open()
+drflac_open_with_metadata()
+drflac_open_file()
+drflac_open_file_w()
+drflac_open_file_with_metadata()
+drflac_open_file_with_metadata_w()
+drflac_open_memory()
+drflac_open_memory_with_metadata()
+*/
+DRFLAC_API void drflac_close(drflac* pFlac);
+
+
+/*
+Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM.
+
+
+Parameters
+----------
+pFlac (in)
+    The decoder.
+
+framesToRead (in)
+    The number of PCM frames to read.
+
+pBufferOut (out, optional)
+    A pointer to the buffer that will receive the decoded samples.
+
+
+Return Value
+------------
+Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end.
+
+
+Remarks
+-------
+pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked.
+*/
+DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut);
+
+
+/*
+Reads sample data from the given FLAC decoder, output as interleaved signed 16-bit PCM.
+
+
+Parameters
+----------
+pFlac (in)
+    The decoder.
+
+framesToRead (in)
+    The number of PCM frames to read.
+
+pBufferOut (out, optional)
+    A pointer to the buffer that will receive the decoded samples.
+
+
+Return Value
+------------
+Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end.
+
+
+Remarks
+-------
+pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked.
+
+Note that this is lossy for streams where the bits per sample is larger than 16.
+*/
+DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut);
+
+/*
+Reads sample data from the given FLAC decoder, output as interleaved 32-bit floating point PCM.
+
+
+Parameters
+----------
+pFlac (in)
+    The decoder.
+
+framesToRead (in)
+    The number of PCM frames to read.
+
+pBufferOut (out, optional)
+    A pointer to the buffer that will receive the decoded samples.
+
+
+Return Value
+------------
+Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end.
+
+
+Remarks
+-------
+pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked.
+
+Note that this should be considered lossy due to the nature of floating point numbers not being able to exactly represent every possible number.
+*/
+DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut);
+
+/*
+Seeks to the PCM frame at the given index.
+
+
+Parameters
+----------
+pFlac (in)
+    The decoder.
+
+pcmFrameIndex (in)
+    The index of the PCM frame to seek to. See notes below.
+
+
+Return Value
+-------------
+`DRFLAC_TRUE` if successful; `DRFLAC_FALSE` otherwise.
+*/
+DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex);
+
+
+
+#ifndef DR_FLAC_NO_STDIO
+/*
+Opens a FLAC decoder from the file at the given path.
+
+
+Parameters
+----------
+pFileName (in)
+    The path of the file to open, either absolute or relative to the current directory.
+
+pAllocationCallbacks (in, optional)
+    A pointer to application defined callbacks for managing memory allocations.
+
+
+Return Value
+------------
+A pointer to an object representing the decoder.
+
+
+Remarks
+-------
+Close the decoder with drflac_close().
+
+
+Remarks
+-------
+This will hold a handle to the file until the decoder is closed with drflac_close(). Some platforms will restrict the number of files a process can have open
+at any given time, so keep this mind if you have many decoders open at the same time.
+
+
+See Also
+--------
+drflac_open_file_with_metadata()
+drflac_open()
+drflac_close()
+*/
+DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
+DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/*
+Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.)
+
+
+Parameters
+----------
+pFileName (in)
+    The path of the file to open, either absolute or relative to the current directory.
+
+pAllocationCallbacks (in, optional)
+    A pointer to application defined callbacks for managing memory allocations.
+
+onMeta (in)
+    The callback to fire for each metadata block.
+
+pUserData (in)
+    A pointer to the user data to pass to the metadata callback.
+
+pAllocationCallbacks (in)
+    A pointer to application defined callbacks for managing memory allocations.
+
+
+Remarks
+-------
+Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled.
+
+
+See Also
+--------
+drflac_open_with_metadata()
+drflac_open()
+drflac_close()
+*/
+DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
+DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
+#endif
+
+/*
+Opens a FLAC decoder from a pre-allocated block of memory
+
+
+Parameters
+----------
+pData (in)
+    A pointer to the raw encoded FLAC data.
+
+dataSize (in)
+    The size in bytes of `data`.
+
+pAllocationCallbacks (in)
+    A pointer to application defined callbacks for managing memory allocations.
+
+
+Return Value
+------------
+A pointer to an object representing the decoder.
+
+
+Remarks
+-------
+This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for the lifetime of the decoder.
+
+
+See Also
+--------
+drflac_open()
+drflac_close()
+*/
+DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/*
+Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.)
+
+
+Parameters
+----------
+pData (in)
+    A pointer to the raw encoded FLAC data.
+
+dataSize (in)
+    The size in bytes of `data`.
+
+onMeta (in)
+    The callback to fire for each metadata block.
+
+pUserData (in)
+    A pointer to the user data to pass to the metadata callback.
+
+pAllocationCallbacks (in)
+    A pointer to application defined callbacks for managing memory allocations.
+
+
+Remarks
+-------
+Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled.
+
+
+See Also
+-------
+drflac_open_with_metadata()
+drflac_open()
+drflac_close()
+*/
+DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+
+
+/* High Level APIs */
+
+/*
+Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a
+pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with drflac_free().
+
+You can pass in custom memory allocation callbacks via the pAllocationCallbacks parameter. This can be NULL in which
+case it will use DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE.
+
+Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously
+read samples into a dynamically sized buffer on the heap until no samples are left.
+
+Do not call this function on a broadcast type of stream (like internet radio streams and whatnot).
+*/
+DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
+DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
+DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+#ifndef DR_FLAC_NO_STDIO
+/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */
+DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
+DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
+DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
+#endif
+
+/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a block of memory. */
+DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */
+DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */
+DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+/*
+Frees memory that was allocated internally by dr_flac.
+
+Set pAllocationCallbacks to the same object that was passed to drflac_open_*_and_read_pcm_frames_*(). If you originally passed in NULL, pass in NULL for this.
+*/
+DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks);
+
+
+/* Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block. */
+typedef struct
+{
+    drflac_uint32 countRemaining;
+    const char* pRunningData;
+} drflac_vorbis_comment_iterator;
+
+/*
+Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT
+metadata block.
+*/
+DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments);
+
+/*
+Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The
+returned string is NOT null terminated.
+*/
+DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut);
+
+
+/* Structure representing an iterator for cuesheet tracks in a CUESHEET metadata block. */
+typedef struct
+{
+    drflac_uint32 countRemaining;
+    const char* pRunningData;
+} drflac_cuesheet_track_iterator;
+
+/* Packing is important on this structure because we map this directly to the raw data within the CUESHEET metadata block. */
+#pragma pack(4)
+typedef struct
+{
+    drflac_uint64 offset;
+    drflac_uint8 index;
+    drflac_uint8 reserved[3];
+} drflac_cuesheet_track_index;
+#pragma pack()
+
+typedef struct
+{
+    drflac_uint64 offset;
+    drflac_uint8 trackNumber;
+    char ISRC[12];
+    drflac_bool8 isAudio;
+    drflac_bool8 preEmphasis;
+    drflac_uint8 indexCount;
+    const drflac_cuesheet_track_index* pIndexPoints;
+} drflac_cuesheet_track;
+
+/*
+Initializes a cuesheet track iterator. This can be used for iterating over the cuesheet tracks in a CUESHEET metadata
+block.
+*/
+DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData);
+
+/* Goes to the next cuesheet track in the given iterator. If DRFLAC_FALSE is returned it means there are no more comments. */
+DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif  /* dr_flac_h */
+
+
+/************************************************************************************************************************************************************
+ ************************************************************************************************************************************************************
+
+ IMPLEMENTATION
+
+ ************************************************************************************************************************************************************
+ ************************************************************************************************************************************************************/
+#if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION)
+#ifndef dr_flac_c
+#define dr_flac_c
+
+/* Disable some annoying warnings. */
+#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
+    #pragma GCC diagnostic push
+    #if __GNUC__ >= 7
+    #pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
+    #endif
+#endif
+
+#ifdef __linux__
+    #ifndef _BSD_SOURCE
+        #define _BSD_SOURCE
+    #endif
+    #ifndef _DEFAULT_SOURCE
+        #define _DEFAULT_SOURCE
+    #endif
+    #ifndef __USE_BSD
+        #define __USE_BSD
+    #endif
+    #include <endian.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _MSC_VER
+    #define DRFLAC_INLINE __forceinline
+#elif defined(__GNUC__)
+    /*
+    I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when
+    the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some
+    case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the
+    command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue
+    I am using "__inline__" only when we're compiling in strict ANSI mode.
+    */
+    #if defined(__STRICT_ANSI__)
+        #define DRFLAC_INLINE __inline__ __attribute__((always_inline))
+    #else
+        #define DRFLAC_INLINE inline __attribute__((always_inline))
+    #endif
+#elif defined(__WATCOMC__)
+    #define DRFLAC_INLINE __inline
+#else
+    #define DRFLAC_INLINE
+#endif
+
+/* CPU architecture. */
+#if defined(__x86_64__) || defined(_M_X64)
+    #define DRFLAC_X64
+#elif defined(__i386) || defined(_M_IX86)
+    #define DRFLAC_X86
+#elif defined(__arm__) || defined(_M_ARM) || defined(_M_ARM64)
+    #define DRFLAC_ARM
+#endif
+
+/*
+Intrinsics Support
+
+There's a bug in GCC 4.2.x which results in an incorrect compilation error when using _mm_slli_epi32() where it complains with
+
+    "error: shift must be an immediate"
+
+Unfortuantely dr_flac depends on this for a few things so we're just going to disable SSE on GCC 4.2 and below.
+*/
+#if !defined(DR_FLAC_NO_SIMD)
+    #if defined(DRFLAC_X64) || defined(DRFLAC_X86)
+        #if defined(_MSC_VER) && !defined(__clang__)
+            /* MSVC. */
+            #if _MSC_VER >= 1400 && !defined(DRFLAC_NO_SSE2)    /* 2005 */
+                #define DRFLAC_SUPPORT_SSE2
+            #endif
+            #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41)   /* 2010 */
+                #define DRFLAC_SUPPORT_SSE41
+            #endif
+        #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
+            /* Assume GNUC-style. */
+            #if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2)
+                #define DRFLAC_SUPPORT_SSE2
+            #endif
+            #if defined(__SSE4_1__) && !defined(DRFLAC_NO_SSE41)
+                #define DRFLAC_SUPPORT_SSE41
+            #endif
+        #endif
+
+        /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */
+        #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
+            #if !defined(DRFLAC_SUPPORT_SSE2) && !defined(DRFLAC_NO_SSE2) && __has_include(<emmintrin.h>)
+                #define DRFLAC_SUPPORT_SSE2
+            #endif
+            #if !defined(DRFLAC_SUPPORT_SSE41) && !defined(DRFLAC_NO_SSE41) && __has_include(<smmintrin.h>)
+                #define DRFLAC_SUPPORT_SSE41
+            #endif
+        #endif
+
+        #if defined(DRFLAC_SUPPORT_SSE41)
+            #include <smmintrin.h>
+        #elif defined(DRFLAC_SUPPORT_SSE2)
+            #include <emmintrin.h>
+        #endif
+    #endif
+
+    #if defined(DRFLAC_ARM)
+        #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
+            #define DRFLAC_SUPPORT_NEON
+        #endif
+
+        /* Fall back to looking for the #include file. */
+        #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include)
+            #if !defined(DRFLAC_SUPPORT_NEON) && !defined(DRFLAC_NO_NEON) && __has_include(<arm_neon.h>)
+                #define DRFLAC_SUPPORT_NEON
+            #endif
+        #endif
+
+        #if defined(DRFLAC_SUPPORT_NEON)
+            #include <arm_neon.h>
+        #endif
+    #endif
+#endif
+
+/* Compile-time CPU feature support. */
+#if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64))
+    #if defined(_MSC_VER) && !defined(__clang__)
+        #if _MSC_VER >= 1400
+            #include <intrin.h>
+            static void drflac__cpuid(int info[4], int fid)
+            {
+                __cpuid(info, fid);
+            }
+        #else
+            #define DRFLAC_NO_CPUID
+        #endif
+    #else
+        #if defined(__GNUC__) || defined(__clang__)
+            static void drflac__cpuid(int info[4], int fid)
+            {
+                /*
+                It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the
+                specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for
+                supporting different assembly dialects.
+
+                What's basically happening is that we're saving and restoring the ebx register manually.
+                */
+                #if defined(DRFLAC_X86) && defined(__PIC__)
+                    __asm__ __volatile__ (
+                        "xchg{l} {%%}ebx, %k1;"
+                        "cpuid;"
+                        "xchg{l} {%%}ebx, %k1;"
+                        : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
+                    );
+                #else
+                    __asm__ __volatile__ (
+                        "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0)
+                    );
+                #endif
+            }
+        #else
+            #define DRFLAC_NO_CPUID
+        #endif
+    #endif
+#else
+    #define DRFLAC_NO_CPUID
+#endif
+
+static DRFLAC_INLINE drflac_bool32 drflac_has_sse2(void)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE2)
+        #if defined(DRFLAC_X64)
+            return DRFLAC_TRUE;    /* 64-bit targets always support SSE2. */
+        #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__)
+            return DRFLAC_TRUE;    /* If the compiler is allowed to freely generate SSE2 code we can assume support. */
+        #else
+            #if defined(DRFLAC_NO_CPUID)
+                return DRFLAC_FALSE;
+            #else
+                int info[4];
+                drflac__cpuid(info, 1);
+                return (info[3] & (1 << 26)) != 0;
+            #endif
+        #endif
+    #else
+        return DRFLAC_FALSE;       /* SSE2 is only supported on x86 and x64 architectures. */
+    #endif
+#else
+    return DRFLAC_FALSE;           /* No compiler support. */
+#endif
+}
+
+static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void)
+{
+#if defined(DRFLAC_SUPPORT_SSE41)
+    #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41)
+        #if defined(DRFLAC_X64)
+            return DRFLAC_TRUE;    /* 64-bit targets always support SSE4.1. */
+        #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE4_1__)
+            return DRFLAC_TRUE;    /* If the compiler is allowed to freely generate SSE41 code we can assume support. */
+        #else
+            #if defined(DRFLAC_NO_CPUID)
+                return DRFLAC_FALSE;
+            #else
+                int info[4];
+                drflac__cpuid(info, 1);
+                return (info[2] & (1 << 19)) != 0;
+            #endif
+        #endif
+    #else
+        return DRFLAC_FALSE;       /* SSE41 is only supported on x86 and x64 architectures. */
+    #endif
+#else
+    return DRFLAC_FALSE;           /* No compiler support. */
+#endif
+}
+
+
+#if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) && !defined(__clang__)
+    #define DRFLAC_HAS_LZCNT_INTRINSIC
+#elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)))
+    #define DRFLAC_HAS_LZCNT_INTRINSIC
+#elif defined(__clang__)
+    #if defined(__has_builtin)
+        #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl)
+            #define DRFLAC_HAS_LZCNT_INTRINSIC
+        #endif
+    #endif
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__clang__)
+    #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
+    #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
+    #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
+#elif defined(__clang__)
+    #if defined(__has_builtin)
+        #if __has_builtin(__builtin_bswap16)
+            #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
+        #endif
+        #if __has_builtin(__builtin_bswap32)
+            #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
+        #endif
+        #if __has_builtin(__builtin_bswap64)
+            #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
+        #endif
+    #endif
+#elif defined(__GNUC__)
+    #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+        #define DRFLAC_HAS_BYTESWAP32_INTRINSIC
+        #define DRFLAC_HAS_BYTESWAP64_INTRINSIC
+    #endif
+    #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
+        #define DRFLAC_HAS_BYTESWAP16_INTRINSIC
+    #endif
+#endif
+
+
+/* Standard library stuff. */
+#ifndef DRFLAC_ASSERT
+#include <assert.h>
+#define DRFLAC_ASSERT(expression)           assert(expression)
+#endif
+#ifndef DRFLAC_MALLOC
+#define DRFLAC_MALLOC(sz)                   malloc((sz))
+#endif
+#ifndef DRFLAC_REALLOC
+#define DRFLAC_REALLOC(p, sz)               realloc((p), (sz))
+#endif
+#ifndef DRFLAC_FREE
+#define DRFLAC_FREE(p)                      free((p))
+#endif
+#ifndef DRFLAC_COPY_MEMORY
+#define DRFLAC_COPY_MEMORY(dst, src, sz)    memcpy((dst), (src), (sz))
+#endif
+#ifndef DRFLAC_ZERO_MEMORY
+#define DRFLAC_ZERO_MEMORY(p, sz)           memset((p), 0, (sz))
+#endif
+#ifndef DRFLAC_ZERO_OBJECT
+#define DRFLAC_ZERO_OBJECT(p)               DRFLAC_ZERO_MEMORY((p), sizeof(*(p)))
+#endif
+
+#define DRFLAC_MAX_SIMD_VECTOR_SIZE                     64  /* 64 for AVX-512 in the future. */
+
+typedef drflac_int32 drflac_result;
+#define DRFLAC_SUCCESS                                   0
+#define DRFLAC_ERROR                                    -1   /* A generic error. */
+#define DRFLAC_INVALID_ARGS                             -2
+#define DRFLAC_INVALID_OPERATION                        -3
+#define DRFLAC_OUT_OF_MEMORY                            -4
+#define DRFLAC_OUT_OF_RANGE                             -5
+#define DRFLAC_ACCESS_DENIED                            -6
+#define DRFLAC_DOES_NOT_EXIST                           -7
+#define DRFLAC_ALREADY_EXISTS                           -8
+#define DRFLAC_TOO_MANY_OPEN_FILES                      -9
+#define DRFLAC_INVALID_FILE                             -10
+#define DRFLAC_TOO_BIG                                  -11
+#define DRFLAC_PATH_TOO_LONG                            -12
+#define DRFLAC_NAME_TOO_LONG                            -13
+#define DRFLAC_NOT_DIRECTORY                            -14
+#define DRFLAC_IS_DIRECTORY                             -15
+#define DRFLAC_DIRECTORY_NOT_EMPTY                      -16
+#define DRFLAC_END_OF_FILE                              -17
+#define DRFLAC_NO_SPACE                                 -18
+#define DRFLAC_BUSY                                     -19
+#define DRFLAC_IO_ERROR                                 -20
+#define DRFLAC_INTERRUPT                                -21
+#define DRFLAC_UNAVAILABLE                              -22
+#define DRFLAC_ALREADY_IN_USE                           -23
+#define DRFLAC_BAD_ADDRESS                              -24
+#define DRFLAC_BAD_SEEK                                 -25
+#define DRFLAC_BAD_PIPE                                 -26
+#define DRFLAC_DEADLOCK                                 -27
+#define DRFLAC_TOO_MANY_LINKS                           -28
+#define DRFLAC_NOT_IMPLEMENTED                          -29
+#define DRFLAC_NO_MESSAGE                               -30
+#define DRFLAC_BAD_MESSAGE                              -31
+#define DRFLAC_NO_DATA_AVAILABLE                        -32
+#define DRFLAC_INVALID_DATA                             -33
+#define DRFLAC_TIMEOUT                                  -34
+#define DRFLAC_NO_NETWORK                               -35
+#define DRFLAC_NOT_UNIQUE                               -36
+#define DRFLAC_NOT_SOCKET                               -37
+#define DRFLAC_NO_ADDRESS                               -38
+#define DRFLAC_BAD_PROTOCOL                             -39
+#define DRFLAC_PROTOCOL_UNAVAILABLE                     -40
+#define DRFLAC_PROTOCOL_NOT_SUPPORTED                   -41
+#define DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED            -42
+#define DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED             -43
+#define DRFLAC_SOCKET_NOT_SUPPORTED                     -44
+#define DRFLAC_CONNECTION_RESET                         -45
+#define DRFLAC_ALREADY_CONNECTED                        -46
+#define DRFLAC_NOT_CONNECTED                            -47
+#define DRFLAC_CONNECTION_REFUSED                       -48
+#define DRFLAC_NO_HOST                                  -49
+#define DRFLAC_IN_PROGRESS                              -50
+#define DRFLAC_CANCELLED                                -51
+#define DRFLAC_MEMORY_ALREADY_MAPPED                    -52
+#define DRFLAC_AT_END                                   -53
+#define DRFLAC_CRC_MISMATCH                             -128
+
+#define DRFLAC_SUBFRAME_CONSTANT                        0
+#define DRFLAC_SUBFRAME_VERBATIM                        1
+#define DRFLAC_SUBFRAME_FIXED                           8
+#define DRFLAC_SUBFRAME_LPC                             32
+#define DRFLAC_SUBFRAME_RESERVED                        255
+
+#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE  0
+#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1
+
+#define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT           0
+#define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE             8
+#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE            9
+#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE              10
+
+#define drflac_align(x, a)                              ((((x) + (a) - 1) / (a)) * (a))
+
+
+DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision)
+{
+    if (pMajor) {
+        *pMajor = DRFLAC_VERSION_MAJOR;
+    }
+
+    if (pMinor) {
+        *pMinor = DRFLAC_VERSION_MINOR;
+    }
+
+    if (pRevision) {
+        *pRevision = DRFLAC_VERSION_REVISION;
+    }
+}
+
+DRFLAC_API const char* drflac_version_string(void)
+{
+    return DRFLAC_VERSION_STRING;
+}
+
+
+/* CPU caps. */
+#if defined(__has_feature)
+    #if __has_feature(thread_sanitizer)
+        #define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread")))
+    #else
+        #define DRFLAC_NO_THREAD_SANITIZE
+    #endif
+#else
+    #define DRFLAC_NO_THREAD_SANITIZE
+#endif
+
+#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
+static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE;
+#endif
+
+#ifndef DRFLAC_NO_CPUID
+static drflac_bool32 drflac__gIsSSE2Supported  = DRFLAC_FALSE;
+static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE;
+
+/*
+I've had a bug report that Clang's ThreadSanitizer presents a warning in this function. Having reviewed this, this does
+actually make sense. However, since CPU caps should never differ for a running process, I don't think the trade off of
+complicating internal API's by passing around CPU caps versus just disabling the warnings is worthwhile. I'm therefore
+just going to disable these warnings. This is disabled via the DRFLAC_NO_THREAD_SANITIZE attribute.
+*/
+DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
+{
+    static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE;
+
+    if (!isCPUCapsInitialized) {
+        /* LZCNT */
+#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
+        int info[4] = {0};
+        drflac__cpuid(info, 0x80000001);
+        drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0;
+#endif
+
+        /* SSE2 */
+        drflac__gIsSSE2Supported = drflac_has_sse2();
+
+        /* SSE4.1 */
+        drflac__gIsSSE41Supported = drflac_has_sse41();
+
+        /* Initialized. */
+        isCPUCapsInitialized = DRFLAC_TRUE;
+    }
+}
+#else
+static drflac_bool32 drflac__gIsNEONSupported  = DRFLAC_FALSE;
+
+static DRFLAC_INLINE drflac_bool32 drflac__has_neon(void)
+{
+#if defined(DRFLAC_SUPPORT_NEON)
+    #if defined(DRFLAC_ARM) && !defined(DRFLAC_NO_NEON)
+        #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64))
+            return DRFLAC_TRUE;    /* If the compiler is allowed to freely generate NEON code we can assume support. */
+        #else
+            /* TODO: Runtime check. */
+            return DRFLAC_FALSE;
+        #endif
+    #else
+        return DRFLAC_FALSE;       /* NEON is only supported on ARM architectures. */
+    #endif
+#else
+    return DRFLAC_FALSE;           /* No compiler support. */
+#endif
+}
+
+DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void)
+{
+    drflac__gIsNEONSupported = drflac__has_neon();
+
+#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
+    drflac__gIsLZCNTSupported = DRFLAC_TRUE;
+#endif
+}
+#endif
+
+
+/* Endian Management */
+static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian(void)
+{
+#if defined(DRFLAC_X86) || defined(DRFLAC_X64)
+    return DRFLAC_TRUE;
+#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN
+    return DRFLAC_TRUE;
+#else
+    int n = 1;
+    return (*(char*)&n) == 1;
+#endif
+}
+
+static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n)
+{
+#ifdef DRFLAC_HAS_BYTESWAP16_INTRINSIC
+    #if defined(_MSC_VER) && !defined(__clang__)
+        return _byteswap_ushort(n);
+    #elif defined(__GNUC__) || defined(__clang__)
+        return __builtin_bswap16(n);
+    #else
+        #error "This compiler does not support the byte swap intrinsic."
+    #endif
+#else
+    return ((n & 0xFF00) >> 8) |
+           ((n & 0x00FF) << 8);
+#endif
+}
+
+static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n)
+{
+#ifdef DRFLAC_HAS_BYTESWAP32_INTRINSIC
+    #if defined(_MSC_VER) && !defined(__clang__)
+        return _byteswap_ulong(n);
+    #elif defined(__GNUC__) || defined(__clang__)
+        #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(DRFLAC_64BIT)   /* <-- 64-bit inline assembly has not been tested, so disabling for now. */
+            /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */
+            drflac_uint32 r;
+            __asm__ __volatile__ (
+            #if defined(DRFLAC_64BIT)
+                "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n)   /* <-- This is untested. If someone in the community could test this, that would be appreciated! */
+            #else
+                "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n)
+            #endif
+            );
+            return r;
+        #else
+            return __builtin_bswap32(n);
+        #endif
+    #else
+        #error "This compiler does not support the byte swap intrinsic."
+    #endif
+#else
+    return ((n & 0xFF000000) >> 24) |
+           ((n & 0x00FF0000) >>  8) |
+           ((n & 0x0000FF00) <<  8) |
+           ((n & 0x000000FF) << 24);
+#endif
+}
+
+static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n)
+{
+#ifdef DRFLAC_HAS_BYTESWAP64_INTRINSIC
+    #if defined(_MSC_VER) && !defined(__clang__)
+        return _byteswap_uint64(n);
+    #elif defined(__GNUC__) || defined(__clang__)
+        return __builtin_bswap64(n);
+    #else
+        #error "This compiler does not support the byte swap intrinsic."
+    #endif
+#else
+    /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
+    return ((n & ((drflac_uint64)0xFF000000 << 32)) >> 56) |
+           ((n & ((drflac_uint64)0x00FF0000 << 32)) >> 40) |
+           ((n & ((drflac_uint64)0x0000FF00 << 32)) >> 24) |
+           ((n & ((drflac_uint64)0x000000FF << 32)) >>  8) |
+           ((n & ((drflac_uint64)0xFF000000      )) <<  8) |
+           ((n & ((drflac_uint64)0x00FF0000      )) << 24) |
+           ((n & ((drflac_uint64)0x0000FF00      )) << 40) |
+           ((n & ((drflac_uint64)0x000000FF      )) << 56);
+#endif
+}
+
+
+static DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n)
+{
+    if (drflac__is_little_endian()) {
+        return drflac__swap_endian_uint16(n);
+    }
+
+    return n;
+}
+
+static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n)
+{
+    if (drflac__is_little_endian()) {
+        return drflac__swap_endian_uint32(n);
+    }
+
+    return n;
+}
+
+static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n)
+{
+    if (drflac__is_little_endian()) {
+        return drflac__swap_endian_uint64(n);
+    }
+
+    return n;
+}
+
+
+static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n)
+{
+    if (!drflac__is_little_endian()) {
+        return drflac__swap_endian_uint32(n);
+    }
+
+    return n;
+}
+
+
+static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n)
+{
+    drflac_uint32 result = 0;
+    result |= (n & 0x7F000000) >> 3;
+    result |= (n & 0x007F0000) >> 2;
+    result |= (n & 0x00007F00) >> 1;
+    result |= (n & 0x0000007F) >> 0;
+
+    return result;
+}
+
+
+
+/* The CRC code below is based on this document: http://zlib.net/crc_v3.txt */
+static drflac_uint8 drflac__crc8_table[] = {
+    0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+    0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+    0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+    0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+    0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+    0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+    0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+    0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+    0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+    0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+    0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+    0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+    0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+    0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+    0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+    0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+static drflac_uint16 drflac__crc16_table[] = {
+    0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
+    0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
+    0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
+    0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
+    0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
+    0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
+    0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
+    0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
+    0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
+    0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
+    0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
+    0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
+    0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
+    0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
+    0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
+    0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
+    0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
+    0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
+    0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
+    0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
+    0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
+    0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
+    0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
+    0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
+    0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
+    0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
+    0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
+    0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
+    0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
+    0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
+    0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
+    0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
+};
+
+static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint8 data)
+{
+    return drflac__crc8_table[crc ^ data];
+}
+
+static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count)
+{
+#ifdef DR_FLAC_NO_CRC
+    (void)crc;
+    (void)data;
+    (void)count;
+    return 0;
+#else
+#if 0
+    /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc8(crc, 0, 8);") */
+    drflac_uint8 p = 0x07;
+    for (int i = count-1; i >= 0; --i) {
+        drflac_uint8 bit = (data & (1 << i)) >> i;
+        if (crc & 0x80) {
+            crc = ((crc << 1) | bit) ^ p;
+        } else {
+            crc = ((crc << 1) | bit);
+        }
+    }
+    return crc;
+#else
+    drflac_uint32 wholeBytes;
+    drflac_uint32 leftoverBits;
+    drflac_uint64 leftoverDataMask;
+
+    static drflac_uint64 leftoverDataMaskTable[8] = {
+        0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
+    };
+
+    DRFLAC_ASSERT(count <= 32);
+
+    wholeBytes = count >> 3;
+    leftoverBits = count - (wholeBytes*8);
+    leftoverDataMask = leftoverDataMaskTable[leftoverBits];
+
+    switch (wholeBytes) {
+        case 4: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits)));
+        case 3: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits)));
+        case 2: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits)));
+        case 1: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits)));
+        case 0: if (leftoverBits > 0) crc = (drflac_uint8)((crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]);
+    }
+    return crc;
+#endif
+#endif
+}
+
+static DRFLAC_INLINE drflac_uint16 drflac_crc16_byte(drflac_uint16 crc, drflac_uint8 data)
+{
+    return (crc << 8) ^ drflac__crc16_table[(drflac_uint8)(crc >> 8) ^ data];
+}
+
+static DRFLAC_INLINE drflac_uint16 drflac_crc16_cache(drflac_uint16 crc, drflac_cache_t data)
+{
+#ifdef DRFLAC_64BIT
+    crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF));
+    crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF));
+    crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF));
+    crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF));
+#endif
+    crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF));
+    crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF));
+    crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  8) & 0xFF));
+    crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  0) & 0xFF));
+
+    return crc;
+}
+
+static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 byteCount)
+{
+    switch (byteCount)
+    {
+#ifdef DRFLAC_64BIT
+    case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF));
+    case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF));
+    case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF));
+    case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF));
+#endif
+    case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF));
+    case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF));
+    case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  8) & 0xFF));
+    case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >>  0) & 0xFF));
+    }
+
+    return crc;
+}
+
+#if 0
+static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count)
+{
+#ifdef DR_FLAC_NO_CRC
+    (void)crc;
+    (void)data;
+    (void)count;
+    return 0;
+#else
+#if 0
+    /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc16(crc, 0, 16);") */
+    drflac_uint16 p = 0x8005;
+    for (int i = count-1; i >= 0; --i) {
+        drflac_uint16 bit = (data & (1ULL << i)) >> i;
+        if (r & 0x8000) {
+            r = ((r << 1) | bit) ^ p;
+        } else {
+            r = ((r << 1) | bit);
+        }
+    }
+
+    return crc;
+#else
+    drflac_uint32 wholeBytes;
+    drflac_uint32 leftoverBits;
+    drflac_uint64 leftoverDataMask;
+
+    static drflac_uint64 leftoverDataMaskTable[8] = {
+        0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
+    };
+
+    DRFLAC_ASSERT(count <= 64);
+
+    wholeBytes = count >> 3;
+    leftoverBits = count & 7;
+    leftoverDataMask = leftoverDataMaskTable[leftoverBits];
+
+    switch (wholeBytes) {
+        default:
+        case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits)));
+        case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits)));
+        case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits)));
+        case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits)));
+        case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)];
+    }
+    return crc;
+#endif
+#endif
+}
+
+static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count)
+{
+#ifdef DR_FLAC_NO_CRC
+    (void)crc;
+    (void)data;
+    (void)count;
+    return 0;
+#else
+    drflac_uint32 wholeBytes;
+    drflac_uint32 leftoverBits;
+    drflac_uint64 leftoverDataMask;
+
+    static drflac_uint64 leftoverDataMaskTable[8] = {
+        0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F
+    };
+
+    DRFLAC_ASSERT(count <= 64);
+
+    wholeBytes = count >> 3;
+    leftoverBits = count & 7;
+    leftoverDataMask = leftoverDataMaskTable[leftoverBits];
+
+    switch (wholeBytes) {
+        default:
+        case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 << 32) << leftoverBits)) >> (56 + leftoverBits)));    /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */
+        case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 << 32) << leftoverBits)) >> (48 + leftoverBits)));
+        case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 << 32) << leftoverBits)) >> (40 + leftoverBits)));
+        case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF << 32) << leftoverBits)) >> (32 + leftoverBits)));
+        case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000      ) << leftoverBits)) >> (24 + leftoverBits)));
+        case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000      ) << leftoverBits)) >> (16 + leftoverBits)));
+        case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00      ) << leftoverBits)) >> ( 8 + leftoverBits)));
+        case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF      ) << leftoverBits)) >> ( 0 + leftoverBits)));
+        case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)];
+    }
+    return crc;
+#endif
+}
+
+
+static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 count)
+{
+#ifdef DRFLAC_64BIT
+    return drflac_crc16__64bit(crc, data, count);
+#else
+    return drflac_crc16__32bit(crc, data, count);
+#endif
+}
+#endif
+
+
+#ifdef DRFLAC_64BIT
+#define drflac__be2host__cache_line drflac__be2host_64
+#else
+#define drflac__be2host__cache_line drflac__be2host_32
+#endif
+
+/*
+BIT READING ATTEMPT #2
+
+This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting
+on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache
+is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an
+array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data
+from onRead() is read into.
+*/
+#define DRFLAC_CACHE_L1_SIZE_BYTES(bs)                      (sizeof((bs)->cache))
+#define DRFLAC_CACHE_L1_SIZE_BITS(bs)                       (sizeof((bs)->cache)*8)
+#define DRFLAC_CACHE_L1_BITS_REMAINING(bs)                  (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits)
+#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount)           (~((~(drflac_cache_t)0) >> (_bitCount)))
+#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount)      (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount))
+#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount)               (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount))
+#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount)     (DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >>  DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)))
+#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, _bitCount)(DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> (DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)) & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1)))
+#define DRFLAC_CACHE_L2_SIZE_BYTES(bs)                      (sizeof((bs)->cacheL2))
+#define DRFLAC_CACHE_L2_LINE_COUNT(bs)                      (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0]))
+#define DRFLAC_CACHE_L2_LINES_REMAINING(bs)                 (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line)
+
+
+#ifndef DR_FLAC_NO_CRC
+static DRFLAC_INLINE void drflac__reset_crc16(drflac_bs* bs)
+{
+    bs->crc16 = 0;
+    bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
+}
+
+static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs)
+{
+    if (bs->crc16CacheIgnoredBytes == 0) {
+        bs->crc16 = drflac_crc16_cache(bs->crc16, bs->crc16Cache);
+    } else {
+        bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes);
+        bs->crc16CacheIgnoredBytes = 0;
+    }
+}
+
+static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs)
+{
+    /* We should never be flushing in a situation where we are not aligned on a byte boundary. */
+    DRFLAC_ASSERT((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0);
+
+    /*
+    The bits that were read from the L1 cache need to be accumulated. The number of bytes needing to be accumulated is determined
+    by the number of bits that have been consumed.
+    */
+    if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) {
+        drflac__update_crc16(bs);
+    } else {
+        /* We only accumulate the consumed bits. */
+        bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes);
+
+        /*
+        The bits that we just accumulated should never be accumulated again. We need to keep track of how many bytes were accumulated
+        so we can handle that later.
+        */
+        bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
+    }
+
+    return bs->crc16;
+}
+#endif
+
+static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs)
+{
+    size_t bytesRead;
+    size_t alignedL1LineCount;
+
+    /* Fast path. Try loading straight from L2. */
+    if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
+        bs->cache = bs->cacheL2[bs->nextL2Line++];
+        return DRFLAC_TRUE;
+    }
+
+    /*
+    If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's
+    any left.
+    */
+    if (bs->unalignedByteCount > 0) {
+        return DRFLAC_FALSE;   /* If we have any unaligned bytes it means there's no more aligned bytes left in the client. */
+    }
+
+    bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs));
+
+    bs->nextL2Line = 0;
+    if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) {
+        bs->cache = bs->cacheL2[bs->nextL2Line++];
+        return DRFLAC_TRUE;
+    }
+
+
+    /*
+    If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably
+    means we've just reached the end of the file. We need to move the valid data down to the end of the buffer
+    and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to
+    the size of the L1 so we'll need to seek backwards by any misaligned bytes.
+    */
+    alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs);
+
+    /* We need to keep track of any unaligned bytes for later use. */
+    bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs));
+    if (bs->unalignedByteCount > 0) {
+        bs->unalignedCache = bs->cacheL2[alignedL1LineCount];
+    }
+
+    if (alignedL1LineCount > 0) {
+        size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount;
+        size_t i;
+        for (i = alignedL1LineCount; i > 0; --i) {
+            bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1];
+        }
+
+        bs->nextL2Line = (drflac_uint32)offset;
+        bs->cache = bs->cacheL2[bs->nextL2Line++];
+        return DRFLAC_TRUE;
+    } else {
+        /* If we get into this branch it means we weren't able to load any L1-aligned data. */
+        bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs);
+        return DRFLAC_FALSE;
+    }
+}
+
+static drflac_bool32 drflac__reload_cache(drflac_bs* bs)
+{
+    size_t bytesRead;
+
+#ifndef DR_FLAC_NO_CRC
+    drflac__update_crc16(bs);
+#endif
+
+    /* Fast path. Try just moving the next value in the L2 cache to the L1 cache. */
+    if (drflac__reload_l1_cache_from_l2(bs)) {
+        bs->cache = drflac__be2host__cache_line(bs->cache);
+        bs->consumedBits = 0;
+#ifndef DR_FLAC_NO_CRC
+        bs->crc16Cache = bs->cache;
+#endif
+        return DRFLAC_TRUE;
+    }
+
+    /* Slow path. */
+
+    /*
+    If we get here it means we have failed to load the L1 cache from the L2. Likely we've just reached the end of the stream and the last
+    few bytes did not meet the alignment requirements for the L2 cache. In this case we need to fall back to a slower path and read the
+    data from the unaligned cache.
+    */
+    bytesRead = bs->unalignedByteCount;
+    if (bytesRead == 0) {
+        bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);   /* <-- The stream has been exhausted, so marked the bits as consumed. */
+        return DRFLAC_FALSE;
+    }
+
+    DRFLAC_ASSERT(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs));
+    bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8;
+
+    bs->cache = drflac__be2host__cache_line(bs->unalignedCache);
+    bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs));    /* <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. */
+    bs->unalignedByteCount = 0;     /* <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. */
+
+#ifndef DR_FLAC_NO_CRC
+    bs->crc16Cache = bs->cache >> bs->consumedBits;
+    bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3;
+#endif
+    return DRFLAC_TRUE;
+}
+
+static void drflac__reset_cache(drflac_bs* bs)
+{
+    bs->nextL2Line   = DRFLAC_CACHE_L2_LINE_COUNT(bs);  /* <-- This clears the L2 cache. */
+    bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);   /* <-- This clears the L1 cache. */
+    bs->cache = 0;
+    bs->unalignedByteCount = 0;                         /* <-- This clears the trailing unaligned bytes. */
+    bs->unalignedCache = 0;
+
+#ifndef DR_FLAC_NO_CRC
+    bs->crc16Cache = 0;
+    bs->crc16CacheIgnoredBytes = 0;
+#endif
+}
+
+
+static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, drflac_uint32* pResultOut)
+{
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(pResultOut != NULL);
+    DRFLAC_ASSERT(bitCount > 0);
+    DRFLAC_ASSERT(bitCount <= 32);
+
+    if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
+        if (!drflac__reload_cache(bs)) {
+            return DRFLAC_FALSE;
+        }
+    }
+
+    if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
+        /*
+        If we want to load all 32-bits from a 32-bit cache we need to do it slightly differently because we can't do
+        a 32-bit shift on a 32-bit integer. This will never be the case on 64-bit caches, so we can have a slightly
+        more optimal solution for this.
+        */
+#ifdef DRFLAC_64BIT
+        *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
+        bs->consumedBits += bitCount;
+        bs->cache <<= bitCount;
+#else
+        if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
+            *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount);
+            bs->consumedBits += bitCount;
+            bs->cache <<= bitCount;
+        } else {
+            /* Cannot shift by 32-bits, so need to do it differently. */
+            *pResultOut = (drflac_uint32)bs->cache;
+            bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs);
+            bs->cache = 0;
+        }
+#endif
+
+        return DRFLAC_TRUE;
+    } else {
+        /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */
+        drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+        drflac_uint32 bitCountLo = bitCount - bitCountHi;
+        drflac_uint32 resultHi;
+
+        DRFLAC_ASSERT(bitCountHi > 0);
+        DRFLAC_ASSERT(bitCountHi < 32);
+        resultHi = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi);
+
+        if (!drflac__reload_cache(bs)) {
+            return DRFLAC_FALSE;
+        }
+
+        *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo);
+        bs->consumedBits += bitCountLo;
+        bs->cache <<= bitCountLo;
+        return DRFLAC_TRUE;
+    }
+}
+
+static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult)
+{
+    drflac_uint32 result;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(pResult != NULL);
+    DRFLAC_ASSERT(bitCount > 0);
+    DRFLAC_ASSERT(bitCount <= 32);
+
+    if (!drflac__read_uint32(bs, bitCount, &result)) {
+        return DRFLAC_FALSE;
+    }
+
+    /* Do not attempt to shift by 32 as it's undefined. */
+    if (bitCount < 32) {
+        drflac_uint32 signbit;
+        signbit = ((result >> (bitCount-1)) & 0x01);
+        result |= (~signbit + 1) << bitCount;
+    }
+
+    *pResult = (drflac_int32)result;
+    return DRFLAC_TRUE;
+}
+
+#ifdef DRFLAC_64BIT
+static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut)
+{
+    drflac_uint32 resultHi;
+    drflac_uint32 resultLo;
+
+    DRFLAC_ASSERT(bitCount <= 64);
+    DRFLAC_ASSERT(bitCount >  32);
+
+    if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) {
+        return DRFLAC_FALSE;
+    }
+
+    if (!drflac__read_uint32(bs, 32, &resultLo)) {
+        return DRFLAC_FALSE;
+    }
+
+    *pResultOut = (((drflac_uint64)resultHi) << 32) | ((drflac_uint64)resultLo);
+    return DRFLAC_TRUE;
+}
+#endif
+
+/* Function below is unused, but leaving it here in case I need to quickly add it again. */
+#if 0
+static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut)
+{
+    drflac_uint64 result;
+    drflac_uint64 signbit;
+
+    DRFLAC_ASSERT(bitCount <= 64);
+
+    if (!drflac__read_uint64(bs, bitCount, &result)) {
+        return DRFLAC_FALSE;
+    }
+
+    signbit = ((result >> (bitCount-1)) & 0x01);
+    result |= (~signbit + 1) << bitCount;
+
+    *pResultOut = (drflac_int64)result;
+    return DRFLAC_TRUE;
+}
+#endif
+
+static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult)
+{
+    drflac_uint32 result;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(pResult != NULL);
+    DRFLAC_ASSERT(bitCount > 0);
+    DRFLAC_ASSERT(bitCount <= 16);
+
+    if (!drflac__read_uint32(bs, bitCount, &result)) {
+        return DRFLAC_FALSE;
+    }
+
+    *pResult = (drflac_uint16)result;
+    return DRFLAC_TRUE;
+}
+
+#if 0
+static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult)
+{
+    drflac_int32 result;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(pResult != NULL);
+    DRFLAC_ASSERT(bitCount > 0);
+    DRFLAC_ASSERT(bitCount <= 16);
+
+    if (!drflac__read_int32(bs, bitCount, &result)) {
+        return DRFLAC_FALSE;
+    }
+
+    *pResult = (drflac_int16)result;
+    return DRFLAC_TRUE;
+}
+#endif
+
+static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult)
+{
+    drflac_uint32 result;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(pResult != NULL);
+    DRFLAC_ASSERT(bitCount > 0);
+    DRFLAC_ASSERT(bitCount <= 8);
+
+    if (!drflac__read_uint32(bs, bitCount, &result)) {
+        return DRFLAC_FALSE;
+    }
+
+    *pResult = (drflac_uint8)result;
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult)
+{
+    drflac_int32 result;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(pResult != NULL);
+    DRFLAC_ASSERT(bitCount > 0);
+    DRFLAC_ASSERT(bitCount <= 8);
+
+    if (!drflac__read_int32(bs, bitCount, &result)) {
+        return DRFLAC_FALSE;
+    }
+
+    *pResult = (drflac_int8)result;
+    return DRFLAC_TRUE;
+}
+
+
+static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek)
+{
+    if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
+        bs->consumedBits += (drflac_uint32)bitsToSeek;
+        bs->cache <<= bitsToSeek;
+        return DRFLAC_TRUE;
+    } else {
+        /* It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here. */
+        bitsToSeek       -= DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+        bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+        bs->cache         = 0;
+
+        /* Simple case. Seek in groups of the same number as bits that fit within a cache line. */
+#ifdef DRFLAC_64BIT
+        while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
+            drflac_uint64 bin;
+            if (!drflac__read_uint64(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
+                return DRFLAC_FALSE;
+            }
+            bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
+        }
+#else
+        while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) {
+            drflac_uint32 bin;
+            if (!drflac__read_uint32(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) {
+                return DRFLAC_FALSE;
+            }
+            bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs);
+        }
+#endif
+
+        /* Whole leftover bytes. */
+        while (bitsToSeek >= 8) {
+            drflac_uint8 bin;
+            if (!drflac__read_uint8(bs, 8, &bin)) {
+                return DRFLAC_FALSE;
+            }
+            bitsToSeek -= 8;
+        }
+
+        /* Leftover bits. */
+        if (bitsToSeek > 0) {
+            drflac_uint8 bin;
+            if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) {
+                return DRFLAC_FALSE;
+            }
+            bitsToSeek = 0; /* <-- Necessary for the assert below. */
+        }
+
+        DRFLAC_ASSERT(bitsToSeek == 0);
+        return DRFLAC_TRUE;
+    }
+}
+
+
+/* This function moves the bit streamer to the first bit after the sync code (bit 15 of the of the frame header). It will also update the CRC-16. */
+static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs)
+{
+    DRFLAC_ASSERT(bs != NULL);
+
+    /*
+    The sync code is always aligned to 8 bits. This is convenient for us because it means we can do byte-aligned movements. The first
+    thing to do is align to the next byte.
+    */
+    if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
+        return DRFLAC_FALSE;
+    }
+
+    for (;;) {
+        drflac_uint8 hi;
+
+#ifndef DR_FLAC_NO_CRC
+        drflac__reset_crc16(bs);
+#endif
+
+        if (!drflac__read_uint8(bs, 8, &hi)) {
+            return DRFLAC_FALSE;
+        }
+
+        if (hi == 0xFF) {
+            drflac_uint8 lo;
+            if (!drflac__read_uint8(bs, 6, &lo)) {
+                return DRFLAC_FALSE;
+            }
+
+            if (lo == 0x3E) {
+                return DRFLAC_TRUE;
+            } else {
+                if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) {
+                    return DRFLAC_FALSE;
+                }
+            }
+        }
+    }
+
+    /* Should never get here. */
+    /*return DRFLAC_FALSE;*/
+}
+
+
+#if defined(DRFLAC_HAS_LZCNT_INTRINSIC)
+#define DRFLAC_IMPLEMENT_CLZ_LZCNT
+#endif
+#if  defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__)
+#define DRFLAC_IMPLEMENT_CLZ_MSVC
+#endif
+
+static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x)
+{
+    drflac_uint32 n;
+    static drflac_uint32 clz_table_4[] = {
+        0,
+        4,
+        3, 3,
+        2, 2, 2, 2,
+        1, 1, 1, 1, 1, 1, 1, 1
+    };
+
+    if (x == 0) {
+        return sizeof(x)*8;
+    }
+
+    n = clz_table_4[x >> (sizeof(x)*8 - 4)];
+    if (n == 0) {
+#ifdef DRFLAC_64BIT
+        if ((x & ((drflac_uint64)0xFFFFFFFF << 32)) == 0) { n  = 32; x <<= 32; }
+        if ((x & ((drflac_uint64)0xFFFF0000 << 32)) == 0) { n += 16; x <<= 16; }
+        if ((x & ((drflac_uint64)0xFF000000 << 32)) == 0) { n += 8;  x <<= 8;  }
+        if ((x & ((drflac_uint64)0xF0000000 << 32)) == 0) { n += 4;  x <<= 4;  }
+#else
+        if ((x & 0xFFFF0000) == 0) { n  = 16; x <<= 16; }
+        if ((x & 0xFF000000) == 0) { n += 8;  x <<= 8;  }
+        if ((x & 0xF0000000) == 0) { n += 4;  x <<= 4;  }
+#endif
+        n += clz_table_4[x >> (sizeof(x)*8 - 4)];
+    }
+
+    return n - 1;
+}
+
+#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT
+static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void)
+{
+    /* Fast compile time check for ARM. */
+#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5)
+    return DRFLAC_TRUE;
+#else
+    /* If the compiler itself does not support the intrinsic then we'll need to return false. */
+    #ifdef DRFLAC_HAS_LZCNT_INTRINSIC
+        return drflac__gIsLZCNTSupported;
+    #else
+        return DRFLAC_FALSE;
+    #endif
+#endif
+}
+
+static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x)
+{
+    /*
+    It's critical for competitive decoding performance that this function be highly optimal. With MSVC we can use the __lzcnt64() and __lzcnt() intrinsics
+    to achieve good performance, however on GCC and Clang it's a little bit more annoying. The __builtin_clzl() and __builtin_clzll() intrinsics leave
+    it undefined as to the return value when `x` is 0. We need this to be well defined as returning 32 or 64, depending on whether or not it's a 32- or
+    64-bit build. To work around this we would need to add a conditional to check for the x = 0 case, but this creates unnecessary inefficiency. To work
+    around this problem I have written some inline assembly to emit the LZCNT (x86) or CLZ (ARM) instruction directly which removes the need to include
+    the conditional. This has worked well in the past, but for some reason Clang's MSVC compatible driver, clang-cl, does not seem to be handling this
+    in the same way as the normal Clang driver. It seems that `clang-cl` is just outputting the wrong results sometimes, maybe due to some register
+    getting clobbered?
+
+    I'm not sure if this is a bug with dr_flac's inlined assembly (most likely), a bug in `clang-cl` or just a misunderstanding on my part with inline
+    assembly rules for `clang-cl`. If somebody can identify an error in dr_flac's inlined assembly I'm happy to get that fixed.
+
+    Fortunately there is an easy workaround for this. Clang implements MSVC-specific intrinsics for compatibility. It also defines _MSC_VER for extra
+    compatibility. We can therefore just check for _MSC_VER and use the MSVC intrinsic which, fortunately for us, Clang supports. It would still be nice
+    to know how to fix the inlined assembly for correctness sake, however.
+    */
+
+#if defined(_MSC_VER) /*&& !defined(__clang__)*/    /* <-- Intentionally wanting Clang to use the MSVC __lzcnt64/__lzcnt intrinsics due to above ^. */
+    #ifdef DRFLAC_64BIT
+        return (drflac_uint32)__lzcnt64(x);
+    #else
+        return (drflac_uint32)__lzcnt(x);
+    #endif
+#else
+    #if defined(__GNUC__) || defined(__clang__)
+        #if defined(DRFLAC_X64)
+            {
+                drflac_uint64 r;
+                __asm__ __volatile__ (
+                    "lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+                );
+
+                return (drflac_uint32)r;
+            }
+        #elif defined(DRFLAC_X86)
+            {
+                drflac_uint32 r;
+                __asm__ __volatile__ (
+                    "lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"
+                );
+
+                return r;
+            }
+        #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(DRFLAC_64BIT)   /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */
+            {
+                unsigned int r;
+                __asm__ __volatile__ (
+                #if defined(DRFLAC_64BIT)
+                    "clz %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(x)   /* <-- This is untested. If someone in the community could test this, that would be appreciated! */
+                #else
+                    "clz %[out], %[in]" : [out]"=r"(r) : [in]"r"(x)
+                #endif
+                );
+
+                return r;
+            }
+        #else
+            if (x == 0) {
+                return sizeof(x)*8;
+            }
+            #ifdef DRFLAC_64BIT
+                return (drflac_uint32)__builtin_clzll((drflac_uint64)x);
+            #else
+                return (drflac_uint32)__builtin_clzl((drflac_uint32)x);
+            #endif
+        #endif
+    #else
+        /* Unsupported compiler. */
+        #error "This compiler does not support the lzcnt intrinsic."
+    #endif
+#endif
+}
+#endif
+
+#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC
+#include <intrin.h> /* For BitScanReverse(). */
+
+static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x)
+{
+    drflac_uint32 n;
+
+    if (x == 0) {
+        return sizeof(x)*8;
+    }
+
+#ifdef DRFLAC_64BIT
+    _BitScanReverse64((unsigned long*)&n, x);
+#else
+    _BitScanReverse((unsigned long*)&n, x);
+#endif
+    return sizeof(x)*8 - n - 1;
+}
+#endif
+
+static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x)
+{
+#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT
+    if (drflac__is_lzcnt_supported()) {
+        return drflac__clz_lzcnt(x);
+    } else
+#endif
+    {
+#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC
+        return drflac__clz_msvc(x);
+#else
+        return drflac__clz_software(x);
+#endif
+    }
+}
+
+
+static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut)
+{
+    drflac_uint32 zeroCounter = 0;
+    drflac_uint32 setBitOffsetPlus1;
+
+    while (bs->cache == 0) {
+        zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+        if (!drflac__reload_cache(bs)) {
+            return DRFLAC_FALSE;
+        }
+    }
+
+    setBitOffsetPlus1 = drflac__clz(bs->cache);
+    setBitOffsetPlus1 += 1;
+
+    bs->consumedBits += setBitOffsetPlus1;
+    bs->cache <<= setBitOffsetPlus1;
+
+    *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1;
+    return DRFLAC_TRUE;
+}
+
+
+
+static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFromStart)
+{
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(offsetFromStart > 0);
+
+    /*
+    Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which
+    is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit.
+    To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder.
+    */
+    if (offsetFromStart > 0x7FFFFFFF) {
+        drflac_uint64 bytesRemaining = offsetFromStart;
+        if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
+            return DRFLAC_FALSE;
+        }
+        bytesRemaining -= 0x7FFFFFFF;
+
+        while (bytesRemaining > 0x7FFFFFFF) {
+            if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
+                return DRFLAC_FALSE;
+            }
+            bytesRemaining -= 0x7FFFFFFF;
+        }
+
+        if (bytesRemaining > 0) {
+            if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, drflac_seek_origin_current)) {
+                return DRFLAC_FALSE;
+            }
+        }
+    } else {
+        if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, drflac_seek_origin_start)) {
+            return DRFLAC_FALSE;
+        }
+    }
+
+    /* The cache should be reset to force a reload of fresh data from the client. */
+    drflac__reset_cache(bs);
+    return DRFLAC_TRUE;
+}
+
+
+static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut)
+{
+    drflac_uint8 crc;
+    drflac_uint64 result;
+    drflac_uint8 utf8[7] = {0};
+    int byteCount;
+    int i;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(pNumberOut != NULL);
+    DRFLAC_ASSERT(pCRCOut != NULL);
+
+    crc = *pCRCOut;
+
+    if (!drflac__read_uint8(bs, 8, utf8)) {
+        *pNumberOut = 0;
+        return DRFLAC_AT_END;
+    }
+    crc = drflac_crc8(crc, utf8[0], 8);
+
+    if ((utf8[0] & 0x80) == 0) {
+        *pNumberOut = utf8[0];
+        *pCRCOut = crc;
+        return DRFLAC_SUCCESS;
+    }
+
+    /*byteCount = 1;*/
+    if ((utf8[0] & 0xE0) == 0xC0) {
+        byteCount = 2;
+    } else if ((utf8[0] & 0xF0) == 0xE0) {
+        byteCount = 3;
+    } else if ((utf8[0] & 0xF8) == 0xF0) {
+        byteCount = 4;
+    } else if ((utf8[0] & 0xFC) == 0xF8) {
+        byteCount = 5;
+    } else if ((utf8[0] & 0xFE) == 0xFC) {
+        byteCount = 6;
+    } else if ((utf8[0] & 0xFF) == 0xFE) {
+        byteCount = 7;
+    } else {
+        *pNumberOut = 0;
+        return DRFLAC_CRC_MISMATCH;     /* Bad UTF-8 encoding. */
+    }
+
+    /* Read extra bytes. */
+    DRFLAC_ASSERT(byteCount > 1);
+
+    result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1)));
+    for (i = 1; i < byteCount; ++i) {
+        if (!drflac__read_uint8(bs, 8, utf8 + i)) {
+            *pNumberOut = 0;
+            return DRFLAC_AT_END;
+        }
+        crc = drflac_crc8(crc, utf8[i], 8);
+
+        result = (result << 6) | (utf8[i] & 0x3F);
+    }
+
+    *pNumberOut = result;
+    *pCRCOut = crc;
+    return DRFLAC_SUCCESS;
+}
+
+
+
+/*
+The next two functions are responsible for calculating the prediction.
+
+When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's
+safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16.
+*/
+static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
+{
+    drflac_int32 prediction = 0;
+
+    DRFLAC_ASSERT(order <= 32);
+
+    /* 32-bit version. */
+
+    /* VC++ optimizes this to a single jmp. I've not yet verified this for other compilers. */
+    switch (order)
+    {
+    case 32: prediction += coefficients[31] * pDecodedSamples[-32];
+    case 31: prediction += coefficients[30] * pDecodedSamples[-31];
+    case 30: prediction += coefficients[29] * pDecodedSamples[-30];
+    case 29: prediction += coefficients[28] * pDecodedSamples[-29];
+    case 28: prediction += coefficients[27] * pDecodedSamples[-28];
+    case 27: prediction += coefficients[26] * pDecodedSamples[-27];
+    case 26: prediction += coefficients[25] * pDecodedSamples[-26];
+    case 25: prediction += coefficients[24] * pDecodedSamples[-25];
+    case 24: prediction += coefficients[23] * pDecodedSamples[-24];
+    case 23: prediction += coefficients[22] * pDecodedSamples[-23];
+    case 22: prediction += coefficients[21] * pDecodedSamples[-22];
+    case 21: prediction += coefficients[20] * pDecodedSamples[-21];
+    case 20: prediction += coefficients[19] * pDecodedSamples[-20];
+    case 19: prediction += coefficients[18] * pDecodedSamples[-19];
+    case 18: prediction += coefficients[17] * pDecodedSamples[-18];
+    case 17: prediction += coefficients[16] * pDecodedSamples[-17];
+    case 16: prediction += coefficients[15] * pDecodedSamples[-16];
+    case 15: prediction += coefficients[14] * pDecodedSamples[-15];
+    case 14: prediction += coefficients[13] * pDecodedSamples[-14];
+    case 13: prediction += coefficients[12] * pDecodedSamples[-13];
+    case 12: prediction += coefficients[11] * pDecodedSamples[-12];
+    case 11: prediction += coefficients[10] * pDecodedSamples[-11];
+    case 10: prediction += coefficients[ 9] * pDecodedSamples[-10];
+    case  9: prediction += coefficients[ 8] * pDecodedSamples[- 9];
+    case  8: prediction += coefficients[ 7] * pDecodedSamples[- 8];
+    case  7: prediction += coefficients[ 6] * pDecodedSamples[- 7];
+    case  6: prediction += coefficients[ 5] * pDecodedSamples[- 6];
+    case  5: prediction += coefficients[ 4] * pDecodedSamples[- 5];
+    case  4: prediction += coefficients[ 3] * pDecodedSamples[- 4];
+    case  3: prediction += coefficients[ 2] * pDecodedSamples[- 3];
+    case  2: prediction += coefficients[ 1] * pDecodedSamples[- 2];
+    case  1: prediction += coefficients[ 0] * pDecodedSamples[- 1];
+    }
+
+    return (drflac_int32)(prediction >> shift);
+}
+
+static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
+{
+    drflac_int64 prediction;
+
+    DRFLAC_ASSERT(order <= 32);
+
+    /* 64-bit version. */
+
+    /* This method is faster on the 32-bit build when compiling with VC++. See note below. */
+#ifndef DRFLAC_64BIT
+    if (order == 8)
+    {
+        prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
+        prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
+        prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
+        prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
+        prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
+        prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8];
+    }
+    else if (order == 7)
+    {
+        prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
+        prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
+        prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
+        prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
+        prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7];
+    }
+    else if (order == 3)
+    {
+        prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
+    }
+    else if (order == 6)
+    {
+        prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
+        prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
+        prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
+        prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6];
+    }
+    else if (order == 5)
+    {
+        prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
+        prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
+        prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5];
+    }
+    else if (order == 4)
+    {
+        prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3];
+        prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4];
+    }
+    else if (order == 12)
+    {
+        prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
+        prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
+        prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
+        prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
+        prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
+        prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
+        prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
+        prediction += coefficients[9]  * (drflac_int64)pDecodedSamples[-10];
+        prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
+        prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12];
+    }
+    else if (order == 2)
+    {
+        prediction  = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2];
+    }
+    else if (order == 1)
+    {
+        prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1];
+    }
+    else if (order == 10)
+    {
+        prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
+        prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
+        prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
+        prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
+        prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
+        prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
+        prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
+        prediction += coefficients[9]  * (drflac_int64)pDecodedSamples[-10];
+    }
+    else if (order == 9)
+    {
+        prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
+        prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
+        prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
+        prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
+        prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
+        prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
+        prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
+    }
+    else if (order == 11)
+    {
+        prediction  = coefficients[0]  * (drflac_int64)pDecodedSamples[-1];
+        prediction += coefficients[1]  * (drflac_int64)pDecodedSamples[-2];
+        prediction += coefficients[2]  * (drflac_int64)pDecodedSamples[-3];
+        prediction += coefficients[3]  * (drflac_int64)pDecodedSamples[-4];
+        prediction += coefficients[4]  * (drflac_int64)pDecodedSamples[-5];
+        prediction += coefficients[5]  * (drflac_int64)pDecodedSamples[-6];
+        prediction += coefficients[6]  * (drflac_int64)pDecodedSamples[-7];
+        prediction += coefficients[7]  * (drflac_int64)pDecodedSamples[-8];
+        prediction += coefficients[8]  * (drflac_int64)pDecodedSamples[-9];
+        prediction += coefficients[9]  * (drflac_int64)pDecodedSamples[-10];
+        prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
+    }
+    else
+    {
+        int j;
+
+        prediction = 0;
+        for (j = 0; j < (int)order; ++j) {
+            prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1];
+        }
+    }
+#endif
+
+    /*
+    VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some
+    reason. The ugly version above is faster so we'll just switch between the two depending on the target platform.
+    */
+#ifdef DRFLAC_64BIT
+    prediction = 0;
+    switch (order)
+    {
+    case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32];
+    case 31: prediction += coefficients[30] * (drflac_int64)pDecodedSamples[-31];
+    case 30: prediction += coefficients[29] * (drflac_int64)pDecodedSamples[-30];
+    case 29: prediction += coefficients[28] * (drflac_int64)pDecodedSamples[-29];
+    case 28: prediction += coefficients[27] * (drflac_int64)pDecodedSamples[-28];
+    case 27: prediction += coefficients[26] * (drflac_int64)pDecodedSamples[-27];
+    case 26: prediction += coefficients[25] * (drflac_int64)pDecodedSamples[-26];
+    case 25: prediction += coefficients[24] * (drflac_int64)pDecodedSamples[-25];
+    case 24: prediction += coefficients[23] * (drflac_int64)pDecodedSamples[-24];
+    case 23: prediction += coefficients[22] * (drflac_int64)pDecodedSamples[-23];
+    case 22: prediction += coefficients[21] * (drflac_int64)pDecodedSamples[-22];
+    case 21: prediction += coefficients[20] * (drflac_int64)pDecodedSamples[-21];
+    case 20: prediction += coefficients[19] * (drflac_int64)pDecodedSamples[-20];
+    case 19: prediction += coefficients[18] * (drflac_int64)pDecodedSamples[-19];
+    case 18: prediction += coefficients[17] * (drflac_int64)pDecodedSamples[-18];
+    case 17: prediction += coefficients[16] * (drflac_int64)pDecodedSamples[-17];
+    case 16: prediction += coefficients[15] * (drflac_int64)pDecodedSamples[-16];
+    case 15: prediction += coefficients[14] * (drflac_int64)pDecodedSamples[-15];
+    case 14: prediction += coefficients[13] * (drflac_int64)pDecodedSamples[-14];
+    case 13: prediction += coefficients[12] * (drflac_int64)pDecodedSamples[-13];
+    case 12: prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12];
+    case 11: prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11];
+    case 10: prediction += coefficients[ 9] * (drflac_int64)pDecodedSamples[-10];
+    case  9: prediction += coefficients[ 8] * (drflac_int64)pDecodedSamples[- 9];
+    case  8: prediction += coefficients[ 7] * (drflac_int64)pDecodedSamples[- 8];
+    case  7: prediction += coefficients[ 6] * (drflac_int64)pDecodedSamples[- 7];
+    case  6: prediction += coefficients[ 5] * (drflac_int64)pDecodedSamples[- 6];
+    case  5: prediction += coefficients[ 4] * (drflac_int64)pDecodedSamples[- 5];
+    case  4: prediction += coefficients[ 3] * (drflac_int64)pDecodedSamples[- 4];
+    case  3: prediction += coefficients[ 2] * (drflac_int64)pDecodedSamples[- 3];
+    case  2: prediction += coefficients[ 1] * (drflac_int64)pDecodedSamples[- 2];
+    case  1: prediction += coefficients[ 0] * (drflac_int64)pDecodedSamples[- 1];
+    }
+#endif
+
+    return (drflac_int32)(prediction >> shift);
+}
+
+
+#if 0
+/*
+Reference implementation for reading and decoding samples with residual. This is intentionally left unoptimized for the
+sake of readability and should only be used as a reference.
+*/
+static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    drflac_uint32 i;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(count > 0);
+    DRFLAC_ASSERT(pSamplesOut != NULL);
+
+    for (i = 0; i < count; ++i) {
+        drflac_uint32 zeroCounter = 0;
+        for (;;) {
+            drflac_uint8 bit;
+            if (!drflac__read_uint8(bs, 1, &bit)) {
+                return DRFLAC_FALSE;
+            }
+
+            if (bit == 0) {
+                zeroCounter += 1;
+            } else {
+                break;
+            }
+        }
+
+        drflac_uint32 decodedRice;
+        if (riceParam > 0) {
+            if (!drflac__read_uint32(bs, riceParam, &decodedRice)) {
+                return DRFLAC_FALSE;
+            }
+        } else {
+            decodedRice = 0;
+        }
+
+        decodedRice |= (zeroCounter << riceParam);
+        if ((decodedRice & 0x01)) {
+            decodedRice = ~(decodedRice >> 1);
+        } else {
+            decodedRice =  (decodedRice >> 1);
+        }
+
+
+        if (bitsPerSample+shift >= 32) {
+            pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i);
+        } else {
+            pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i);
+        }
+    }
+
+    return DRFLAC_TRUE;
+}
+#endif
+
+#if 0
+static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
+{
+    drflac_uint32 zeroCounter = 0;
+    drflac_uint32 decodedRice;
+
+    for (;;) {
+        drflac_uint8 bit;
+        if (!drflac__read_uint8(bs, 1, &bit)) {
+            return DRFLAC_FALSE;
+        }
+
+        if (bit == 0) {
+            zeroCounter += 1;
+        } else {
+            break;
+        }
+    }
+
+    if (riceParam > 0) {
+        if (!drflac__read_uint32(bs, riceParam, &decodedRice)) {
+            return DRFLAC_FALSE;
+        }
+    } else {
+        decodedRice = 0;
+    }
+
+    *pZeroCounterOut = zeroCounter;
+    *pRiceParamPartOut = decodedRice;
+    return DRFLAC_TRUE;
+}
+#endif
+
+#if 0
+static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
+{
+    drflac_cache_t riceParamMask;
+    drflac_uint32 zeroCounter;
+    drflac_uint32 setBitOffsetPlus1;
+    drflac_uint32 riceParamPart;
+    drflac_uint32 riceLength;
+
+    DRFLAC_ASSERT(riceParam > 0);   /* <-- riceParam should never be 0. drflac__read_rice_parts__param_equals_zero() should be used instead for this case. */
+
+    riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam);
+
+    zeroCounter = 0;
+    while (bs->cache == 0) {
+        zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs);
+        if (!drflac__reload_cache(bs)) {
+            return DRFLAC_FALSE;
+        }
+    }
+
+    setBitOffsetPlus1 = drflac__clz(bs->cache);
+    zeroCounter += setBitOffsetPlus1;
+    setBitOffsetPlus1 += 1;
+
+    riceLength = setBitOffsetPlus1 + riceParam;
+    if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) {
+        riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength));
+
+        bs->consumedBits += riceLength;
+        bs->cache <<= riceLength;
+    } else {
+        drflac_uint32 bitCountLo;
+        drflac_cache_t resultHi;
+
+        bs->consumedBits += riceLength;
+        bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1);    /* <-- Equivalent to "if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { bs->cache <<= setBitOffsetPlus1; }" */
+
+        /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */
+        bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs);
+        resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam);  /* <-- Use DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE() if ever this function allows riceParam=0. */
+
+        if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
+#ifndef DR_FLAC_NO_CRC
+            drflac__update_crc16(bs);
+#endif
+            bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
+            bs->consumedBits = 0;
+#ifndef DR_FLAC_NO_CRC
+            bs->crc16Cache = bs->cache;
+#endif
+        } else {
+            /* Slow path. We need to fetch more data from the client. */
+            if (!drflac__reload_cache(bs)) {
+                return DRFLAC_FALSE;
+            }
+        }
+
+        riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo));
+
+        bs->consumedBits += bitCountLo;
+        bs->cache <<= bitCountLo;
+    }
+
+    pZeroCounterOut[0] = zeroCounter;
+    pRiceParamPartOut[0] = riceParamPart;
+
+    return DRFLAC_TRUE;
+}
+#endif
+
+static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut)
+{
+    drflac_uint32  riceParamPlus1 = riceParam + 1;
+    /*drflac_cache_t riceParamPlus1Mask  = DRFLAC_CACHE_L1_SELECTION_MASK(riceParamPlus1);*/
+    drflac_uint32  riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1);
+    drflac_uint32  riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1;
+
+    /*
+    The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have
+    no idea how this will work in practice...
+    */
+    drflac_cache_t bs_cache = bs->cache;
+    drflac_uint32  bs_consumedBits = bs->consumedBits;
+
+    /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */
+    drflac_uint32  lzcount = drflac__clz(bs_cache);
+    if (lzcount < sizeof(bs_cache)*8) {
+        pZeroCounterOut[0] = lzcount;
+
+        /*
+        It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting
+        this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled
+        outside of this function at a higher level.
+        */
+    extract_rice_param_part:
+        bs_cache       <<= lzcount;
+        bs_consumedBits += lzcount;
+
+        if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) {
+            /* Getting here means the rice parameter part is wholly contained within the current cache line. */
+            pRiceParamPartOut[0] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift);
+            bs_cache       <<= riceParamPlus1;
+            bs_consumedBits += riceParamPlus1;
+        } else {
+            drflac_uint32 riceParamPartHi;
+            drflac_uint32 riceParamPartLo;
+            drflac_uint32 riceParamPartLoBitCount;
+
+            /*
+            Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache
+            line, reload the cache, and then combine it with the head of the next cache line.
+            */
+
+            /* Grab the high part of the rice parameter part. */
+            riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift);
+
+            /* Before reloading the cache we need to grab the size in bits of the low part. */
+            riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits;
+            DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32);
+
+            /* Now reload the cache. */
+            if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
+            #ifndef DR_FLAC_NO_CRC
+                drflac__update_crc16(bs);
+            #endif
+                bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
+                bs_consumedBits = riceParamPartLoBitCount;
+            #ifndef DR_FLAC_NO_CRC
+                bs->crc16Cache = bs_cache;
+            #endif
+            } else {
+                /* Slow path. We need to fetch more data from the client. */
+                if (!drflac__reload_cache(bs)) {
+                    return DRFLAC_FALSE;
+                }
+
+                bs_cache = bs->cache;
+                bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount;
+            }
+
+            /* We should now have enough information to construct the rice parameter part. */
+            riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount)));
+            pRiceParamPartOut[0] = riceParamPartHi | riceParamPartLo;
+
+            bs_cache <<= riceParamPartLoBitCount;
+        }
+    } else {
+        /*
+        Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call
+        to drflac__clz() and we need to reload the cache.
+        */
+        drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits);
+        for (;;) {
+            if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
+            #ifndef DR_FLAC_NO_CRC
+                drflac__update_crc16(bs);
+            #endif
+                bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
+                bs_consumedBits = 0;
+            #ifndef DR_FLAC_NO_CRC
+                bs->crc16Cache = bs_cache;
+            #endif
+            } else {
+                /* Slow path. We need to fetch more data from the client. */
+                if (!drflac__reload_cache(bs)) {
+                    return DRFLAC_FALSE;
+                }
+
+                bs_cache = bs->cache;
+                bs_consumedBits = bs->consumedBits;
+            }
+
+            lzcount = drflac__clz(bs_cache);
+            zeroCounter += lzcount;
+
+            if (lzcount < sizeof(bs_cache)*8) {
+                break;
+            }
+        }
+
+        pZeroCounterOut[0] = zeroCounter;
+        goto extract_rice_param_part;
+    }
+
+    /* Make sure the cache is restored at the end of it all. */
+    bs->cache = bs_cache;
+    bs->consumedBits = bs_consumedBits;
+
+    return DRFLAC_TRUE;
+}
+
+static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac_uint8 riceParam)
+{
+    drflac_uint32  riceParamPlus1 = riceParam + 1;
+    drflac_uint32  riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1;
+
+    /*
+    The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have
+    no idea how this will work in practice...
+    */
+    drflac_cache_t bs_cache = bs->cache;
+    drflac_uint32  bs_consumedBits = bs->consumedBits;
+
+    /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */
+    drflac_uint32  lzcount = drflac__clz(bs_cache);
+    if (lzcount < sizeof(bs_cache)*8) {
+        /*
+        It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting
+        this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled
+        outside of this function at a higher level.
+        */
+    extract_rice_param_part:
+        bs_cache       <<= lzcount;
+        bs_consumedBits += lzcount;
+
+        if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) {
+            /* Getting here means the rice parameter part is wholly contained within the current cache line. */
+            bs_cache       <<= riceParamPlus1;
+            bs_consumedBits += riceParamPlus1;
+        } else {
+            /*
+            Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache
+            line, reload the cache, and then combine it with the head of the next cache line.
+            */
+
+            /* Before reloading the cache we need to grab the size in bits of the low part. */
+            drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits;
+            DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32);
+
+            /* Now reload the cache. */
+            if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
+            #ifndef DR_FLAC_NO_CRC
+                drflac__update_crc16(bs);
+            #endif
+                bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
+                bs_consumedBits = riceParamPartLoBitCount;
+            #ifndef DR_FLAC_NO_CRC
+                bs->crc16Cache = bs_cache;
+            #endif
+            } else {
+                /* Slow path. We need to fetch more data from the client. */
+                if (!drflac__reload_cache(bs)) {
+                    return DRFLAC_FALSE;
+                }
+
+                bs_cache = bs->cache;
+                bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount;
+            }
+
+            bs_cache <<= riceParamPartLoBitCount;
+        }
+    } else {
+        /*
+        Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call
+        to drflac__clz() and we need to reload the cache.
+        */
+        for (;;) {
+            if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) {
+            #ifndef DR_FLAC_NO_CRC
+                drflac__update_crc16(bs);
+            #endif
+                bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]);
+                bs_consumedBits = 0;
+            #ifndef DR_FLAC_NO_CRC
+                bs->crc16Cache = bs_cache;
+            #endif
+            } else {
+                /* Slow path. We need to fetch more data from the client. */
+                if (!drflac__reload_cache(bs)) {
+                    return DRFLAC_FALSE;
+                }
+
+                bs_cache = bs->cache;
+                bs_consumedBits = bs->consumedBits;
+            }
+
+            lzcount = drflac__clz(bs_cache);
+            if (lzcount < sizeof(bs_cache)*8) {
+                break;
+            }
+        }
+
+        goto extract_rice_param_part;
+    }
+
+    /* Make sure the cache is restored at the end of it all. */
+    bs->cache = bs_cache;
+    bs->consumedBits = bs_consumedBits;
+
+    return DRFLAC_TRUE;
+}
+
+
+static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorder(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
+    drflac_uint32 zeroCountPart0;
+    drflac_uint32 riceParamPart0;
+    drflac_uint32 riceParamMask;
+    drflac_uint32 i;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(count > 0);
+    DRFLAC_ASSERT(pSamplesOut != NULL);
+
+    (void)bitsPerSample;
+    (void)order;
+    (void)shift;
+    (void)coefficients;
+
+    riceParamMask  = (drflac_uint32)~((~0UL) << riceParam);
+
+    i = 0;
+    while (i < count) {
+        /* Rice extraction. */
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) {
+            return DRFLAC_FALSE;
+        }
+
+        /* Rice reconstruction. */
+        riceParamPart0 &= riceParamMask;
+        riceParamPart0 |= (zeroCountPart0 << riceParam);
+        riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
+
+        pSamplesOut[i] = riceParamPart0;
+
+        i += 1;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
+    drflac_uint32 zeroCountPart0 = 0;
+    drflac_uint32 zeroCountPart1 = 0;
+    drflac_uint32 zeroCountPart2 = 0;
+    drflac_uint32 zeroCountPart3 = 0;
+    drflac_uint32 riceParamPart0 = 0;
+    drflac_uint32 riceParamPart1 = 0;
+    drflac_uint32 riceParamPart2 = 0;
+    drflac_uint32 riceParamPart3 = 0;
+    drflac_uint32 riceParamMask;
+    const drflac_int32* pSamplesOutEnd;
+    drflac_uint32 i;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(count > 0);
+    DRFLAC_ASSERT(pSamplesOut != NULL);
+
+    if (order == 0) {
+        return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
+    }
+
+    riceParamMask  = (drflac_uint32)~((~0UL) << riceParam);
+    pSamplesOutEnd = pSamplesOut + (count & ~3);
+
+    if (bitsPerSample+shift > 32) {
+        while (pSamplesOut < pSamplesOutEnd) {
+            /*
+            Rice extraction. It's faster to do this one at a time against local variables than it is to use the x4 version
+            against an array. Not sure why, but perhaps it's making more efficient use of registers?
+            */
+            if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) ||
+                !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) ||
+                !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) ||
+                !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) {
+                return DRFLAC_FALSE;
+            }
+
+            riceParamPart0 &= riceParamMask;
+            riceParamPart1 &= riceParamMask;
+            riceParamPart2 &= riceParamMask;
+            riceParamPart3 &= riceParamMask;
+
+            riceParamPart0 |= (zeroCountPart0 << riceParam);
+            riceParamPart1 |= (zeroCountPart1 << riceParam);
+            riceParamPart2 |= (zeroCountPart2 << riceParam);
+            riceParamPart3 |= (zeroCountPart3 << riceParam);
+
+            riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
+            riceParamPart1  = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01];
+            riceParamPart2  = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01];
+            riceParamPart3  = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01];
+
+            pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0);
+            pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 1);
+            pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 2);
+            pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 3);
+
+            pSamplesOut += 4;
+        }
+    } else {
+        while (pSamplesOut < pSamplesOutEnd) {
+            if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) ||
+                !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) ||
+                !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) ||
+                !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) {
+                return DRFLAC_FALSE;
+            }
+
+            riceParamPart0 &= riceParamMask;
+            riceParamPart1 &= riceParamMask;
+            riceParamPart2 &= riceParamMask;
+            riceParamPart3 &= riceParamMask;
+
+            riceParamPart0 |= (zeroCountPart0 << riceParam);
+            riceParamPart1 |= (zeroCountPart1 << riceParam);
+            riceParamPart2 |= (zeroCountPart2 << riceParam);
+            riceParamPart3 |= (zeroCountPart3 << riceParam);
+
+            riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
+            riceParamPart1  = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01];
+            riceParamPart2  = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01];
+            riceParamPart3  = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01];
+
+            pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0);
+            pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 1);
+            pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 2);
+            pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 3);
+
+            pSamplesOut += 4;
+        }
+    }
+
+    i = (count & ~3);
+    while (i < count) {
+        /* Rice extraction. */
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) {
+            return DRFLAC_FALSE;
+        }
+
+        /* Rice reconstruction. */
+        riceParamPart0 &= riceParamMask;
+        riceParamPart0 |= (zeroCountPart0 << riceParam);
+        riceParamPart0  = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01];
+        /*riceParamPart0  = (riceParamPart0 >> 1) ^ (~(riceParamPart0 & 0x01) + 1);*/
+
+        /* Sample reconstruction. */
+        if (bitsPerSample+shift > 32) {
+            pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + 0);
+        } else {
+            pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + 0);
+        }
+
+        i += 1;
+        pSamplesOut += 1;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE __m128i drflac__mm_packs_interleaved_epi32(__m128i a, __m128i b)
+{
+    __m128i r;
+
+    /* Pack. */
+    r = _mm_packs_epi32(a, b);
+
+    /* a3a2 a1a0 b3b2 b1b0 -> a3a2 b3b2 a1a0 b1b0 */
+    r = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 1, 2, 0));
+
+    /* a3a2 b3b2 a1a0 b1b0 -> a3b3 a2b2 a1b1 a0b0 */
+    r = _mm_shufflehi_epi16(r, _MM_SHUFFLE(3, 1, 2, 0));
+    r = _mm_shufflelo_epi16(r, _MM_SHUFFLE(3, 1, 2, 0));
+
+    return r;
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_SSE41)
+static DRFLAC_INLINE __m128i drflac__mm_not_si128(__m128i a)
+{
+    return _mm_xor_si128(a, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128()));
+}
+
+static DRFLAC_INLINE __m128i drflac__mm_hadd_epi32(__m128i x)
+{
+    __m128i x64 = _mm_add_epi32(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2)));
+    __m128i x32 = _mm_shufflelo_epi16(x64, _MM_SHUFFLE(1, 0, 3, 2));
+    return _mm_add_epi32(x64, x32);
+}
+
+static DRFLAC_INLINE __m128i drflac__mm_hadd_epi64(__m128i x)
+{
+    return _mm_add_epi64(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2)));
+}
+
+static DRFLAC_INLINE __m128i drflac__mm_srai_epi64(__m128i x, int count)
+{
+    /*
+    To simplify this we are assuming count < 32. This restriction allows us to work on a low side and a high side. The low side
+    is shifted with zero bits, whereas the right side is shifted with sign bits.
+    */
+    __m128i lo = _mm_srli_epi64(x, count);
+    __m128i hi = _mm_srai_epi32(x, count);
+
+    hi = _mm_and_si128(hi, _mm_set_epi32(0xFFFFFFFF, 0, 0xFFFFFFFF, 0));    /* The high part needs to have the low part cleared. */
+
+    return _mm_or_si128(lo, hi);
+}
+
+static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    int i;
+    drflac_uint32 riceParamMask;
+    drflac_int32* pDecodedSamples    = pSamplesOut;
+    drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
+    drflac_uint32 zeroCountParts0 = 0;
+    drflac_uint32 zeroCountParts1 = 0;
+    drflac_uint32 zeroCountParts2 = 0;
+    drflac_uint32 zeroCountParts3 = 0;
+    drflac_uint32 riceParamParts0 = 0;
+    drflac_uint32 riceParamParts1 = 0;
+    drflac_uint32 riceParamParts2 = 0;
+    drflac_uint32 riceParamParts3 = 0;
+    __m128i coefficients128_0;
+    __m128i coefficients128_4;
+    __m128i coefficients128_8;
+    __m128i samples128_0;
+    __m128i samples128_4;
+    __m128i samples128_8;
+    __m128i riceParamMask128;
+
+    const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
+
+    riceParamMask    = (drflac_uint32)~((~0UL) << riceParam);
+    riceParamMask128 = _mm_set1_epi32(riceParamMask);
+
+    /* Pre-load. */
+    coefficients128_0 = _mm_setzero_si128();
+    coefficients128_4 = _mm_setzero_si128();
+    coefficients128_8 = _mm_setzero_si128();
+
+    samples128_0 = _mm_setzero_si128();
+    samples128_4 = _mm_setzero_si128();
+    samples128_8 = _mm_setzero_si128();
+
+    /*
+    Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than
+    what's available in the input buffers. It would be convenient to use a fall-through switch to do this, but this results
+    in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted
+    so I think there's opportunity for this to be simplified.
+    */
+#if 1
+    {
+        int runningOrder = order;
+
+        /* 0 - 3. */
+        if (runningOrder >= 4) {
+            coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0));
+            samples128_0      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 4));
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break;
+                case 2: coefficients128_0 = _mm_set_epi32(0, 0,               coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0,               0); break;
+                case 1: coefficients128_0 = _mm_set_epi32(0, 0,               0,               coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0,               0,               0); break;
+            }
+            runningOrder = 0;
+        }
+
+        /* 4 - 7 */
+        if (runningOrder >= 4) {
+            coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4));
+            samples128_4      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 8));
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break;
+                case 2: coefficients128_4 = _mm_set_epi32(0, 0,               coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0,               0); break;
+                case 1: coefficients128_4 = _mm_set_epi32(0, 0,               0,               coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0,               0,               0); break;
+            }
+            runningOrder = 0;
+        }
+
+        /* 8 - 11 */
+        if (runningOrder == 4) {
+            coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8));
+            samples128_8      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 12));
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break;
+                case 2: coefficients128_8 = _mm_set_epi32(0, 0,                coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0,                0); break;
+                case 1: coefficients128_8 = _mm_set_epi32(0, 0,                0,               coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0,                0,                0); break;
+            }
+            runningOrder = 0;
+        }
+
+        /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */
+        coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3));
+        coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3));
+        coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3));
+    }
+#else
+    /* This causes strict-aliasing warnings with GCC. */
+    switch (order)
+    {
+    case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12];
+    case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11];
+    case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10];
+    case 9:  ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9];
+    case 8:  ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8];
+    case 7:  ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7];
+    case 6:  ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6];
+    case 5:  ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5];
+    case 4:  ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4];
+    case 3:  ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3];
+    case 2:  ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2];
+    case 1:  ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1];
+    }
+#endif
+
+    /* For this version we are doing one sample at a time. */
+    while (pDecodedSamples < pDecodedSamplesEnd) {
+        __m128i prediction128;
+        __m128i zeroCountPart128;
+        __m128i riceParamPart128;
+
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) {
+            return DRFLAC_FALSE;
+        }
+
+        zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0);
+        riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0);
+
+        riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128);
+        riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam));
+        riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01))), _mm_set1_epi32(0x01)));  /* <-- SSE2 compatible */
+        /*riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_mullo_epi32(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01)), _mm_set1_epi32(0xFFFFFFFF)));*/   /* <-- Only supported from SSE4.1 and is slower in my testing... */
+
+        if (order <= 4) {
+            for (i = 0; i < 4; i += 1) {
+                prediction128 = _mm_mullo_epi32(coefficients128_0, samples128_0);
+
+                /* Horizontal add and shift. */
+                prediction128 = drflac__mm_hadd_epi32(prediction128);
+                prediction128 = _mm_srai_epi32(prediction128, shift);
+                prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
+
+                samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
+                riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
+            }
+        } else if (order <= 8) {
+            for (i = 0; i < 4; i += 1) {
+                prediction128 =                              _mm_mullo_epi32(coefficients128_4, samples128_4);
+                prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0));
+
+                /* Horizontal add and shift. */
+                prediction128 = drflac__mm_hadd_epi32(prediction128);
+                prediction128 = _mm_srai_epi32(prediction128, shift);
+                prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
+
+                samples128_4 = _mm_alignr_epi8(samples128_0,  samples128_4, 4);
+                samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
+                riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
+            }
+        } else {
+            for (i = 0; i < 4; i += 1) {
+                prediction128 =                              _mm_mullo_epi32(coefficients128_8, samples128_8);
+                prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_4, samples128_4));
+                prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0));
+
+                /* Horizontal add and shift. */
+                prediction128 = drflac__mm_hadd_epi32(prediction128);
+                prediction128 = _mm_srai_epi32(prediction128, shift);
+                prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
+
+                samples128_8 = _mm_alignr_epi8(samples128_4,  samples128_8, 4);
+                samples128_4 = _mm_alignr_epi8(samples128_0,  samples128_4, 4);
+                samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
+                riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
+            }
+        }
+
+        /* We store samples in groups of 4. */
+        _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0);
+        pDecodedSamples += 4;
+    }
+
+    /* Make sure we process the last few samples. */
+    i = (count & ~3);
+    while (i < (int)count) {
+        /* Rice extraction. */
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) {
+            return DRFLAC_FALSE;
+        }
+
+        /* Rice reconstruction. */
+        riceParamParts0 &= riceParamMask;
+        riceParamParts0 |= (zeroCountParts0 << riceParam);
+        riceParamParts0  = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01];
+
+        /* Sample reconstruction. */
+        pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples);
+
+        i += 1;
+        pDecodedSamples += 1;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    int i;
+    drflac_uint32 riceParamMask;
+    drflac_int32* pDecodedSamples    = pSamplesOut;
+    drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
+    drflac_uint32 zeroCountParts0 = 0;
+    drflac_uint32 zeroCountParts1 = 0;
+    drflac_uint32 zeroCountParts2 = 0;
+    drflac_uint32 zeroCountParts3 = 0;
+    drflac_uint32 riceParamParts0 = 0;
+    drflac_uint32 riceParamParts1 = 0;
+    drflac_uint32 riceParamParts2 = 0;
+    drflac_uint32 riceParamParts3 = 0;
+    __m128i coefficients128_0;
+    __m128i coefficients128_4;
+    __m128i coefficients128_8;
+    __m128i samples128_0;
+    __m128i samples128_4;
+    __m128i samples128_8;
+    __m128i prediction128;
+    __m128i riceParamMask128;
+
+    const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
+
+    DRFLAC_ASSERT(order <= 12);
+
+    riceParamMask    = (drflac_uint32)~((~0UL) << riceParam);
+    riceParamMask128 = _mm_set1_epi32(riceParamMask);
+
+    prediction128 = _mm_setzero_si128();
+
+    /* Pre-load. */
+    coefficients128_0  = _mm_setzero_si128();
+    coefficients128_4  = _mm_setzero_si128();
+    coefficients128_8  = _mm_setzero_si128();
+
+    samples128_0  = _mm_setzero_si128();
+    samples128_4  = _mm_setzero_si128();
+    samples128_8  = _mm_setzero_si128();
+
+#if 1
+    {
+        int runningOrder = order;
+
+        /* 0 - 3. */
+        if (runningOrder >= 4) {
+            coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0));
+            samples128_0      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 4));
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break;
+                case 2: coefficients128_0 = _mm_set_epi32(0, 0,               coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0,               0); break;
+                case 1: coefficients128_0 = _mm_set_epi32(0, 0,               0,               coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0,               0,               0); break;
+            }
+            runningOrder = 0;
+        }
+
+        /* 4 - 7 */
+        if (runningOrder >= 4) {
+            coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4));
+            samples128_4      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 8));
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break;
+                case 2: coefficients128_4 = _mm_set_epi32(0, 0,               coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0,               0); break;
+                case 1: coefficients128_4 = _mm_set_epi32(0, 0,               0,               coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0,               0,               0); break;
+            }
+            runningOrder = 0;
+        }
+
+        /* 8 - 11 */
+        if (runningOrder == 4) {
+            coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8));
+            samples128_8      = _mm_loadu_si128((const __m128i*)(pSamplesOut  - 12));
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break;
+                case 2: coefficients128_8 = _mm_set_epi32(0, 0,                coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0,                0); break;
+                case 1: coefficients128_8 = _mm_set_epi32(0, 0,                0,               coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0,                0,                0); break;
+            }
+            runningOrder = 0;
+        }
+
+        /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */
+        coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3));
+        coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3));
+        coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3));
+    }
+#else
+    switch (order)
+    {
+    case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12];
+    case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11];
+    case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10];
+    case 9:  ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9];
+    case 8:  ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8];
+    case 7:  ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7];
+    case 6:  ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6];
+    case 5:  ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5];
+    case 4:  ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4];
+    case 3:  ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3];
+    case 2:  ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2];
+    case 1:  ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1];
+    }
+#endif
+
+    /* For this version we are doing one sample at a time. */
+    while (pDecodedSamples < pDecodedSamplesEnd) {
+        __m128i zeroCountPart128;
+        __m128i riceParamPart128;
+
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) {
+            return DRFLAC_FALSE;
+        }
+
+        zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0);
+        riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0);
+
+        riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128);
+        riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam));
+        riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(1))), _mm_set1_epi32(1)));
+
+        for (i = 0; i < 4; i += 1) {
+            prediction128 = _mm_xor_si128(prediction128, prediction128);    /* Reset to 0. */
+
+            switch (order)
+            {
+            case 12:
+            case 11: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(1, 1, 0, 0))));
+            case 10:
+            case  9: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(3, 3, 2, 2))));
+            case  8:
+            case  7: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(1, 1, 0, 0))));
+            case  6:
+            case  5: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(3, 3, 2, 2))));
+            case  4:
+            case  3: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(1, 1, 0, 0))));
+            case  2:
+            case  1: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(3, 3, 2, 2))));
+            }
+
+            /* Horizontal add and shift. */
+            prediction128 = drflac__mm_hadd_epi64(prediction128);
+            prediction128 = drflac__mm_srai_epi64(prediction128, shift);
+            prediction128 = _mm_add_epi32(riceParamPart128, prediction128);
+
+            /* Our value should be sitting in prediction128[0]. We need to combine this with our SSE samples. */
+            samples128_8 = _mm_alignr_epi8(samples128_4,  samples128_8, 4);
+            samples128_4 = _mm_alignr_epi8(samples128_0,  samples128_4, 4);
+            samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4);
+
+            /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */
+            riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4);
+        }
+
+        /* We store samples in groups of 4. */
+        _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0);
+        pDecodedSamples += 4;
+    }
+
+    /* Make sure we process the last few samples. */
+    i = (count & ~3);
+    while (i < (int)count) {
+        /* Rice extraction. */
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) {
+            return DRFLAC_FALSE;
+        }
+
+        /* Rice reconstruction. */
+        riceParamParts0 &= riceParamMask;
+        riceParamParts0 |= (zeroCountParts0 << riceParam);
+        riceParamParts0  = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01];
+
+        /* Sample reconstruction. */
+        pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples);
+
+        i += 1;
+        pDecodedSamples += 1;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(count > 0);
+    DRFLAC_ASSERT(pSamplesOut != NULL);
+
+    /* In my testing the order is rarely > 12, so in this case I'm going to simplify the SSE implementation by only handling order <= 12. */
+    if (order > 0 && order <= 12) {
+        if (bitsPerSample+shift > 32) {
+            return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
+        } else {
+            return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
+        }
+    } else {
+        return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac__vst2q_s32(drflac_int32* p, int32x4x2_t x)
+{
+    vst1q_s32(p+0, x.val[0]);
+    vst1q_s32(p+4, x.val[1]);
+}
+
+static DRFLAC_INLINE void drflac__vst2q_u32(drflac_uint32* p, uint32x4x2_t x)
+{
+    vst1q_u32(p+0, x.val[0]);
+    vst1q_u32(p+4, x.val[1]);
+}
+
+static DRFLAC_INLINE void drflac__vst2q_f32(float* p, float32x4x2_t x)
+{
+    vst1q_f32(p+0, x.val[0]);
+    vst1q_f32(p+4, x.val[1]);
+}
+
+static DRFLAC_INLINE void drflac__vst2q_s16(drflac_int16* p, int16x4x2_t x)
+{
+    vst1q_s16(p, vcombine_s16(x.val[0], x.val[1]));
+}
+
+static DRFLAC_INLINE void drflac__vst2q_u16(drflac_uint16* p, uint16x4x2_t x)
+{
+    vst1q_u16(p, vcombine_u16(x.val[0], x.val[1]));
+}
+
+static DRFLAC_INLINE int32x4_t drflac__vdupq_n_s32x4(drflac_int32 x3, drflac_int32 x2, drflac_int32 x1, drflac_int32 x0)
+{
+    drflac_int32 x[4];
+    x[3] = x3;
+    x[2] = x2;
+    x[1] = x1;
+    x[0] = x0;
+    return vld1q_s32(x);
+}
+
+static DRFLAC_INLINE int32x4_t drflac__valignrq_s32_1(int32x4_t a, int32x4_t b)
+{
+    /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */
+
+    /* Reference */
+    /*return drflac__vdupq_n_s32x4(
+        vgetq_lane_s32(a, 0),
+        vgetq_lane_s32(b, 3),
+        vgetq_lane_s32(b, 2),
+        vgetq_lane_s32(b, 1)
+    );*/
+
+    return vextq_s32(b, a, 1);
+}
+
+static DRFLAC_INLINE uint32x4_t drflac__valignrq_u32_1(uint32x4_t a, uint32x4_t b)
+{
+    /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */
+
+    /* Reference */
+    /*return drflac__vdupq_n_s32x4(
+        vgetq_lane_s32(a, 0),
+        vgetq_lane_s32(b, 3),
+        vgetq_lane_s32(b, 2),
+        vgetq_lane_s32(b, 1)
+    );*/
+
+    return vextq_u32(b, a, 1);
+}
+
+static DRFLAC_INLINE int32x2_t drflac__vhaddq_s32(int32x4_t x)
+{
+    /* The sum must end up in position 0. */
+
+    /* Reference */
+    /*return vdupq_n_s32(
+        vgetq_lane_s32(x, 3) +
+        vgetq_lane_s32(x, 2) +
+        vgetq_lane_s32(x, 1) +
+        vgetq_lane_s32(x, 0)
+    );*/
+
+    int32x2_t r = vadd_s32(vget_high_s32(x), vget_low_s32(x));
+    return vpadd_s32(r, r);
+}
+
+static DRFLAC_INLINE int64x1_t drflac__vhaddq_s64(int64x2_t x)
+{
+    return vadd_s64(vget_high_s64(x), vget_low_s64(x));
+}
+
+static DRFLAC_INLINE int32x4_t drflac__vrevq_s32(int32x4_t x)
+{
+    /* Reference */
+    /*return drflac__vdupq_n_s32x4(
+        vgetq_lane_s32(x, 0),
+        vgetq_lane_s32(x, 1),
+        vgetq_lane_s32(x, 2),
+        vgetq_lane_s32(x, 3)
+    );*/
+
+    return vrev64q_s32(vcombine_s32(vget_high_s32(x), vget_low_s32(x)));
+}
+
+static DRFLAC_INLINE int32x4_t drflac__vnotq_s32(int32x4_t x)
+{
+    return veorq_s32(x, vdupq_n_s32(0xFFFFFFFF));
+}
+
+static DRFLAC_INLINE uint32x4_t drflac__vnotq_u32(uint32x4_t x)
+{
+    return veorq_u32(x, vdupq_n_u32(0xFFFFFFFF));
+}
+
+static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    int i;
+    drflac_uint32 riceParamMask;
+    drflac_int32* pDecodedSamples    = pSamplesOut;
+    drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
+    drflac_uint32 zeroCountParts[4];
+    drflac_uint32 riceParamParts[4];
+    int32x4_t coefficients128_0;
+    int32x4_t coefficients128_4;
+    int32x4_t coefficients128_8;
+    int32x4_t samples128_0;
+    int32x4_t samples128_4;
+    int32x4_t samples128_8;
+    uint32x4_t riceParamMask128;
+    int32x4_t riceParam128;
+    int32x2_t shift64;
+    uint32x4_t one128;
+
+    const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
+
+    riceParamMask    = ~((~0UL) << riceParam);
+    riceParamMask128 = vdupq_n_u32(riceParamMask);
+
+    riceParam128 = vdupq_n_s32(riceParam);
+    shift64 = vdup_n_s32(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */
+    one128 = vdupq_n_u32(1);
+
+    /*
+    Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than
+    what's available in the input buffers. It would be conenient to use a fall-through switch to do this, but this results
+    in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted
+    so I think there's opportunity for this to be simplified.
+    */
+    {
+        int runningOrder = order;
+        drflac_int32 tempC[4] = {0, 0, 0, 0};
+        drflac_int32 tempS[4] = {0, 0, 0, 0};
+
+        /* 0 - 3. */
+        if (runningOrder >= 4) {
+            coefficients128_0 = vld1q_s32(coefficients + 0);
+            samples128_0      = vld1q_s32(pSamplesOut  - 4);
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */
+                case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */
+                case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */
+            }
+
+            coefficients128_0 = vld1q_s32(tempC);
+            samples128_0      = vld1q_s32(tempS);
+            runningOrder = 0;
+        }
+
+        /* 4 - 7 */
+        if (runningOrder >= 4) {
+            coefficients128_4 = vld1q_s32(coefficients + 4);
+            samples128_4      = vld1q_s32(pSamplesOut  - 8);
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */
+                case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */
+                case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */
+            }
+
+            coefficients128_4 = vld1q_s32(tempC);
+            samples128_4      = vld1q_s32(tempS);
+            runningOrder = 0;
+        }
+
+        /* 8 - 11 */
+        if (runningOrder == 4) {
+            coefficients128_8 = vld1q_s32(coefficients + 8);
+            samples128_8      = vld1q_s32(pSamplesOut  - 12);
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */
+                case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */
+                case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */
+            }
+
+            coefficients128_8 = vld1q_s32(tempC);
+            samples128_8      = vld1q_s32(tempS);
+            runningOrder = 0;
+        }
+
+        /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */
+        coefficients128_0 = drflac__vrevq_s32(coefficients128_0);
+        coefficients128_4 = drflac__vrevq_s32(coefficients128_4);
+        coefficients128_8 = drflac__vrevq_s32(coefficients128_8);
+    }
+
+    /* For this version we are doing one sample at a time. */
+    while (pDecodedSamples < pDecodedSamplesEnd) {
+        int32x4_t prediction128;
+        int32x2_t prediction64;
+        uint32x4_t zeroCountPart128;
+        uint32x4_t riceParamPart128;
+
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) {
+            return DRFLAC_FALSE;
+        }
+
+        zeroCountPart128 = vld1q_u32(zeroCountParts);
+        riceParamPart128 = vld1q_u32(riceParamParts);
+
+        riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128);
+        riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128));
+        riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128));
+
+        if (order <= 4) {
+            for (i = 0; i < 4; i += 1) {
+                prediction128 = vmulq_s32(coefficients128_0, samples128_0);
+
+                /* Horizontal add and shift. */
+                prediction64 = drflac__vhaddq_s32(prediction128);
+                prediction64 = vshl_s32(prediction64, shift64);
+                prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
+
+                samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
+                riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
+            }
+        } else if (order <= 8) {
+            for (i = 0; i < 4; i += 1) {
+                prediction128 =                vmulq_s32(coefficients128_4, samples128_4);
+                prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0);
+
+                /* Horizontal add and shift. */
+                prediction64 = drflac__vhaddq_s32(prediction128);
+                prediction64 = vshl_s32(prediction64, shift64);
+                prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
+
+                samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
+                samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
+                riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
+            }
+        } else {
+            for (i = 0; i < 4; i += 1) {
+                prediction128 =                vmulq_s32(coefficients128_8, samples128_8);
+                prediction128 = vmlaq_s32(prediction128, coefficients128_4, samples128_4);
+                prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0);
+
+                /* Horizontal add and shift. */
+                prediction64 = drflac__vhaddq_s32(prediction128);
+                prediction64 = vshl_s32(prediction64, shift64);
+                prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128)));
+
+                samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8);
+                samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
+                samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0);
+                riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
+            }
+        }
+
+        /* We store samples in groups of 4. */
+        vst1q_s32(pDecodedSamples, samples128_0);
+        pDecodedSamples += 4;
+    }
+
+    /* Make sure we process the last few samples. */
+    i = (count & ~3);
+    while (i < (int)count) {
+        /* Rice extraction. */
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) {
+            return DRFLAC_FALSE;
+        }
+
+        /* Rice reconstruction. */
+        riceParamParts[0] &= riceParamMask;
+        riceParamParts[0] |= (zeroCountParts[0] << riceParam);
+        riceParamParts[0]  = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01];
+
+        /* Sample reconstruction. */
+        pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples);
+
+        i += 1;
+        pDecodedSamples += 1;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    int i;
+    drflac_uint32 riceParamMask;
+    drflac_int32* pDecodedSamples    = pSamplesOut;
+    drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3);
+    drflac_uint32 zeroCountParts[4];
+    drflac_uint32 riceParamParts[4];
+    int32x4_t coefficients128_0;
+    int32x4_t coefficients128_4;
+    int32x4_t coefficients128_8;
+    int32x4_t samples128_0;
+    int32x4_t samples128_4;
+    int32x4_t samples128_8;
+    uint32x4_t riceParamMask128;
+    int32x4_t riceParam128;
+    int64x1_t shift64;
+    uint32x4_t one128;
+
+    const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF};
+
+    riceParamMask    = ~((~0UL) << riceParam);
+    riceParamMask128 = vdupq_n_u32(riceParamMask);
+
+    riceParam128 = vdupq_n_s32(riceParam);
+    shift64 = vdup_n_s64(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */
+    one128 = vdupq_n_u32(1);
+
+    /*
+    Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than
+    what's available in the input buffers. It would be conenient to use a fall-through switch to do this, but this results
+    in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted
+    so I think there's opportunity for this to be simplified.
+    */
+    {
+        int runningOrder = order;
+        drflac_int32 tempC[4] = {0, 0, 0, 0};
+        drflac_int32 tempS[4] = {0, 0, 0, 0};
+
+        /* 0 - 3. */
+        if (runningOrder >= 4) {
+            coefficients128_0 = vld1q_s32(coefficients + 0);
+            samples128_0      = vld1q_s32(pSamplesOut  - 4);
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */
+                case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */
+                case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */
+            }
+
+            coefficients128_0 = vld1q_s32(tempC);
+            samples128_0      = vld1q_s32(tempS);
+            runningOrder = 0;
+        }
+
+        /* 4 - 7 */
+        if (runningOrder >= 4) {
+            coefficients128_4 = vld1q_s32(coefficients + 4);
+            samples128_4      = vld1q_s32(pSamplesOut  - 8);
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */
+                case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */
+                case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */
+            }
+
+            coefficients128_4 = vld1q_s32(tempC);
+            samples128_4      = vld1q_s32(tempS);
+            runningOrder = 0;
+        }
+
+        /* 8 - 11 */
+        if (runningOrder == 4) {
+            coefficients128_8 = vld1q_s32(coefficients + 8);
+            samples128_8      = vld1q_s32(pSamplesOut  - 12);
+            runningOrder -= 4;
+        } else {
+            switch (runningOrder) {
+                case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */
+                case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */
+                case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */
+            }
+
+            coefficients128_8 = vld1q_s32(tempC);
+            samples128_8      = vld1q_s32(tempS);
+            runningOrder = 0;
+        }
+
+        /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */
+        coefficients128_0 = drflac__vrevq_s32(coefficients128_0);
+        coefficients128_4 = drflac__vrevq_s32(coefficients128_4);
+        coefficients128_8 = drflac__vrevq_s32(coefficients128_8);
+    }
+
+    /* For this version we are doing one sample at a time. */
+    while (pDecodedSamples < pDecodedSamplesEnd) {
+        int64x2_t prediction128;
+        uint32x4_t zeroCountPart128;
+        uint32x4_t riceParamPart128;
+
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) ||
+            !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) {
+            return DRFLAC_FALSE;
+        }
+
+        zeroCountPart128 = vld1q_u32(zeroCountParts);
+        riceParamPart128 = vld1q_u32(riceParamParts);
+
+        riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128);
+        riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128));
+        riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128));
+
+        for (i = 0; i < 4; i += 1) {
+            int64x1_t prediction64;
+
+            prediction128 = veorq_s64(prediction128, prediction128);    /* Reset to 0. */
+            switch (order)
+            {
+            case 12:
+            case 11: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_8), vget_low_s32(samples128_8)));
+            case 10:
+            case  9: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_8), vget_high_s32(samples128_8)));
+            case  8:
+            case  7: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_4), vget_low_s32(samples128_4)));
+            case  6:
+            case  5: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_4), vget_high_s32(samples128_4)));
+            case  4:
+            case  3: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_0), vget_low_s32(samples128_0)));
+            case  2:
+            case  1: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_0), vget_high_s32(samples128_0)));
+            }
+
+            /* Horizontal add and shift. */
+            prediction64 = drflac__vhaddq_s64(prediction128);
+            prediction64 = vshl_s64(prediction64, shift64);
+            prediction64 = vadd_s64(prediction64, vdup_n_s64(vgetq_lane_u32(riceParamPart128, 0)));
+
+            /* Our value should be sitting in prediction64[0]. We need to combine this with our SSE samples. */
+            samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8);
+            samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4);
+            samples128_0 = drflac__valignrq_s32_1(vcombine_s32(vreinterpret_s32_s64(prediction64), vdup_n_s32(0)), samples128_0);
+
+            /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */
+            riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128);
+        }
+
+        /* We store samples in groups of 4. */
+        vst1q_s32(pDecodedSamples, samples128_0);
+        pDecodedSamples += 4;
+    }
+
+    /* Make sure we process the last few samples. */
+    i = (count & ~3);
+    while (i < (int)count) {
+        /* Rice extraction. */
+        if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) {
+            return DRFLAC_FALSE;
+        }
+
+        /* Rice reconstruction. */
+        riceParamParts[0] &= riceParamMask;
+        riceParamParts[0] |= (zeroCountParts[0] << riceParam);
+        riceParamParts[0]  = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01];
+
+        /* Sample reconstruction. */
+        pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples);
+
+        i += 1;
+        pDecodedSamples += 1;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(count > 0);
+    DRFLAC_ASSERT(pSamplesOut != NULL);
+
+    /* In my testing the order is rarely > 12, so in this case I'm going to simplify the NEON implementation by only handling order <= 12. */
+    if (order > 0 && order <= 12) {
+        if (bitsPerSample+shift > 32) {
+            return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
+        } else {
+            return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, order, shift, coefficients, pSamplesOut);
+        }
+    } else {
+        return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
+    }
+}
+#endif
+
+static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+#if defined(DRFLAC_SUPPORT_SSE41)
+    if (drflac__gIsSSE41Supported) {
+        return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported) {
+        return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+    #if 0
+        return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
+    #else
+        return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, order, shift, coefficients, pSamplesOut);
+    #endif
+    }
+}
+
+/* Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes. */
+static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam)
+{
+    drflac_uint32 i;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(count > 0);
+
+    for (i = 0; i < count; ++i) {
+        if (!drflac__seek_rice_parts(bs, riceParam)) {
+            return DRFLAC_FALSE;
+        }
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut)
+{
+    drflac_uint32 i;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(count > 0);
+    DRFLAC_ASSERT(unencodedBitsPerSample <= 31);    /* <-- unencodedBitsPerSample is a 5 bit number, so cannot exceed 31. */
+    DRFLAC_ASSERT(pSamplesOut != NULL);
+
+    for (i = 0; i < count; ++i) {
+        if (unencodedBitsPerSample > 0) {
+            if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) {
+                return DRFLAC_FALSE;
+            }
+        } else {
+            pSamplesOut[i] = 0;
+        }
+
+        if (bitsPerSample >= 24) {
+            pSamplesOut[i] += drflac__calculate_prediction_64(order, shift, coefficients, pSamplesOut + i);
+        } else {
+            pSamplesOut[i] += drflac__calculate_prediction_32(order, shift, coefficients, pSamplesOut + i);
+        }
+    }
+
+    return DRFLAC_TRUE;
+}
+
+
+/*
+Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called
+when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be ignored. The
+<blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
+*/
+static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples)
+{
+    drflac_uint8 residualMethod;
+    drflac_uint8 partitionOrder;
+    drflac_uint32 samplesInPartition;
+    drflac_uint32 partitionsRemaining;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(blockSize != 0);
+    DRFLAC_ASSERT(pDecodedSamples != NULL);       /* <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? */
+
+    if (!drflac__read_uint8(bs, 2, &residualMethod)) {
+        return DRFLAC_FALSE;
+    }
+
+    if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+        return DRFLAC_FALSE;    /* Unknown or unsupported residual coding method. */
+    }
+
+    /* Ignore the first <order> values. */
+    pDecodedSamples += order;
+
+    if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
+        return DRFLAC_FALSE;
+    }
+
+    /*
+    From the FLAC spec:
+      The Rice partition order in a Rice-coded residual section must be less than or equal to 8.
+    */
+    if (partitionOrder > 8) {
+        return DRFLAC_FALSE;
+    }
+
+    /* Validation check. */
+    if ((blockSize / (1 << partitionOrder)) <= order) {
+        return DRFLAC_FALSE;
+    }
+
+    samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
+    partitionsRemaining = (1 << partitionOrder);
+    for (;;) {
+        drflac_uint8 riceParam = 0;
+        if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
+            if (!drflac__read_uint8(bs, 4, &riceParam)) {
+                return DRFLAC_FALSE;
+            }
+            if (riceParam == 15) {
+                riceParam = 0xFF;
+            }
+        } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+            if (!drflac__read_uint8(bs, 5, &riceParam)) {
+                return DRFLAC_FALSE;
+            }
+            if (riceParam == 31) {
+                riceParam = 0xFF;
+            }
+        }
+
+        if (riceParam != 0xFF) {
+            if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, order, shift, coefficients, pDecodedSamples)) {
+                return DRFLAC_FALSE;
+            }
+        } else {
+            drflac_uint8 unencodedBitsPerSample = 0;
+            if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
+                return DRFLAC_FALSE;
+            }
+
+            if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, order, shift, coefficients, pDecodedSamples)) {
+                return DRFLAC_FALSE;
+            }
+        }
+
+        pDecodedSamples += samplesInPartition;
+
+        if (partitionsRemaining == 1) {
+            break;
+        }
+
+        partitionsRemaining -= 1;
+
+        if (partitionOrder != 0) {
+            samplesInPartition = blockSize / (1 << partitionOrder);
+        }
+    }
+
+    return DRFLAC_TRUE;
+}
+
+/*
+Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called
+when the decoder is sitting at the very start of the RESIDUAL block. The first <order> residuals will be set to 0. The
+<blockSize> and <order> parameters are used to determine how many residual values need to be decoded.
+*/
+static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order)
+{
+    drflac_uint8 residualMethod;
+    drflac_uint8 partitionOrder;
+    drflac_uint32 samplesInPartition;
+    drflac_uint32 partitionsRemaining;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(blockSize != 0);
+
+    if (!drflac__read_uint8(bs, 2, &residualMethod)) {
+        return DRFLAC_FALSE;
+    }
+
+    if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+        return DRFLAC_FALSE;    /* Unknown or unsupported residual coding method. */
+    }
+
+    if (!drflac__read_uint8(bs, 4, &partitionOrder)) {
+        return DRFLAC_FALSE;
+    }
+
+    /*
+    From the FLAC spec:
+      The Rice partition order in a Rice-coded residual section must be less than or equal to 8.
+    */
+    if (partitionOrder > 8) {
+        return DRFLAC_FALSE;
+    }
+
+    /* Validation check. */
+    if ((blockSize / (1 << partitionOrder)) <= order) {
+        return DRFLAC_FALSE;
+    }
+
+    samplesInPartition = (blockSize / (1 << partitionOrder)) - order;
+    partitionsRemaining = (1 << partitionOrder);
+    for (;;)
+    {
+        drflac_uint8 riceParam = 0;
+        if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) {
+            if (!drflac__read_uint8(bs, 4, &riceParam)) {
+                return DRFLAC_FALSE;
+            }
+            if (riceParam == 15) {
+                riceParam = 0xFF;
+            }
+        } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) {
+            if (!drflac__read_uint8(bs, 5, &riceParam)) {
+                return DRFLAC_FALSE;
+            }
+            if (riceParam == 31) {
+                riceParam = 0xFF;
+            }
+        }
+
+        if (riceParam != 0xFF) {
+            if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) {
+                return DRFLAC_FALSE;
+            }
+        } else {
+            drflac_uint8 unencodedBitsPerSample = 0;
+            if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) {
+                return DRFLAC_FALSE;
+            }
+
+            if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) {
+                return DRFLAC_FALSE;
+            }
+        }
+
+
+        if (partitionsRemaining == 1) {
+            break;
+        }
+
+        partitionsRemaining -= 1;
+        samplesInPartition = blockSize / (1 << partitionOrder);
+    }
+
+    return DRFLAC_TRUE;
+}
+
+
+static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
+{
+    drflac_uint32 i;
+
+    /* Only a single sample needs to be decoded here. */
+    drflac_int32 sample;
+    if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
+        return DRFLAC_FALSE;
+    }
+
+    /*
+    We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely)
+    we'll want to look at a more efficient way.
+    */
+    for (i = 0; i < blockSize; ++i) {
+        pDecodedSamples[i] = sample;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples)
+{
+    drflac_uint32 i;
+
+    for (i = 0; i < blockSize; ++i) {
+        drflac_int32 sample;
+        if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
+            return DRFLAC_FALSE;
+        }
+
+        pDecodedSamples[i] = sample;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
+{
+    drflac_uint32 i;
+
+    static drflac_int32 lpcCoefficientsTable[5][4] = {
+        {0,  0, 0,  0},
+        {1,  0, 0,  0},
+        {2, -1, 0,  0},
+        {3, -3, 1,  0},
+        {4, -6, 4, -1}
+    };
+
+    /* Warm up samples and coefficients. */
+    for (i = 0; i < lpcOrder; ++i) {
+        drflac_int32 sample;
+        if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) {
+            return DRFLAC_FALSE;
+        }
+
+        pDecodedSamples[i] = sample;
+    }
+
+    if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) {
+        return DRFLAC_FALSE;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples)
+{
+    drflac_uint8 i;
+    drflac_uint8 lpcPrecision;
+    drflac_int8 lpcShift;
+    drflac_int32 coefficients[32];
+
+    /* Warm up samples. */
+    for (i = 0; i < lpcOrder; ++i) {
+        drflac_int32 sample;
+        if (!drflac__read_int32(bs, bitsPerSample, &sample)) {
+            return DRFLAC_FALSE;
+        }
+
+        pDecodedSamples[i] = sample;
+    }
+
+    if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
+        return DRFLAC_FALSE;
+    }
+    if (lpcPrecision == 15) {
+        return DRFLAC_FALSE;    /* Invalid. */
+    }
+    lpcPrecision += 1;
+
+    if (!drflac__read_int8(bs, 5, &lpcShift)) {
+        return DRFLAC_FALSE;
+    }
+
+    /*
+    From the FLAC specification:
+
+        Quantized linear predictor coefficient shift needed in bits (NOTE: this number is signed two's-complement)
+
+    Emphasis on the "signed two's-complement". In practice there does not seem to be any encoders nor decoders supporting negative shifts. For now dr_flac is
+    not going to support negative shifts as I don't have any reference files. However, when a reference file comes through I will consider adding support.
+    */
+    if (lpcShift < 0) {
+        return DRFLAC_FALSE;
+    }
+
+    DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients));
+    for (i = 0; i < lpcOrder; ++i) {
+        if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) {
+            return DRFLAC_FALSE;
+        }
+    }
+
+    if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, coefficients, pDecodedSamples)) {
+        return DRFLAC_FALSE;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+
+static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header)
+{
+    const drflac_uint32 sampleRateTable[12]  = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000};
+    const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1};   /* -1 = reserved. */
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(header != NULL);
+
+    /* Keep looping until we find a valid sync code. */
+    for (;;) {
+        drflac_uint8 crc8 = 0xCE; /* 0xCE = drflac_crc8(0, 0x3FFE, 14); */
+        drflac_uint8 reserved = 0;
+        drflac_uint8 blockingStrategy = 0;
+        drflac_uint8 blockSize = 0;
+        drflac_uint8 sampleRate = 0;
+        drflac_uint8 channelAssignment = 0;
+        drflac_uint8 bitsPerSample = 0;
+        drflac_bool32 isVariableBlockSize;
+
+        if (!drflac__find_and_seek_to_next_sync_code(bs)) {
+            return DRFLAC_FALSE;
+        }
+
+        if (!drflac__read_uint8(bs, 1, &reserved)) {
+            return DRFLAC_FALSE;
+        }
+        if (reserved == 1) {
+            continue;
+        }
+        crc8 = drflac_crc8(crc8, reserved, 1);
+
+        if (!drflac__read_uint8(bs, 1, &blockingStrategy)) {
+            return DRFLAC_FALSE;
+        }
+        crc8 = drflac_crc8(crc8, blockingStrategy, 1);
+
+        if (!drflac__read_uint8(bs, 4, &blockSize)) {
+            return DRFLAC_FALSE;
+        }
+        if (blockSize == 0) {
+            continue;
+        }
+        crc8 = drflac_crc8(crc8, blockSize, 4);
+
+        if (!drflac__read_uint8(bs, 4, &sampleRate)) {
+            return DRFLAC_FALSE;
+        }
+        crc8 = drflac_crc8(crc8, sampleRate, 4);
+
+        if (!drflac__read_uint8(bs, 4, &channelAssignment)) {
+            return DRFLAC_FALSE;
+        }
+        if (channelAssignment > 10) {
+            continue;
+        }
+        crc8 = drflac_crc8(crc8, channelAssignment, 4);
+
+        if (!drflac__read_uint8(bs, 3, &bitsPerSample)) {
+            return DRFLAC_FALSE;
+        }
+        if (bitsPerSample == 3 || bitsPerSample == 7) {
+            continue;
+        }
+        crc8 = drflac_crc8(crc8, bitsPerSample, 3);
+
+
+        if (!drflac__read_uint8(bs, 1, &reserved)) {
+            return DRFLAC_FALSE;
+        }
+        if (reserved == 1) {
+            continue;
+        }
+        crc8 = drflac_crc8(crc8, reserved, 1);
+
+
+        isVariableBlockSize = blockingStrategy == 1;
+        if (isVariableBlockSize) {
+            drflac_uint64 pcmFrameNumber;
+            drflac_result result = drflac__read_utf8_coded_number(bs, &pcmFrameNumber, &crc8);
+            if (result != DRFLAC_SUCCESS) {
+                if (result == DRFLAC_AT_END) {
+                    return DRFLAC_FALSE;
+                } else {
+                    continue;
+                }
+            }
+            header->flacFrameNumber  = 0;
+            header->pcmFrameNumber = pcmFrameNumber;
+        } else {
+            drflac_uint64 flacFrameNumber = 0;
+            drflac_result result = drflac__read_utf8_coded_number(bs, &flacFrameNumber, &crc8);
+            if (result != DRFLAC_SUCCESS) {
+                if (result == DRFLAC_AT_END) {
+                    return DRFLAC_FALSE;
+                } else {
+                    continue;
+                }
+            }
+            header->flacFrameNumber  = (drflac_uint32)flacFrameNumber;   /* <-- Safe cast. */
+            header->pcmFrameNumber = 0;
+        }
+
+
+        DRFLAC_ASSERT(blockSize > 0);
+        if (blockSize == 1) {
+            header->blockSizeInPCMFrames = 192;
+        } else if (blockSize <= 5) {
+            DRFLAC_ASSERT(blockSize >= 2);
+            header->blockSizeInPCMFrames = 576 * (1 << (blockSize - 2));
+        } else if (blockSize == 6) {
+            if (!drflac__read_uint16(bs, 8, &header->blockSizeInPCMFrames)) {
+                return DRFLAC_FALSE;
+            }
+            crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 8);
+            header->blockSizeInPCMFrames += 1;
+        } else if (blockSize == 7) {
+            if (!drflac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) {
+                return DRFLAC_FALSE;
+            }
+            crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16);
+            header->blockSizeInPCMFrames += 1;
+        } else {
+            DRFLAC_ASSERT(blockSize >= 8);
+            header->blockSizeInPCMFrames = 256 * (1 << (blockSize - 8));
+        }
+
+
+        if (sampleRate <= 11) {
+            header->sampleRate = sampleRateTable[sampleRate];
+        } else if (sampleRate == 12) {
+            if (!drflac__read_uint32(bs, 8, &header->sampleRate)) {
+                return DRFLAC_FALSE;
+            }
+            crc8 = drflac_crc8(crc8, header->sampleRate, 8);
+            header->sampleRate *= 1000;
+        } else if (sampleRate == 13) {
+            if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
+                return DRFLAC_FALSE;
+            }
+            crc8 = drflac_crc8(crc8, header->sampleRate, 16);
+        } else if (sampleRate == 14) {
+            if (!drflac__read_uint32(bs, 16, &header->sampleRate)) {
+                return DRFLAC_FALSE;
+            }
+            crc8 = drflac_crc8(crc8, header->sampleRate, 16);
+            header->sampleRate *= 10;
+        } else {
+            continue;  /* Invalid. Assume an invalid block. */
+        }
+
+
+        header->channelAssignment = channelAssignment;
+
+        header->bitsPerSample = bitsPerSampleTable[bitsPerSample];
+        if (header->bitsPerSample == 0) {
+            header->bitsPerSample = streaminfoBitsPerSample;
+        }
+
+        if (!drflac__read_uint8(bs, 8, &header->crc8)) {
+            return DRFLAC_FALSE;
+        }
+
+#ifndef DR_FLAC_NO_CRC
+        if (header->crc8 != crc8) {
+            continue;    /* CRC mismatch. Loop back to the top and find the next sync code. */
+        }
+#endif
+        return DRFLAC_TRUE;
+    }
+}
+
+static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe)
+{
+    drflac_uint8 header;
+    int type;
+
+    if (!drflac__read_uint8(bs, 8, &header)) {
+        return DRFLAC_FALSE;
+    }
+
+    /* First bit should always be 0. */
+    if ((header & 0x80) != 0) {
+        return DRFLAC_FALSE;
+    }
+
+    type = (header & 0x7E) >> 1;
+    if (type == 0) {
+        pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT;
+    } else if (type == 1) {
+        pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM;
+    } else {
+        if ((type & 0x20) != 0) {
+            pSubframe->subframeType = DRFLAC_SUBFRAME_LPC;
+            pSubframe->lpcOrder = (drflac_uint8)(type & 0x1F) + 1;
+        } else if ((type & 0x08) != 0) {
+            pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED;
+            pSubframe->lpcOrder = (drflac_uint8)(type & 0x07);
+            if (pSubframe->lpcOrder > 4) {
+                pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
+                pSubframe->lpcOrder = 0;
+            }
+        } else {
+            pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED;
+        }
+    }
+
+    if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) {
+        return DRFLAC_FALSE;
+    }
+
+    /* Wasted bits per sample. */
+    pSubframe->wastedBitsPerSample = 0;
+    if ((header & 0x01) == 1) {
+        unsigned int wastedBitsPerSample;
+        if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) {
+            return DRFLAC_FALSE;
+        }
+        pSubframe->wastedBitsPerSample = (drflac_uint8)wastedBitsPerSample + 1;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut)
+{
+    drflac_subframe* pSubframe;
+    drflac_uint32 subframeBitsPerSample;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(frame != NULL);
+
+    pSubframe = frame->subframes + subframeIndex;
+    if (!drflac__read_subframe_header(bs, pSubframe)) {
+        return DRFLAC_FALSE;
+    }
+
+    /* Side channels require an extra bit per sample. Took a while to figure that one out... */
+    subframeBitsPerSample = frame->header.bitsPerSample;
+    if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
+        subframeBitsPerSample += 1;
+    } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
+        subframeBitsPerSample += 1;
+    }
+
+    /* Need to handle wasted bits per sample. */
+    if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
+        return DRFLAC_FALSE;
+    }
+    subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
+
+    pSubframe->pSamplesS32 = pDecodedSamplesOut;
+
+    switch (pSubframe->subframeType)
+    {
+        case DRFLAC_SUBFRAME_CONSTANT:
+        {
+            drflac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
+        } break;
+
+        case DRFLAC_SUBFRAME_VERBATIM:
+        {
+            drflac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32);
+        } break;
+
+        case DRFLAC_SUBFRAME_FIXED:
+        {
+            drflac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
+        } break;
+
+        case DRFLAC_SUBFRAME_LPC:
+        {
+            drflac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32);
+        } break;
+
+        default: return DRFLAC_FALSE;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex)
+{
+    drflac_subframe* pSubframe;
+    drflac_uint32 subframeBitsPerSample;
+
+    DRFLAC_ASSERT(bs != NULL);
+    DRFLAC_ASSERT(frame != NULL);
+
+    pSubframe = frame->subframes + subframeIndex;
+    if (!drflac__read_subframe_header(bs, pSubframe)) {
+        return DRFLAC_FALSE;
+    }
+
+    /* Side channels require an extra bit per sample. Took a while to figure that one out... */
+    subframeBitsPerSample = frame->header.bitsPerSample;
+    if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) {
+        subframeBitsPerSample += 1;
+    } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) {
+        subframeBitsPerSample += 1;
+    }
+
+    /* Need to handle wasted bits per sample. */
+    if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) {
+        return DRFLAC_FALSE;
+    }
+    subframeBitsPerSample -= pSubframe->wastedBitsPerSample;
+
+    pSubframe->pSamplesS32 = NULL;
+
+    switch (pSubframe->subframeType)
+    {
+        case DRFLAC_SUBFRAME_CONSTANT:
+        {
+            if (!drflac__seek_bits(bs, subframeBitsPerSample)) {
+                return DRFLAC_FALSE;
+            }
+        } break;
+
+        case DRFLAC_SUBFRAME_VERBATIM:
+        {
+            unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample;
+            if (!drflac__seek_bits(bs, bitsToSeek)) {
+                return DRFLAC_FALSE;
+            }
+        } break;
+
+        case DRFLAC_SUBFRAME_FIXED:
+        {
+            unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
+            if (!drflac__seek_bits(bs, bitsToSeek)) {
+                return DRFLAC_FALSE;
+            }
+
+            if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
+                return DRFLAC_FALSE;
+            }
+        } break;
+
+        case DRFLAC_SUBFRAME_LPC:
+        {
+            drflac_uint8 lpcPrecision;
+
+            unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample;
+            if (!drflac__seek_bits(bs, bitsToSeek)) {
+                return DRFLAC_FALSE;
+            }
+
+            if (!drflac__read_uint8(bs, 4, &lpcPrecision)) {
+                return DRFLAC_FALSE;
+            }
+            if (lpcPrecision == 15) {
+                return DRFLAC_FALSE;    /* Invalid. */
+            }
+            lpcPrecision += 1;
+
+
+            bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5;    /* +5 for shift. */
+            if (!drflac__seek_bits(bs, bitsToSeek)) {
+                return DRFLAC_FALSE;
+            }
+
+            if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) {
+                return DRFLAC_FALSE;
+            }
+        } break;
+
+        default: return DRFLAC_FALSE;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+
+static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment)
+{
+    drflac_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2};
+
+    DRFLAC_ASSERT(channelAssignment <= 10);
+    return lookup[channelAssignment];
+}
+
+static drflac_result drflac__decode_flac_frame(drflac* pFlac)
+{
+    int channelCount;
+    int i;
+    drflac_uint8 paddingSizeInBits;
+    drflac_uint16 desiredCRC16;
+#ifndef DR_FLAC_NO_CRC
+    drflac_uint16 actualCRC16;
+#endif
+
+    /* This function should be called while the stream is sitting on the first byte after the frame header. */
+    DRFLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes));
+
+    /* The frame block size must never be larger than the maximum block size defined by the FLAC stream. */
+    if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) {
+        return DRFLAC_ERROR;
+    }
+
+    /* The number of channels in the frame must match the channel count from the STREAMINFO block. */
+    channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
+    if (channelCount != (int)pFlac->channels) {
+        return DRFLAC_ERROR;
+    }
+
+    for (i = 0; i < channelCount; ++i) {
+        if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) {
+            return DRFLAC_ERROR;
+        }
+    }
+
+    paddingSizeInBits = (drflac_uint8)(DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7);
+    if (paddingSizeInBits > 0) {
+        drflac_uint8 padding = 0;
+        if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) {
+            return DRFLAC_AT_END;
+        }
+    }
+
+#ifndef DR_FLAC_NO_CRC
+    actualCRC16 = drflac__flush_crc16(&pFlac->bs);
+#endif
+    if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
+        return DRFLAC_AT_END;
+    }
+
+#ifndef DR_FLAC_NO_CRC
+    if (actualCRC16 != desiredCRC16) {
+        return DRFLAC_CRC_MISMATCH;    /* CRC mismatch. */
+    }
+#endif
+
+    pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
+
+    return DRFLAC_SUCCESS;
+}
+
+static drflac_result drflac__seek_flac_frame(drflac* pFlac)
+{
+    int channelCount;
+    int i;
+    drflac_uint16 desiredCRC16;
+#ifndef DR_FLAC_NO_CRC
+    drflac_uint16 actualCRC16;
+#endif
+
+    channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
+    for (i = 0; i < channelCount; ++i) {
+        if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) {
+            return DRFLAC_ERROR;
+        }
+    }
+
+    /* Padding. */
+    if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) {
+        return DRFLAC_ERROR;
+    }
+
+    /* CRC. */
+#ifndef DR_FLAC_NO_CRC
+    actualCRC16 = drflac__flush_crc16(&pFlac->bs);
+#endif
+    if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) {
+        return DRFLAC_AT_END;
+    }
+
+#ifndef DR_FLAC_NO_CRC
+    if (actualCRC16 != desiredCRC16) {
+        return DRFLAC_CRC_MISMATCH;    /* CRC mismatch. */
+    }
+#endif
+
+    return DRFLAC_SUCCESS;
+}
+
+static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac)
+{
+    DRFLAC_ASSERT(pFlac != NULL);
+
+    for (;;) {
+        drflac_result result;
+
+        if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+            return DRFLAC_FALSE;
+        }
+
+        result = drflac__decode_flac_frame(pFlac);
+        if (result != DRFLAC_SUCCESS) {
+            if (result == DRFLAC_CRC_MISMATCH) {
+                continue;   /* CRC mismatch. Skip to the next frame. */
+            } else {
+                return DRFLAC_FALSE;
+            }
+        }
+
+        return DRFLAC_TRUE;
+    }
+}
+
+static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drflac_uint64* pFirstPCMFrame, drflac_uint64* pLastPCMFrame)
+{
+    drflac_uint64 firstPCMFrame;
+    drflac_uint64 lastPCMFrame;
+
+    DRFLAC_ASSERT(pFlac != NULL);
+
+    firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber;
+    if (firstPCMFrame == 0) {
+        firstPCMFrame = ((drflac_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames;
+    }
+
+    lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
+    if (lastPCMFrame > 0) {
+        lastPCMFrame -= 1; /* Needs to be zero based. */
+    }
+
+    if (pFirstPCMFrame) {
+        *pFirstPCMFrame = firstPCMFrame;
+    }
+    if (pLastPCMFrame) {
+        *pLastPCMFrame = lastPCMFrame;
+    }
+}
+
+static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac)
+{
+    drflac_bool32 result;
+
+    DRFLAC_ASSERT(pFlac != NULL);
+
+    result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes);
+
+    DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
+    pFlac->currentPCMFrame = 0;
+
+    return result;
+}
+
+static DRFLAC_INLINE drflac_result drflac__seek_to_next_flac_frame(drflac* pFlac)
+{
+    /* This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section. */
+    DRFLAC_ASSERT(pFlac != NULL);
+    return drflac__seek_flac_frame(pFlac);
+}
+
+
+static drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pcmFramesToSeek)
+{
+    drflac_uint64 pcmFramesRead = 0;
+    while (pcmFramesToSeek > 0) {
+        if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
+            if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
+                break;  /* Couldn't read the next frame, so just break from the loop and return. */
+            }
+        } else {
+            if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) {
+                pcmFramesRead   += pcmFramesToSeek;
+                pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)pcmFramesToSeek;   /* <-- Safe cast. Will always be < currentFrame.pcmFramesRemaining < 65536. */
+                pcmFramesToSeek  = 0;
+            } else {
+                pcmFramesRead   += pFlac->currentFLACFrame.pcmFramesRemaining;
+                pcmFramesToSeek -= pFlac->currentFLACFrame.pcmFramesRemaining;
+                pFlac->currentFLACFrame.pcmFramesRemaining = 0;
+            }
+        }
+    }
+
+    pFlac->currentPCMFrame += pcmFramesRead;
+    return pcmFramesRead;
+}
+
+
+static drflac_bool32 drflac__seek_to_pcm_frame__brute_force(drflac* pFlac, drflac_uint64 pcmFrameIndex)
+{
+    drflac_bool32 isMidFrame = DRFLAC_FALSE;
+    drflac_uint64 runningPCMFrameCount;
+
+    DRFLAC_ASSERT(pFlac != NULL);
+
+    /* If we are seeking forward we start from the current position. Otherwise we need to start all the way from the start of the file. */
+    if (pcmFrameIndex >= pFlac->currentPCMFrame) {
+        /* Seeking forward. Need to seek from the current position. */
+        runningPCMFrameCount = pFlac->currentPCMFrame;
+
+        /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */
+        if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
+            if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+                return DRFLAC_FALSE;
+            }
+        } else {
+            isMidFrame = DRFLAC_TRUE;
+        }
+    } else {
+        /* Seeking backwards. Need to seek from the start of the file. */
+        runningPCMFrameCount = 0;
+
+        /* Move back to the start. */
+        if (!drflac__seek_to_first_frame(pFlac)) {
+            return DRFLAC_FALSE;
+        }
+
+        /* Decode the first frame in preparation for sample-exact seeking below. */
+        if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+            return DRFLAC_FALSE;
+        }
+    }
+
+    /*
+    We need to as quickly as possible find the frame that contains the target sample. To do this, we iterate over each frame and inspect its
+    header. If based on the header we can determine that the frame contains the sample, we do a full decode of that frame.
+    */
+    for (;;) {
+        drflac_uint64 pcmFrameCountInThisFLACFrame;
+        drflac_uint64 firstPCMFrameInFLACFrame = 0;
+        drflac_uint64 lastPCMFrameInFLACFrame = 0;
+
+        drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
+
+        pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
+        if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
+            /*
+            The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend
+            it never existed and keep iterating.
+            */
+            drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
+
+            if (!isMidFrame) {
+                drflac_result result = drflac__decode_flac_frame(pFlac);
+                if (result == DRFLAC_SUCCESS) {
+                    /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */
+                    return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;  /* <-- If this fails, something bad has happened (it should never fail). */
+                } else {
+                    if (result == DRFLAC_CRC_MISMATCH) {
+                        goto next_iteration;   /* CRC mismatch. Pretend this frame never existed. */
+                    } else {
+                        return DRFLAC_FALSE;
+                    }
+                }
+            } else {
+                /* We started seeking mid-frame which means we need to skip the frame decoding part. */
+                return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
+            }
+        } else {
+            /*
+            It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this
+            frame never existed and leave the running sample count untouched.
+            */
+            if (!isMidFrame) {
+                drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
+                if (result == DRFLAC_SUCCESS) {
+                    runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
+                } else {
+                    if (result == DRFLAC_CRC_MISMATCH) {
+                        goto next_iteration;   /* CRC mismatch. Pretend this frame never existed. */
+                    } else {
+                        return DRFLAC_FALSE;
+                    }
+                }
+            } else {
+                /*
+                We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with
+                drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header.
+                */
+                runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
+                pFlac->currentFLACFrame.pcmFramesRemaining = 0;
+                isMidFrame = DRFLAC_FALSE;
+            }
+
+            /* If we are seeking to the end of the file and we've just hit it, we're done. */
+            if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
+                return DRFLAC_TRUE;
+            }
+        }
+
+    next_iteration:
+        /* Grab the next frame in preparation for the next iteration. */
+        if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+            return DRFLAC_FALSE;
+        }
+    }
+}
+
+
+#if !defined(DR_FLAC_NO_CRC)
+/*
+We use an average compression ratio to determine our approximate start location. FLAC files are generally about 50%-70% the size of their
+uncompressed counterparts so we'll use this as a basis. I'm going to split the middle and use a factor of 0.6 to determine the starting
+location.
+*/
+#define DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO 0.6f
+
+static drflac_bool32 drflac__seek_to_approximate_flac_frame_to_byte(drflac* pFlac, drflac_uint64 targetByte, drflac_uint64 rangeLo, drflac_uint64 rangeHi, drflac_uint64* pLastSuccessfulSeekOffset)
+{
+    DRFLAC_ASSERT(pFlac != NULL);
+    DRFLAC_ASSERT(pLastSuccessfulSeekOffset != NULL);
+    DRFLAC_ASSERT(targetByte >= rangeLo);
+    DRFLAC_ASSERT(targetByte <= rangeHi);
+
+    *pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes;
+
+    for (;;) {
+        /* After rangeLo == rangeHi == targetByte fails, we need to break out. */
+        drflac_uint64 lastTargetByte = targetByte;
+
+        /* When seeking to a byte, failure probably means we've attempted to seek beyond the end of the stream. To counter this we just halve it each attempt. */
+        if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) {
+            /* If we couldn't even seek to the first byte in the stream we have a problem. Just abandon the whole thing. */
+            if (targetByte == 0) {
+                drflac__seek_to_first_frame(pFlac); /* Try to recover. */
+                return DRFLAC_FALSE;
+            }
+
+            /* Halve the byte location and continue. */
+            targetByte = rangeLo + ((rangeHi - rangeLo)/2);
+            rangeHi = targetByte;
+        } else {
+            /* Getting here should mean that we have seeked to an appropriate byte. */
+
+            /* Clear the details of the FLAC frame so we don't misreport data. */
+            DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame));
+
+            /*
+            Now seek to the next FLAC frame. We need to decode the entire frame (not just the header) because it's possible for the header to incorrectly pass the
+            CRC check and return bad data. We need to decode the entire frame to be more certain. Although this seems unlikely, this has happened to me in testing
+            so it needs to stay this way for now.
+            */
+#if 1
+            if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
+                /* Halve the byte location and continue. */
+                targetByte = rangeLo + ((rangeHi - rangeLo)/2);
+                rangeHi = targetByte;
+            } else {
+                break;
+            }
+#else
+            if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+                /* Halve the byte location and continue. */
+                targetByte = rangeLo + ((rangeHi - rangeLo)/2);
+                rangeHi = targetByte;
+            } else {
+                break;
+            }
+#endif
+        }
+
+        /* We already tried this byte and there are no more to try, break out. */
+        if(targetByte == lastTargetByte) {
+            return DRFLAC_FALSE;
+        }
+    }
+
+    /* The current PCM frame needs to be updated based on the frame we just seeked to. */
+    drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
+
+    DRFLAC_ASSERT(targetByte <= rangeHi);
+
+    *pLastSuccessfulSeekOffset = targetByte;
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 offset)
+{
+    /* This section of code would be used if we were only decoding the FLAC frame header when calling drflac__seek_to_approximate_flac_frame_to_byte(). */
+#if 0
+    if (drflac__decode_flac_frame(pFlac) != DRFLAC_SUCCESS) {
+        /* We failed to decode this frame which may be due to it being corrupt. We'll just use the next valid FLAC frame. */
+        if (drflac__read_and_decode_next_flac_frame(pFlac) == DRFLAC_FALSE) {
+            return DRFLAC_FALSE;
+        }
+    }
+#endif
+
+    return drflac__seek_forward_by_pcm_frames(pFlac, offset) == offset;
+}
+
+
+static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* pFlac, drflac_uint64 pcmFrameIndex, drflac_uint64 byteRangeLo, drflac_uint64 byteRangeHi)
+{
+    /* This assumes pFlac->currentPCMFrame is sitting on byteRangeLo upon entry. */
+
+    drflac_uint64 targetByte;
+    drflac_uint64 pcmRangeLo = pFlac->totalPCMFrameCount;
+    drflac_uint64 pcmRangeHi = 0;
+    drflac_uint64 lastSuccessfulSeekOffset = (drflac_uint64)-1;
+    drflac_uint64 closestSeekOffsetBeforeTargetPCMFrame = byteRangeLo;
+    drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
+
+    targetByte = byteRangeLo + (drflac_uint64)(((drflac_int64)((pcmFrameIndex - pFlac->currentPCMFrame) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO);
+    if (targetByte > byteRangeHi) {
+        targetByte = byteRangeHi;
+    }
+
+    for (;;) {
+        if (drflac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) {
+            /* We found a FLAC frame. We need to check if it contains the sample we're looking for. */
+            drflac_uint64 newPCMRangeLo;
+            drflac_uint64 newPCMRangeHi;
+            drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi);
+
+            /* If we selected the same frame, it means we should be pretty close. Just decode the rest. */
+            if (pcmRangeLo == newPCMRangeLo) {
+                if (!drflac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) {
+                    break;  /* Failed to seek to closest frame. */
+                }
+
+                if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
+                    return DRFLAC_TRUE;
+                } else {
+                    break;  /* Failed to seek forward. */
+                }
+            }
+
+            pcmRangeLo = newPCMRangeLo;
+            pcmRangeHi = newPCMRangeHi;
+
+            if (pcmRangeLo <= pcmFrameIndex && pcmRangeHi >= pcmFrameIndex) {
+                /* The target PCM frame is in this FLAC frame. */
+                if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) {
+                    return DRFLAC_TRUE;
+                } else {
+                    break;  /* Failed to seek to FLAC frame. */
+                }
+            } else {
+                const float approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0f);
+
+                if (pcmRangeLo > pcmFrameIndex) {
+                    /* We seeked too far forward. We need to move our target byte backward and try again. */
+                    byteRangeHi = lastSuccessfulSeekOffset;
+                    if (byteRangeLo > byteRangeHi) {
+                        byteRangeLo = byteRangeHi;
+                    }
+
+                    targetByte = byteRangeLo + ((byteRangeHi - byteRangeLo) / 2);
+                    if (targetByte < byteRangeLo) {
+                        targetByte = byteRangeLo;
+                    }
+                } else /*if (pcmRangeHi < pcmFrameIndex)*/ {
+                    /* We didn't seek far enough. We need to move our target byte forward and try again. */
+
+                    /* If we're close enough we can just seek forward. */
+                    if ((pcmFrameIndex - pcmRangeLo) < seekForwardThreshold) {
+                        if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) {
+                            return DRFLAC_TRUE;
+                        } else {
+                            break;  /* Failed to seek to FLAC frame. */
+                        }
+                    } else {
+                        byteRangeLo = lastSuccessfulSeekOffset;
+                        if (byteRangeHi < byteRangeLo) {
+                            byteRangeHi = byteRangeLo;
+                        }
+
+                        targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * approxCompressionRatio);
+                        if (targetByte > byteRangeHi) {
+                            targetByte = byteRangeHi;
+                        }
+
+                        if (closestSeekOffsetBeforeTargetPCMFrame < lastSuccessfulSeekOffset) {
+                            closestSeekOffsetBeforeTargetPCMFrame = lastSuccessfulSeekOffset;
+                        }
+                    }
+                }
+            }
+        } else {
+            /* Getting here is really bad. We just recover as best we can, but moving to the first frame in the stream, and then abort. */
+            break;
+        }
+    }
+
+    drflac__seek_to_first_frame(pFlac); /* <-- Try to recover. */
+    return DRFLAC_FALSE;
+}
+
+static drflac_bool32 drflac__seek_to_pcm_frame__binary_search(drflac* pFlac, drflac_uint64 pcmFrameIndex)
+{
+    drflac_uint64 byteRangeLo;
+    drflac_uint64 byteRangeHi;
+    drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096;
+
+    /* Our algorithm currently assumes the FLAC stream is currently sitting at the start. */
+    if (drflac__seek_to_first_frame(pFlac) == DRFLAC_FALSE) {
+        return DRFLAC_FALSE;
+    }
+
+    /* If we're close enough to the start, just move to the start and seek forward. */
+    if (pcmFrameIndex < seekForwardThreshold) {
+        return drflac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex;
+    }
+
+    /*
+    Our starting byte range is the byte position of the first FLAC frame and the approximate end of the file as if it were completely uncompressed. This ensures
+    the entire file is included, even though most of the time it'll exceed the end of the actual stream. This is OK as the frame searching logic will handle it.
+    */
+    byteRangeLo = pFlac->firstFLACFramePosInBytes;
+    byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
+
+    return drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi);
+}
+#endif  /* !DR_FLAC_NO_CRC */
+
+static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac_uint64 pcmFrameIndex)
+{
+    drflac_uint32 iClosestSeekpoint = 0;
+    drflac_bool32 isMidFrame = DRFLAC_FALSE;
+    drflac_uint64 runningPCMFrameCount;
+    drflac_uint32 iSeekpoint;
+
+
+    DRFLAC_ASSERT(pFlac != NULL);
+
+    if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) {
+        return DRFLAC_FALSE;
+    }
+
+    for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
+        if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) {
+            break;
+        }
+
+        iClosestSeekpoint = iSeekpoint;
+    }
+
+    /* There's been cases where the seek table contains only zeros. We need to do some basic validation on the closest seekpoint. */
+    if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) {
+        return DRFLAC_FALSE;
+    }
+    if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) {
+        return DRFLAC_FALSE;
+    }
+
+#if !defined(DR_FLAC_NO_CRC)
+    /* At this point we should know the closest seek point. We can use a binary search for this. We need to know the total sample count for this. */
+    if (pFlac->totalPCMFrameCount > 0) {
+        drflac_uint64 byteRangeLo;
+        drflac_uint64 byteRangeHi;
+
+        byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f);
+        byteRangeLo = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset;
+
+        /*
+        If our closest seek point is not the last one, we only need to search between it and the next one. The section below calculates an appropriate starting
+        value for byteRangeHi which will clamp it appropriately.
+
+        Note that the next seekpoint must have an offset greater than the closest seekpoint because otherwise our binary search algorithm will break down. There
+        have been cases where a seektable consists of seek points where every byte offset is set to 0 which causes problems. If this happens we need to abort.
+        */
+        if (iClosestSeekpoint < pFlac->seekpointCount-1) {
+            drflac_uint32 iNextSeekpoint = iClosestSeekpoint + 1;
+
+            /* Basic validation on the seekpoints to ensure they're usable. */
+            if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) {
+                return DRFLAC_FALSE;    /* The next seekpoint doesn't look right. The seek table cannot be trusted from here. Abort. */
+            }
+
+            if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((drflac_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) { /* Make sure it's not a placeholder seekpoint. */
+                byteRangeHi = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset - 1; /* byteRangeHi must be zero based. */
+            }
+        }
+
+        if (drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
+            if (drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+                drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL);
+
+                if (drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi)) {
+                    return DRFLAC_TRUE;
+                }
+            }
+        }
+    }
+#endif  /* !DR_FLAC_NO_CRC */
+
+    /* Getting here means we need to use a slower algorithm because the binary search method failed or cannot be used. */
+
+    /*
+    If we are seeking forward and the closest seekpoint is _before_ the current sample, we just seek forward from where we are. Otherwise we start seeking
+    from the seekpoint's first sample.
+    */
+    if (pcmFrameIndex >= pFlac->currentPCMFrame && pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame <= pFlac->currentPCMFrame) {
+        /* Optimized case. Just seek forward from where we are. */
+        runningPCMFrameCount = pFlac->currentPCMFrame;
+
+        /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */
+        if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
+            if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+                return DRFLAC_FALSE;
+            }
+        } else {
+            isMidFrame = DRFLAC_TRUE;
+        }
+    } else {
+        /* Slower case. Seek to the start of the seekpoint and then seek forward from there. */
+        runningPCMFrameCount = pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame;
+
+        if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) {
+            return DRFLAC_FALSE;
+        }
+
+        /* Grab the frame the seekpoint is sitting on in preparation for the sample-exact seeking below. */
+        if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+            return DRFLAC_FALSE;
+        }
+    }
+
+    for (;;) {
+        drflac_uint64 pcmFrameCountInThisFLACFrame;
+        drflac_uint64 firstPCMFrameInFLACFrame = 0;
+        drflac_uint64 lastPCMFrameInFLACFrame = 0;
+
+        drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
+
+        pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
+        if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) {
+            /*
+            The sample should be in this frame. We need to fully decode it, but if it's an invalid frame (a CRC mismatch) we need to pretend
+            it never existed and keep iterating.
+            */
+            drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount;
+
+            if (!isMidFrame) {
+                drflac_result result = drflac__decode_flac_frame(pFlac);
+                if (result == DRFLAC_SUCCESS) {
+                    /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */
+                    return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;  /* <-- If this fails, something bad has happened (it should never fail). */
+                } else {
+                    if (result == DRFLAC_CRC_MISMATCH) {
+                        goto next_iteration;   /* CRC mismatch. Pretend this frame never existed. */
+                    } else {
+                        return DRFLAC_FALSE;
+                    }
+                }
+            } else {
+                /* We started seeking mid-frame which means we need to skip the frame decoding part. */
+                return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;
+            }
+        } else {
+            /*
+            It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this
+            frame never existed and leave the running sample count untouched.
+            */
+            if (!isMidFrame) {
+                drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
+                if (result == DRFLAC_SUCCESS) {
+                    runningPCMFrameCount += pcmFrameCountInThisFLACFrame;
+                } else {
+                    if (result == DRFLAC_CRC_MISMATCH) {
+                        goto next_iteration;   /* CRC mismatch. Pretend this frame never existed. */
+                    } else {
+                        return DRFLAC_FALSE;
+                    }
+                }
+            } else {
+                /*
+                We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with
+                drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header.
+                */
+                runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining;
+                pFlac->currentFLACFrame.pcmFramesRemaining = 0;
+                isMidFrame = DRFLAC_FALSE;
+            }
+
+            /* If we are seeking to the end of the file and we've just hit it, we're done. */
+            if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) {
+                return DRFLAC_TRUE;
+            }
+        }
+
+    next_iteration:
+        /* Grab the next frame in preparation for the next iteration. */
+        if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+            return DRFLAC_FALSE;
+        }
+    }
+}
+
+
+#ifndef DR_FLAC_NO_OGG
+typedef struct
+{
+    drflac_uint8 capturePattern[4];  /* Should be "OggS" */
+    drflac_uint8 structureVersion;   /* Always 0. */
+    drflac_uint8 headerType;
+    drflac_uint64 granulePosition;
+    drflac_uint32 serialNumber;
+    drflac_uint32 sequenceNumber;
+    drflac_uint32 checksum;
+    drflac_uint8 segmentCount;
+    drflac_uint8 segmentTable[255];
+} drflac_ogg_page_header;
+#endif
+
+typedef struct
+{
+    drflac_read_proc onRead;
+    drflac_seek_proc onSeek;
+    drflac_meta_proc onMeta;
+    drflac_container container;
+    void* pUserData;
+    void* pUserDataMD;
+    drflac_uint32 sampleRate;
+    drflac_uint8  channels;
+    drflac_uint8  bitsPerSample;
+    drflac_uint64 totalPCMFrameCount;
+    drflac_uint16 maxBlockSizeInPCMFrames;
+    drflac_uint64 runningFilePos;
+    drflac_bool32 hasStreamInfoBlock;
+    drflac_bool32 hasMetadataBlocks;
+    drflac_bs bs;                           /* <-- A bit streamer is required for loading data during initialization. */
+    drflac_frame_header firstFrameHeader;   /* <-- The header of the first frame that was read during relaxed initalization. Only set if there is no STREAMINFO block. */
+
+#ifndef DR_FLAC_NO_OGG
+    drflac_uint32 oggSerial;
+    drflac_uint64 oggFirstBytePos;
+    drflac_ogg_page_header oggBosHeader;
+#endif
+} drflac_init_info;
+
+static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
+{
+    blockHeader = drflac__be2host_32(blockHeader);
+    *isLastBlock = (drflac_uint8)((blockHeader & 0x80000000UL) >> 31);
+    *blockType   = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24);
+    *blockSize   =                (blockHeader & 0x00FFFFFFUL);
+}
+
+static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize)
+{
+    drflac_uint32 blockHeader;
+
+    *blockSize = 0;
+    if (onRead(pUserData, &blockHeader, 4) != 4) {
+        return DRFLAC_FALSE;
+    }
+
+    drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize);
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo)
+{
+    drflac_uint32 blockSizes;
+    drflac_uint64 frameSizes = 0;
+    drflac_uint64 importantProps;
+    drflac_uint8 md5[16];
+
+    /* min/max block size. */
+    if (onRead(pUserData, &blockSizes, 4) != 4) {
+        return DRFLAC_FALSE;
+    }
+
+    /* min/max frame size. */
+    if (onRead(pUserData, &frameSizes, 6) != 6) {
+        return DRFLAC_FALSE;
+    }
+
+    /* Sample rate, channels, bits per sample and total sample count. */
+    if (onRead(pUserData, &importantProps, 8) != 8) {
+        return DRFLAC_FALSE;
+    }
+
+    /* MD5 */
+    if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) {
+        return DRFLAC_FALSE;
+    }
+
+    blockSizes     = drflac__be2host_32(blockSizes);
+    frameSizes     = drflac__be2host_64(frameSizes);
+    importantProps = drflac__be2host_64(importantProps);
+
+    pStreamInfo->minBlockSizeInPCMFrames = (drflac_uint16)((blockSizes & 0xFFFF0000) >> 16);
+    pStreamInfo->maxBlockSizeInPCMFrames = (drflac_uint16) (blockSizes & 0x0000FFFF);
+    pStreamInfo->minFrameSizeInPCMFrames = (drflac_uint32)((frameSizes     &  (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40);
+    pStreamInfo->maxFrameSizeInPCMFrames = (drflac_uint32)((frameSizes     &  (((drflac_uint64)0x00FFFFFF << 16) <<  0)) >> 16);
+    pStreamInfo->sampleRate              = (drflac_uint32)((importantProps &  (((drflac_uint64)0x000FFFFF << 16) << 28)) >> 44);
+    pStreamInfo->channels                = (drflac_uint8 )((importantProps &  (((drflac_uint64)0x0000000E << 16) << 24)) >> 41) + 1;
+    pStreamInfo->bitsPerSample           = (drflac_uint8 )((importantProps &  (((drflac_uint64)0x0000001F << 16) << 20)) >> 36) + 1;
+    pStreamInfo->totalPCMFrameCount      =                ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF)));
+    DRFLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5));
+
+    return DRFLAC_TRUE;
+}
+
+
+static void* drflac__malloc_default(size_t sz, void* pUserData)
+{
+    (void)pUserData;
+    return DRFLAC_MALLOC(sz);
+}
+
+static void* drflac__realloc_default(void* p, size_t sz, void* pUserData)
+{
+    (void)pUserData;
+    return DRFLAC_REALLOC(p, sz);
+}
+
+static void drflac__free_default(void* p, void* pUserData)
+{
+    (void)pUserData;
+    DRFLAC_FREE(p);
+}
+
+
+static void* drflac__malloc_from_callbacks(size_t sz, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    if (pAllocationCallbacks == NULL) {
+        return NULL;
+    }
+
+    if (pAllocationCallbacks->onMalloc != NULL) {
+        return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData);
+    }
+
+    /* Try using realloc(). */
+    if (pAllocationCallbacks->onRealloc != NULL) {
+        return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData);
+    }
+
+    return NULL;
+}
+
+static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    if (pAllocationCallbacks == NULL) {
+        return NULL;
+    }
+
+    if (pAllocationCallbacks->onRealloc != NULL) {
+        return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData);
+    }
+
+    /* Try emulating realloc() in terms of malloc()/free(). */
+    if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) {
+        void* p2;
+
+        p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData);
+        if (p2 == NULL) {
+            return NULL;
+        }
+
+        if (p != NULL) {
+            DRFLAC_COPY_MEMORY(p2, p, szOld);
+            pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
+        }
+
+        return p2;
+    }
+
+    return NULL;
+}
+
+static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    if (p == NULL || pAllocationCallbacks == NULL) {
+        return;
+    }
+
+    if (pAllocationCallbacks->onFree != NULL) {
+        pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData);
+    }
+}
+
+
+static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeektableSize, drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    /*
+    We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that
+    we'll be sitting on byte 42.
+    */
+    drflac_uint64 runningFilePos = 42;
+    drflac_uint64 seektablePos   = 0;
+    drflac_uint32 seektableSize  = 0;
+
+    for (;;) {
+        drflac_metadata metadata;
+        drflac_uint8 isLastBlock = 0;
+        drflac_uint8 blockType;
+        drflac_uint32 blockSize;
+        if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) {
+            return DRFLAC_FALSE;
+        }
+        runningFilePos += 4;
+
+        metadata.type = blockType;
+        metadata.pRawData = NULL;
+        metadata.rawDataSize = 0;
+
+        switch (blockType)
+        {
+            case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION:
+            {
+                if (blockSize < 4) {
+                    return DRFLAC_FALSE;
+                }
+
+                if (onMeta) {
+                    void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
+                    if (pRawData == NULL) {
+                        return DRFLAC_FALSE;
+                    }
+
+                    if (onRead(pUserData, pRawData, blockSize) != blockSize) {
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+
+                    metadata.pRawData = pRawData;
+                    metadata.rawDataSize = blockSize;
+                    metadata.data.application.id       = drflac__be2host_32(*(drflac_uint32*)pRawData);
+                    metadata.data.application.pData    = (const void*)((drflac_uint8*)pRawData + sizeof(drflac_uint32));
+                    metadata.data.application.dataSize = blockSize - sizeof(drflac_uint32);
+                    onMeta(pUserDataMD, &metadata);
+
+                    drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                }
+            } break;
+
+            case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE:
+            {
+                seektablePos  = runningFilePos;
+                seektableSize = blockSize;
+
+                if (onMeta) {
+                    drflac_uint32 iSeekpoint;
+                    void* pRawData;
+
+                    pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
+                    if (pRawData == NULL) {
+                        return DRFLAC_FALSE;
+                    }
+
+                    if (onRead(pUserData, pRawData, blockSize) != blockSize) {
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+
+                    metadata.pRawData = pRawData;
+                    metadata.rawDataSize = blockSize;
+                    metadata.data.seektable.seekpointCount = blockSize/sizeof(drflac_seekpoint);
+                    metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData;
+
+                    /* Endian swap. */
+                    for (iSeekpoint = 0; iSeekpoint < metadata.data.seektable.seekpointCount; ++iSeekpoint) {
+                        drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint;
+                        pSeekpoint->firstPCMFrame   = drflac__be2host_64(pSeekpoint->firstPCMFrame);
+                        pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset);
+                        pSeekpoint->pcmFrameCount   = drflac__be2host_16(pSeekpoint->pcmFrameCount);
+                    }
+
+                    onMeta(pUserDataMD, &metadata);
+
+                    drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                }
+            } break;
+
+            case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT:
+            {
+                if (blockSize < 8) {
+                    return DRFLAC_FALSE;
+                }
+
+                if (onMeta) {
+                    void* pRawData;
+                    const char* pRunningData;
+                    const char* pRunningDataEnd;
+                    drflac_uint32 i;
+
+                    pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
+                    if (pRawData == NULL) {
+                        return DRFLAC_FALSE;
+                    }
+
+                    if (onRead(pUserData, pRawData, blockSize) != blockSize) {
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+
+                    metadata.pRawData = pRawData;
+                    metadata.rawDataSize = blockSize;
+
+                    pRunningData    = (const char*)pRawData;
+                    pRunningDataEnd = (const char*)pRawData + blockSize;
+
+                    metadata.data.vorbis_comment.vendorLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+
+                    /* Need space for the rest of the block */
+                    if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+                    metadata.data.vorbis_comment.vendor       = pRunningData;                                            pRunningData += metadata.data.vorbis_comment.vendorLength;
+                    metadata.data.vorbis_comment.commentCount = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+
+                    /* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */
+                    if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { /* <-- Note the order of operations to avoid overflow to a valid value */
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+                    metadata.data.vorbis_comment.pComments    = pRunningData;
+
+                    /* Check that the comments section is valid before passing it to the callback */
+                    for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) {
+                        drflac_uint32 commentLength;
+
+                        if (pRunningDataEnd - pRunningData < 4) {
+                            drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                            return DRFLAC_FALSE;
+                        }
+
+                        commentLength = drflac__le2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+                        if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
+                            drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                            return DRFLAC_FALSE;
+                        }
+                        pRunningData += commentLength;
+                    }
+
+                    onMeta(pUserDataMD, &metadata);
+
+                    drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                }
+            } break;
+
+            case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET:
+            {
+                if (blockSize < 396) {
+                    return DRFLAC_FALSE;
+                }
+
+                if (onMeta) {
+                    void* pRawData;
+                    const char* pRunningData;
+                    const char* pRunningDataEnd;
+                    drflac_uint8 iTrack;
+                    drflac_uint8 iIndex;
+
+                    pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
+                    if (pRawData == NULL) {
+                        return DRFLAC_FALSE;
+                    }
+
+                    if (onRead(pUserData, pRawData, blockSize) != blockSize) {
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+
+                    metadata.pRawData = pRawData;
+                    metadata.rawDataSize = blockSize;
+
+                    pRunningData    = (const char*)pRawData;
+                    pRunningDataEnd = (const char*)pRawData + blockSize;
+
+                    DRFLAC_COPY_MEMORY(metadata.data.cuesheet.catalog, pRunningData, 128);                              pRunningData += 128;
+                    metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8;
+                    metadata.data.cuesheet.isCD              = (pRunningData[0] & 0x80) != 0;                           pRunningData += 259;
+                    metadata.data.cuesheet.trackCount        = pRunningData[0];                                         pRunningData += 1;
+                    metadata.data.cuesheet.pTrackData        = pRunningData;
+
+                    /* Check that the cuesheet tracks are valid before passing it to the callback */
+                    for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) {
+                        drflac_uint8 indexCount;
+                        drflac_uint32 indexPointSize;
+
+                        if (pRunningDataEnd - pRunningData < 36) {
+                            drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                            return DRFLAC_FALSE;
+                        }
+
+                        /* Skip to the index point count */
+                        pRunningData += 35;
+                        indexCount = pRunningData[0]; pRunningData += 1;
+                        indexPointSize = indexCount * sizeof(drflac_cuesheet_track_index);
+                        if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) {
+                            drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                            return DRFLAC_FALSE;
+                        }
+
+                        /* Endian swap. */
+                        for (iIndex = 0; iIndex < indexCount; ++iIndex) {
+                            drflac_cuesheet_track_index* pTrack = (drflac_cuesheet_track_index*)pRunningData;
+                            pRunningData += sizeof(drflac_cuesheet_track_index);
+                            pTrack->offset = drflac__be2host_64(pTrack->offset);
+                        }
+                    }
+
+                    onMeta(pUserDataMD, &metadata);
+
+                    drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                }
+            } break;
+
+            case DRFLAC_METADATA_BLOCK_TYPE_PICTURE:
+            {
+                if (blockSize < 32) {
+                    return DRFLAC_FALSE;
+                }
+
+                if (onMeta) {
+                    void* pRawData;
+                    const char* pRunningData;
+                    const char* pRunningDataEnd;
+
+                    pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
+                    if (pRawData == NULL) {
+                        return DRFLAC_FALSE;
+                    }
+
+                    if (onRead(pUserData, pRawData, blockSize) != blockSize) {
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+
+                    metadata.pRawData = pRawData;
+                    metadata.rawDataSize = blockSize;
+
+                    pRunningData    = (const char*)pRawData;
+                    pRunningDataEnd = (const char*)pRawData + blockSize;
+
+                    metadata.data.picture.type       = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+                    metadata.data.picture.mimeLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+
+                    /* Need space for the rest of the block */
+                    if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+                    metadata.data.picture.mime              = pRunningData;                                            pRunningData += metadata.data.picture.mimeLength;
+                    metadata.data.picture.descriptionLength = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+
+                    /* Need space for the rest of the block */
+                    if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { /* <-- Note the order of operations to avoid overflow to a valid value */
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+                    metadata.data.picture.description     = pRunningData;                                            pRunningData += metadata.data.picture.descriptionLength;
+                    metadata.data.picture.width           = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+                    metadata.data.picture.height          = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+                    metadata.data.picture.colorDepth      = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+                    metadata.data.picture.indexColorCount = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+                    metadata.data.picture.pictureDataSize = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+                    metadata.data.picture.pPictureData    = (const drflac_uint8*)pRunningData;
+
+                    /* Need space for the picture after the block */
+                    if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { /* <-- Note the order of operations to avoid overflow to a valid value */
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+
+                    onMeta(pUserDataMD, &metadata);
+
+                    drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                }
+            } break;
+
+            case DRFLAC_METADATA_BLOCK_TYPE_PADDING:
+            {
+                if (onMeta) {
+                    metadata.data.padding.unused = 0;
+
+                    /* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */
+                    if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
+                        isLastBlock = DRFLAC_TRUE;  /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
+                    } else {
+                        onMeta(pUserDataMD, &metadata);
+                    }
+                }
+            } break;
+
+            case DRFLAC_METADATA_BLOCK_TYPE_INVALID:
+            {
+                /* Invalid chunk. Just skip over this one. */
+                if (onMeta) {
+                    if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
+                        isLastBlock = DRFLAC_TRUE;  /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */
+                    }
+                }
+            } break;
+
+            default:
+            {
+                /*
+                It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we
+                can at the very least report the chunk to the application and let it look at the raw data.
+                */
+                if (onMeta) {
+                    void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks);
+                    if (pRawData == NULL) {
+                        return DRFLAC_FALSE;
+                    }
+
+                    if (onRead(pUserData, pRawData, blockSize) != blockSize) {
+                        drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                        return DRFLAC_FALSE;
+                    }
+
+                    metadata.pRawData = pRawData;
+                    metadata.rawDataSize = blockSize;
+                    onMeta(pUserDataMD, &metadata);
+
+                    drflac__free_from_callbacks(pRawData, pAllocationCallbacks);
+                }
+            } break;
+        }
+
+        /* If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. */
+        if (onMeta == NULL && blockSize > 0) {
+            if (!onSeek(pUserData, blockSize, drflac_seek_origin_current)) {
+                isLastBlock = DRFLAC_TRUE;
+            }
+        }
+
+        runningFilePos += blockSize;
+        if (isLastBlock) {
+            break;
+        }
+    }
+
+    *pSeektablePos = seektablePos;
+    *pSeektableSize = seektableSize;
+    *pFirstFramePos = runningFilePos;
+
+    return DRFLAC_TRUE;
+}
+
+static drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed)
+{
+    /* Pre Condition: The bit stream should be sitting just past the 4-byte id header. */
+
+    drflac_uint8 isLastBlock;
+    drflac_uint8 blockType;
+    drflac_uint32 blockSize;
+
+    (void)onSeek;
+
+    pInit->container = drflac_container_native;
+
+    /* The first metadata block should be the STREAMINFO block. */
+    if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
+        return DRFLAC_FALSE;
+    }
+
+    if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
+        if (!relaxed) {
+            /* We're opening in strict mode and the first block is not the STREAMINFO block. Error. */
+            return DRFLAC_FALSE;
+        } else {
+            /*
+            Relaxed mode. To open from here we need to just find the first frame and set the sample rate, etc. to whatever is defined
+            for that frame.
+            */
+            pInit->hasStreamInfoBlock = DRFLAC_FALSE;
+            pInit->hasMetadataBlocks  = DRFLAC_FALSE;
+
+            if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) {
+                return DRFLAC_FALSE;    /* Couldn't find a frame. */
+            }
+
+            if (pInit->firstFrameHeader.bitsPerSample == 0) {
+                return DRFLAC_FALSE;    /* Failed to initialize because the first frame depends on the STREAMINFO block, which does not exist. */
+            }
+
+            pInit->sampleRate              = pInit->firstFrameHeader.sampleRate;
+            pInit->channels                = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment);
+            pInit->bitsPerSample           = pInit->firstFrameHeader.bitsPerSample;
+            pInit->maxBlockSizeInPCMFrames = 65535;   /* <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo */
+            return DRFLAC_TRUE;
+        }
+    } else {
+        drflac_streaminfo streaminfo;
+        if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
+            return DRFLAC_FALSE;
+        }
+
+        pInit->hasStreamInfoBlock      = DRFLAC_TRUE;
+        pInit->sampleRate              = streaminfo.sampleRate;
+        pInit->channels                = streaminfo.channels;
+        pInit->bitsPerSample           = streaminfo.bitsPerSample;
+        pInit->totalPCMFrameCount      = streaminfo.totalPCMFrameCount;
+        pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames;    /* Don't care about the min block size - only the max (used for determining the size of the memory allocation). */
+        pInit->hasMetadataBlocks       = !isLastBlock;
+
+        if (onMeta) {
+            drflac_metadata metadata;
+            metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
+            metadata.pRawData = NULL;
+            metadata.rawDataSize = 0;
+            metadata.data.streaminfo = streaminfo;
+            onMeta(pUserDataMD, &metadata);
+        }
+
+        return DRFLAC_TRUE;
+    }
+}
+
+#ifndef DR_FLAC_NO_OGG
+#define DRFLAC_OGG_MAX_PAGE_SIZE            65307
+#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32    1605413199  /* CRC-32 of "OggS". */
+
+typedef enum
+{
+    drflac_ogg_recover_on_crc_mismatch,
+    drflac_ogg_fail_on_crc_mismatch
+} drflac_ogg_crc_mismatch_recovery;
+
+#ifndef DR_FLAC_NO_CRC
+static drflac_uint32 drflac__crc32_table[] = {
+    0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L,
+    0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L,
+    0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L,
+    0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
+    0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L,
+    0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L,
+    0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L,
+    0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL,
+    0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
+    0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L,
+    0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L,
+    0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL,
+    0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L,
+    0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
+    0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L,
+    0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL,
+    0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL,
+    0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L,
+    0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
+    0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL,
+    0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL,
+    0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L,
+    0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L,
+    0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
+    0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL,
+    0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L,
+    0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L,
+    0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL,
+    0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
+    0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L,
+    0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L,
+    0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL,
+    0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L,
+    0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
+    0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL,
+    0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L,
+    0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L,
+    0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL,
+    0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
+    0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L,
+    0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L,
+    0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL,
+    0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL,
+    0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
+    0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L,
+    0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL,
+    0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL,
+    0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L,
+    0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
+    0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL,
+    0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L,
+    0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L,
+    0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L,
+    0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
+    0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L,
+    0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L,
+    0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L,
+    0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL,
+    0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
+    0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L,
+    0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L,
+    0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL,
+    0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L,
+    0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
+};
+#endif
+
+static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data)
+{
+#ifndef DR_FLAC_NO_CRC
+    return (crc32 << 8) ^ drflac__crc32_table[(drflac_uint8)((crc32 >> 24) & 0xFF) ^ data];
+#else
+    (void)data;
+    return crc32;
+#endif
+}
+
+#if 0
+static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint32(drflac_uint32 crc32, drflac_uint32 data)
+{
+    crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 24) & 0xFF));
+    crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 16) & 0xFF));
+    crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >>  8) & 0xFF));
+    crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >>  0) & 0xFF));
+    return crc32;
+}
+
+static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drflac_uint64 data)
+{
+    crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 32) & 0xFFFFFFFF));
+    crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >>  0) & 0xFFFFFFFF));
+    return crc32;
+}
+#endif
+
+static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize)
+{
+    /* This can be optimized. */
+    drflac_uint32 i;
+    for (i = 0; i < dataSize; ++i) {
+        crc32 = drflac_crc32_byte(crc32, pData[i]);
+    }
+    return crc32;
+}
+
+
+static DRFLAC_INLINE drflac_bool32 drflac_ogg__is_capture_pattern(drflac_uint8 pattern[4])
+{
+    return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S';
+}
+
+static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader)
+{
+    return 27 + pHeader->segmentCount;
+}
+
+static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader)
+{
+    drflac_uint32 pageBodySize = 0;
+    int i;
+
+    for (i = 0; i < pHeader->segmentCount; ++i) {
+        pageBodySize += pHeader->segmentTable[i];
+    }
+
+    return pageBodySize;
+}
+
+static drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32)
+{
+    drflac_uint8 data[23];
+    drflac_uint32 i;
+
+    DRFLAC_ASSERT(*pCRC32 == DRFLAC_OGG_CAPTURE_PATTERN_CRC32);
+
+    if (onRead(pUserData, data, 23) != 23) {
+        return DRFLAC_AT_END;
+    }
+    *pBytesRead += 23;
+
+    /*
+    It's not actually used, but set the capture pattern to 'OggS' for completeness. Not doing this will cause static analysers to complain about
+    us trying to access uninitialized data. We could alternatively just comment out this member of the drflac_ogg_page_header structure, but I
+    like to have it map to the structure of the underlying data.
+    */
+    pHeader->capturePattern[0] = 'O';
+    pHeader->capturePattern[1] = 'g';
+    pHeader->capturePattern[2] = 'g';
+    pHeader->capturePattern[3] = 'S';
+
+    pHeader->structureVersion = data[0];
+    pHeader->headerType       = data[1];
+    DRFLAC_COPY_MEMORY(&pHeader->granulePosition, &data[ 2], 8);
+    DRFLAC_COPY_MEMORY(&pHeader->serialNumber,    &data[10], 4);
+    DRFLAC_COPY_MEMORY(&pHeader->sequenceNumber,  &data[14], 4);
+    DRFLAC_COPY_MEMORY(&pHeader->checksum,        &data[18], 4);
+    pHeader->segmentCount     = data[22];
+
+    /* Calculate the CRC. Note that for the calculation the checksum part of the page needs to be set to 0. */
+    data[18] = 0;
+    data[19] = 0;
+    data[20] = 0;
+    data[21] = 0;
+
+    for (i = 0; i < 23; ++i) {
+        *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]);
+    }
+
+
+    if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) {
+        return DRFLAC_AT_END;
+    }
+    *pBytesRead += pHeader->segmentCount;
+
+    for (i = 0; i < pHeader->segmentCount; ++i) {
+        *pCRC32 = drflac_crc32_byte(*pCRC32, pHeader->segmentTable[i]);
+    }
+
+    return DRFLAC_SUCCESS;
+}
+
+static drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32)
+{
+    drflac_uint8 id[4];
+
+    *pBytesRead = 0;
+
+    if (onRead(pUserData, id, 4) != 4) {
+        return DRFLAC_AT_END;
+    }
+    *pBytesRead += 4;
+
+    /* We need to read byte-by-byte until we find the OggS capture pattern. */
+    for (;;) {
+        if (drflac_ogg__is_capture_pattern(id)) {
+            drflac_result result;
+
+            *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32;
+
+            result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32);
+            if (result == DRFLAC_SUCCESS) {
+                return DRFLAC_SUCCESS;
+            } else {
+                if (result == DRFLAC_CRC_MISMATCH) {
+                    continue;
+                } else {
+                    return result;
+                }
+            }
+        } else {
+            /* The first 4 bytes did not equal the capture pattern. Read the next byte and try again. */
+            id[0] = id[1];
+            id[1] = id[2];
+            id[2] = id[3];
+            if (onRead(pUserData, &id[3], 1) != 1) {
+                return DRFLAC_AT_END;
+            }
+            *pBytesRead += 1;
+        }
+    }
+}
+
+
+/*
+The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works
+in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is designed
+in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type
+dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from
+the physical Ogg bitstream are converted and delivered in native FLAC format.
+*/
+typedef struct
+{
+    drflac_read_proc onRead;                /* The original onRead callback from drflac_open() and family. */
+    drflac_seek_proc onSeek;                /* The original onSeek callback from drflac_open() and family. */
+    void* pUserData;                        /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */
+    drflac_uint64 currentBytePos;           /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */
+    drflac_uint64 firstBytePos;             /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */
+    drflac_uint32 serialNumber;             /* The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. */
+    drflac_ogg_page_header bosPageHeader;   /* Used for seeking. */
+    drflac_ogg_page_header currentPageHeader;
+    drflac_uint32 bytesRemainingInPage;
+    drflac_uint32 pageDataSize;
+    drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE];
+} drflac_oggbs; /* oggbs = Ogg Bitstream */
+
+static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead)
+{
+    size_t bytesActuallyRead = oggbs->onRead(oggbs->pUserData, bufferOut, bytesToRead);
+    oggbs->currentBytePos += bytesActuallyRead;
+
+    return bytesActuallyRead;
+}
+
+static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin)
+{
+    if (origin == drflac_seek_origin_start) {
+        if (offset <= 0x7FFFFFFF) {
+            if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_start)) {
+                return DRFLAC_FALSE;
+            }
+            oggbs->currentBytePos = offset;
+
+            return DRFLAC_TRUE;
+        } else {
+            if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_start)) {
+                return DRFLAC_FALSE;
+            }
+            oggbs->currentBytePos = offset;
+
+            return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, drflac_seek_origin_current);
+        }
+    } else {
+        while (offset > 0x7FFFFFFF) {
+            if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, drflac_seek_origin_current)) {
+                return DRFLAC_FALSE;
+            }
+            oggbs->currentBytePos += 0x7FFFFFFF;
+            offset -= 0x7FFFFFFF;
+        }
+
+        if (!oggbs->onSeek(oggbs->pUserData, (int)offset, drflac_seek_origin_current)) {    /* <-- Safe cast thanks to the loop above. */
+            return DRFLAC_FALSE;
+        }
+        oggbs->currentBytePos += offset;
+
+        return DRFLAC_TRUE;
+    }
+}
+
+static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_ogg_crc_mismatch_recovery recoveryMethod)
+{
+    drflac_ogg_page_header header;
+    for (;;) {
+        drflac_uint32 crc32 = 0;
+        drflac_uint32 bytesRead;
+        drflac_uint32 pageBodySize;
+#ifndef DR_FLAC_NO_CRC
+        drflac_uint32 actualCRC32;
+#endif
+
+        if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
+            return DRFLAC_FALSE;
+        }
+        oggbs->currentBytePos += bytesRead;
+
+        pageBodySize = drflac_ogg__get_page_body_size(&header);
+        if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) {
+            continue;   /* Invalid page size. Assume it's corrupted and just move to the next page. */
+        }
+
+        if (header.serialNumber != oggbs->serialNumber) {
+            /* It's not a FLAC page. Skip it. */
+            if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, drflac_seek_origin_current)) {
+                return DRFLAC_FALSE;
+            }
+            continue;
+        }
+
+
+        /* We need to read the entire page and then do a CRC check on it. If there's a CRC mismatch we need to skip this page. */
+        if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) {
+            return DRFLAC_FALSE;
+        }
+        oggbs->pageDataSize = pageBodySize;
+
+#ifndef DR_FLAC_NO_CRC
+        actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize);
+        if (actualCRC32 != header.checksum) {
+            if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) {
+                continue;   /* CRC mismatch. Skip this page. */
+            } else {
+                /*
+                Even though we are failing on a CRC mismatch, we still want our stream to be in a good state. Therefore we
+                go to the next valid page to ensure we're in a good state, but return false to let the caller know that the
+                seek did not fully complete.
+                */
+                drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch);
+                return DRFLAC_FALSE;
+            }
+        }
+#else
+        (void)recoveryMethod;   /* <-- Silence a warning. */
+#endif
+
+        oggbs->currentPageHeader = header;
+        oggbs->bytesRemainingInPage = pageBodySize;
+        return DRFLAC_TRUE;
+    }
+}
+
+/* Function below is unused at the moment, but I might be re-adding it later. */
+#if 0
+static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg)
+{
+    drflac_uint32 bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage;
+    drflac_uint8 iSeg = 0;
+    drflac_uint32 iByte = 0;
+    while (iByte < bytesConsumedInPage) {
+        drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
+        if (iByte + segmentSize > bytesConsumedInPage) {
+            break;
+        } else {
+            iSeg += 1;
+            iByte += segmentSize;
+        }
+    }
+
+    *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (drflac_uint8)(bytesConsumedInPage - iByte);
+    return iSeg;
+}
+
+static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs)
+{
+    /* The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page. */
+    for (;;) {
+        drflac_bool32 atEndOfPage = DRFLAC_FALSE;
+
+        drflac_uint8 bytesRemainingInSeg;
+        drflac_uint8 iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg);
+
+        drflac_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg;
+        for (drflac_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) {
+            drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg];
+            if (segmentSize < 255) {
+                if (iSeg == oggbs->currentPageHeader.segmentCount-1) {
+                    atEndOfPage = DRFLAC_TRUE;
+                }
+
+                break;
+            }
+
+            bytesToEndOfPacketOrPage += segmentSize;
+        }
+
+        /*
+        At this point we will have found either the packet or the end of the page. If were at the end of the page we'll
+        want to load the next page and keep searching for the end of the packet.
+        */
+        drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, drflac_seek_origin_current);
+        oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage;
+
+        if (atEndOfPage) {
+            /*
+            We're potentially at the next packet, but we need to check the next page first to be sure because the packet may
+            straddle pages.
+            */
+            if (!drflac_oggbs__goto_next_page(oggbs)) {
+                return DRFLAC_FALSE;
+            }
+
+            /* If it's a fresh packet it most likely means we're at the next packet. */
+            if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {
+                return DRFLAC_TRUE;
+            }
+        } else {
+            /* We're at the next packet. */
+            return DRFLAC_TRUE;
+        }
+    }
+}
+
+static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs)
+{
+    /* The bitstream should be sitting on the first byte just after the header of the frame. */
+
+    /* What we're actually doing here is seeking to the start of the next packet. */
+    return drflac_oggbs__seek_to_next_packet(oggbs);
+}
+#endif
+
+static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+    drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
+    drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut;
+    size_t bytesRead = 0;
+
+    DRFLAC_ASSERT(oggbs != NULL);
+    DRFLAC_ASSERT(pRunningBufferOut != NULL);
+
+    /* Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one. */
+    while (bytesRead < bytesToRead) {
+        size_t bytesRemainingToRead = bytesToRead - bytesRead;
+
+        if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) {
+            DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead);
+            bytesRead += bytesRemainingToRead;
+            oggbs->bytesRemainingInPage -= (drflac_uint32)bytesRemainingToRead;
+            break;
+        }
+
+        /* If we get here it means some of the requested data is contained in the next pages. */
+        if (oggbs->bytesRemainingInPage > 0) {
+            DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage);
+            bytesRead += oggbs->bytesRemainingInPage;
+            pRunningBufferOut += oggbs->bytesRemainingInPage;
+            oggbs->bytesRemainingInPage = 0;
+        }
+
+        DRFLAC_ASSERT(bytesRemainingToRead > 0);
+        if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
+            break;  /* Failed to go to the next page. Might have simply hit the end of the stream. */
+        }
+    }
+
+    return bytesRead;
+}
+
+static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin)
+{
+    drflac_oggbs* oggbs = (drflac_oggbs*)pUserData;
+    int bytesSeeked = 0;
+
+    DRFLAC_ASSERT(oggbs != NULL);
+    DRFLAC_ASSERT(offset >= 0);  /* <-- Never seek backwards. */
+
+    /* Seeking is always forward which makes things a lot simpler. */
+    if (origin == drflac_seek_origin_start) {
+        if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, drflac_seek_origin_start)) {
+            return DRFLAC_FALSE;
+        }
+
+        if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
+            return DRFLAC_FALSE;
+        }
+
+        return drflac__on_seek_ogg(pUserData, offset, drflac_seek_origin_current);
+    }
+
+    DRFLAC_ASSERT(origin == drflac_seek_origin_current);
+
+    while (bytesSeeked < offset) {
+        int bytesRemainingToSeek = offset - bytesSeeked;
+        DRFLAC_ASSERT(bytesRemainingToSeek >= 0);
+
+        if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) {
+            bytesSeeked += bytesRemainingToSeek;
+            (void)bytesSeeked;  /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */
+            oggbs->bytesRemainingInPage -= bytesRemainingToSeek;
+            break;
+        }
+
+        /* If we get here it means some of the requested data is contained in the next pages. */
+        if (oggbs->bytesRemainingInPage > 0) {
+            bytesSeeked += (int)oggbs->bytesRemainingInPage;
+            oggbs->bytesRemainingInPage = 0;
+        }
+
+        DRFLAC_ASSERT(bytesRemainingToSeek > 0);
+        if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) {
+            /* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */
+            return DRFLAC_FALSE;
+        }
+    }
+
+    return DRFLAC_TRUE;
+}
+
+
+static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
+{
+    drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
+    drflac_uint64 originalBytePos;
+    drflac_uint64 runningGranulePosition;
+    drflac_uint64 runningFrameBytePos;
+    drflac_uint64 runningPCMFrameCount;
+
+    DRFLAC_ASSERT(oggbs != NULL);
+
+    originalBytePos = oggbs->currentBytePos;   /* For recovery. Points to the OggS identifier. */
+
+    /* First seek to the first frame. */
+    if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) {
+        return DRFLAC_FALSE;
+    }
+    oggbs->bytesRemainingInPage = 0;
+
+    runningGranulePosition = 0;
+    for (;;) {
+        if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
+            drflac_oggbs__seek_physical(oggbs, originalBytePos, drflac_seek_origin_start);
+            return DRFLAC_FALSE;   /* Never did find that sample... */
+        }
+
+        runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize;
+        if (oggbs->currentPageHeader.granulePosition >= pcmFrameIndex) {
+            break; /* The sample is somewhere in the previous page. */
+        }
+
+        /*
+        At this point we know the sample is not in the previous page. It could possibly be in this page. For simplicity we
+        disregard any pages that do not begin a fresh packet.
+        */
+        if ((oggbs->currentPageHeader.headerType & 0x01) == 0) {    /* <-- Is it a fresh page? */
+            if (oggbs->currentPageHeader.segmentTable[0] >= 2) {
+                drflac_uint8 firstBytesInPage[2];
+                firstBytesInPage[0] = oggbs->pageData[0];
+                firstBytesInPage[1] = oggbs->pageData[1];
+
+                if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) {    /* <-- Does the page begin with a frame's sync code? */
+                    runningGranulePosition = oggbs->currentPageHeader.granulePosition;
+                }
+
+                continue;
+            }
+        }
+    }
+
+    /*
+    We found the page that that is closest to the sample, so now we need to find it. The first thing to do is seek to the
+    start of that page. In the loop above we checked that it was a fresh page which means this page is also the start of
+    a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until
+    we find the one containing the target sample.
+    */
+    if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, drflac_seek_origin_start)) {
+        return DRFLAC_FALSE;
+    }
+    if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) {
+        return DRFLAC_FALSE;
+    }
+
+    /*
+    At this point we'll be sitting on the first byte of the frame header of the first frame in the page. We just keep
+    looping over these frames until we find the one containing the sample we're after.
+    */
+    runningPCMFrameCount = runningGranulePosition;
+    for (;;) {
+        /*
+        There are two ways to find the sample and seek past irrelevant frames:
+          1) Use the native FLAC decoder.
+          2) Use Ogg's framing system.
+
+        Both of these options have their own pros and cons. Using the native FLAC decoder is slower because it needs to
+        do a full decode of the frame. Using Ogg's framing system is faster, but more complicated and involves some code
+        duplication for the decoding of frame headers.
+
+        Another thing to consider is that using the Ogg framing system will perform direct seeking of the physical Ogg
+        bitstream. This is important to consider because it means we cannot read data from the drflac_bs object using the
+        standard drflac__*() APIs because that will read in extra data for its own internal caching which in turn breaks
+        the positioning of the read pointer of the physical Ogg bitstream. Therefore, anything that would normally be read
+        using the native FLAC decoding APIs, such as drflac__read_next_flac_frame_header(), need to be re-implemented so as to
+        avoid the use of the drflac_bs object.
+
+        Considering these issues, I have decided to use the slower native FLAC decoding method for the following reasons:
+          1) Seeking is already partially accelerated using Ogg's paging system in the code block above.
+          2) Seeking in an Ogg encapsulated FLAC stream is probably quite uncommon.
+          3) Simplicity.
+        */
+        drflac_uint64 firstPCMFrameInFLACFrame = 0;
+        drflac_uint64 lastPCMFrameInFLACFrame = 0;
+        drflac_uint64 pcmFrameCountInThisFrame;
+
+        if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+            return DRFLAC_FALSE;
+        }
+
+        drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame);
+
+        pcmFrameCountInThisFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1;
+
+        /* If we are seeking to the end of the file and we've just hit it, we're done. */
+        if (pcmFrameIndex == pFlac->totalPCMFrameCount && (runningPCMFrameCount + pcmFrameCountInThisFrame) == pFlac->totalPCMFrameCount) {
+            drflac_result result = drflac__decode_flac_frame(pFlac);
+            if (result == DRFLAC_SUCCESS) {
+                pFlac->currentPCMFrame = pcmFrameIndex;
+                pFlac->currentFLACFrame.pcmFramesRemaining = 0;
+                return DRFLAC_TRUE;
+            } else {
+                return DRFLAC_FALSE;
+            }
+        }
+
+        if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFrame)) {
+            /*
+            The sample should be in this FLAC frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend
+            it never existed and keep iterating.
+            */
+            drflac_result result = drflac__decode_flac_frame(pFlac);
+            if (result == DRFLAC_SUCCESS) {
+                /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */
+                drflac_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount);    /* <-- Safe cast because the maximum number of samples in a frame is 65535. */
+                if (pcmFramesToDecode == 0) {
+                    return DRFLAC_TRUE;
+                }
+
+                pFlac->currentPCMFrame = runningPCMFrameCount;
+
+                return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode;  /* <-- If this fails, something bad has happened (it should never fail). */
+            } else {
+                if (result == DRFLAC_CRC_MISMATCH) {
+                    continue;   /* CRC mismatch. Pretend this frame never existed. */
+                } else {
+                    return DRFLAC_FALSE;
+                }
+            }
+        } else {
+            /*
+            It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this
+            frame never existed and leave the running sample count untouched.
+            */
+            drflac_result result = drflac__seek_to_next_flac_frame(pFlac);
+            if (result == DRFLAC_SUCCESS) {
+                runningPCMFrameCount += pcmFrameCountInThisFrame;
+            } else {
+                if (result == DRFLAC_CRC_MISMATCH) {
+                    continue;   /* CRC mismatch. Pretend this frame never existed. */
+                } else {
+                    return DRFLAC_FALSE;
+                }
+            }
+        }
+    }
+}
+
+
+
+static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed)
+{
+    drflac_ogg_page_header header;
+    drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32;
+    drflac_uint32 bytesRead = 0;
+
+    /* Pre Condition: The bit stream should be sitting just past the 4-byte OggS capture pattern. */
+    (void)relaxed;
+
+    pInit->container = drflac_container_ogg;
+    pInit->oggFirstBytePos = 0;
+
+    /*
+    We'll get here if the first 4 bytes of the stream were the OggS capture pattern, however it doesn't necessarily mean the
+    stream includes FLAC encoded audio. To check for this we need to scan the beginning-of-stream page markers and check if
+    any match the FLAC specification. Important to keep in mind that the stream may be multiplexed.
+    */
+    if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
+        return DRFLAC_FALSE;
+    }
+    pInit->runningFilePos += bytesRead;
+
+    for (;;) {
+        int pageBodySize;
+
+        /* Break if we're past the beginning of stream page. */
+        if ((header.headerType & 0x02) == 0) {
+            return DRFLAC_FALSE;
+        }
+
+        /* Check if it's a FLAC header. */
+        pageBodySize = drflac_ogg__get_page_body_size(&header);
+        if (pageBodySize == 51) {   /* 51 = the lacing value of the FLAC header packet. */
+            /* It could be a FLAC page... */
+            drflac_uint32 bytesRemainingInPage = pageBodySize;
+            drflac_uint8 packetType;
+
+            if (onRead(pUserData, &packetType, 1) != 1) {
+                return DRFLAC_FALSE;
+            }
+
+            bytesRemainingInPage -= 1;
+            if (packetType == 0x7F) {
+                /* Increasingly more likely to be a FLAC page... */
+                drflac_uint8 sig[4];
+                if (onRead(pUserData, sig, 4) != 4) {
+                    return DRFLAC_FALSE;
+                }
+
+                bytesRemainingInPage -= 4;
+                if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') {
+                    /* Almost certainly a FLAC page... */
+                    drflac_uint8 mappingVersion[2];
+                    if (onRead(pUserData, mappingVersion, 2) != 2) {
+                        return DRFLAC_FALSE;
+                    }
+
+                    if (mappingVersion[0] != 1) {
+                        return DRFLAC_FALSE;   /* Only supporting version 1.x of the Ogg mapping. */
+                    }
+
+                    /*
+                    The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to
+                    be handling it in a generic way based on the serial number and packet types.
+                    */
+                    if (!onSeek(pUserData, 2, drflac_seek_origin_current)) {
+                        return DRFLAC_FALSE;
+                    }
+
+                    /* Expecting the native FLAC signature "fLaC". */
+                    if (onRead(pUserData, sig, 4) != 4) {
+                        return DRFLAC_FALSE;
+                    }
+
+                    if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') {
+                        /* The remaining data in the page should be the STREAMINFO block. */
+                        drflac_streaminfo streaminfo;
+                        drflac_uint8 isLastBlock;
+                        drflac_uint8 blockType;
+                        drflac_uint32 blockSize;
+                        if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) {
+                            return DRFLAC_FALSE;
+                        }
+
+                        if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) {
+                            return DRFLAC_FALSE;    /* Invalid block type. First block must be the STREAMINFO block. */
+                        }
+
+                        if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) {
+                            /* Success! */
+                            pInit->hasStreamInfoBlock      = DRFLAC_TRUE;
+                            pInit->sampleRate              = streaminfo.sampleRate;
+                            pInit->channels                = streaminfo.channels;
+                            pInit->bitsPerSample           = streaminfo.bitsPerSample;
+                            pInit->totalPCMFrameCount      = streaminfo.totalPCMFrameCount;
+                            pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames;
+                            pInit->hasMetadataBlocks       = !isLastBlock;
+
+                            if (onMeta) {
+                                drflac_metadata metadata;
+                                metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO;
+                                metadata.pRawData = NULL;
+                                metadata.rawDataSize = 0;
+                                metadata.data.streaminfo = streaminfo;
+                                onMeta(pUserDataMD, &metadata);
+                            }
+
+                            pInit->runningFilePos  += pageBodySize;
+                            pInit->oggFirstBytePos  = pInit->runningFilePos - 79;   /* Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page. */
+                            pInit->oggSerial        = header.serialNumber;
+                            pInit->oggBosHeader     = header;
+                            break;
+                        } else {
+                            /* Failed to read STREAMINFO block. Aww, so close... */
+                            return DRFLAC_FALSE;
+                        }
+                    } else {
+                        /* Invalid file. */
+                        return DRFLAC_FALSE;
+                    }
+                } else {
+                    /* Not a FLAC header. Skip it. */
+                    if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
+                        return DRFLAC_FALSE;
+                    }
+                }
+            } else {
+                /* Not a FLAC header. Seek past the entire page and move on to the next. */
+                if (!onSeek(pUserData, bytesRemainingInPage, drflac_seek_origin_current)) {
+                    return DRFLAC_FALSE;
+                }
+            }
+        } else {
+            if (!onSeek(pUserData, pageBodySize, drflac_seek_origin_current)) {
+                return DRFLAC_FALSE;
+            }
+        }
+
+        pInit->runningFilePos += pageBodySize;
+
+
+        /* Read the header of the next page. */
+        if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) {
+            return DRFLAC_FALSE;
+        }
+        pInit->runningFilePos += bytesRead;
+    }
+
+    /*
+    If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next
+    packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialization phase for Ogg is to create the
+    Ogg bistream object.
+    */
+    pInit->hasMetadataBlocks = DRFLAC_TRUE;    /* <-- Always have at least VORBIS_COMMENT metadata block. */
+    return DRFLAC_TRUE;
+}
+#endif
+
+static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD)
+{
+    drflac_bool32 relaxed;
+    drflac_uint8 id[4];
+
+    if (pInit == NULL || onRead == NULL || onSeek == NULL) {
+        return DRFLAC_FALSE;
+    }
+
+    DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit));
+    pInit->onRead       = onRead;
+    pInit->onSeek       = onSeek;
+    pInit->onMeta       = onMeta;
+    pInit->container    = container;
+    pInit->pUserData    = pUserData;
+    pInit->pUserDataMD  = pUserDataMD;
+
+    pInit->bs.onRead    = onRead;
+    pInit->bs.onSeek    = onSeek;
+    pInit->bs.pUserData = pUserData;
+    drflac__reset_cache(&pInit->bs);
+
+
+    /* If the container is explicitly defined then we can try opening in relaxed mode. */
+    relaxed = container != drflac_container_unknown;
+
+    /* Skip over any ID3 tags. */
+    for (;;) {
+        if (onRead(pUserData, id, 4) != 4) {
+            return DRFLAC_FALSE;    /* Ran out of data. */
+        }
+        pInit->runningFilePos += 4;
+
+        if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') {
+            drflac_uint8 header[6];
+            drflac_uint8 flags;
+            drflac_uint32 headerSize;
+
+            if (onRead(pUserData, header, 6) != 6) {
+                return DRFLAC_FALSE;    /* Ran out of data. */
+            }
+            pInit->runningFilePos += 6;
+
+            flags = header[1];
+
+            DRFLAC_COPY_MEMORY(&headerSize, header+2, 4);
+            headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize));
+            if (flags & 0x10) {
+                headerSize += 10;
+            }
+
+            if (!onSeek(pUserData, headerSize, drflac_seek_origin_current)) {
+                return DRFLAC_FALSE;    /* Failed to seek past the tag. */
+            }
+            pInit->runningFilePos += headerSize;
+        } else {
+            break;
+        }
+    }
+
+    if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') {
+        return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
+    }
+#ifndef DR_FLAC_NO_OGG
+    if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') {
+        return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
+    }
+#endif
+
+    /* If we get here it means we likely don't have a header. Try opening in relaxed mode, if applicable. */
+    if (relaxed) {
+        if (container == drflac_container_native) {
+            return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
+        }
+#ifndef DR_FLAC_NO_OGG
+        if (container == drflac_container_ogg) {
+            return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed);
+        }
+#endif
+    }
+
+    /* Unsupported container. */
+    return DRFLAC_FALSE;
+}
+
+static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit)
+{
+    DRFLAC_ASSERT(pFlac != NULL);
+    DRFLAC_ASSERT(pInit != NULL);
+
+    DRFLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac));
+    pFlac->bs                      = pInit->bs;
+    pFlac->onMeta                  = pInit->onMeta;
+    pFlac->pUserDataMD             = pInit->pUserDataMD;
+    pFlac->maxBlockSizeInPCMFrames = pInit->maxBlockSizeInPCMFrames;
+    pFlac->sampleRate              = pInit->sampleRate;
+    pFlac->channels                = (drflac_uint8)pInit->channels;
+    pFlac->bitsPerSample           = (drflac_uint8)pInit->bitsPerSample;
+    pFlac->totalPCMFrameCount      = pInit->totalPCMFrameCount;
+    pFlac->container               = pInit->container;
+}
+
+
+static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac_init_info init;
+    drflac_uint32 allocationSize;
+    drflac_uint32 wholeSIMDVectorCountPerChannel;
+    drflac_uint32 decodedSamplesAllocationSize;
+#ifndef DR_FLAC_NO_OGG
+    drflac_oggbs oggbs;
+#endif
+    drflac_uint64 firstFramePos;
+    drflac_uint64 seektablePos;
+    drflac_uint32 seektableSize;
+    drflac_allocation_callbacks allocationCallbacks;
+    drflac* pFlac;
+
+    /* CPU support first. */
+    drflac__init_cpu_caps();
+
+    if (!drflac__init_private(&init, onRead, onSeek, onMeta, container, pUserData, pUserDataMD)) {
+        return NULL;
+    }
+
+    if (pAllocationCallbacks != NULL) {
+        allocationCallbacks = *pAllocationCallbacks;
+        if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) {
+            return NULL;    /* Invalid allocation callbacks. */
+        }
+    } else {
+        allocationCallbacks.pUserData = NULL;
+        allocationCallbacks.onMalloc  = drflac__malloc_default;
+        allocationCallbacks.onRealloc = drflac__realloc_default;
+        allocationCallbacks.onFree    = drflac__free_default;
+    }
+
+
+    /*
+    The size of the allocation for the drflac object needs to be large enough to fit the following:
+      1) The main members of the drflac structure
+      2) A block of memory large enough to store the decoded samples of the largest frame in the stream
+      3) If the container is Ogg, a drflac_oggbs object
+
+    The complicated part of the allocation is making sure there's enough room the decoded samples, taking into consideration
+    the different SIMD instruction sets.
+    */
+    allocationSize = sizeof(drflac);
+
+    /*
+    The allocation size for decoded frames depends on the number of 32-bit integers that fit inside the largest SIMD vector
+    we are supporting.
+    */
+    if ((init.maxBlockSizeInPCMFrames % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) {
+        wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32)));
+    } else {
+        wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1;
+    }
+
+    decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels;
+
+    allocationSize += decodedSamplesAllocationSize;
+    allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE;  /* Allocate extra bytes to ensure we have enough for alignment. */
+
+#ifndef DR_FLAC_NO_OGG
+    /* There's additional data required for Ogg streams. */
+    if (init.container == drflac_container_ogg) {
+        allocationSize += sizeof(drflac_oggbs);
+    }
+
+    DRFLAC_ZERO_MEMORY(&oggbs, sizeof(oggbs));
+    if (init.container == drflac_container_ogg) {
+        oggbs.onRead = onRead;
+        oggbs.onSeek = onSeek;
+        oggbs.pUserData = pUserData;
+        oggbs.currentBytePos = init.oggFirstBytePos;
+        oggbs.firstBytePos = init.oggFirstBytePos;
+        oggbs.serialNumber = init.oggSerial;
+        oggbs.bosPageHeader = init.oggBosHeader;
+        oggbs.bytesRemainingInPage = 0;
+    }
+#endif
+
+    /*
+    This part is a bit awkward. We need to load the seektable so that it can be referenced in-memory, but I want the drflac object to
+    consist of only a single heap allocation. To this, the size of the seek table needs to be known, which we determine when reading
+    and decoding the metadata.
+    */
+    firstFramePos = 42;   /* <-- We know we are at byte 42 at this point. */
+    seektablePos  = 0;
+    seektableSize = 0;
+    if (init.hasMetadataBlocks) {
+        drflac_read_proc onReadOverride = onRead;
+        drflac_seek_proc onSeekOverride = onSeek;
+        void* pUserDataOverride = pUserData;
+
+#ifndef DR_FLAC_NO_OGG
+        if (init.container == drflac_container_ogg) {
+            onReadOverride = drflac__on_read_ogg;
+            onSeekOverride = drflac__on_seek_ogg;
+            pUserDataOverride = (void*)&oggbs;
+        }
+#endif
+
+        if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seektableSize, &allocationCallbacks)) {
+            return NULL;
+        }
+
+        allocationSize += seektableSize;
+    }
+
+
+    pFlac = (drflac*)drflac__malloc_from_callbacks(allocationSize, &allocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    drflac__init_from_info(pFlac, &init);
+    pFlac->allocationCallbacks = allocationCallbacks;
+    pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE);
+
+#ifndef DR_FLAC_NO_OGG
+    if (init.container == drflac_container_ogg) {
+        drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + seektableSize);
+        *pInternalOggbs = oggbs;
+
+        /* The Ogg bistream needs to be layered on top of the original bitstream. */
+        pFlac->bs.onRead = drflac__on_read_ogg;
+        pFlac->bs.onSeek = drflac__on_seek_ogg;
+        pFlac->bs.pUserData = (void*)pInternalOggbs;
+        pFlac->_oggbs = (void*)pInternalOggbs;
+    }
+#endif
+
+    pFlac->firstFLACFramePosInBytes = firstFramePos;
+
+    /* NOTE: Seektables are not currently compatible with Ogg encapsulation (Ogg has its own accelerated seeking system). I may change this later, so I'm leaving this here for now. */
+#ifndef DR_FLAC_NO_OGG
+    if (init.container == drflac_container_ogg)
+    {
+        pFlac->pSeekpoints = NULL;
+        pFlac->seekpointCount = 0;
+    }
+    else
+#endif
+    {
+        /* If we have a seektable we need to load it now, making sure we move back to where we were previously. */
+        if (seektablePos != 0) {
+            pFlac->seekpointCount = seektableSize / sizeof(*pFlac->pSeekpoints);
+            pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize);
+
+            DRFLAC_ASSERT(pFlac->bs.onSeek != NULL);
+            DRFLAC_ASSERT(pFlac->bs.onRead != NULL);
+
+            /* Seek to the seektable, then just read directly into our seektable buffer. */
+            if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, drflac_seek_origin_start)) {
+                if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints, seektableSize) == seektableSize) {
+                    /* Endian swap. */
+                    drflac_uint32 iSeekpoint;
+                    for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) {
+                        pFlac->pSeekpoints[iSeekpoint].firstPCMFrame   = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame);
+                        pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset);
+                        pFlac->pSeekpoints[iSeekpoint].pcmFrameCount   = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount);
+                    }
+                } else {
+                    /* Failed to read the seektable. Pretend we don't have one. */
+                    pFlac->pSeekpoints = NULL;
+                    pFlac->seekpointCount = 0;
+                }
+
+                /* We need to seek back to where we were. If this fails it's a critical error. */
+                if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
+                    drflac__free_from_callbacks(pFlac, &allocationCallbacks);
+                    return NULL;
+                }
+            } else {
+                /* Failed to seek to the seektable. Ominous sign, but for now we can just pretend we don't have one. */
+                pFlac->pSeekpoints = NULL;
+                pFlac->seekpointCount = 0;
+            }
+        }
+    }
+
+
+    /*
+    If we get here, but don't have a STREAMINFO block, it means we've opened the stream in relaxed mode and need to decode
+    the first frame.
+    */
+    if (!init.hasStreamInfoBlock) {
+        pFlac->currentFLACFrame.header = init.firstFrameHeader;
+        for (;;) {
+            drflac_result result = drflac__decode_flac_frame(pFlac);
+            if (result == DRFLAC_SUCCESS) {
+                break;
+            } else {
+                if (result == DRFLAC_CRC_MISMATCH) {
+                    if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
+                        drflac__free_from_callbacks(pFlac, &allocationCallbacks);
+                        return NULL;
+                    }
+                    continue;
+                } else {
+                    drflac__free_from_callbacks(pFlac, &allocationCallbacks);
+                    return NULL;
+                }
+            }
+        }
+    }
+
+    return pFlac;
+}
+
+
+
+#ifndef DR_FLAC_NO_STDIO
+#include <stdio.h>
+#include <wchar.h>      /* For wcslen(), wcsrtombs() */
+
+/* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */
+#include <errno.h>
+static drflac_result drflac_result_from_errno(int e)
+{
+    switch (e)
+    {
+        case 0: return DRFLAC_SUCCESS;
+    #ifdef EPERM
+        case EPERM: return DRFLAC_INVALID_OPERATION;
+    #endif
+    #ifdef ENOENT
+        case ENOENT: return DRFLAC_DOES_NOT_EXIST;
+    #endif
+    #ifdef ESRCH
+        case ESRCH: return DRFLAC_DOES_NOT_EXIST;
+    #endif
+    #ifdef EINTR
+        case EINTR: return DRFLAC_INTERRUPT;
+    #endif
+    #ifdef EIO
+        case EIO: return DRFLAC_IO_ERROR;
+    #endif
+    #ifdef ENXIO
+        case ENXIO: return DRFLAC_DOES_NOT_EXIST;
+    #endif
+    #ifdef E2BIG
+        case E2BIG: return DRFLAC_INVALID_ARGS;
+    #endif
+    #ifdef ENOEXEC
+        case ENOEXEC: return DRFLAC_INVALID_FILE;
+    #endif
+    #ifdef EBADF
+        case EBADF: return DRFLAC_INVALID_FILE;
+    #endif
+    #ifdef ECHILD
+        case ECHILD: return DRFLAC_ERROR;
+    #endif
+    #ifdef EAGAIN
+        case EAGAIN: return DRFLAC_UNAVAILABLE;
+    #endif
+    #ifdef ENOMEM
+        case ENOMEM: return DRFLAC_OUT_OF_MEMORY;
+    #endif
+    #ifdef EACCES
+        case EACCES: return DRFLAC_ACCESS_DENIED;
+    #endif
+    #ifdef EFAULT
+        case EFAULT: return DRFLAC_BAD_ADDRESS;
+    #endif
+    #ifdef ENOTBLK
+        case ENOTBLK: return DRFLAC_ERROR;
+    #endif
+    #ifdef EBUSY
+        case EBUSY: return DRFLAC_BUSY;
+    #endif
+    #ifdef EEXIST
+        case EEXIST: return DRFLAC_ALREADY_EXISTS;
+    #endif
+    #ifdef EXDEV
+        case EXDEV: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENODEV
+        case ENODEV: return DRFLAC_DOES_NOT_EXIST;
+    #endif
+    #ifdef ENOTDIR
+        case ENOTDIR: return DRFLAC_NOT_DIRECTORY;
+    #endif
+    #ifdef EISDIR
+        case EISDIR: return DRFLAC_IS_DIRECTORY;
+    #endif
+    #ifdef EINVAL
+        case EINVAL: return DRFLAC_INVALID_ARGS;
+    #endif
+    #ifdef ENFILE
+        case ENFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
+    #endif
+    #ifdef EMFILE
+        case EMFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
+    #endif
+    #ifdef ENOTTY
+        case ENOTTY: return DRFLAC_INVALID_OPERATION;
+    #endif
+    #ifdef ETXTBSY
+        case ETXTBSY: return DRFLAC_BUSY;
+    #endif
+    #ifdef EFBIG
+        case EFBIG: return DRFLAC_TOO_BIG;
+    #endif
+    #ifdef ENOSPC
+        case ENOSPC: return DRFLAC_NO_SPACE;
+    #endif
+    #ifdef ESPIPE
+        case ESPIPE: return DRFLAC_BAD_SEEK;
+    #endif
+    #ifdef EROFS
+        case EROFS: return DRFLAC_ACCESS_DENIED;
+    #endif
+    #ifdef EMLINK
+        case EMLINK: return DRFLAC_TOO_MANY_LINKS;
+    #endif
+    #ifdef EPIPE
+        case EPIPE: return DRFLAC_BAD_PIPE;
+    #endif
+    #ifdef EDOM
+        case EDOM: return DRFLAC_OUT_OF_RANGE;
+    #endif
+    #ifdef ERANGE
+        case ERANGE: return DRFLAC_OUT_OF_RANGE;
+    #endif
+    #ifdef EDEADLK
+        case EDEADLK: return DRFLAC_DEADLOCK;
+    #endif
+    #ifdef ENAMETOOLONG
+        case ENAMETOOLONG: return DRFLAC_PATH_TOO_LONG;
+    #endif
+    #ifdef ENOLCK
+        case ENOLCK: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENOSYS
+        case ENOSYS: return DRFLAC_NOT_IMPLEMENTED;
+    #endif
+    #ifdef ENOTEMPTY
+        case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY;
+    #endif
+    #ifdef ELOOP
+        case ELOOP: return DRFLAC_TOO_MANY_LINKS;
+    #endif
+    #ifdef ENOMSG
+        case ENOMSG: return DRFLAC_NO_MESSAGE;
+    #endif
+    #ifdef EIDRM
+        case EIDRM: return DRFLAC_ERROR;
+    #endif
+    #ifdef ECHRNG
+        case ECHRNG: return DRFLAC_ERROR;
+    #endif
+    #ifdef EL2NSYNC
+        case EL2NSYNC: return DRFLAC_ERROR;
+    #endif
+    #ifdef EL3HLT
+        case EL3HLT: return DRFLAC_ERROR;
+    #endif
+    #ifdef EL3RST
+        case EL3RST: return DRFLAC_ERROR;
+    #endif
+    #ifdef ELNRNG
+        case ELNRNG: return DRFLAC_OUT_OF_RANGE;
+    #endif
+    #ifdef EUNATCH
+        case EUNATCH: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENOCSI
+        case ENOCSI: return DRFLAC_ERROR;
+    #endif
+    #ifdef EL2HLT
+        case EL2HLT: return DRFLAC_ERROR;
+    #endif
+    #ifdef EBADE
+        case EBADE: return DRFLAC_ERROR;
+    #endif
+    #ifdef EBADR
+        case EBADR: return DRFLAC_ERROR;
+    #endif
+    #ifdef EXFULL
+        case EXFULL: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENOANO
+        case ENOANO: return DRFLAC_ERROR;
+    #endif
+    #ifdef EBADRQC
+        case EBADRQC: return DRFLAC_ERROR;
+    #endif
+    #ifdef EBADSLT
+        case EBADSLT: return DRFLAC_ERROR;
+    #endif
+    #ifdef EBFONT
+        case EBFONT: return DRFLAC_INVALID_FILE;
+    #endif
+    #ifdef ENOSTR
+        case ENOSTR: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENODATA
+        case ENODATA: return DRFLAC_NO_DATA_AVAILABLE;
+    #endif
+    #ifdef ETIME
+        case ETIME: return DRFLAC_TIMEOUT;
+    #endif
+    #ifdef ENOSR
+        case ENOSR: return DRFLAC_NO_DATA_AVAILABLE;
+    #endif
+    #ifdef ENONET
+        case ENONET: return DRFLAC_NO_NETWORK;
+    #endif
+    #ifdef ENOPKG
+        case ENOPKG: return DRFLAC_ERROR;
+    #endif
+    #ifdef EREMOTE
+        case EREMOTE: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENOLINK
+        case ENOLINK: return DRFLAC_ERROR;
+    #endif
+    #ifdef EADV
+        case EADV: return DRFLAC_ERROR;
+    #endif
+    #ifdef ESRMNT
+        case ESRMNT: return DRFLAC_ERROR;
+    #endif
+    #ifdef ECOMM
+        case ECOMM: return DRFLAC_ERROR;
+    #endif
+    #ifdef EPROTO
+        case EPROTO: return DRFLAC_ERROR;
+    #endif
+    #ifdef EMULTIHOP
+        case EMULTIHOP: return DRFLAC_ERROR;
+    #endif
+    #ifdef EDOTDOT
+        case EDOTDOT: return DRFLAC_ERROR;
+    #endif
+    #ifdef EBADMSG
+        case EBADMSG: return DRFLAC_BAD_MESSAGE;
+    #endif
+    #ifdef EOVERFLOW
+        case EOVERFLOW: return DRFLAC_TOO_BIG;
+    #endif
+    #ifdef ENOTUNIQ
+        case ENOTUNIQ: return DRFLAC_NOT_UNIQUE;
+    #endif
+    #ifdef EBADFD
+        case EBADFD: return DRFLAC_ERROR;
+    #endif
+    #ifdef EREMCHG
+        case EREMCHG: return DRFLAC_ERROR;
+    #endif
+    #ifdef ELIBACC
+        case ELIBACC: return DRFLAC_ACCESS_DENIED;
+    #endif
+    #ifdef ELIBBAD
+        case ELIBBAD: return DRFLAC_INVALID_FILE;
+    #endif
+    #ifdef ELIBSCN
+        case ELIBSCN: return DRFLAC_INVALID_FILE;
+    #endif
+    #ifdef ELIBMAX
+        case ELIBMAX: return DRFLAC_ERROR;
+    #endif
+    #ifdef ELIBEXEC
+        case ELIBEXEC: return DRFLAC_ERROR;
+    #endif
+    #ifdef EILSEQ
+        case EILSEQ: return DRFLAC_INVALID_DATA;
+    #endif
+    #ifdef ERESTART
+        case ERESTART: return DRFLAC_ERROR;
+    #endif
+    #ifdef ESTRPIPE
+        case ESTRPIPE: return DRFLAC_ERROR;
+    #endif
+    #ifdef EUSERS
+        case EUSERS: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENOTSOCK
+        case ENOTSOCK: return DRFLAC_NOT_SOCKET;
+    #endif
+    #ifdef EDESTADDRREQ
+        case EDESTADDRREQ: return DRFLAC_NO_ADDRESS;
+    #endif
+    #ifdef EMSGSIZE
+        case EMSGSIZE: return DRFLAC_TOO_BIG;
+    #endif
+    #ifdef EPROTOTYPE
+        case EPROTOTYPE: return DRFLAC_BAD_PROTOCOL;
+    #endif
+    #ifdef ENOPROTOOPT
+        case ENOPROTOOPT: return DRFLAC_PROTOCOL_UNAVAILABLE;
+    #endif
+    #ifdef EPROTONOSUPPORT
+        case EPROTONOSUPPORT: return DRFLAC_PROTOCOL_NOT_SUPPORTED;
+    #endif
+    #ifdef ESOCKTNOSUPPORT
+        case ESOCKTNOSUPPORT: return DRFLAC_SOCKET_NOT_SUPPORTED;
+    #endif
+    #ifdef EOPNOTSUPP
+        case EOPNOTSUPP: return DRFLAC_INVALID_OPERATION;
+    #endif
+    #ifdef EPFNOSUPPORT
+        case EPFNOSUPPORT: return DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED;
+    #endif
+    #ifdef EAFNOSUPPORT
+        case EAFNOSUPPORT: return DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED;
+    #endif
+    #ifdef EADDRINUSE
+        case EADDRINUSE: return DRFLAC_ALREADY_IN_USE;
+    #endif
+    #ifdef EADDRNOTAVAIL
+        case EADDRNOTAVAIL: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENETDOWN
+        case ENETDOWN: return DRFLAC_NO_NETWORK;
+    #endif
+    #ifdef ENETUNREACH
+        case ENETUNREACH: return DRFLAC_NO_NETWORK;
+    #endif
+    #ifdef ENETRESET
+        case ENETRESET: return DRFLAC_NO_NETWORK;
+    #endif
+    #ifdef ECONNABORTED
+        case ECONNABORTED: return DRFLAC_NO_NETWORK;
+    #endif
+    #ifdef ECONNRESET
+        case ECONNRESET: return DRFLAC_CONNECTION_RESET;
+    #endif
+    #ifdef ENOBUFS
+        case ENOBUFS: return DRFLAC_NO_SPACE;
+    #endif
+    #ifdef EISCONN
+        case EISCONN: return DRFLAC_ALREADY_CONNECTED;
+    #endif
+    #ifdef ENOTCONN
+        case ENOTCONN: return DRFLAC_NOT_CONNECTED;
+    #endif
+    #ifdef ESHUTDOWN
+        case ESHUTDOWN: return DRFLAC_ERROR;
+    #endif
+    #ifdef ETOOMANYREFS
+        case ETOOMANYREFS: return DRFLAC_ERROR;
+    #endif
+    #ifdef ETIMEDOUT
+        case ETIMEDOUT: return DRFLAC_TIMEOUT;
+    #endif
+    #ifdef ECONNREFUSED
+        case ECONNREFUSED: return DRFLAC_CONNECTION_REFUSED;
+    #endif
+    #ifdef EHOSTDOWN
+        case EHOSTDOWN: return DRFLAC_NO_HOST;
+    #endif
+    #ifdef EHOSTUNREACH
+        case EHOSTUNREACH: return DRFLAC_NO_HOST;
+    #endif
+    #ifdef EALREADY
+        case EALREADY: return DRFLAC_IN_PROGRESS;
+    #endif
+    #ifdef EINPROGRESS
+        case EINPROGRESS: return DRFLAC_IN_PROGRESS;
+    #endif
+    #ifdef ESTALE
+        case ESTALE: return DRFLAC_INVALID_FILE;
+    #endif
+    #ifdef EUCLEAN
+        case EUCLEAN: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENOTNAM
+        case ENOTNAM: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENAVAIL
+        case ENAVAIL: return DRFLAC_ERROR;
+    #endif
+    #ifdef EISNAM
+        case EISNAM: return DRFLAC_ERROR;
+    #endif
+    #ifdef EREMOTEIO
+        case EREMOTEIO: return DRFLAC_IO_ERROR;
+    #endif
+    #ifdef EDQUOT
+        case EDQUOT: return DRFLAC_NO_SPACE;
+    #endif
+    #ifdef ENOMEDIUM
+        case ENOMEDIUM: return DRFLAC_DOES_NOT_EXIST;
+    #endif
+    #ifdef EMEDIUMTYPE
+        case EMEDIUMTYPE: return DRFLAC_ERROR;
+    #endif
+    #ifdef ECANCELED
+        case ECANCELED: return DRFLAC_CANCELLED;
+    #endif
+    #ifdef ENOKEY
+        case ENOKEY: return DRFLAC_ERROR;
+    #endif
+    #ifdef EKEYEXPIRED
+        case EKEYEXPIRED: return DRFLAC_ERROR;
+    #endif
+    #ifdef EKEYREVOKED
+        case EKEYREVOKED: return DRFLAC_ERROR;
+    #endif
+    #ifdef EKEYREJECTED
+        case EKEYREJECTED: return DRFLAC_ERROR;
+    #endif
+    #ifdef EOWNERDEAD
+        case EOWNERDEAD: return DRFLAC_ERROR;
+    #endif
+    #ifdef ENOTRECOVERABLE
+        case ENOTRECOVERABLE: return DRFLAC_ERROR;
+    #endif
+    #ifdef ERFKILL
+        case ERFKILL: return DRFLAC_ERROR;
+    #endif
+    #ifdef EHWPOISON
+        case EHWPOISON: return DRFLAC_ERROR;
+    #endif
+        default: return DRFLAC_ERROR;
+    }
+}
+
+static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
+{
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+    errno_t err;
+#endif
+
+    if (ppFile != NULL) {
+        *ppFile = NULL;  /* Safety. */
+    }
+
+    if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
+        return DRFLAC_INVALID_ARGS;
+    }
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+    err = fopen_s(ppFile, pFilePath, pOpenMode);
+    if (err != 0) {
+        return drflac_result_from_errno(err);
+    }
+#else
+#if defined(_WIN32) || defined(__APPLE__)
+    *ppFile = fopen(pFilePath, pOpenMode);
+#else
+    #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
+        *ppFile = fopen64(pFilePath, pOpenMode);
+    #else
+        *ppFile = fopen(pFilePath, pOpenMode);
+    #endif
+#endif
+    if (*ppFile == NULL) {
+        drflac_result result = drflac_result_from_errno(errno);
+        if (result == DRFLAC_SUCCESS) {
+            result = DRFLAC_ERROR;   /* Just a safety check to make sure we never ever return success when pFile == NULL. */
+        }
+
+        return result;
+    }
+#endif
+
+    return DRFLAC_SUCCESS;
+}
+
+/*
+_wfopen() isn't always available in all compilation environments.
+
+    * Windows only.
+    * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
+    * MinGW-64 (both 32- and 64-bit) seems to support it.
+    * MinGW wraps it in !defined(__STRICT_ANSI__).
+    * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
+
+This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
+fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
+*/
+#if defined(_WIN32)
+    #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
+        #define DRFLAC_HAS_WFOPEN
+    #endif
+#endif
+
+static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    if (ppFile != NULL) {
+        *ppFile = NULL;  /* Safety. */
+    }
+
+    if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
+        return DRFLAC_INVALID_ARGS;
+    }
+
+#if defined(DRFLAC_HAS_WFOPEN)
+    {
+        /* Use _wfopen() on Windows. */
+    #if defined(_MSC_VER) && _MSC_VER >= 1400
+        errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
+        if (err != 0) {
+            return drflac_result_from_errno(err);
+        }
+    #else
+        *ppFile = _wfopen(pFilePath, pOpenMode);
+        if (*ppFile == NULL) {
+            return drflac_result_from_errno(errno);
+        }
+    #endif
+        (void)pAllocationCallbacks;
+    }
+#else
+    /*
+    Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
+    think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
+    maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
+    */
+    {
+        mbstate_t mbs;
+        size_t lenMB;
+        const wchar_t* pFilePathTemp = pFilePath;
+        char* pFilePathMB = NULL;
+        char pOpenModeMB[32] = {0};
+
+        /* Get the length first. */
+        DRFLAC_ZERO_OBJECT(&mbs);
+        lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
+        if (lenMB == (size_t)-1) {
+            return drflac_result_from_errno(errno);
+        }
+
+        pFilePathMB = (char*)drflac__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
+        if (pFilePathMB == NULL) {
+            return DRFLAC_OUT_OF_MEMORY;
+        }
+
+        pFilePathTemp = pFilePath;
+        DRFLAC_ZERO_OBJECT(&mbs);
+        wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
+
+        /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
+        {
+            size_t i = 0;
+            for (;;) {
+                if (pOpenMode[i] == 0) {
+                    pOpenModeMB[i] = '\0';
+                    break;
+                }
+
+                pOpenModeMB[i] = (char)pOpenMode[i];
+                i += 1;
+            }
+        }
+
+        *ppFile = fopen(pFilePathMB, pOpenModeMB);
+
+        drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
+    }
+
+    if (*ppFile == NULL) {
+        return DRFLAC_ERROR;
+    }
+#endif
+
+    return DRFLAC_SUCCESS;
+}
+
+static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+    return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
+}
+
+static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
+{
+    DRFLAC_ASSERT(offset >= 0);  /* <-- Never seek backwards. */
+
+    return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
+}
+
+
+DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+    FILE* pFile;
+
+    if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
+        return NULL;
+    }
+
+    pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        fclose(pFile);
+        return NULL;
+    }
+
+    return pFlac;
+}
+
+DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+    FILE* pFile;
+
+    if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
+        return NULL;
+    }
+
+    pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        fclose(pFile);
+        return NULL;
+    }
+
+    return pFlac;
+}
+
+DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+    FILE* pFile;
+
+    if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
+        return NULL;
+    }
+
+    pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        fclose(pFile);
+        return pFlac;
+    }
+
+    return pFlac;
+}
+
+DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+    FILE* pFile;
+
+    if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
+        return NULL;
+    }
+
+    pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        fclose(pFile);
+        return pFlac;
+    }
+
+    return pFlac;
+}
+#endif  /* DR_FLAC_NO_STDIO */
+
+static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead)
+{
+    drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
+    size_t bytesRemaining;
+
+    DRFLAC_ASSERT(memoryStream != NULL);
+    DRFLAC_ASSERT(memoryStream->dataSize >= memoryStream->currentReadPos);
+
+    bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos;
+    if (bytesToRead > bytesRemaining) {
+        bytesToRead = bytesRemaining;
+    }
+
+    if (bytesToRead > 0) {
+        DRFLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead);
+        memoryStream->currentReadPos += bytesToRead;
+    }
+
+    return bytesToRead;
+}
+
+static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin)
+{
+    drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData;
+
+    DRFLAC_ASSERT(memoryStream != NULL);
+    DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
+
+    if (offset > (drflac_int64)memoryStream->dataSize) {
+        return DRFLAC_FALSE;
+    }
+
+    if (origin == drflac_seek_origin_current) {
+        if (memoryStream->currentReadPos + offset <= memoryStream->dataSize) {
+            memoryStream->currentReadPos += offset;
+        } else {
+            return DRFLAC_FALSE;  /* Trying to seek too far forward. */
+        }
+    } else {
+        if ((drflac_uint32)offset <= memoryStream->dataSize) {
+            memoryStream->currentReadPos = offset;
+        } else {
+            return DRFLAC_FALSE;  /* Trying to seek too far forward. */
+        }
+    }
+
+    return DRFLAC_TRUE;
+}
+
+DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac__memory_stream memoryStream;
+    drflac* pFlac;
+
+    memoryStream.data = (const drflac_uint8*)pData;
+    memoryStream.dataSize = dataSize;
+    memoryStream.currentReadPos = 0;
+    pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, &memoryStream, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    pFlac->memoryStream = memoryStream;
+
+    /* This is an awful hack... */
+#ifndef DR_FLAC_NO_OGG
+    if (pFlac->container == drflac_container_ogg)
+    {
+        drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
+        oggbs->pUserData = &pFlac->memoryStream;
+    }
+    else
+#endif
+    {
+        pFlac->bs.pUserData = &pFlac->memoryStream;
+    }
+
+    return pFlac;
+}
+
+DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac__memory_stream memoryStream;
+    drflac* pFlac;
+
+    memoryStream.data = (const drflac_uint8*)pData;
+    memoryStream.dataSize = dataSize;
+    memoryStream.currentReadPos = 0;
+    pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    pFlac->memoryStream = memoryStream;
+
+    /* This is an awful hack... */
+#ifndef DR_FLAC_NO_OGG
+    if (pFlac->container == drflac_container_ogg)
+    {
+        drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
+        oggbs->pUserData = &pFlac->memoryStream;
+    }
+    else
+#endif
+    {
+        pFlac->bs.pUserData = &pFlac->memoryStream;
+    }
+
+    return pFlac;
+}
+
+
+
+DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    return drflac_open_with_metadata_private(onRead, onSeek, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
+}
+DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    return drflac_open_with_metadata_private(onRead, onSeek, NULL, container, pUserData, pUserData, pAllocationCallbacks);
+}
+
+DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    return drflac_open_with_metadata_private(onRead, onSeek, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks);
+}
+DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    return drflac_open_with_metadata_private(onRead, onSeek, onMeta, container, pUserData, pUserData, pAllocationCallbacks);
+}
+
+DRFLAC_API void drflac_close(drflac* pFlac)
+{
+    if (pFlac == NULL) {
+        return;
+    }
+
+#ifndef DR_FLAC_NO_STDIO
+    /*
+    If we opened the file with drflac_open_file() we will want to close the file handle. We can know whether or not drflac_open_file()
+    was used by looking at the callbacks.
+    */
+    if (pFlac->bs.onRead == drflac__on_read_stdio) {
+        fclose((FILE*)pFlac->bs.pUserData);
+    }
+
+#ifndef DR_FLAC_NO_OGG
+    /* Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained. */
+    if (pFlac->container == drflac_container_ogg) {
+        drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs;
+        DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg);
+
+        if (oggbs->onRead == drflac__on_read_stdio) {
+            fclose((FILE*)oggbs->pUserData);
+        }
+    }
+#endif
+#endif
+
+    drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks);
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    for (i = 0; i < frameCount; ++i) {
+        drflac_uint32 left  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+        drflac_uint32 side  = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+        drflac_uint32 right = left - side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left;
+        pOutputSamples[i*2+1] = (drflac_int32)right;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    for (i = 0; i < frameCount4; ++i) {
+        drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
+        drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
+        drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
+        drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
+
+        drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
+        drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
+        drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
+        drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
+
+        drflac_uint32 right0 = left0 - side0;
+        drflac_uint32 right1 = left1 - side1;
+        drflac_uint32 right2 = left2 - side2;
+        drflac_uint32 right3 = left3 - side3;
+
+        pOutputSamples[i*8+0] = (drflac_int32)left0;
+        pOutputSamples[i*8+1] = (drflac_int32)right0;
+        pOutputSamples[i*8+2] = (drflac_int32)left1;
+        pOutputSamples[i*8+3] = (drflac_int32)right1;
+        pOutputSamples[i*8+4] = (drflac_int32)left2;
+        pOutputSamples[i*8+5] = (drflac_int32)right2;
+        pOutputSamples[i*8+6] = (drflac_int32)left3;
+        pOutputSamples[i*8+7] = (drflac_int32)right3;
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 left  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 side  = pInputSamples1U32[i] << shift1;
+        drflac_uint32 right = left - side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left;
+        pOutputSamples[i*2+1] = (drflac_int32)right;
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    for (i = 0; i < frameCount4; ++i) {
+        __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
+        __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
+        __m128i right = _mm_sub_epi32(left, side);
+
+        _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
+        _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 left  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 side  = pInputSamples1U32[i] << shift1;
+        drflac_uint32 right = left - side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left;
+        pOutputSamples[i*2+1] = (drflac_int32)right;
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+    int32x4_t shift0_4;
+    int32x4_t shift1_4;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    shift0_4 = vdupq_n_s32(shift0);
+    shift1_4 = vdupq_n_s32(shift1);
+
+    for (i = 0; i < frameCount4; ++i) {
+        uint32x4_t left;
+        uint32x4_t side;
+        uint32x4_t right;
+
+        left  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
+        side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
+        right = vsubq_u32(left, side);
+
+        drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 left  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 side  = pInputSamples1U32[i] << shift1;
+        drflac_uint32 right = left - side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left;
+        pOutputSamples[i*2+1] = (drflac_int32)right;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    for (i = 0; i < frameCount; ++i) {
+        drflac_uint32 side  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+        drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+        drflac_uint32 left  = right + side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left;
+        pOutputSamples[i*2+1] = (drflac_int32)right;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    for (i = 0; i < frameCount4; ++i) {
+        drflac_uint32 side0  = pInputSamples0U32[i*4+0] << shift0;
+        drflac_uint32 side1  = pInputSamples0U32[i*4+1] << shift0;
+        drflac_uint32 side2  = pInputSamples0U32[i*4+2] << shift0;
+        drflac_uint32 side3  = pInputSamples0U32[i*4+3] << shift0;
+
+        drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
+        drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
+        drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
+        drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
+
+        drflac_uint32 left0 = right0 + side0;
+        drflac_uint32 left1 = right1 + side1;
+        drflac_uint32 left2 = right2 + side2;
+        drflac_uint32 left3 = right3 + side3;
+
+        pOutputSamples[i*8+0] = (drflac_int32)left0;
+        pOutputSamples[i*8+1] = (drflac_int32)right0;
+        pOutputSamples[i*8+2] = (drflac_int32)left1;
+        pOutputSamples[i*8+3] = (drflac_int32)right1;
+        pOutputSamples[i*8+4] = (drflac_int32)left2;
+        pOutputSamples[i*8+5] = (drflac_int32)right2;
+        pOutputSamples[i*8+6] = (drflac_int32)left3;
+        pOutputSamples[i*8+7] = (drflac_int32)right3;
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 side  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 right = pInputSamples1U32[i] << shift1;
+        drflac_uint32 left  = right + side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left;
+        pOutputSamples[i*2+1] = (drflac_int32)right;
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    for (i = 0; i < frameCount4; ++i) {
+        __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
+        __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
+        __m128i left  = _mm_add_epi32(right, side);
+
+        _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
+        _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 side  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 right = pInputSamples1U32[i] << shift1;
+        drflac_uint32 left  = right + side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left;
+        pOutputSamples[i*2+1] = (drflac_int32)right;
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+    int32x4_t shift0_4;
+    int32x4_t shift1_4;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    shift0_4 = vdupq_n_s32(shift0);
+    shift1_4 = vdupq_n_s32(shift1);
+
+    for (i = 0; i < frameCount4; ++i) {
+        uint32x4_t side;
+        uint32x4_t right;
+        uint32x4_t left;
+
+        side  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
+        right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
+        left  = vaddq_u32(right, side);
+
+        drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 side  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 right = pInputSamples1U32[i] << shift1;
+        drflac_uint32 left  = right + side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left;
+        pOutputSamples[i*2+1] = (drflac_int32)right;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    for (drflac_uint64 i = 0; i < frameCount; ++i) {
+        drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+        drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+        mid = (mid << 1) | (side & 0x01);
+
+        pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
+        pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_int32 shift = unusedBitsPerSample;
+
+    if (shift > 0) {
+        shift -= 1;
+        for (i = 0; i < frameCount4; ++i) {
+            drflac_uint32 temp0L;
+            drflac_uint32 temp1L;
+            drflac_uint32 temp2L;
+            drflac_uint32 temp3L;
+            drflac_uint32 temp0R;
+            drflac_uint32 temp1R;
+            drflac_uint32 temp2R;
+            drflac_uint32 temp3R;
+
+            drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+
+            drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid0 = (mid0 << 1) | (side0 & 0x01);
+            mid1 = (mid1 << 1) | (side1 & 0x01);
+            mid2 = (mid2 << 1) | (side2 & 0x01);
+            mid3 = (mid3 << 1) | (side3 & 0x01);
+
+            temp0L = (mid0 + side0) << shift;
+            temp1L = (mid1 + side1) << shift;
+            temp2L = (mid2 + side2) << shift;
+            temp3L = (mid3 + side3) << shift;
+
+            temp0R = (mid0 - side0) << shift;
+            temp1R = (mid1 - side1) << shift;
+            temp2R = (mid2 - side2) << shift;
+            temp3R = (mid3 - side3) << shift;
+
+            pOutputSamples[i*8+0] = (drflac_int32)temp0L;
+            pOutputSamples[i*8+1] = (drflac_int32)temp0R;
+            pOutputSamples[i*8+2] = (drflac_int32)temp1L;
+            pOutputSamples[i*8+3] = (drflac_int32)temp1R;
+            pOutputSamples[i*8+4] = (drflac_int32)temp2L;
+            pOutputSamples[i*8+5] = (drflac_int32)temp2R;
+            pOutputSamples[i*8+6] = (drflac_int32)temp3L;
+            pOutputSamples[i*8+7] = (drflac_int32)temp3R;
+        }
+    } else {
+        for (i = 0; i < frameCount4; ++i) {
+            drflac_uint32 temp0L;
+            drflac_uint32 temp1L;
+            drflac_uint32 temp2L;
+            drflac_uint32 temp3L;
+            drflac_uint32 temp0R;
+            drflac_uint32 temp1R;
+            drflac_uint32 temp2R;
+            drflac_uint32 temp3R;
+
+            drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+
+            drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid0 = (mid0 << 1) | (side0 & 0x01);
+            mid1 = (mid1 << 1) | (side1 & 0x01);
+            mid2 = (mid2 << 1) | (side2 & 0x01);
+            mid3 = (mid3 << 1) | (side3 & 0x01);
+
+            temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
+            temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
+            temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
+            temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
+
+            temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
+            temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
+            temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
+            temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
+
+            pOutputSamples[i*8+0] = (drflac_int32)temp0L;
+            pOutputSamples[i*8+1] = (drflac_int32)temp0R;
+            pOutputSamples[i*8+2] = (drflac_int32)temp1L;
+            pOutputSamples[i*8+3] = (drflac_int32)temp1R;
+            pOutputSamples[i*8+4] = (drflac_int32)temp2L;
+            pOutputSamples[i*8+5] = (drflac_int32)temp2R;
+            pOutputSamples[i*8+6] = (drflac_int32)temp3L;
+            pOutputSamples[i*8+7] = (drflac_int32)temp3R;
+        }
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+        drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+        mid = (mid << 1) | (side & 0x01);
+
+        pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample);
+        pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample);
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_int32 shift = unusedBitsPerSample;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    if (shift == 0) {
+        for (i = 0; i < frameCount4; ++i) {
+            __m128i mid;
+            __m128i side;
+            __m128i left;
+            __m128i right;
+
+            mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+            side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+
+            mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
+
+            left  = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
+            right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
+
+            _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
+            _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
+            pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
+        }
+    } else {
+        shift -= 1;
+        for (i = 0; i < frameCount4; ++i) {
+            __m128i mid;
+            __m128i side;
+            __m128i left;
+            __m128i right;
+
+            mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+            side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+
+            mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
+
+            left  = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
+            right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
+
+            _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
+            _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
+            pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
+        }
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_int32 shift = unusedBitsPerSample;
+    int32x4_t  wbpsShift0_4; /* wbps = Wasted Bits Per Sample */
+    int32x4_t  wbpsShift1_4; /* wbps = Wasted Bits Per Sample */
+    uint32x4_t one4;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+    wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+    one4         = vdupq_n_u32(1);
+
+    if (shift == 0) {
+        for (i = 0; i < frameCount4; ++i) {
+            uint32x4_t mid;
+            uint32x4_t side;
+            int32x4_t left;
+            int32x4_t right;
+
+            mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
+            side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
+
+            mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
+
+            left  = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
+            right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
+
+            drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1;
+            pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1;
+        }
+    } else {
+        int32x4_t shift4;
+
+        shift -= 1;
+        shift4 = vdupq_n_s32(shift);
+
+        for (i = 0; i < frameCount4; ++i) {
+            uint32x4_t mid;
+            uint32x4_t side;
+            int32x4_t left;
+            int32x4_t right;
+
+            mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
+            side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
+
+            mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4));
+
+            left  = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
+            right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
+
+            drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift);
+            pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift);
+        }
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    for (drflac_uint64 i = 0; i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample));
+        pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample));
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    for (i = 0; i < frameCount4; ++i) {
+        drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
+        drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
+        drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
+        drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
+
+        drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
+        drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
+        drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
+        drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
+
+        pOutputSamples[i*8+0] = (drflac_int32)tempL0;
+        pOutputSamples[i*8+1] = (drflac_int32)tempR0;
+        pOutputSamples[i*8+2] = (drflac_int32)tempL1;
+        pOutputSamples[i*8+3] = (drflac_int32)tempR1;
+        pOutputSamples[i*8+4] = (drflac_int32)tempL2;
+        pOutputSamples[i*8+5] = (drflac_int32)tempR2;
+        pOutputSamples[i*8+6] = (drflac_int32)tempL3;
+        pOutputSamples[i*8+7] = (drflac_int32)tempR3;
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
+        pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    for (i = 0; i < frameCount4; ++i) {
+        __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
+        __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
+
+        _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right));
+        _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
+        pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    int32x4_t shift4_0 = vdupq_n_s32(shift0);
+    int32x4_t shift4_1 = vdupq_n_s32(shift1);
+
+    for (i = 0; i < frameCount4; ++i) {
+        int32x4_t left;
+        int32x4_t right;
+
+        left  = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift4_0));
+        right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift4_1));
+
+        drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0);
+        pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1);
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+
+DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut)
+{
+    drflac_uint64 framesRead;
+    drflac_uint32 unusedBitsPerSample;
+
+    if (pFlac == NULL || framesToRead == 0) {
+        return 0;
+    }
+
+    if (pBufferOut == NULL) {
+        return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
+    }
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
+    unusedBitsPerSample = 32 - pFlac->bitsPerSample;
+
+    framesRead = 0;
+    while (framesToRead > 0) {
+        /* If we've run out of samples in this frame, go to the next. */
+        if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
+            if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
+                break;  /* Couldn't read the next frame, so just break from the loop and return. */
+            }
+        } else {
+            unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
+            drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
+            drflac_uint64 frameCountThisIteration = framesToRead;
+
+            if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
+                frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
+            }
+
+            if (channelCount == 2) {
+                const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
+                const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
+
+                switch (pFlac->currentFLACFrame.header.channelAssignment)
+                {
+                    case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
+                    {
+                        drflac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+
+                    case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+                    {
+                        drflac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+
+                    case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
+                    {
+                        drflac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+
+                    case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
+                    default:
+                    {
+                        drflac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+                }
+            } else {
+                /* Generic interleaving. */
+                drflac_uint64 i;
+                for (i = 0; i < frameCountThisIteration; ++i) {
+                    unsigned int j;
+                    for (j = 0; j < channelCount; ++j) {
+                        pBufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
+                    }
+                }
+            }
+
+            framesRead                += frameCountThisIteration;
+            pBufferOut                += frameCountThisIteration * channelCount;
+            framesToRead              -= frameCountThisIteration;
+            pFlac->currentPCMFrame    += frameCountThisIteration;
+            pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
+        }
+    }
+
+    return framesRead;
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    for (i = 0; i < frameCount; ++i) {
+        drflac_uint32 left  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+        drflac_uint32 side  = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+        drflac_uint32 right = left - side;
+
+        left  >>= 16;
+        right >>= 16;
+
+        pOutputSamples[i*2+0] = (drflac_int16)left;
+        pOutputSamples[i*2+1] = (drflac_int16)right;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    for (i = 0; i < frameCount4; ++i) {
+        drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
+        drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
+        drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
+        drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
+
+        drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
+        drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
+        drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
+        drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
+
+        drflac_uint32 right0 = left0 - side0;
+        drflac_uint32 right1 = left1 - side1;
+        drflac_uint32 right2 = left2 - side2;
+        drflac_uint32 right3 = left3 - side3;
+
+        left0  >>= 16;
+        left1  >>= 16;
+        left2  >>= 16;
+        left3  >>= 16;
+
+        right0 >>= 16;
+        right1 >>= 16;
+        right2 >>= 16;
+        right3 >>= 16;
+
+        pOutputSamples[i*8+0] = (drflac_int16)left0;
+        pOutputSamples[i*8+1] = (drflac_int16)right0;
+        pOutputSamples[i*8+2] = (drflac_int16)left1;
+        pOutputSamples[i*8+3] = (drflac_int16)right1;
+        pOutputSamples[i*8+4] = (drflac_int16)left2;
+        pOutputSamples[i*8+5] = (drflac_int16)right2;
+        pOutputSamples[i*8+6] = (drflac_int16)left3;
+        pOutputSamples[i*8+7] = (drflac_int16)right3;
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 left  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 side  = pInputSamples1U32[i] << shift1;
+        drflac_uint32 right = left - side;
+
+        left  >>= 16;
+        right >>= 16;
+
+        pOutputSamples[i*2+0] = (drflac_int16)left;
+        pOutputSamples[i*2+1] = (drflac_int16)right;
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    for (i = 0; i < frameCount4; ++i) {
+        __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
+        __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
+        __m128i right = _mm_sub_epi32(left, side);
+
+        left  = _mm_srai_epi32(left,  16);
+        right = _mm_srai_epi32(right, 16);
+
+        _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 left  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 side  = pInputSamples1U32[i] << shift1;
+        drflac_uint32 right = left - side;
+
+        left  >>= 16;
+        right >>= 16;
+
+        pOutputSamples[i*2+0] = (drflac_int16)left;
+        pOutputSamples[i*2+1] = (drflac_int16)right;
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+    int32x4_t shift0_4;
+    int32x4_t shift1_4;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    shift0_4 = vdupq_n_s32(shift0);
+    shift1_4 = vdupq_n_s32(shift1);
+
+    for (i = 0; i < frameCount4; ++i) {
+        uint32x4_t left;
+        uint32x4_t side;
+        uint32x4_t right;
+
+        left  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
+        side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
+        right = vsubq_u32(left, side);
+
+        left  = vshrq_n_u32(left,  16);
+        right = vshrq_n_u32(right, 16);
+
+        drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 left  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 side  = pInputSamples1U32[i] << shift1;
+        drflac_uint32 right = left - side;
+
+        left  >>= 16;
+        right >>= 16;
+
+        pOutputSamples[i*2+0] = (drflac_int16)left;
+        pOutputSamples[i*2+1] = (drflac_int16)right;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s16__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s16__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    for (i = 0; i < frameCount; ++i) {
+        drflac_uint32 side  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+        drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+        drflac_uint32 left  = right + side;
+
+        left  >>= 16;
+        right >>= 16;
+
+        pOutputSamples[i*2+0] = (drflac_int16)left;
+        pOutputSamples[i*2+1] = (drflac_int16)right;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    for (i = 0; i < frameCount4; ++i) {
+        drflac_uint32 side0  = pInputSamples0U32[i*4+0] << shift0;
+        drflac_uint32 side1  = pInputSamples0U32[i*4+1] << shift0;
+        drflac_uint32 side2  = pInputSamples0U32[i*4+2] << shift0;
+        drflac_uint32 side3  = pInputSamples0U32[i*4+3] << shift0;
+
+        drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
+        drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
+        drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
+        drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
+
+        drflac_uint32 left0 = right0 + side0;
+        drflac_uint32 left1 = right1 + side1;
+        drflac_uint32 left2 = right2 + side2;
+        drflac_uint32 left3 = right3 + side3;
+
+        left0  >>= 16;
+        left1  >>= 16;
+        left2  >>= 16;
+        left3  >>= 16;
+
+        right0 >>= 16;
+        right1 >>= 16;
+        right2 >>= 16;
+        right3 >>= 16;
+
+        pOutputSamples[i*8+0] = (drflac_int16)left0;
+        pOutputSamples[i*8+1] = (drflac_int16)right0;
+        pOutputSamples[i*8+2] = (drflac_int16)left1;
+        pOutputSamples[i*8+3] = (drflac_int16)right1;
+        pOutputSamples[i*8+4] = (drflac_int16)left2;
+        pOutputSamples[i*8+5] = (drflac_int16)right2;
+        pOutputSamples[i*8+6] = (drflac_int16)left3;
+        pOutputSamples[i*8+7] = (drflac_int16)right3;
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 side  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 right = pInputSamples1U32[i] << shift1;
+        drflac_uint32 left  = right + side;
+
+        left  >>= 16;
+        right >>= 16;
+
+        pOutputSamples[i*2+0] = (drflac_int16)left;
+        pOutputSamples[i*2+1] = (drflac_int16)right;
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    for (i = 0; i < frameCount4; ++i) {
+        __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
+        __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
+        __m128i left  = _mm_add_epi32(right, side);
+
+        left  = _mm_srai_epi32(left,  16);
+        right = _mm_srai_epi32(right, 16);
+
+        _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 side  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 right = pInputSamples1U32[i] << shift1;
+        drflac_uint32 left  = right + side;
+
+        left  >>= 16;
+        right >>= 16;
+
+        pOutputSamples[i*2+0] = (drflac_int16)left;
+        pOutputSamples[i*2+1] = (drflac_int16)right;
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+    int32x4_t shift0_4;
+    int32x4_t shift1_4;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    shift0_4 = vdupq_n_s32(shift0);
+    shift1_4 = vdupq_n_s32(shift1);
+
+    for (i = 0; i < frameCount4; ++i) {
+        uint32x4_t side;
+        uint32x4_t right;
+        uint32x4_t left;
+
+        side  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
+        right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
+        left  = vaddq_u32(right, side);
+
+        left  = vshrq_n_u32(left,  16);
+        right = vshrq_n_u32(right, 16);
+
+        drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right)));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 side  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 right = pInputSamples1U32[i] << shift1;
+        drflac_uint32 left  = right + side;
+
+        left  >>= 16;
+        right >>= 16;
+
+        pOutputSamples[i*2+0] = (drflac_int16)left;
+        pOutputSamples[i*2+1] = (drflac_int16)right;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s16__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s16__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    for (drflac_uint64 i = 0; i < frameCount; ++i) {
+        drflac_uint32 mid  = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+        drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+        mid = (mid << 1) | (side & 0x01);
+
+        pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
+        pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift = unusedBitsPerSample;
+
+    if (shift > 0) {
+        shift -= 1;
+        for (i = 0; i < frameCount4; ++i) {
+            drflac_uint32 temp0L;
+            drflac_uint32 temp1L;
+            drflac_uint32 temp2L;
+            drflac_uint32 temp3L;
+            drflac_uint32 temp0R;
+            drflac_uint32 temp1R;
+            drflac_uint32 temp2R;
+            drflac_uint32 temp3R;
+
+            drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+
+            drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid0 = (mid0 << 1) | (side0 & 0x01);
+            mid1 = (mid1 << 1) | (side1 & 0x01);
+            mid2 = (mid2 << 1) | (side2 & 0x01);
+            mid3 = (mid3 << 1) | (side3 & 0x01);
+
+            temp0L = (mid0 + side0) << shift;
+            temp1L = (mid1 + side1) << shift;
+            temp2L = (mid2 + side2) << shift;
+            temp3L = (mid3 + side3) << shift;
+
+            temp0R = (mid0 - side0) << shift;
+            temp1R = (mid1 - side1) << shift;
+            temp2R = (mid2 - side2) << shift;
+            temp3R = (mid3 - side3) << shift;
+
+            temp0L >>= 16;
+            temp1L >>= 16;
+            temp2L >>= 16;
+            temp3L >>= 16;
+
+            temp0R >>= 16;
+            temp1R >>= 16;
+            temp2R >>= 16;
+            temp3R >>= 16;
+
+            pOutputSamples[i*8+0] = (drflac_int16)temp0L;
+            pOutputSamples[i*8+1] = (drflac_int16)temp0R;
+            pOutputSamples[i*8+2] = (drflac_int16)temp1L;
+            pOutputSamples[i*8+3] = (drflac_int16)temp1R;
+            pOutputSamples[i*8+4] = (drflac_int16)temp2L;
+            pOutputSamples[i*8+5] = (drflac_int16)temp2R;
+            pOutputSamples[i*8+6] = (drflac_int16)temp3L;
+            pOutputSamples[i*8+7] = (drflac_int16)temp3R;
+        }
+    } else {
+        for (i = 0; i < frameCount4; ++i) {
+            drflac_uint32 temp0L;
+            drflac_uint32 temp1L;
+            drflac_uint32 temp2L;
+            drflac_uint32 temp3L;
+            drflac_uint32 temp0R;
+            drflac_uint32 temp1R;
+            drflac_uint32 temp2R;
+            drflac_uint32 temp3R;
+
+            drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+
+            drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid0 = (mid0 << 1) | (side0 & 0x01);
+            mid1 = (mid1 << 1) | (side1 & 0x01);
+            mid2 = (mid2 << 1) | (side2 & 0x01);
+            mid3 = (mid3 << 1) | (side3 & 0x01);
+
+            temp0L = ((drflac_int32)(mid0 + side0) >> 1);
+            temp1L = ((drflac_int32)(mid1 + side1) >> 1);
+            temp2L = ((drflac_int32)(mid2 + side2) >> 1);
+            temp3L = ((drflac_int32)(mid3 + side3) >> 1);
+
+            temp0R = ((drflac_int32)(mid0 - side0) >> 1);
+            temp1R = ((drflac_int32)(mid1 - side1) >> 1);
+            temp2R = ((drflac_int32)(mid2 - side2) >> 1);
+            temp3R = ((drflac_int32)(mid3 - side3) >> 1);
+
+            temp0L >>= 16;
+            temp1L >>= 16;
+            temp2L >>= 16;
+            temp3L >>= 16;
+
+            temp0R >>= 16;
+            temp1R >>= 16;
+            temp2R >>= 16;
+            temp3R >>= 16;
+
+            pOutputSamples[i*8+0] = (drflac_int16)temp0L;
+            pOutputSamples[i*8+1] = (drflac_int16)temp0R;
+            pOutputSamples[i*8+2] = (drflac_int16)temp1L;
+            pOutputSamples[i*8+3] = (drflac_int16)temp1R;
+            pOutputSamples[i*8+4] = (drflac_int16)temp2L;
+            pOutputSamples[i*8+5] = (drflac_int16)temp2R;
+            pOutputSamples[i*8+6] = (drflac_int16)temp3L;
+            pOutputSamples[i*8+7] = (drflac_int16)temp3R;
+        }
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+        drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+        mid = (mid << 1) | (side & 0x01);
+
+        pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16);
+        pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16);
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift = unusedBitsPerSample;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    if (shift == 0) {
+        for (i = 0; i < frameCount4; ++i) {
+            __m128i mid;
+            __m128i side;
+            __m128i left;
+            __m128i right;
+
+            mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+            side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+
+            mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
+
+            left  = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
+            right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
+
+            left  = _mm_srai_epi32(left,  16);
+            right = _mm_srai_epi32(right, 16);
+
+            _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
+            pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
+        }
+    } else {
+        shift -= 1;
+        for (i = 0; i < frameCount4; ++i) {
+            __m128i mid;
+            __m128i side;
+            __m128i left;
+            __m128i right;
+
+            mid   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+            side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+
+            mid   = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
+
+            left  = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
+            right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
+
+            left  = _mm_srai_epi32(left,  16);
+            right = _mm_srai_epi32(right, 16);
+
+            _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
+            pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
+        }
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift = unusedBitsPerSample;
+    int32x4_t wbpsShift0_4; /* wbps = Wasted Bits Per Sample */
+    int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+    wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+
+    if (shift == 0) {
+        for (i = 0; i < frameCount4; ++i) {
+            uint32x4_t mid;
+            uint32x4_t side;
+            int32x4_t left;
+            int32x4_t right;
+
+            mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
+            side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
+
+            mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
+
+            left  = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
+            right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
+
+            left  = vshrq_n_s32(left,  16);
+            right = vshrq_n_s32(right, 16);
+
+            drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16);
+            pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16);
+        }
+    } else {
+        int32x4_t shift4;
+
+        shift -= 1;
+        shift4 = vdupq_n_s32(shift);
+
+        for (i = 0; i < frameCount4; ++i) {
+            uint32x4_t mid;
+            uint32x4_t side;
+            int32x4_t left;
+            int32x4_t right;
+
+            mid   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4);
+            side  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4);
+
+            mid   = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
+
+            left  = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
+            right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
+
+            left  = vshrq_n_s32(left,  16);
+            right = vshrq_n_s32(right, 16);
+
+            drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16);
+            pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16);
+        }
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s16__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s16__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    for (drflac_uint64 i = 0; i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) >> 16);
+        pOutputSamples[i*2+1] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) >> 16);
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    for (i = 0; i < frameCount4; ++i) {
+        drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
+        drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
+        drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
+        drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
+
+        drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
+        drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
+        drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
+        drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
+
+        tempL0 >>= 16;
+        tempL1 >>= 16;
+        tempL2 >>= 16;
+        tempL3 >>= 16;
+
+        tempR0 >>= 16;
+        tempR1 >>= 16;
+        tempR2 >>= 16;
+        tempR3 >>= 16;
+
+        pOutputSamples[i*8+0] = (drflac_int16)tempL0;
+        pOutputSamples[i*8+1] = (drflac_int16)tempR0;
+        pOutputSamples[i*8+2] = (drflac_int16)tempL1;
+        pOutputSamples[i*8+3] = (drflac_int16)tempR1;
+        pOutputSamples[i*8+4] = (drflac_int16)tempL2;
+        pOutputSamples[i*8+5] = (drflac_int16)tempR2;
+        pOutputSamples[i*8+6] = (drflac_int16)tempL3;
+        pOutputSamples[i*8+7] = (drflac_int16)tempR3;
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
+        pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    for (i = 0; i < frameCount4; ++i) {
+        __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
+        __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
+
+        left  = _mm_srai_epi32(left,  16);
+        right = _mm_srai_epi32(right, 16);
+
+        /* At this point we have results. We can now pack and interleave these into a single __m128i object and then store the in the output buffer. */
+        _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
+        pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    int32x4_t shift0_4 = vdupq_n_s32(shift0);
+    int32x4_t shift1_4 = vdupq_n_s32(shift1);
+
+    for (i = 0; i < frameCount4; ++i) {
+        int32x4_t left;
+        int32x4_t right;
+
+        left  = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
+        right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
+
+        left  = vshrq_n_s32(left,  16);
+        right = vshrq_n_s32(right, 16);
+
+        drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right)));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16);
+        pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16);
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_s16__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut)
+{
+    drflac_uint64 framesRead;
+    drflac_uint32 unusedBitsPerSample;
+
+    if (pFlac == NULL || framesToRead == 0) {
+        return 0;
+    }
+
+    if (pBufferOut == NULL) {
+        return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
+    }
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
+    unusedBitsPerSample = 32 - pFlac->bitsPerSample;
+
+    framesRead = 0;
+    while (framesToRead > 0) {
+        /* If we've run out of samples in this frame, go to the next. */
+        if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
+            if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
+                break;  /* Couldn't read the next frame, so just break from the loop and return. */
+            }
+        } else {
+            unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
+            drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
+            drflac_uint64 frameCountThisIteration = framesToRead;
+
+            if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
+                frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
+            }
+
+            if (channelCount == 2) {
+                const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
+                const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
+
+                switch (pFlac->currentFLACFrame.header.channelAssignment)
+                {
+                    case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
+                    {
+                        drflac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+
+                    case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+                    {
+                        drflac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+
+                    case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
+                    {
+                        drflac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+
+                    case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
+                    default:
+                    {
+                        drflac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+                }
+            } else {
+                /* Generic interleaving. */
+                drflac_uint64 i;
+                for (i = 0; i < frameCountThisIteration; ++i) {
+                    unsigned int j;
+                    for (j = 0; j < channelCount; ++j) {
+                        drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
+                        pBufferOut[(i*channelCount)+j] = (drflac_int16)(sampleS32 >> 16);
+                    }
+                }
+            }
+
+            framesRead                += frameCountThisIteration;
+            pBufferOut                += frameCountThisIteration * channelCount;
+            framesToRead              -= frameCountThisIteration;
+            pFlac->currentPCMFrame    += frameCountThisIteration;
+            pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration;
+        }
+    }
+
+    return framesRead;
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    for (i = 0; i < frameCount; ++i) {
+        drflac_uint32 left  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+        drflac_uint32 side  = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+        drflac_uint32 right = left - side;
+
+        pOutputSamples[i*2+0] = (float)((drflac_int32)left  / 2147483648.0);
+        pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+    float factor = 1 / 2147483648.0;
+
+    for (i = 0; i < frameCount4; ++i) {
+        drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0;
+        drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0;
+        drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0;
+        drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0;
+
+        drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1;
+        drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1;
+        drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1;
+        drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1;
+
+        drflac_uint32 right0 = left0 - side0;
+        drflac_uint32 right1 = left1 - side1;
+        drflac_uint32 right2 = left2 - side2;
+        drflac_uint32 right3 = left3 - side3;
+
+        pOutputSamples[i*8+0] = (drflac_int32)left0  * factor;
+        pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
+        pOutputSamples[i*8+2] = (drflac_int32)left1  * factor;
+        pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
+        pOutputSamples[i*8+4] = (drflac_int32)left2  * factor;
+        pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
+        pOutputSamples[i*8+6] = (drflac_int32)left3  * factor;
+        pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 left  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 side  = pInputSamples1U32[i] << shift1;
+        drflac_uint32 right = left - side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left  * factor;
+        pOutputSamples[i*2+1] = (drflac_int32)right * factor;
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
+    drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
+    __m128 factor;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    factor = _mm_set1_ps(1.0f / 8388608.0f);
+
+    for (i = 0; i < frameCount4; ++i) {
+        __m128i left  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
+        __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
+        __m128i right = _mm_sub_epi32(left, side);
+        __m128 leftf  = _mm_mul_ps(_mm_cvtepi32_ps(left),  factor);
+        __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
+
+        _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
+        _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 left  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 side  = pInputSamples1U32[i] << shift1;
+        drflac_uint32 right = left - side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
+        pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
+    drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
+    float32x4_t factor4;
+    int32x4_t shift0_4;
+    int32x4_t shift1_4;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    factor4  = vdupq_n_f32(1.0f / 8388608.0f);
+    shift0_4 = vdupq_n_s32(shift0);
+    shift1_4 = vdupq_n_s32(shift1);
+
+    for (i = 0; i < frameCount4; ++i) {
+        uint32x4_t left;
+        uint32x4_t side;
+        uint32x4_t right;
+        float32x4_t leftf;
+        float32x4_t rightf;
+
+        left   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
+        side   = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
+        right  = vsubq_u32(left, side);
+        leftf  = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)),  factor4);
+        rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
+
+        drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 left  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 side  = pInputSamples1U32[i] << shift1;
+        drflac_uint32 right = left - side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
+        pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_f32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_f32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    for (i = 0; i < frameCount; ++i) {
+        drflac_uint32 side  = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+        drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+        drflac_uint32 left  = right + side;
+
+        pOutputSamples[i*2+0] = (float)((drflac_int32)left  / 2147483648.0);
+        pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0);
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+    float factor = 1 / 2147483648.0;
+
+    for (i = 0; i < frameCount4; ++i) {
+        drflac_uint32 side0  = pInputSamples0U32[i*4+0] << shift0;
+        drflac_uint32 side1  = pInputSamples0U32[i*4+1] << shift0;
+        drflac_uint32 side2  = pInputSamples0U32[i*4+2] << shift0;
+        drflac_uint32 side3  = pInputSamples0U32[i*4+3] << shift0;
+
+        drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1;
+        drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1;
+        drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1;
+        drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1;
+
+        drflac_uint32 left0 = right0 + side0;
+        drflac_uint32 left1 = right1 + side1;
+        drflac_uint32 left2 = right2 + side2;
+        drflac_uint32 left3 = right3 + side3;
+
+        pOutputSamples[i*8+0] = (drflac_int32)left0  * factor;
+        pOutputSamples[i*8+1] = (drflac_int32)right0 * factor;
+        pOutputSamples[i*8+2] = (drflac_int32)left1  * factor;
+        pOutputSamples[i*8+3] = (drflac_int32)right1 * factor;
+        pOutputSamples[i*8+4] = (drflac_int32)left2  * factor;
+        pOutputSamples[i*8+5] = (drflac_int32)right2 * factor;
+        pOutputSamples[i*8+6] = (drflac_int32)left3  * factor;
+        pOutputSamples[i*8+7] = (drflac_int32)right3 * factor;
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 side  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 right = pInputSamples1U32[i] << shift1;
+        drflac_uint32 left  = right + side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left  * factor;
+        pOutputSamples[i*2+1] = (drflac_int32)right * factor;
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
+    drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
+    __m128 factor;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    factor = _mm_set1_ps(1.0f / 8388608.0f);
+
+    for (i = 0; i < frameCount4; ++i) {
+        __m128i side  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
+        __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
+        __m128i left  = _mm_add_epi32(right, side);
+        __m128 leftf  = _mm_mul_ps(_mm_cvtepi32_ps(left),  factor);
+        __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor);
+
+        _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
+        _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 side  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 right = pInputSamples1U32[i] << shift1;
+        drflac_uint32 left  = right + side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
+        pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
+    drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
+    float32x4_t factor4;
+    int32x4_t shift0_4;
+    int32x4_t shift1_4;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    factor4  = vdupq_n_f32(1.0f / 8388608.0f);
+    shift0_4 = vdupq_n_s32(shift0);
+    shift1_4 = vdupq_n_s32(shift1);
+
+    for (i = 0; i < frameCount4; ++i) {
+        uint32x4_t side;
+        uint32x4_t right;
+        uint32x4_t left;
+        float32x4_t leftf;
+        float32x4_t rightf;
+
+        side   = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4);
+        right  = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4);
+        left   = vaddq_u32(right, side);
+        leftf  = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)),  factor4);
+        rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4);
+
+        drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 side  = pInputSamples0U32[i] << shift0;
+        drflac_uint32 right = pInputSamples1U32[i] << shift1;
+        drflac_uint32 left  = right + side;
+
+        pOutputSamples[i*2+0] = (drflac_int32)left  / 8388608.0f;
+        pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_f32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_f32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    for (drflac_uint64 i = 0; i < frameCount; ++i) {
+        drflac_uint32 mid  = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+        drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+        mid = (mid << 1) | (side & 0x01);
+
+        pOutputSamples[i*2+0] = (float)((((drflac_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
+        pOutputSamples[i*2+1] = (float)((((drflac_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0);
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift = unusedBitsPerSample;
+    float factor = 1 / 2147483648.0;
+
+    if (shift > 0) {
+        shift -= 1;
+        for (i = 0; i < frameCount4; ++i) {
+            drflac_uint32 temp0L;
+            drflac_uint32 temp1L;
+            drflac_uint32 temp2L;
+            drflac_uint32 temp3L;
+            drflac_uint32 temp0R;
+            drflac_uint32 temp1R;
+            drflac_uint32 temp2R;
+            drflac_uint32 temp3R;
+
+            drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+
+            drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid0 = (mid0 << 1) | (side0 & 0x01);
+            mid1 = (mid1 << 1) | (side1 & 0x01);
+            mid2 = (mid2 << 1) | (side2 & 0x01);
+            mid3 = (mid3 << 1) | (side3 & 0x01);
+
+            temp0L = (mid0 + side0) << shift;
+            temp1L = (mid1 + side1) << shift;
+            temp2L = (mid2 + side2) << shift;
+            temp3L = (mid3 + side3) << shift;
+
+            temp0R = (mid0 - side0) << shift;
+            temp1R = (mid1 - side1) << shift;
+            temp2R = (mid2 - side2) << shift;
+            temp3R = (mid3 - side3) << shift;
+
+            pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
+            pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
+            pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
+            pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
+            pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
+            pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
+            pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
+            pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
+        }
+    } else {
+        for (i = 0; i < frameCount4; ++i) {
+            drflac_uint32 temp0L;
+            drflac_uint32 temp1L;
+            drflac_uint32 temp2L;
+            drflac_uint32 temp3L;
+            drflac_uint32 temp0R;
+            drflac_uint32 temp1R;
+            drflac_uint32 temp2R;
+            drflac_uint32 temp3R;
+
+            drflac_uint32 mid0  = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid1  = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid2  = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 mid3  = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+
+            drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+            drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid0 = (mid0 << 1) | (side0 & 0x01);
+            mid1 = (mid1 << 1) | (side1 & 0x01);
+            mid2 = (mid2 << 1) | (side2 & 0x01);
+            mid3 = (mid3 << 1) | (side3 & 0x01);
+
+            temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1);
+            temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1);
+            temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1);
+            temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1);
+
+            temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1);
+            temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1);
+            temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1);
+            temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1);
+
+            pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor;
+            pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor;
+            pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor;
+            pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor;
+            pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor;
+            pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor;
+            pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor;
+            pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor;
+        }
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+        drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+        mid = (mid << 1) | (side & 0x01);
+
+        pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) * factor;
+        pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) * factor;
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift = unusedBitsPerSample - 8;
+    float factor;
+    __m128 factor128;
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    factor = 1.0f / 8388608.0f;
+    factor128 = _mm_set1_ps(factor);
+
+    if (shift == 0) {
+        for (i = 0; i < frameCount4; ++i) {
+            __m128i mid;
+            __m128i side;
+            __m128i tempL;
+            __m128i tempR;
+            __m128  leftf;
+            __m128  rightf;
+
+            mid    = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+            side   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+
+            mid    = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
+
+            tempL  = _mm_srai_epi32(_mm_add_epi32(mid, side), 1);
+            tempR  = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1);
+
+            leftf  = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
+            rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
+
+            _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
+            _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
+            pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
+        }
+    } else {
+        shift -= 1;
+        for (i = 0; i < frameCount4; ++i) {
+            __m128i mid;
+            __m128i side;
+            __m128i tempL;
+            __m128i tempR;
+            __m128 leftf;
+            __m128 rightf;
+
+            mid    = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+            side   = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+
+            mid    = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01)));
+
+            tempL  = _mm_slli_epi32(_mm_add_epi32(mid, side), shift);
+            tempR  = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift);
+
+            leftf  = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128);
+            rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128);
+
+            _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
+            _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
+            pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
+        }
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift = unusedBitsPerSample - 8;
+    float factor;
+    float32x4_t factor4;
+    int32x4_t shift4;
+    int32x4_t wbps0_4;  /* Wasted Bits Per Sample */
+    int32x4_t wbps1_4;  /* Wasted Bits Per Sample */
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 24);
+
+    factor  = 1.0f / 8388608.0f;
+    factor4 = vdupq_n_f32(factor);
+    wbps0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample);
+    wbps1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample);
+
+    if (shift == 0) {
+        for (i = 0; i < frameCount4; ++i) {
+            int32x4_t lefti;
+            int32x4_t righti;
+            float32x4_t leftf;
+            float32x4_t rightf;
+
+            uint32x4_t mid  = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
+            uint32x4_t side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
+
+            mid    = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
+
+            lefti  = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1);
+            righti = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1);
+
+            leftf  = vmulq_f32(vcvtq_f32_s32(lefti),  factor4);
+            rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
+
+            drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor;
+            pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor;
+        }
+    } else {
+        shift -= 1;
+        shift4 = vdupq_n_s32(shift);
+        for (i = 0; i < frameCount4; ++i) {
+            uint32x4_t mid;
+            uint32x4_t side;
+            int32x4_t lefti;
+            int32x4_t righti;
+            float32x4_t leftf;
+            float32x4_t rightf;
+
+            mid    = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4);
+            side   = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4);
+
+            mid    = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1)));
+
+            lefti  = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4));
+            righti = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4));
+
+            leftf  = vmulq_f32(vcvtq_f32_s32(lefti),  factor4);
+            rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
+
+            drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
+        }
+
+        for (i = (frameCount4 << 2); i < frameCount; ++i) {
+            drflac_uint32 mid  = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+            drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+
+            mid = (mid << 1) | (side & 0x01);
+
+            pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor;
+            pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor;
+        }
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_f32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_f32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+#if 0
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    for (drflac_uint64 i = 0; i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (float)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) / 2147483648.0);
+        pOutputSamples[i*2+1] = (float)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) / 2147483648.0);
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample;
+    drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample;
+    float factor = 1 / 2147483648.0;
+
+    for (i = 0; i < frameCount4; ++i) {
+        drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0;
+        drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0;
+        drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0;
+        drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0;
+
+        drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1;
+        drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1;
+        drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1;
+        drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1;
+
+        pOutputSamples[i*8+0] = (drflac_int32)tempL0 * factor;
+        pOutputSamples[i*8+1] = (drflac_int32)tempR0 * factor;
+        pOutputSamples[i*8+2] = (drflac_int32)tempL1 * factor;
+        pOutputSamples[i*8+3] = (drflac_int32)tempR1 * factor;
+        pOutputSamples[i*8+4] = (drflac_int32)tempL2 * factor;
+        pOutputSamples[i*8+5] = (drflac_int32)tempR2 * factor;
+        pOutputSamples[i*8+6] = (drflac_int32)tempL3 * factor;
+        pOutputSamples[i*8+7] = (drflac_int32)tempR3 * factor;
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
+        pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
+    }
+}
+
+#if defined(DRFLAC_SUPPORT_SSE2)
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
+    drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
+
+    float factor = 1.0f / 8388608.0f;
+    __m128 factor128 = _mm_set1_ps(factor);
+
+    for (i = 0; i < frameCount4; ++i) {
+        __m128i lefti;
+        __m128i righti;
+        __m128 leftf;
+        __m128 rightf;
+
+        lefti  = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0);
+        righti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1);
+
+        leftf  = _mm_mul_ps(_mm_cvtepi32_ps(lefti),  factor128);
+        rightf = _mm_mul_ps(_mm_cvtepi32_ps(righti), factor128);
+
+        _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf));
+        _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
+        pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
+    }
+}
+#endif
+
+#if defined(DRFLAC_SUPPORT_NEON)
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+    drflac_uint64 i;
+    drflac_uint64 frameCount4 = frameCount >> 2;
+    const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0;
+    const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1;
+    drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8;
+    drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8;
+
+    float factor = 1.0f / 8388608.0f;
+    float32x4_t factor4 = vdupq_n_f32(factor);
+    int32x4_t shift0_4  = vdupq_n_s32(shift0);
+    int32x4_t shift1_4  = vdupq_n_s32(shift1);
+
+    for (i = 0; i < frameCount4; ++i) {
+        int32x4_t lefti;
+        int32x4_t righti;
+        float32x4_t leftf;
+        float32x4_t rightf;
+
+        lefti  = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4));
+        righti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4));
+
+        leftf  = vmulq_f32(vcvtq_f32_s32(lefti),  factor4);
+        rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4);
+
+        drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf));
+    }
+
+    for (i = (frameCount4 << 2); i < frameCount; ++i) {
+        pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor;
+        pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor;
+    }
+}
+#endif
+
+static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples)
+{
+#if defined(DRFLAC_SUPPORT_SSE2)
+    if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#elif defined(DRFLAC_SUPPORT_NEON)
+    if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) {
+        drflac_read_pcm_frames_f32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+    } else
+#endif
+    {
+        /* Scalar fallback. */
+#if 0
+        drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#else
+        drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples);
+#endif
+    }
+}
+
+DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut)
+{
+    drflac_uint64 framesRead;
+    drflac_uint32 unusedBitsPerSample;
+
+    if (pFlac == NULL || framesToRead == 0) {
+        return 0;
+    }
+
+    if (pBufferOut == NULL) {
+        return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead);
+    }
+
+    DRFLAC_ASSERT(pFlac->bitsPerSample <= 32);
+    unusedBitsPerSample = 32 - pFlac->bitsPerSample;
+
+    framesRead = 0;
+    while (framesToRead > 0) {
+        /* If we've run out of samples in this frame, go to the next. */
+        if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) {
+            if (!drflac__read_and_decode_next_flac_frame(pFlac)) {
+                break;  /* Couldn't read the next frame, so just break from the loop and return. */
+            }
+        } else {
+            unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment);
+            drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining;
+            drflac_uint64 frameCountThisIteration = framesToRead;
+
+            if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) {
+                frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining;
+            }
+
+            if (channelCount == 2) {
+                const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame;
+                const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame;
+
+                switch (pFlac->currentFLACFrame.header.channelAssignment)
+                {
+                    case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE:
+                    {
+                        drflac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+
+                    case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+                    {
+                        drflac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+
+                    case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE:
+                    {
+                        drflac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+
+                    case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT:
+                    default:
+                    {
+                        drflac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut);
+                    } break;
+                }
+            } else {
+                /* Generic interleaving. */
+                drflac_uint64 i;
+                for (i = 0; i < frameCountThisIteration; ++i) {
+                    unsigned int j;
+                    for (j = 0; j < channelCount; ++j) {
+                        drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample));
+                        pBufferOut[(i*channelCount)+j] = (float)(sampleS32 / 2147483648.0);
+                    }
+                }
+            }
+
+            framesRead                += frameCountThisIteration;
+            pBufferOut                += frameCountThisIteration * channelCount;
+            framesToRead              -= frameCountThisIteration;
+            pFlac->currentPCMFrame    += frameCountThisIteration;
+            pFlac->currentFLACFrame.pcmFramesRemaining -= (unsigned int)frameCountThisIteration;
+        }
+    }
+
+    return framesRead;
+}
+
+
+DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex)
+{
+    if (pFlac == NULL) {
+        return DRFLAC_FALSE;
+    }
+
+    /* Don't do anything if we're already on the seek point. */
+    if (pFlac->currentPCMFrame == pcmFrameIndex) {
+        return DRFLAC_TRUE;
+    }
+
+    /*
+    If we don't know where the first frame begins then we can't seek. This will happen when the STREAMINFO block was not present
+    when the decoder was opened.
+    */
+    if (pFlac->firstFLACFramePosInBytes == 0) {
+        return DRFLAC_FALSE;
+    }
+
+    if (pcmFrameIndex == 0) {
+        pFlac->currentPCMFrame = 0;
+        return drflac__seek_to_first_frame(pFlac);
+    } else {
+        drflac_bool32 wasSuccessful = DRFLAC_FALSE;
+
+        /* Clamp the sample to the end. */
+        if (pcmFrameIndex > pFlac->totalPCMFrameCount) {
+            pcmFrameIndex = pFlac->totalPCMFrameCount;
+        }
+
+        /* If the target sample and the current sample are in the same frame we just move the position forward. */
+        if (pcmFrameIndex > pFlac->currentPCMFrame) {
+            /* Forward. */
+            drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex - pFlac->currentPCMFrame);
+            if (pFlac->currentFLACFrame.pcmFramesRemaining >  offset) {
+                pFlac->currentFLACFrame.pcmFramesRemaining -= offset;
+                pFlac->currentPCMFrame = pcmFrameIndex;
+                return DRFLAC_TRUE;
+            }
+        } else {
+            /* Backward. */
+            drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentPCMFrame - pcmFrameIndex);
+            drflac_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames;
+            drflac_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining;
+            if (currentFLACFramePCMFramesConsumed > offsetAbs) {
+                pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs;
+                pFlac->currentPCMFrame = pcmFrameIndex;
+                return DRFLAC_TRUE;
+            }
+        }
+
+        /*
+        Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so
+        we'll instead use Ogg's natural seeking facility.
+        */
+#ifndef DR_FLAC_NO_OGG
+        if (pFlac->container == drflac_container_ogg)
+        {
+            wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex);
+        }
+        else
+#endif
+        {
+            /* First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. */
+            if (/*!wasSuccessful && */!pFlac->_noSeekTableSeek) {
+                wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex);
+            }
+
+#if !defined(DR_FLAC_NO_CRC)
+            /* Fall back to binary search if seek table seeking fails. This requires the length of the stream to be known. */
+            if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) {
+                wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex);
+            }
+#endif
+
+            /* Fall back to brute force if all else fails. */
+            if (!wasSuccessful && !pFlac->_noBruteForceSeek) {
+                wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex);
+            }
+        }
+
+        pFlac->currentPCMFrame = pcmFrameIndex;
+        return wasSuccessful;
+    }
+}
+
+
+
+/* High Level APIs */
+
+#if defined(SIZE_MAX)
+    #define DRFLAC_SIZE_MAX  SIZE_MAX
+#else
+    #if defined(DRFLAC_64BIT)
+        #define DRFLAC_SIZE_MAX  ((drflac_uint64)0xFFFFFFFFFFFFFFFF)
+    #else
+        #define DRFLAC_SIZE_MAX  0xFFFFFFFF
+    #endif
+#endif
+
+
+/* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */
+#define DRFLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \
+static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut)\
+{                                                                                                                                                                   \
+    type* pSampleData = NULL;                                                                                                                                       \
+    drflac_uint64 totalPCMFrameCount;                                                                                                                               \
+                                                                                                                                                                    \
+    DRFLAC_ASSERT(pFlac != NULL);                                                                                                                                   \
+                                                                                                                                                                    \
+    totalPCMFrameCount = pFlac->totalPCMFrameCount;                                                                                                                 \
+                                                                                                                                                                    \
+    if (totalPCMFrameCount == 0) {                                                                                                                                  \
+        type buffer[4096];                                                                                                                                          \
+        drflac_uint64 pcmFramesRead;                                                                                                                                \
+        size_t sampleDataBufferSize = sizeof(buffer);                                                                                                               \
+                                                                                                                                                                    \
+        pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks);                                                      \
+        if (pSampleData == NULL) {                                                                                                                                  \
+            goto on_error;                                                                                                                                          \
+        }                                                                                                                                                           \
+                                                                                                                                                                    \
+        while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) {          \
+            if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) {                                                   \
+                type* pNewSampleData;                                                                                                                               \
+                size_t newSampleDataBufferSize;                                                                                                                     \
+                                                                                                                                                                    \
+                newSampleDataBufferSize = sampleDataBufferSize * 2;                                                                                                 \
+                pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks);    \
+                if (pNewSampleData == NULL) {                                                                                                                       \
+                    drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks);                                                                          \
+                    goto on_error;                                                                                                                                  \
+                }                                                                                                                                                   \
+                                                                                                                                                                    \
+                sampleDataBufferSize = newSampleDataBufferSize;                                                                                                     \
+                pSampleData = pNewSampleData;                                                                                                                       \
+            }                                                                                                                                                       \
+                                                                                                                                                                    \
+            DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type)));                   \
+            totalPCMFrameCount += pcmFramesRead;                                                                                                                    \
+        }                                                                                                                                                           \
+                                                                                                                                                                    \
+        /* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to                                       \
+           protect those ears from random noise! */                                                                                                                 \
+        DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type)));   \
+    } else {                                                                                                                                                        \
+        drflac_uint64 dataSize = totalPCMFrameCount*pFlac->channels*sizeof(type);                                                                                   \
+        if (dataSize > DRFLAC_SIZE_MAX) {                                                                                                                           \
+            goto on_error;  /* The decoded data is too big. */                                                                                                      \
+        }                                                                                                                                                           \
+                                                                                                                                                                    \
+        pSampleData = (type*)drflac__malloc_from_callbacks((size_t)dataSize, &pFlac->allocationCallbacks);    /* <-- Safe cast as per the check above. */           \
+        if (pSampleData == NULL) {                                                                                                                                  \
+            goto on_error;                                                                                                                                          \
+        }                                                                                                                                                           \
+                                                                                                                                                                    \
+        totalPCMFrameCount = drflac_read_pcm_frames_##extension(pFlac, pFlac->totalPCMFrameCount, pSampleData);                                                     \
+    }                                                                                                                                                               \
+                                                                                                                                                                    \
+    if (sampleRateOut) *sampleRateOut = pFlac->sampleRate;                                                                                                          \
+    if (channelsOut) *channelsOut = pFlac->channels;                                                                                                                \
+    if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount;                                                                                         \
+                                                                                                                                                                    \
+    drflac_close(pFlac);                                                                                                                                            \
+    return pSampleData;                                                                                                                                             \
+                                                                                                                                                                    \
+on_error:                                                                                                                                                           \
+    drflac_close(pFlac);                                                                                                                                            \
+    return NULL;                                                                                                                                                    \
+}
+
+DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32)
+DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16)
+DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float)
+
+DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+
+    if (channelsOut) {
+        *channelsOut = 0;
+    }
+    if (sampleRateOut) {
+        *sampleRateOut = 0;
+    }
+    if (totalPCMFrameCountOut) {
+        *totalPCMFrameCountOut = 0;
+    }
+
+    pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
+}
+
+DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+
+    if (channelsOut) {
+        *channelsOut = 0;
+    }
+    if (sampleRateOut) {
+        *sampleRateOut = 0;
+    }
+    if (totalPCMFrameCountOut) {
+        *totalPCMFrameCountOut = 0;
+    }
+
+    pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
+}
+
+DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+
+    if (channelsOut) {
+        *channelsOut = 0;
+    }
+    if (sampleRateOut) {
+        *sampleRateOut = 0;
+    }
+    if (totalPCMFrameCountOut) {
+        *totalPCMFrameCountOut = 0;
+    }
+
+    pFlac = drflac_open(onRead, onSeek, pUserData, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut);
+}
+
+#ifndef DR_FLAC_NO_STDIO
+DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+
+    if (sampleRate) {
+        *sampleRate = 0;
+    }
+    if (channels) {
+        *channels = 0;
+    }
+    if (totalPCMFrameCount) {
+        *totalPCMFrameCount = 0;
+    }
+
+    pFlac = drflac_open_file(filename, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
+}
+
+DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+
+    if (sampleRate) {
+        *sampleRate = 0;
+    }
+    if (channels) {
+        *channels = 0;
+    }
+    if (totalPCMFrameCount) {
+        *totalPCMFrameCount = 0;
+    }
+
+    pFlac = drflac_open_file(filename, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
+}
+
+DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+
+    if (sampleRate) {
+        *sampleRate = 0;
+    }
+    if (channels) {
+        *channels = 0;
+    }
+    if (totalPCMFrameCount) {
+        *totalPCMFrameCount = 0;
+    }
+
+    pFlac = drflac_open_file(filename, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
+}
+#endif
+
+DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+
+    if (sampleRate) {
+        *sampleRate = 0;
+    }
+    if (channels) {
+        *channels = 0;
+    }
+    if (totalPCMFrameCount) {
+        *totalPCMFrameCount = 0;
+    }
+
+    pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount);
+}
+
+DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+
+    if (sampleRate) {
+        *sampleRate = 0;
+    }
+    if (channels) {
+        *channels = 0;
+    }
+    if (totalPCMFrameCount) {
+        *totalPCMFrameCount = 0;
+    }
+
+    pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount);
+}
+
+DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    drflac* pFlac;
+
+    if (sampleRate) {
+        *sampleRate = 0;
+    }
+    if (channels) {
+        *channels = 0;
+    }
+    if (totalPCMFrameCount) {
+        *totalPCMFrameCount = 0;
+    }
+
+    pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks);
+    if (pFlac == NULL) {
+        return NULL;
+    }
+
+    return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount);
+}
+
+
+DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks)
+{
+    if (pAllocationCallbacks != NULL) {
+        drflac__free_from_callbacks(p, pAllocationCallbacks);
+    } else {
+        drflac__free_default(p, NULL);
+    }
+}
+
+
+
+
+DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments)
+{
+    if (pIter == NULL) {
+        return;
+    }
+
+    pIter->countRemaining = commentCount;
+    pIter->pRunningData   = (const char*)pComments;
+}
+
+DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut)
+{
+    drflac_int32 length;
+    const char* pComment;
+
+    /* Safety. */
+    if (pCommentLengthOut) {
+        *pCommentLengthOut = 0;
+    }
+
+    if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
+        return NULL;
+    }
+
+    length = drflac__le2host_32(*(const drflac_uint32*)pIter->pRunningData);
+    pIter->pRunningData += 4;
+
+    pComment = pIter->pRunningData;
+    pIter->pRunningData += length;
+    pIter->countRemaining -= 1;
+
+    if (pCommentLengthOut) {
+        *pCommentLengthOut = length;
+    }
+
+    return pComment;
+}
+
+
+
+
+DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData)
+{
+    if (pIter == NULL) {
+        return;
+    }
+
+    pIter->countRemaining = trackCount;
+    pIter->pRunningData   = (const char*)pTrackData;
+}
+
+DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack)
+{
+    drflac_cuesheet_track cuesheetTrack;
+    const char* pRunningData;
+    drflac_uint64 offsetHi;
+    drflac_uint64 offsetLo;
+
+    if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) {
+        return DRFLAC_FALSE;
+    }
+
+    pRunningData = pIter->pRunningData;
+
+    offsetHi                   = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+    offsetLo                   = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4;
+    cuesheetTrack.offset       = offsetLo | (offsetHi << 32);
+    cuesheetTrack.trackNumber  = pRunningData[0];                                         pRunningData += 1;
+    DRFLAC_COPY_MEMORY(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC));     pRunningData += 12;
+    cuesheetTrack.isAudio      = (pRunningData[0] & 0x80) != 0;
+    cuesheetTrack.preEmphasis  = (pRunningData[0] & 0x40) != 0;                           pRunningData += 14;
+    cuesheetTrack.indexCount   = pRunningData[0];                                         pRunningData += 1;
+    cuesheetTrack.pIndexPoints = (const drflac_cuesheet_track_index*)pRunningData;        pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index);
+
+    pIter->pRunningData = pRunningData;
+    pIter->countRemaining -= 1;
+
+    if (pCuesheetTrack) {
+        *pCuesheetTrack = cuesheetTrack;
+    }
+
+    return DRFLAC_TRUE;
+}
+
+#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
+    #pragma GCC diagnostic pop
+#endif
+#endif  /* dr_flac_c */
+#endif  /* DR_FLAC_IMPLEMENTATION */
+
+
+/*
+REVISION HISTORY
+================
+v0.12.28 - 2021-02-21
+  - Fix a warning due to referencing _MSC_VER when it is undefined.
+
+v0.12.27 - 2021-01-31
+  - Fix a static analysis warning.
+
+v0.12.26 - 2021-01-17
+  - Fix a compilation warning due to _BSD_SOURCE being deprecated.
+
+v0.12.25 - 2020-12-26
+  - Update documentation.
+
+v0.12.24 - 2020-11-29
+  - Fix ARM64/NEON detection when compiling with MSVC.
+
+v0.12.23 - 2020-11-21
+  - Fix compilation with OpenWatcom.
+
+v0.12.22 - 2020-11-01
+  - Fix an error with the previous release.
+
+v0.12.21 - 2020-11-01
+  - Fix a possible deadlock when seeking.
+  - Improve compiler support for older versions of GCC.
+
+v0.12.20 - 2020-09-08
+  - Fix a compilation error on older compilers.
+
+v0.12.19 - 2020-08-30
+  - Fix a bug due to an undefined 32-bit shift.
+
+v0.12.18 - 2020-08-14
+  - Fix a crash when compiling with clang-cl.
+
+v0.12.17 - 2020-08-02
+  - Simplify sized types.
+
+v0.12.16 - 2020-07-25
+  - Fix a compilation warning.
+
+v0.12.15 - 2020-07-06
+  - Check for negative LPC shifts and return an error.
+
+v0.12.14 - 2020-06-23
+  - Add include guard for the implementation section.
+
+v0.12.13 - 2020-05-16
+  - Add compile-time and run-time version querying.
+    - DRFLAC_VERSION_MINOR
+    - DRFLAC_VERSION_MAJOR
+    - DRFLAC_VERSION_REVISION
+    - DRFLAC_VERSION_STRING
+    - drflac_version()
+    - drflac_version_string()
+
+v0.12.12 - 2020-04-30
+  - Fix compilation errors with VC6.
+
+v0.12.11 - 2020-04-19
+  - Fix some pedantic warnings.
+  - Fix some undefined behaviour warnings.
+
+v0.12.10 - 2020-04-10
+  - Fix some bugs when trying to seek with an invalid seek table.
+
+v0.12.9 - 2020-04-05
+  - Fix warnings.
+
+v0.12.8 - 2020-04-04
+  - Add drflac_open_file_w() and drflac_open_file_with_metadata_w().
+  - Fix some static analysis warnings.
+  - Minor documentation updates.
+
+v0.12.7 - 2020-03-14
+  - Fix compilation errors with VC6.
+
+v0.12.6 - 2020-03-07
+  - Fix compilation error with Visual Studio .NET 2003.
+
+v0.12.5 - 2020-01-30
+  - Silence some static analysis warnings.
+
+v0.12.4 - 2020-01-29
+  - Silence some static analysis warnings.
+
+v0.12.3 - 2019-12-02
+  - Fix some warnings when compiling with GCC and the -Og flag.
+  - Fix a crash in out-of-memory situations.
+  - Fix potential integer overflow bug.
+  - Fix some static analysis warnings.
+  - Fix a possible crash when using custom memory allocators without a custom realloc() implementation.
+  - Fix a bug with binary search seeking where the bits per sample is not a multiple of 8.
+
+v0.12.2 - 2019-10-07
+  - Internal code clean up.
+
+v0.12.1 - 2019-09-29
+  - Fix some Clang Static Analyzer warnings.
+  - Fix an unused variable warning.
+
+v0.12.0 - 2019-09-23
+  - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation
+    routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs:
+    - drflac_open()
+    - drflac_open_relaxed()
+    - drflac_open_with_metadata()
+    - drflac_open_with_metadata_relaxed()
+    - drflac_open_file()
+    - drflac_open_file_with_metadata()
+    - drflac_open_memory()
+    - drflac_open_memory_with_metadata()
+    - drflac_open_and_read_pcm_frames_s32()
+    - drflac_open_and_read_pcm_frames_s16()
+    - drflac_open_and_read_pcm_frames_f32()
+    - drflac_open_file_and_read_pcm_frames_s32()
+    - drflac_open_file_and_read_pcm_frames_s16()
+    - drflac_open_file_and_read_pcm_frames_f32()
+    - drflac_open_memory_and_read_pcm_frames_s32()
+    - drflac_open_memory_and_read_pcm_frames_s16()
+    - drflac_open_memory_and_read_pcm_frames_f32()
+    Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use
+    DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE.
+  - Remove deprecated APIs:
+    - drflac_read_s32()
+    - drflac_read_s16()
+    - drflac_read_f32()
+    - drflac_seek_to_sample()
+    - drflac_open_and_decode_s32()
+    - drflac_open_and_decode_s16()
+    - drflac_open_and_decode_f32()
+    - drflac_open_and_decode_file_s32()
+    - drflac_open_and_decode_file_s16()
+    - drflac_open_and_decode_file_f32()
+    - drflac_open_and_decode_memory_s32()
+    - drflac_open_and_decode_memory_s16()
+    - drflac_open_and_decode_memory_f32()
+  - Remove drflac.totalSampleCount which is now replaced with drflac.totalPCMFrameCount. You can emulate drflac.totalSampleCount
+    by doing pFlac->totalPCMFrameCount*pFlac->channels.
+  - Rename drflac.currentFrame to drflac.currentFLACFrame to remove ambiguity with PCM frames.
+  - Fix errors when seeking to the end of a stream.
+  - Optimizations to seeking.
+  - SSE improvements and optimizations.
+  - ARM NEON optimizations.
+  - Optimizations to drflac_read_pcm_frames_s16().
+  - Optimizations to drflac_read_pcm_frames_s32().
+
+v0.11.10 - 2019-06-26
+  - Fix a compiler error.
+
+v0.11.9 - 2019-06-16
+  - Silence some ThreadSanitizer warnings.
+
+v0.11.8 - 2019-05-21
+  - Fix warnings.
+
+v0.11.7 - 2019-05-06
+  - C89 fixes.
+
+v0.11.6 - 2019-05-05
+  - Add support for C89.
+  - Fix a compiler warning when CRC is disabled.
+  - Change license to choice of public domain or MIT-0.
+
+v0.11.5 - 2019-04-19
+  - Fix a compiler error with GCC.
+
+v0.11.4 - 2019-04-17
+  - Fix some warnings with GCC when compiling with -std=c99.
+
+v0.11.3 - 2019-04-07
+  - Silence warnings with GCC.
+
+v0.11.2 - 2019-03-10
+  - Fix a warning.
+
+v0.11.1 - 2019-02-17
+  - Fix a potential bug with seeking.
+
+v0.11.0 - 2018-12-16
+  - API CHANGE: Deprecated drflac_read_s32(), drflac_read_s16() and drflac_read_f32() and replaced them with
+    drflac_read_pcm_frames_s32(), drflac_read_pcm_frames_s16() and drflac_read_pcm_frames_f32(). The new APIs take
+    and return PCM frame counts instead of sample counts. To upgrade you will need to change the input count by
+    dividing it by the channel count, and then do the same with the return value.
+  - API_CHANGE: Deprecated drflac_seek_to_sample() and replaced with drflac_seek_to_pcm_frame(). Same rules as
+    the changes to drflac_read_*() apply.
+  - API CHANGE: Deprecated drflac_open_and_decode_*() and replaced with drflac_open_*_and_read_*(). Same rules as
+    the changes to drflac_read_*() apply.
+  - Optimizations.
+
+v0.10.0 - 2018-09-11
+  - Remove the DR_FLAC_NO_WIN32_IO option and the Win32 file IO functionality. If you need to use Win32 file IO you
+    need to do it yourself via the callback API.
+  - Fix the clang build.
+  - Fix undefined behavior.
+  - Fix errors with CUESHEET metdata blocks.
+  - Add an API for iterating over each cuesheet track in the CUESHEET metadata block. This works the same way as the
+    Vorbis comment API.
+  - Other miscellaneous bug fixes, mostly relating to invalid FLAC streams.
+  - Minor optimizations.
+
+v0.9.11 - 2018-08-29
+  - Fix a bug with sample reconstruction.
+
+v0.9.10 - 2018-08-07
+  - Improve 64-bit detection.
+
+v0.9.9 - 2018-08-05
+  - Fix C++ build on older versions of GCC.
+
+v0.9.8 - 2018-07-24
+  - Fix compilation errors.
+
+v0.9.7 - 2018-07-05
+  - Fix a warning.
+
+v0.9.6 - 2018-06-29
+  - Fix some typos.
+
+v0.9.5 - 2018-06-23
+  - Fix some warnings.
+
+v0.9.4 - 2018-06-14
+  - Optimizations to seeking.
+  - Clean up.
+
+v0.9.3 - 2018-05-22
+  - Bug fix.
+
+v0.9.2 - 2018-05-12
+  - Fix a compilation error due to a missing break statement.
+
+v0.9.1 - 2018-04-29
+  - Fix compilation error with Clang.
+
+v0.9 - 2018-04-24
+  - Fix Clang build.
+  - Start using major.minor.revision versioning.
+
+v0.8g - 2018-04-19
+  - Fix build on non-x86/x64 architectures.
+
+v0.8f - 2018-02-02
+  - Stop pretending to support changing rate/channels mid stream.
+
+v0.8e - 2018-02-01
+  - Fix a crash when the block size of a frame is larger than the maximum block size defined by the FLAC stream.
+  - Fix a crash the the Rice partition order is invalid.
+
+v0.8d - 2017-09-22
+  - Add support for decoding streams with ID3 tags. ID3 tags are just skipped.
+
+v0.8c - 2017-09-07
+  - Fix warning on non-x86/x64 architectures.
+
+v0.8b - 2017-08-19
+  - Fix build on non-x86/x64 architectures.
+
+v0.8a - 2017-08-13
+  - A small optimization for the Clang build.
+
+v0.8 - 2017-08-12
+  - API CHANGE: Rename dr_* types to drflac_*.
+  - Optimizations. This brings dr_flac back to about the same class of efficiency as the reference implementation.
+  - Add support for custom implementations of malloc(), realloc(), etc.
+  - Add CRC checking to Ogg encapsulated streams.
+  - Fix VC++ 6 build. This is only for the C++ compiler. The C compiler is not currently supported.
+  - Bug fixes.
+
+v0.7 - 2017-07-23
+  - Add support for opening a stream without a header block. To do this, use drflac_open_relaxed() / drflac_open_with_metadata_relaxed().
+
+v0.6 - 2017-07-22
+  - Add support for recovering from invalid frames. With this change, dr_flac will simply skip over invalid frames as if they
+    never existed. Frames are checked against their sync code, the CRC-8 of the frame header and the CRC-16 of the whole frame.
+
+v0.5 - 2017-07-16
+  - Fix typos.
+  - Change drflac_bool* types to unsigned.
+  - Add CRC checking. This makes dr_flac slower, but can be disabled with #define DR_FLAC_NO_CRC.
+
+v0.4f - 2017-03-10
+  - Fix a couple of bugs with the bitstreaming code.
+
+v0.4e - 2017-02-17
+  - Fix some warnings.
+
+v0.4d - 2016-12-26
+  - Add support for 32-bit floating-point PCM decoding.
+  - Use drflac_int* and drflac_uint* sized types to improve compiler support.
+  - Minor improvements to documentation.
+
+v0.4c - 2016-12-26
+  - Add support for signed 16-bit integer PCM decoding.
+
+v0.4b - 2016-10-23
+  - A minor change to drflac_bool8 and drflac_bool32 types.
+
+v0.4a - 2016-10-11
+  - Rename drBool32 to drflac_bool32 for styling consistency.
+
+v0.4 - 2016-09-29
+  - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type.
+  - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32().
+  - API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to
+    keep it consistent with drflac_audio.
+
+v0.3f - 2016-09-21
+  - Fix a warning with GCC.
+
+v0.3e - 2016-09-18
+  - Fixed a bug where GCC 4.3+ was not getting properly identified.
+  - Fixed a few typos.
+  - Changed date formats to ISO 8601 (YYYY-MM-DD).
+
+v0.3d - 2016-06-11
+  - Minor clean up.
+
+v0.3c - 2016-05-28
+  - Fixed compilation error.
+
+v0.3b - 2016-05-16
+  - Fixed Linux/GCC build.
+  - Updated documentation.
+
+v0.3a - 2016-05-15
+  - Minor fixes to documentation.
+
+v0.3 - 2016-05-11
+  - Optimizations. Now at about parity with the reference implementation on 32-bit builds.
+  - Lots of clean up.
+
+v0.2b - 2016-05-10
+  - Bug fixes.
+
+v0.2a - 2016-05-10
+  - Made drflac_open_and_decode() more robust.
+  - Removed an unused debugging variable
+
+v0.2 - 2016-05-09
+  - Added support for Ogg encapsulation.
+  - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek
+    should be relative to the start or the current position. Also changes the seeking rules such that
+    seeking offsets will never be negative.
+  - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count.
+
+v0.1b - 2016-05-07
+  - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize.
+  - Removed a stale comment.
+
+v0.1a - 2016-05-05
+  - Minor formatting changes.
+  - Fixed a warning on the GCC build.
+
+v0.1 - 2016-05-03
+  - Initial versioned release.
+*/
+
+/*
+This software is available as a choice of the following licenses. Choose
+whichever you prefer.
+
+===============================================================================
+ALTERNATIVE 1 - Public Domain (www.unlicense.org)
+===============================================================================
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
+software, either in source code form or as a compiled binary, for any purpose,
+commercial or non-commercial, and by any means.
+
+In jurisdictions that recognize copyright laws, the author or authors of this
+software dedicate any and all copyright interest in the software to the public
+domain. We make this dedication for the benefit of the public at large and to
+the detriment of our heirs and successors. We intend this dedication to be an
+overt act of relinquishment in perpetuity of all present and future rights to
+this software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
+
+===============================================================================
+ALTERNATIVE 2 - MIT No Attribution
+===============================================================================
+Copyright 2020 David Reid
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
diff --git a/deps/libchdr/include/libchdr/bitstream.h b/deps/libchdr/include/libchdr/bitstream.h
new file mode 100644 (file)
index 0000000..d376373
--- /dev/null
@@ -0,0 +1,43 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    bitstream.h
+
+    Helper classes for reading/writing at the bit level.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __BITSTREAM_H__
+#define __BITSTREAM_H__
+
+#include <stdint.h>
+
+/***************************************************************************
+ *  TYPE DEFINITIONS
+ ***************************************************************************
+ */
+
+/* helper class for reading from a bit buffer */
+struct bitstream
+{
+       uint32_t          buffer;       /* current bit accumulator */
+       int               bits;         /* number of bits in the accumulator */
+       const uint8_t *   read;         /* read pointer */
+       uint32_t          doffset;      /* byte offset within the data */
+       uint32_t          dlength;      /* length of the data */
+};
+
+struct bitstream*      create_bitstream(const void *src, uint32_t srclength);
+int                            bitstream_overflow(struct bitstream* bitstream);
+uint32_t                       bitstream_read_offset(struct bitstream* bitstream);
+
+uint32_t                       bitstream_read(struct bitstream* bitstream, int numbits);
+uint32_t                       bitstream_peek(struct bitstream* bitstream, int numbits);
+void                           bitstream_remove(struct bitstream* bitstream, int numbits);
+uint32_t                       bitstream_flush(struct bitstream* bitstream);
+
+
+#endif
diff --git a/deps/libchdr/include/libchdr/cdrom.h b/deps/libchdr/include/libchdr/cdrom.h
new file mode 100644 (file)
index 0000000..816e6a5
--- /dev/null
@@ -0,0 +1,110 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    cdrom.h
+
+    Generic MAME cd-rom implementation
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CDROM_H__
+#define __CDROM_H__
+
+#include <stdint.h>
+#include <libchdr/chdconfig.h>
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+/* tracks are padded to a multiple of this many frames */
+#define CD_TRACK_PADDING       (4)
+#define CD_MAX_TRACKS           (99)    /* AFAIK the theoretical limit */
+#define CD_MAX_SECTOR_DATA      (2352)
+#define CD_MAX_SUBCODE_DATA     (96)
+
+#define CD_FRAME_SIZE           (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA)
+#define CD_FRAMES_PER_HUNK      (8)
+
+#define CD_METADATA_WORDS       (1+(CD_MAX_TRACKS * 6))
+
+enum
+{
+       CD_TRACK_MODE1 = 0,         /* mode 1 2048 bytes/sector */
+       CD_TRACK_MODE1_RAW,         /* mode 1 2352 bytes/sector */
+       CD_TRACK_MODE2,             /* mode 2 2336 bytes/sector */
+       CD_TRACK_MODE2_FORM1,       /* mode 2 2048 bytes/sector */
+       CD_TRACK_MODE2_FORM2,       /* mode 2 2324 bytes/sector */
+       CD_TRACK_MODE2_FORM_MIX,    /* mode 2 2336 bytes/sector */
+       CD_TRACK_MODE2_RAW,         /* mode 2 2352 bytes / sector */
+       CD_TRACK_AUDIO,         /* redbook audio track 2352 bytes/sector (588 samples) */
+
+       CD_TRACK_RAW_DONTCARE       /* special flag for cdrom_read_data: just return me whatever is there */
+};
+
+enum
+{
+       CD_SUB_NORMAL = 0,          /* "cooked" 96 bytes per sector */
+       CD_SUB_RAW,                 /* raw uninterleaved 96 bytes per sector */
+       CD_SUB_NONE                 /* no subcode data stored */
+};
+
+#define CD_FLAG_GDROM   0x00000001  /* disc is a GD-ROM, all tracks should be stored with GD-ROM metadata */
+#define CD_FLAG_GDROMLE 0x00000002  /* legacy GD-ROM, with little-endian CDDA data */
+
+/***************************************************************************
+    FUNCTION PROTOTYPES
+***************************************************************************/
+
+#ifdef WANT_RAW_DATA_SECTOR
+/* ECC utilities */
+int ecc_verify(const uint8_t *sector);
+void ecc_generate(uint8_t *sector);
+void ecc_clear(uint8_t *sector);
+#endif
+
+
+
+/***************************************************************************
+    INLINE FUNCTIONS
+***************************************************************************/
+
+static inline uint32_t msf_to_lba(uint32_t msf)
+{
+       return ( ((msf&0x00ff0000)>>16) * 60 * 75) + (((msf&0x0000ff00)>>8) * 75) + ((msf&0x000000ff)>>0);
+}
+
+static inline uint32_t lba_to_msf(uint32_t lba)
+{
+       uint8_t m, s, f;
+
+       m = lba / (60 * 75);
+       lba -= m * (60 * 75);
+       s = lba / 75;
+       f = lba % 75;
+
+       return ((m / 10) << 20) | ((m % 10) << 16) |
+                       ((s / 10) << 12) | ((s % 10) <<  8) |
+                       ((f / 10) <<  4) | ((f % 10) <<  0);
+}
+
+/**
+ * segacd needs it like this.. investigate
+ * Angelo also says PCE tracks often start playing at the
+ * wrong address.. related?
+ **/
+static inline uint32_t lba_to_msf_alt(int lba)
+{
+       uint32_t ret = 0;
+
+       ret |= ((lba / (60 * 75))&0xff)<<16;
+       ret |= (((lba / 75) % 60)&0xff)<<8;
+       ret |= ((lba % 75)&0xff)<<0;
+
+       return ret;
+}
+
+#endif  /* __CDROM_H__ */
diff --git a/deps/libchdr/include/libchdr/chd.h b/deps/libchdr/include/libchdr/chd.h
new file mode 100644 (file)
index 0000000..a37edc3
--- /dev/null
@@ -0,0 +1,427 @@
+/***************************************************************************
+
+    chd.h
+
+    MAME Compressed Hunks of Data file format
+
+****************************************************************************
+
+    Copyright Aaron Giles
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+        * Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+        * Redistributions in binary form must reproduce the above copyright
+          notice, this list of conditions and the following disclaimer in
+          the documentation and/or other materials provided with the
+          distribution.
+        * Neither the name 'MAME' nor the names of its contributors may be
+          used to endorse or promote products derived from this software
+          without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+    POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CHD_H__
+#define __CHD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libchdr/coretypes.h>
+#include <libchdr/chdconfig.h>
+
+/***************************************************************************
+
+    Compressed Hunks of Data header format. All numbers are stored in
+    Motorola (big-endian) byte ordering. The header is 76 (V1) or 80 (V2)
+    bytes long.
+
+    V1 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] UINT32 length;        // length of header (including tag and length fields)
+    [ 12] UINT32 version;       // drive format version
+    [ 16] UINT32 flags;         // flags (see below)
+    [ 20] UINT32 compression;   // compression type
+    [ 24] UINT32 hunksize;      // 512-byte sectors per hunk
+    [ 28] UINT32 totalhunks;    // total # of hunks represented
+    [ 32] UINT32 cylinders;     // number of cylinders on hard disk
+    [ 36] UINT32 heads;         // number of heads on hard disk
+    [ 40] UINT32 sectors;       // number of sectors on hard disk
+    [ 44] UINT8  md5[16];       // MD5 checksum of raw data
+    [ 60] UINT8  parentmd5[16]; // MD5 checksum of parent file
+    [ 76] (V1 header length)
+
+    V2 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] UINT32 length;        // length of header (including tag and length fields)
+    [ 12] UINT32 version;       // drive format version
+    [ 16] UINT32 flags;         // flags (see below)
+    [ 20] UINT32 compression;   // compression type
+    [ 24] UINT32 hunksize;      // seclen-byte sectors per hunk
+    [ 28] UINT32 totalhunks;    // total # of hunks represented
+    [ 32] UINT32 cylinders;     // number of cylinders on hard disk
+    [ 36] UINT32 heads;         // number of heads on hard disk
+    [ 40] UINT32 sectors;       // number of sectors on hard disk
+    [ 44] UINT8  md5[16];       // MD5 checksum of raw data
+    [ 60] UINT8  parentmd5[16]; // MD5 checksum of parent file
+    [ 76] UINT32 seclen;        // number of bytes per sector
+    [ 80] (V2 header length)
+
+    V3 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] UINT32 length;        // length of header (including tag and length fields)
+    [ 12] UINT32 version;       // drive format version
+    [ 16] UINT32 flags;         // flags (see below)
+    [ 20] UINT32 compression;   // compression type
+    [ 24] UINT32 totalhunks;    // total # of hunks represented
+    [ 28] UINT64 logicalbytes;  // logical size of the data (in bytes)
+    [ 36] UINT64 metaoffset;    // offset to the first blob of metadata
+    [ 44] UINT8  md5[16];       // MD5 checksum of raw data
+    [ 60] UINT8  parentmd5[16]; // MD5 checksum of parent file
+    [ 76] UINT32 hunkbytes;     // number of bytes per hunk
+    [ 80] UINT8  sha1[20];      // SHA1 checksum of raw data
+    [100] UINT8  parentsha1[20];// SHA1 checksum of parent file
+    [120] (V3 header length)
+
+    V4 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] UINT32 length;        // length of header (including tag and length fields)
+    [ 12] UINT32 version;       // drive format version
+    [ 16] UINT32 flags;         // flags (see below)
+    [ 20] UINT32 compression;   // compression type
+    [ 24] UINT32 totalhunks;    // total # of hunks represented
+    [ 28] UINT64 logicalbytes;  // logical size of the data (in bytes)
+    [ 36] UINT64 metaoffset;    // offset to the first blob of metadata
+    [ 44] UINT32 hunkbytes;     // number of bytes per hunk
+    [ 48] UINT8  sha1[20];      // combined raw+meta SHA1
+    [ 68] UINT8  parentsha1[20];// combined raw+meta SHA1 of parent
+    [ 88] UINT8  rawsha1[20];   // raw data SHA1
+    [108] (V4 header length)
+
+    Flags:
+        0x00000001 - set if this drive has a parent
+        0x00000002 - set if this drive allows writes
+
+   =========================================================================
+
+    V5 header:
+
+    [  0] char   tag[8];        // 'MComprHD'
+    [  8] uint32_t length;        // length of header (including tag and length fields)
+    [ 12] uint32_t version;       // drive format version
+    [ 16] uint32_t compressors[4];// which custom compressors are used?
+    [ 32] uint64_t logicalbytes;  // logical size of the data (in bytes)
+    [ 40] uint64_t mapoffset;     // offset to the map
+    [ 48] uint64_t metaoffset;    // offset to the first blob of metadata
+    [ 56] uint32_t hunkbytes;     // number of bytes per hunk (512k maximum)
+    [ 60] uint32_t unitbytes;     // number of bytes per unit within each hunk
+    [ 64] uint8_t  rawsha1[20];   // raw data SHA1
+    [ 84] uint8_t  sha1[20];      // combined raw+meta SHA1
+    [104] uint8_t  parentsha1[20];// combined raw+meta SHA1 of parent
+    [124] (V5 header length)
+
+    If parentsha1 != 0, we have a parent (no need for flags)
+    If compressors[0] == 0, we are uncompressed (including maps)
+
+    V5 uncompressed map format:
+
+    [  0] uint32_t offset;        // starting offset / hunk size
+
+    V5 compressed map format header:
+
+    [  0] uint32_t length;        // length of compressed map
+    [  4] UINT48 datastart;     // offset of first block
+    [ 10] uint16_t crc;           // crc-16 of the map
+    [ 12] uint8_t lengthbits;     // bits used to encode complength
+    [ 13] uint8_t hunkbits;       // bits used to encode self-refs
+    [ 14] uint8_t parentunitbits; // bits used to encode parent unit refs
+    [ 15] uint8_t reserved;       // future use
+    [ 16] (compressed header length)
+
+    Each compressed map entry, once expanded, looks like:
+
+    [  0] uint8_t compression;    // compression type
+    [  1] UINT24 complength;    // compressed length
+    [  4] UINT48 offset;        // offset
+    [ 10] uint16_t crc;           // crc-16 of the data
+
+***************************************************************************/
+
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+/* header information */
+#define CHD_HEADER_VERSION                     5
+#define CHD_V1_HEADER_SIZE                     76
+#define CHD_V2_HEADER_SIZE                     80
+#define CHD_V3_HEADER_SIZE                     120
+#define CHD_V4_HEADER_SIZE                     108
+#define CHD_V5_HEADER_SIZE          124
+
+#define CHD_MAX_HEADER_SIZE                    CHD_V5_HEADER_SIZE
+
+/* checksumming information */
+#define CHD_MD5_BYTES                          16
+#define CHD_SHA1_BYTES                         20
+
+/* CHD global flags */
+#define CHDFLAGS_HAS_PARENT                    0x00000001
+#define CHDFLAGS_IS_WRITEABLE          0x00000002
+#define CHDFLAGS_UNDEFINED                     0xfffffffc
+
+#define CHD_MAKE_TAG(a,b,c,d)       (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+/* compression types */
+#define CHDCOMPRESSION_NONE                    0
+#define CHDCOMPRESSION_ZLIB                    1
+#define CHDCOMPRESSION_ZLIB_PLUS       2
+#define CHDCOMPRESSION_AV                      3
+
+#define CHD_CODEC_NONE 0
+#define CHD_CODEC_ZLIB                         CHD_MAKE_TAG('z','l','i','b')
+/* general codecs with CD frontend */
+#define CHD_CODEC_CD_ZLIB                      CHD_MAKE_TAG('c','d','z','l')
+#define CHD_CODEC_CD_LZMA                      CHD_MAKE_TAG('c','d','l','z')
+#define CHD_CODEC_CD_FLAC                      CHD_MAKE_TAG('c','d','f','l')
+
+/* A/V codec configuration parameters */
+#define AV_CODEC_COMPRESS_CONFIG       1
+#define AV_CODEC_DECOMPRESS_CONFIG     2
+
+/* metadata parameters */
+#define CHDMETATAG_WILDCARD                    0
+#define CHD_METAINDEX_APPEND           ((UINT32)-1)
+
+/* metadata flags */
+#define CHD_MDFLAGS_CHECKSUM           0x01            /* indicates data is checksummed */
+
+/* standard hard disk metadata */
+#define HARD_DISK_METADATA_TAG         CHD_MAKE_TAG('G','D','D','D')
+#define HARD_DISK_METADATA_FORMAT      "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d"
+
+/* hard disk identify information */
+#define HARD_DISK_IDENT_METADATA_TAG CHD_MAKE_TAG('I','D','N','T')
+
+/* hard disk key information */
+#define HARD_DISK_KEY_METADATA_TAG     CHD_MAKE_TAG('K','E','Y',' ')
+
+/* pcmcia CIS information */
+#define PCMCIA_CIS_METADATA_TAG                CHD_MAKE_TAG('C','I','S',' ')
+
+/* standard CD-ROM metadata */
+#define CDROM_OLD_METADATA_TAG         CHD_MAKE_TAG('C','H','C','D')
+#define CDROM_TRACK_METADATA_TAG       CHD_MAKE_TAG('C','H','T','R')
+#define CDROM_TRACK_METADATA_FORMAT    "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"
+#define CDROM_TRACK_METADATA2_TAG      CHD_MAKE_TAG('C','H','T','2')
+#define CDROM_TRACK_METADATA2_FORMAT   "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
+#define GDROM_OLD_METADATA_TAG         CHD_MAKE_TAG('C','H','G','T')
+#define GDROM_TRACK_METADATA_TAG       CHD_MAKE_TAG('C', 'H', 'G', 'D')
+#define GDROM_TRACK_METADATA_FORMAT    "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d PAD:%d PREGAP:%d PGTYPE:%s PGSUB:%s POSTGAP:%d"
+
+/* standard A/V metadata */
+#define AV_METADATA_TAG                                CHD_MAKE_TAG('A','V','A','V')
+#define AV_METADATA_FORMAT                     "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d"
+
+/* A/V laserdisc frame metadata */
+#define AV_LD_METADATA_TAG                     CHD_MAKE_TAG('A','V','L','D')
+
+/* CHD open values */
+#define CHD_OPEN_READ                          1
+#define CHD_OPEN_READWRITE                     2
+
+/* error types */
+enum _chd_error
+{
+       CHDERR_NONE,
+       CHDERR_NO_INTERFACE,
+       CHDERR_OUT_OF_MEMORY,
+       CHDERR_INVALID_FILE,
+       CHDERR_INVALID_PARAMETER,
+       CHDERR_INVALID_DATA,
+       CHDERR_FILE_NOT_FOUND,
+       CHDERR_REQUIRES_PARENT,
+       CHDERR_FILE_NOT_WRITEABLE,
+       CHDERR_READ_ERROR,
+       CHDERR_WRITE_ERROR,
+       CHDERR_CODEC_ERROR,
+       CHDERR_INVALID_PARENT,
+       CHDERR_HUNK_OUT_OF_RANGE,
+       CHDERR_DECOMPRESSION_ERROR,
+       CHDERR_COMPRESSION_ERROR,
+       CHDERR_CANT_CREATE_FILE,
+       CHDERR_CANT_VERIFY,
+       CHDERR_NOT_SUPPORTED,
+       CHDERR_METADATA_NOT_FOUND,
+       CHDERR_INVALID_METADATA_SIZE,
+       CHDERR_UNSUPPORTED_VERSION,
+       CHDERR_VERIFY_INCOMPLETE,
+       CHDERR_INVALID_METADATA,
+       CHDERR_INVALID_STATE,
+       CHDERR_OPERATION_PENDING,
+       CHDERR_NO_ASYNC_OPERATION,
+       CHDERR_UNSUPPORTED_FORMAT
+};
+typedef enum _chd_error chd_error;
+
+
+
+/***************************************************************************
+    TYPE DEFINITIONS
+***************************************************************************/
+
+/* opaque types */
+typedef struct _chd_file chd_file;
+
+
+/* extract header structure (NOT the on-disk header structure) */
+typedef struct _chd_header chd_header;
+struct _chd_header
+{
+       UINT32          length;                                         /* length of header data */
+       UINT32          version;                                        /* drive format version */
+       UINT32          flags;                                          /* flags field */
+       UINT32          compression[4];                         /* compression type */
+       UINT32          hunkbytes;                                      /* number of bytes per hunk */
+       UINT32          totalhunks;                                     /* total # of hunks represented */
+       UINT64          logicalbytes;                           /* logical size of the data */
+       UINT64          metaoffset;                                     /* offset in file of first metadata */
+       UINT64          mapoffset;                                      /* TOOD V5 */
+       UINT8           md5[CHD_MD5_BYTES];                     /* overall MD5 checksum */
+       UINT8           parentmd5[CHD_MD5_BYTES];       /* overall MD5 checksum of parent */
+       UINT8           sha1[CHD_SHA1_BYTES];           /* overall SHA1 checksum */
+       UINT8           rawsha1[CHD_SHA1_BYTES];        /* SHA1 checksum of raw data */
+       UINT8           parentsha1[CHD_SHA1_BYTES];     /* overall SHA1 checksum of parent */
+       UINT32          unitbytes;                                      /* TODO V5 */
+       UINT64          unitcount;                                      /* TODO V5 */
+    UINT32      hunkcount;                  /* TODO V5 */
+
+    /* map information */
+    UINT32      mapentrybytes;              /* length of each entry in a map (V5) */
+    UINT8*      rawmap;                     /* raw map data */
+
+       UINT32          obsolete_cylinders;                     /* obsolete field -- do not use! */
+       UINT32          obsolete_sectors;                       /* obsolete field -- do not use! */
+       UINT32          obsolete_heads;                         /* obsolete field -- do not use! */
+       UINT32          obsolete_hunksize;                      /* obsolete field -- do not use! */
+};
+
+
+/* structure for returning information about a verification pass */
+typedef struct _chd_verify_result chd_verify_result;
+struct _chd_verify_result
+{
+       UINT8           md5[CHD_MD5_BYTES];                     /* overall MD5 checksum */
+       UINT8           sha1[CHD_SHA1_BYTES];           /* overall SHA1 checksum */
+       UINT8           rawsha1[CHD_SHA1_BYTES];        /* SHA1 checksum of raw data */
+       UINT8           metasha1[CHD_SHA1_BYTES];       /* SHA1 checksum of metadata */
+};
+
+
+
+/***************************************************************************
+    FUNCTION PROTOTYPES
+***************************************************************************/
+
+#ifdef _MSC_VER
+#ifdef CHD_DLL
+#ifdef CHD_DLL_EXPORTS
+#define CHD_EXPORT __declspec(dllexport)
+#else
+#define CHD_EXPORT __declspec(dllimport)
+#endif
+#else
+#define CHD_EXPORT
+#endif
+#else
+#define CHD_EXPORT __attribute__ ((visibility("default")))
+#endif
+
+/* ----- CHD file management ----- */
+
+/* create a new CHD file fitting the given description */
+/* chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */
+
+/* same as chd_create(), but accepts an already-opened core_file object */
+/* chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent); */
+
+/* open an existing CHD file */
+CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd);
+CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd);
+
+/* precache underlying file */
+CHD_EXPORT chd_error chd_precache(chd_file *chd);
+
+/* close a CHD file */
+CHD_EXPORT void chd_close(chd_file *chd);
+
+/* return the associated core_file */
+CHD_EXPORT core_file *chd_core_file(chd_file *chd);
+
+/* return an error string for the given CHD error */
+CHD_EXPORT const char *chd_error_string(chd_error err);
+
+
+
+/* ----- CHD header management ----- */
+
+/* return a pointer to the extracted CHD header data */
+CHD_EXPORT const chd_header *chd_get_header(chd_file *chd);
+
+/* read CHD header data from file into the pointed struct */
+CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header);
+
+
+
+/* ----- core data read/write ----- */
+
+/* read one hunk from the CHD file */
+CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer);
+
+
+
+/* ----- metadata management ----- */
+
+/* get indexed metadata of a particular sort */
+CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags);
+
+
+
+
+/* ----- codec interfaces ----- */
+
+/* set internal codec parameters */
+CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config);
+
+/* return a string description of a codec */
+CHD_EXPORT const char *chd_get_codec_name(UINT32 codec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CHD_H__ */
diff --git a/deps/libchdr/include/libchdr/chdconfig.h b/deps/libchdr/include/libchdr/chdconfig.h
new file mode 100644 (file)
index 0000000..752038b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __CHDCONFIG_H__
+#define __CHDCONFIG_H__
+
+/* Configure CHDR features here */
+#define WANT_RAW_DATA_SECTOR    1
+#define WANT_SUBCODE            1
+#define NEED_CACHE_HUNK         1
+#define VERIFY_BLOCK_CRC        1
+
+#endif
diff --git a/deps/libchdr/include/libchdr/coretypes.h b/deps/libchdr/include/libchdr/coretypes.h
new file mode 100644 (file)
index 0000000..99ef322
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __CORETYPES_H__
+#define __CORETYPES_H__
+
+#include <stdint.h>
+#include <stdio.h>
+
+#ifdef USE_LIBRETRO_VFS
+#include <streams/file_stream_transforms.h>
+#endif
+
+#define ARRAY_LENGTH(x) (sizeof(x)/sizeof(x[0]))
+
+typedef uint64_t UINT64;
+typedef uint32_t UINT32;
+typedef uint16_t UINT16;
+typedef uint8_t UINT8;
+
+typedef int64_t INT64;
+typedef int32_t INT32;
+typedef int16_t INT16;
+typedef int8_t INT8;
+
+#ifdef USE_LIBRETRO_VFS
+#define core_file RFILE
+#define core_fopen(file) rfopen(file, "rb")
+#define core_fseek rfseek
+#define core_ftell rftell
+#define core_fread(fc, buff, len) rfread(buff, 1, len, fc)
+#define core_fclose rfclose
+#else
+#define core_file FILE
+#define core_fopen(file) fopen(file, "rb")
+#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WIN64__)
+       #define core_fseek _fseeki64
+       #define core_ftell _ftelli64
+#elif defined(_LARGEFILE_SOURCE) && defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+       #define core_fseek fseeko64
+       #define core_ftell ftello64
+#else
+       #define core_fseek fseeko
+       #define core_ftell ftello
+#endif
+#define core_fread(fc, buff, len) fread(buff, 1, len, fc)
+#define core_fclose fclose
+#endif
+
+#ifdef __GNUC__
+__attribute__ ((unused))
+#endif
+static UINT64 core_fsize(core_file *f)
+{
+    UINT64 rv;
+    UINT64 p = core_ftell(f);
+    core_fseek(f, 0, SEEK_END);
+    rv = core_ftell(f);
+    core_fseek(f, p, SEEK_SET);
+    return rv;
+}
+
+#endif
diff --git a/deps/libchdr/include/libchdr/flac.h b/deps/libchdr/include/libchdr/flac.h
new file mode 100644 (file)
index 0000000..bff255b
--- /dev/null
@@ -0,0 +1,50 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+ ***************************************************************************
+
+    flac.h
+
+    FLAC compression wrappers
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __FLAC_H__
+#define __FLAC_H__
+
+#include <stdint.h>
+
+/***************************************************************************
+ *  TYPE DEFINITIONS
+ ***************************************************************************
+ */
+
+typedef struct _flac_decoder flac_decoder;
+struct _flac_decoder {
+               /* output state */
+       void *                  decoder;                                /* actual encoder */
+       uint32_t                sample_rate;                    /* decoded sample rate */
+       uint8_t                 channels;                               /* decoded number of channels */
+       uint8_t                 bits_per_sample;                /* decoded bits per sample */
+       uint32_t                compressed_offset;              /* current offset in compressed data */
+       const uint8_t *         compressed_start;               /* start of compressed data */
+       uint32_t                compressed_length;              /* length of compressed data */
+       const uint8_t *         compressed2_start;              /* start of compressed data */
+       uint32_t                compressed2_length;             /* length of compressed data */
+       int16_t *               uncompressed_start[8];  /* pointer to start of uncompressed data (up to 8 streams) */
+       uint32_t                uncompressed_offset;    /* current position in uncompressed data */
+       uint32_t                uncompressed_length;    /* length of uncompressed data */
+       int                     uncompressed_swap;              /* swap uncompressed sample data */
+       uint8_t                 custom_header[0x2a];    /* custom header */
+};
+
+/* ======================> flac_decoder */
+
+int            flac_decoder_init(flac_decoder* decoder);
+void           flac_decoder_free(flac_decoder* decoder);
+int            flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length);
+int            flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian);
+uint32_t       flac_decoder_finish(flac_decoder* decoder);
+
+#endif /* __FLAC_H__ */
diff --git a/deps/libchdr/include/libchdr/huffman.h b/deps/libchdr/include/libchdr/huffman.h
new file mode 100644 (file)
index 0000000..6c9f511
--- /dev/null
@@ -0,0 +1,90 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+ ***************************************************************************
+
+    huffman.h
+
+    Static Huffman compression and decompression helpers.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __HUFFMAN_H__
+#define __HUFFMAN_H__
+
+#include <libchdr/bitstream.h>
+
+
+/***************************************************************************
+ *  CONSTANTS
+ ***************************************************************************
+ */
+
+enum huffman_error
+{
+       HUFFERR_NONE = 0,
+       HUFFERR_TOO_MANY_BITS,
+       HUFFERR_INVALID_DATA,
+       HUFFERR_INPUT_BUFFER_TOO_SMALL,
+       HUFFERR_OUTPUT_BUFFER_TOO_SMALL,
+       HUFFERR_INTERNAL_INCONSISTENCY,
+       HUFFERR_TOO_MANY_CONTEXTS
+};
+
+/***************************************************************************
+ *  TYPE DEFINITIONS
+ ***************************************************************************
+ */
+
+typedef uint16_t lookup_value;
+
+/* a node in the huffman tree */
+struct node_t
+{
+       struct node_t*          parent;         /* pointer to parent node */
+       uint32_t                        count;          /* number of hits on this node */
+       uint32_t                        weight;         /* assigned weight of this node */
+       uint32_t                        bits;           /* bits used to encode the node */
+       uint8_t                         numbits;        /* number of bits needed for this node */
+};
+
+/* ======================> huffman_context_base */
+
+/* context class for decoding */
+struct huffman_decoder
+{
+       /* internal state */
+       uint32_t                        numcodes;             /* number of total codes being processed */
+       uint8_t                         maxbits;           /* maximum bits per code */
+       uint8_t                         prevdata;             /* value of the previous data (for delta-RLE encoding) */
+       int                     rleremaining;         /* number of RLE bytes remaining (for delta-RLE encoding) */
+       lookup_value *          lookup;               /* pointer to the lookup table */
+       struct node_t *     huffnode;             /* array of nodes */
+       uint32_t *              datahisto;            /* histogram of data values */
+
+       /* array versions of the info we need */
+#if 0
+       node_t*                 huffnode_array; /* [_NumCodes]; */
+       lookup_value*   lookup_array; /* [1 << _MaxBits]; */
+#endif
+};
+
+/* ======================> huffman_decoder */
+
+struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits);
+void delete_huffman_decoder(struct huffman_decoder* decoder);
+
+/* single item operations */
+uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf);
+
+enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf);
+enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf);
+
+int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight);
+enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder);
+enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder);
+
+void huffman_build_lookup_table(struct huffman_decoder* decoder);
+
+#endif
diff --git a/deps/libchdr/pkg-config.pc.in b/deps/libchdr/pkg-config.pc.in
new file mode 100644 (file)
index 0000000..0289632
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/libchdr
+
+Name: libchdr
+Description: Standalone library for reading MAME's CHDv1-v5 formats
+Version: @CHDR_VERSION_MAJOR@.@CHDR_VERSION_MINOR@
+Libs: -L${libdir} -lchdr @LIBS@
+Cflags: -I${includedir}
+
diff --git a/deps/libchdr/src/libchdr_bitstream.c b/deps/libchdr/src/libchdr_bitstream.c
new file mode 100644 (file)
index 0000000..c82a67d
--- /dev/null
@@ -0,0 +1,125 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    bitstream.c
+
+    Helper classes for reading/writing at the bit level.
+
+***************************************************************************/
+
+#include <stdlib.h>
+#include <libchdr/bitstream.h>
+
+/***************************************************************************
+ *  INLINE FUNCTIONS
+ ***************************************************************************
+ */
+
+int bitstream_overflow(struct bitstream* bitstream) { return ((bitstream->doffset - bitstream->bits / 8) > bitstream->dlength); }
+
+/*-------------------------------------------------
+ *  create_bitstream - constructor
+ *-------------------------------------------------
+ */
+
+struct bitstream* create_bitstream(const void *src, uint32_t srclength)
+{
+       struct bitstream* bitstream = (struct bitstream*)malloc(sizeof(struct bitstream));
+       bitstream->buffer = 0;
+       bitstream->bits = 0;
+       bitstream->read = (const uint8_t*)src;
+       bitstream->doffset = 0;
+       bitstream->dlength = srclength;
+       return bitstream;
+}
+
+
+/*-----------------------------------------------------
+ *  bitstream_peek - fetch the requested number of bits
+ *  but don't advance the input pointer
+ *-----------------------------------------------------
+ */
+
+uint32_t bitstream_peek(struct bitstream* bitstream, int numbits)
+{
+       if (numbits == 0)
+               return 0;
+
+       /* fetch data if we need more */
+       if (numbits > bitstream->bits)
+       {
+               while (bitstream->bits <= 24)
+               {
+                       if (bitstream->doffset < bitstream->dlength)
+                               bitstream->buffer |= bitstream->read[bitstream->doffset] << (24 - bitstream->bits);
+                       bitstream->doffset++;
+                       bitstream->bits += 8;
+               }
+       }
+
+       /* return the data */
+       return bitstream->buffer >> (32 - numbits);
+}
+
+
+/*-----------------------------------------------------
+ *  bitstream_remove - advance the input pointer by the
+ *  specified number of bits
+ *-----------------------------------------------------
+ */
+
+void bitstream_remove(struct bitstream* bitstream, int numbits)
+{
+       bitstream->buffer <<= numbits;
+       bitstream->bits -= numbits;
+}
+
+
+/*-----------------------------------------------------
+ *  bitstream_read - fetch the requested number of bits
+ *-----------------------------------------------------
+ */
+
+uint32_t bitstream_read(struct bitstream* bitstream, int numbits)
+{
+       uint32_t result = bitstream_peek(bitstream, numbits);
+       bitstream_remove(bitstream, numbits);
+       return result;
+}
+
+
+/*-------------------------------------------------
+ *  read_offset - return the current read offset
+ *-------------------------------------------------
+ */
+
+uint32_t bitstream_read_offset(struct bitstream* bitstream)
+{
+       uint32_t result = bitstream->doffset;
+       int bits = bitstream->bits;
+       while (bits >= 8)
+       {
+               result--;
+               bits -= 8;
+       }
+       return result;
+}
+
+
+/*-------------------------------------------------
+ *  flush - flush to the nearest byte
+ *-------------------------------------------------
+ */
+
+uint32_t bitstream_flush(struct bitstream* bitstream)
+{
+       while (bitstream->bits >= 8)
+       {
+               bitstream->doffset--;
+               bitstream->bits -= 8;
+       }
+       bitstream->bits = bitstream->buffer = 0;
+       return bitstream->doffset;
+}
+
diff --git a/deps/libchdr/src/libchdr_cdrom.c b/deps/libchdr/src/libchdr_cdrom.c
new file mode 100644 (file)
index 0000000..58be015
--- /dev/null
@@ -0,0 +1,415 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    cdrom.c
+
+    Generic MAME CD-ROM utilties - build IDE and SCSI CD-ROMs on top of this
+
+****************************************************************************
+
+    IMPORTANT:
+    "physical" block addresses are the actual addresses on the emulated CD.
+    "chd" block addresses are the block addresses in the CHD file.
+    Because we pad each track to a 4-frame boundary, these addressing
+    schemes will differ after track 1!
+
+***************************************************************************/
+#include <assert.h>
+#include <string.h>
+
+#include <libchdr/cdrom.h>
+
+#ifdef WANT_RAW_DATA_SECTOR
+
+/***************************************************************************
+    DEBUGGING
+***************************************************************************/
+
+/** @brief  The verbose. */
+#define VERBOSE (0)
+#if VERBOSE
+
+/**
+ * @def LOG(x) do
+ *
+ * @brief   A macro that defines log.
+ *
+ * @param   x   The void to process.
+ */
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+/**
+ * @fn  void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
+ *
+ * @brief   Logerrors the given text.
+ *
+ * @param   text    The text.
+ *
+ * @return  A CLIB_DECL.
+ */
+
+void CLIB_DECL logerror(const char *text, ...) ATTR_PRINTF(1,2);
+#else
+
+/**
+ * @def LOG(x);
+ *
+ * @brief   A macro that defines log.
+ *
+ * @param   x   The void to process.
+ */
+
+#define LOG(x)
+#endif
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+/** @brief  offset within sector. */
+#define SYNC_OFFSET 0x000
+/** @brief  12 bytes. */
+#define SYNC_NUM_BYTES 12
+
+/** @brief  offset within sector. */
+#define MODE_OFFSET 0x00f
+
+/** @brief  offset within sector. */
+#define ECC_P_OFFSET 0x81c
+/** @brief  2 lots of 86. */
+#define ECC_P_NUM_BYTES 86
+/** @brief  24 bytes each. */
+#define ECC_P_COMP 24
+
+/** @brief  The ECC q offset. */
+#define ECC_Q_OFFSET (ECC_P_OFFSET + 2 * ECC_P_NUM_BYTES)
+/** @brief  2 lots of 52. */
+#define ECC_Q_NUM_BYTES 52
+/** @brief  43 bytes each. */
+#define ECC_Q_COMP 43
+
+/**
+ * @brief   -------------------------------------------------
+ *            ECC lookup tables pre-calculated tables for ECC data calcs
+ *          -------------------------------------------------.
+ */
+
+static const uint8_t ecclow[256] =
+{
+       0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+       0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
+       0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
+       0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
+       0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
+       0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
+       0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+       0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
+       0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0x0d, 0x0f, 0x09, 0x0b, 0x05, 0x07, 0x01, 0x03,
+       0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23,
+       0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43,
+       0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63,
+       0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83,
+       0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3,
+       0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3,
+       0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3
+};
+
+/** @brief  The ecchigh[ 256]. */
+static const uint8_t ecchigh[256] =
+{
+       0x00, 0xf4, 0xf5, 0x01, 0xf7, 0x03, 0x02, 0xf6, 0xf3, 0x07, 0x06, 0xf2, 0x04, 0xf0, 0xf1, 0x05,
+       0xfb, 0x0f, 0x0e, 0xfa, 0x0c, 0xf8, 0xf9, 0x0d, 0x08, 0xfc, 0xfd, 0x09, 0xff, 0x0b, 0x0a, 0xfe,
+       0xeb, 0x1f, 0x1e, 0xea, 0x1c, 0xe8, 0xe9, 0x1d, 0x18, 0xec, 0xed, 0x19, 0xef, 0x1b, 0x1a, 0xee,
+       0x10, 0xe4, 0xe5, 0x11, 0xe7, 0x13, 0x12, 0xe6, 0xe3, 0x17, 0x16, 0xe2, 0x14, 0xe0, 0xe1, 0x15,
+       0xcb, 0x3f, 0x3e, 0xca, 0x3c, 0xc8, 0xc9, 0x3d, 0x38, 0xcc, 0xcd, 0x39, 0xcf, 0x3b, 0x3a, 0xce,
+       0x30, 0xc4, 0xc5, 0x31, 0xc7, 0x33, 0x32, 0xc6, 0xc3, 0x37, 0x36, 0xc2, 0x34, 0xc0, 0xc1, 0x35,
+       0x20, 0xd4, 0xd5, 0x21, 0xd7, 0x23, 0x22, 0xd6, 0xd3, 0x27, 0x26, 0xd2, 0x24, 0xd0, 0xd1, 0x25,
+       0xdb, 0x2f, 0x2e, 0xda, 0x2c, 0xd8, 0xd9, 0x2d, 0x28, 0xdc, 0xdd, 0x29, 0xdf, 0x2b, 0x2a, 0xde,
+       0x8b, 0x7f, 0x7e, 0x8a, 0x7c, 0x88, 0x89, 0x7d, 0x78, 0x8c, 0x8d, 0x79, 0x8f, 0x7b, 0x7a, 0x8e,
+       0x70, 0x84, 0x85, 0x71, 0x87, 0x73, 0x72, 0x86, 0x83, 0x77, 0x76, 0x82, 0x74, 0x80, 0x81, 0x75,
+       0x60, 0x94, 0x95, 0x61, 0x97, 0x63, 0x62, 0x96, 0x93, 0x67, 0x66, 0x92, 0x64, 0x90, 0x91, 0x65,
+       0x9b, 0x6f, 0x6e, 0x9a, 0x6c, 0x98, 0x99, 0x6d, 0x68, 0x9c, 0x9d, 0x69, 0x9f, 0x6b, 0x6a, 0x9e,
+       0x40, 0xb4, 0xb5, 0x41, 0xb7, 0x43, 0x42, 0xb6, 0xb3, 0x47, 0x46, 0xb2, 0x44, 0xb0, 0xb1, 0x45,
+       0xbb, 0x4f, 0x4e, 0xba, 0x4c, 0xb8, 0xb9, 0x4d, 0x48, 0xbc, 0xbd, 0x49, 0xbf, 0x4b, 0x4a, 0xbe,
+       0xab, 0x5f, 0x5e, 0xaa, 0x5c, 0xa8, 0xa9, 0x5d, 0x58, 0xac, 0xad, 0x59, 0xaf, 0x5b, 0x5a, 0xae,
+       0x50, 0xa4, 0xa5, 0x51, 0xa7, 0x53, 0x52, 0xa6, 0xa3, 0x57, 0x56, 0xa2, 0x54, 0xa0, 0xa1, 0x55
+};
+
+/**
+ * @brief   -------------------------------------------------
+ *            poffsets - each row represents the addresses used to calculate a byte of the ECC P
+ *            data 86 (*2) ECC P bytes, 24 values represented by each
+ *          -------------------------------------------------.
+ */
+
+static const uint16_t poffsets[ECC_P_NUM_BYTES][ECC_P_COMP] =
+{
+       { 0x000,0x056,0x0ac,0x102,0x158,0x1ae,0x204,0x25a,0x2b0,0x306,0x35c,0x3b2,0x408,0x45e,0x4b4,0x50a,0x560,0x5b6,0x60c,0x662,0x6b8,0x70e,0x764,0x7ba },
+       { 0x001,0x057,0x0ad,0x103,0x159,0x1af,0x205,0x25b,0x2b1,0x307,0x35d,0x3b3,0x409,0x45f,0x4b5,0x50b,0x561,0x5b7,0x60d,0x663,0x6b9,0x70f,0x765,0x7bb },
+       { 0x002,0x058,0x0ae,0x104,0x15a,0x1b0,0x206,0x25c,0x2b2,0x308,0x35e,0x3b4,0x40a,0x460,0x4b6,0x50c,0x562,0x5b8,0x60e,0x664,0x6ba,0x710,0x766,0x7bc },
+       { 0x003,0x059,0x0af,0x105,0x15b,0x1b1,0x207,0x25d,0x2b3,0x309,0x35f,0x3b5,0x40b,0x461,0x4b7,0x50d,0x563,0x5b9,0x60f,0x665,0x6bb,0x711,0x767,0x7bd },
+       { 0x004,0x05a,0x0b0,0x106,0x15c,0x1b2,0x208,0x25e,0x2b4,0x30a,0x360,0x3b6,0x40c,0x462,0x4b8,0x50e,0x564,0x5ba,0x610,0x666,0x6bc,0x712,0x768,0x7be },
+       { 0x005,0x05b,0x0b1,0x107,0x15d,0x1b3,0x209,0x25f,0x2b5,0x30b,0x361,0x3b7,0x40d,0x463,0x4b9,0x50f,0x565,0x5bb,0x611,0x667,0x6bd,0x713,0x769,0x7bf },
+       { 0x006,0x05c,0x0b2,0x108,0x15e,0x1b4,0x20a,0x260,0x2b6,0x30c,0x362,0x3b8,0x40e,0x464,0x4ba,0x510,0x566,0x5bc,0x612,0x668,0x6be,0x714,0x76a,0x7c0 },
+       { 0x007,0x05d,0x0b3,0x109,0x15f,0x1b5,0x20b,0x261,0x2b7,0x30d,0x363,0x3b9,0x40f,0x465,0x4bb,0x511,0x567,0x5bd,0x613,0x669,0x6bf,0x715,0x76b,0x7c1 },
+       { 0x008,0x05e,0x0b4,0x10a,0x160,0x1b6,0x20c,0x262,0x2b8,0x30e,0x364,0x3ba,0x410,0x466,0x4bc,0x512,0x568,0x5be,0x614,0x66a,0x6c0,0x716,0x76c,0x7c2 },
+       { 0x009,0x05f,0x0b5,0x10b,0x161,0x1b7,0x20d,0x263,0x2b9,0x30f,0x365,0x3bb,0x411,0x467,0x4bd,0x513,0x569,0x5bf,0x615,0x66b,0x6c1,0x717,0x76d,0x7c3 },
+       { 0x00a,0x060,0x0b6,0x10c,0x162,0x1b8,0x20e,0x264,0x2ba,0x310,0x366,0x3bc,0x412,0x468,0x4be,0x514,0x56a,0x5c0,0x616,0x66c,0x6c2,0x718,0x76e,0x7c4 },
+       { 0x00b,0x061,0x0b7,0x10d,0x163,0x1b9,0x20f,0x265,0x2bb,0x311,0x367,0x3bd,0x413,0x469,0x4bf,0x515,0x56b,0x5c1,0x617,0x66d,0x6c3,0x719,0x76f,0x7c5 },
+       { 0x00c,0x062,0x0b8,0x10e,0x164,0x1ba,0x210,0x266,0x2bc,0x312,0x368,0x3be,0x414,0x46a,0x4c0,0x516,0x56c,0x5c2,0x618,0x66e,0x6c4,0x71a,0x770,0x7c6 },
+       { 0x00d,0x063,0x0b9,0x10f,0x165,0x1bb,0x211,0x267,0x2bd,0x313,0x369,0x3bf,0x415,0x46b,0x4c1,0x517,0x56d,0x5c3,0x619,0x66f,0x6c5,0x71b,0x771,0x7c7 },
+       { 0x00e,0x064,0x0ba,0x110,0x166,0x1bc,0x212,0x268,0x2be,0x314,0x36a,0x3c0,0x416,0x46c,0x4c2,0x518,0x56e,0x5c4,0x61a,0x670,0x6c6,0x71c,0x772,0x7c8 },
+       { 0x00f,0x065,0x0bb,0x111,0x167,0x1bd,0x213,0x269,0x2bf,0x315,0x36b,0x3c1,0x417,0x46d,0x4c3,0x519,0x56f,0x5c5,0x61b,0x671,0x6c7,0x71d,0x773,0x7c9 },
+       { 0x010,0x066,0x0bc,0x112,0x168,0x1be,0x214,0x26a,0x2c0,0x316,0x36c,0x3c2,0x418,0x46e,0x4c4,0x51a,0x570,0x5c6,0x61c,0x672,0x6c8,0x71e,0x774,0x7ca },
+       { 0x011,0x067,0x0bd,0x113,0x169,0x1bf,0x215,0x26b,0x2c1,0x317,0x36d,0x3c3,0x419,0x46f,0x4c5,0x51b,0x571,0x5c7,0x61d,0x673,0x6c9,0x71f,0x775,0x7cb },
+       { 0x012,0x068,0x0be,0x114,0x16a,0x1c0,0x216,0x26c,0x2c2,0x318,0x36e,0x3c4,0x41a,0x470,0x4c6,0x51c,0x572,0x5c8,0x61e,0x674,0x6ca,0x720,0x776,0x7cc },
+       { 0x013,0x069,0x0bf,0x115,0x16b,0x1c1,0x217,0x26d,0x2c3,0x319,0x36f,0x3c5,0x41b,0x471,0x4c7,0x51d,0x573,0x5c9,0x61f,0x675,0x6cb,0x721,0x777,0x7cd },
+       { 0x014,0x06a,0x0c0,0x116,0x16c,0x1c2,0x218,0x26e,0x2c4,0x31a,0x370,0x3c6,0x41c,0x472,0x4c8,0x51e,0x574,0x5ca,0x620,0x676,0x6cc,0x722,0x778,0x7ce },
+       { 0x015,0x06b,0x0c1,0x117,0x16d,0x1c3,0x219,0x26f,0x2c5,0x31b,0x371,0x3c7,0x41d,0x473,0x4c9,0x51f,0x575,0x5cb,0x621,0x677,0x6cd,0x723,0x779,0x7cf },
+       { 0x016,0x06c,0x0c2,0x118,0x16e,0x1c4,0x21a,0x270,0x2c6,0x31c,0x372,0x3c8,0x41e,0x474,0x4ca,0x520,0x576,0x5cc,0x622,0x678,0x6ce,0x724,0x77a,0x7d0 },
+       { 0x017,0x06d,0x0c3,0x119,0x16f,0x1c5,0x21b,0x271,0x2c7,0x31d,0x373,0x3c9,0x41f,0x475,0x4cb,0x521,0x577,0x5cd,0x623,0x679,0x6cf,0x725,0x77b,0x7d1 },
+       { 0x018,0x06e,0x0c4,0x11a,0x170,0x1c6,0x21c,0x272,0x2c8,0x31e,0x374,0x3ca,0x420,0x476,0x4cc,0x522,0x578,0x5ce,0x624,0x67a,0x6d0,0x726,0x77c,0x7d2 },
+       { 0x019,0x06f,0x0c5,0x11b,0x171,0x1c7,0x21d,0x273,0x2c9,0x31f,0x375,0x3cb,0x421,0x477,0x4cd,0x523,0x579,0x5cf,0x625,0x67b,0x6d1,0x727,0x77d,0x7d3 },
+       { 0x01a,0x070,0x0c6,0x11c,0x172,0x1c8,0x21e,0x274,0x2ca,0x320,0x376,0x3cc,0x422,0x478,0x4ce,0x524,0x57a,0x5d0,0x626,0x67c,0x6d2,0x728,0x77e,0x7d4 },
+       { 0x01b,0x071,0x0c7,0x11d,0x173,0x1c9,0x21f,0x275,0x2cb,0x321,0x377,0x3cd,0x423,0x479,0x4cf,0x525,0x57b,0x5d1,0x627,0x67d,0x6d3,0x729,0x77f,0x7d5 },
+       { 0x01c,0x072,0x0c8,0x11e,0x174,0x1ca,0x220,0x276,0x2cc,0x322,0x378,0x3ce,0x424,0x47a,0x4d0,0x526,0x57c,0x5d2,0x628,0x67e,0x6d4,0x72a,0x780,0x7d6 },
+       { 0x01d,0x073,0x0c9,0x11f,0x175,0x1cb,0x221,0x277,0x2cd,0x323,0x379,0x3cf,0x425,0x47b,0x4d1,0x527,0x57d,0x5d3,0x629,0x67f,0x6d5,0x72b,0x781,0x7d7 },
+       { 0x01e,0x074,0x0ca,0x120,0x176,0x1cc,0x222,0x278,0x2ce,0x324,0x37a,0x3d0,0x426,0x47c,0x4d2,0x528,0x57e,0x5d4,0x62a,0x680,0x6d6,0x72c,0x782,0x7d8 },
+       { 0x01f,0x075,0x0cb,0x121,0x177,0x1cd,0x223,0x279,0x2cf,0x325,0x37b,0x3d1,0x427,0x47d,0x4d3,0x529,0x57f,0x5d5,0x62b,0x681,0x6d7,0x72d,0x783,0x7d9 },
+       { 0x020,0x076,0x0cc,0x122,0x178,0x1ce,0x224,0x27a,0x2d0,0x326,0x37c,0x3d2,0x428,0x47e,0x4d4,0x52a,0x580,0x5d6,0x62c,0x682,0x6d8,0x72e,0x784,0x7da },
+       { 0x021,0x077,0x0cd,0x123,0x179,0x1cf,0x225,0x27b,0x2d1,0x327,0x37d,0x3d3,0x429,0x47f,0x4d5,0x52b,0x581,0x5d7,0x62d,0x683,0x6d9,0x72f,0x785,0x7db },
+       { 0x022,0x078,0x0ce,0x124,0x17a,0x1d0,0x226,0x27c,0x2d2,0x328,0x37e,0x3d4,0x42a,0x480,0x4d6,0x52c,0x582,0x5d8,0x62e,0x684,0x6da,0x730,0x786,0x7dc },
+       { 0x023,0x079,0x0cf,0x125,0x17b,0x1d1,0x227,0x27d,0x2d3,0x329,0x37f,0x3d5,0x42b,0x481,0x4d7,0x52d,0x583,0x5d9,0x62f,0x685,0x6db,0x731,0x787,0x7dd },
+       { 0x024,0x07a,0x0d0,0x126,0x17c,0x1d2,0x228,0x27e,0x2d4,0x32a,0x380,0x3d6,0x42c,0x482,0x4d8,0x52e,0x584,0x5da,0x630,0x686,0x6dc,0x732,0x788,0x7de },
+       { 0x025,0x07b,0x0d1,0x127,0x17d,0x1d3,0x229,0x27f,0x2d5,0x32b,0x381,0x3d7,0x42d,0x483,0x4d9,0x52f,0x585,0x5db,0x631,0x687,0x6dd,0x733,0x789,0x7df },
+       { 0x026,0x07c,0x0d2,0x128,0x17e,0x1d4,0x22a,0x280,0x2d6,0x32c,0x382,0x3d8,0x42e,0x484,0x4da,0x530,0x586,0x5dc,0x632,0x688,0x6de,0x734,0x78a,0x7e0 },
+       { 0x027,0x07d,0x0d3,0x129,0x17f,0x1d5,0x22b,0x281,0x2d7,0x32d,0x383,0x3d9,0x42f,0x485,0x4db,0x531,0x587,0x5dd,0x633,0x689,0x6df,0x735,0x78b,0x7e1 },
+       { 0x028,0x07e,0x0d4,0x12a,0x180,0x1d6,0x22c,0x282,0x2d8,0x32e,0x384,0x3da,0x430,0x486,0x4dc,0x532,0x588,0x5de,0x634,0x68a,0x6e0,0x736,0x78c,0x7e2 },
+       { 0x029,0x07f,0x0d5,0x12b,0x181,0x1d7,0x22d,0x283,0x2d9,0x32f,0x385,0x3db,0x431,0x487,0x4dd,0x533,0x589,0x5df,0x635,0x68b,0x6e1,0x737,0x78d,0x7e3 },
+       { 0x02a,0x080,0x0d6,0x12c,0x182,0x1d8,0x22e,0x284,0x2da,0x330,0x386,0x3dc,0x432,0x488,0x4de,0x534,0x58a,0x5e0,0x636,0x68c,0x6e2,0x738,0x78e,0x7e4 },
+       { 0x02b,0x081,0x0d7,0x12d,0x183,0x1d9,0x22f,0x285,0x2db,0x331,0x387,0x3dd,0x433,0x489,0x4df,0x535,0x58b,0x5e1,0x637,0x68d,0x6e3,0x739,0x78f,0x7e5 },
+       { 0x02c,0x082,0x0d8,0x12e,0x184,0x1da,0x230,0x286,0x2dc,0x332,0x388,0x3de,0x434,0x48a,0x4e0,0x536,0x58c,0x5e2,0x638,0x68e,0x6e4,0x73a,0x790,0x7e6 },
+       { 0x02d,0x083,0x0d9,0x12f,0x185,0x1db,0x231,0x287,0x2dd,0x333,0x389,0x3df,0x435,0x48b,0x4e1,0x537,0x58d,0x5e3,0x639,0x68f,0x6e5,0x73b,0x791,0x7e7 },
+       { 0x02e,0x084,0x0da,0x130,0x186,0x1dc,0x232,0x288,0x2de,0x334,0x38a,0x3e0,0x436,0x48c,0x4e2,0x538,0x58e,0x5e4,0x63a,0x690,0x6e6,0x73c,0x792,0x7e8 },
+       { 0x02f,0x085,0x0db,0x131,0x187,0x1dd,0x233,0x289,0x2df,0x335,0x38b,0x3e1,0x437,0x48d,0x4e3,0x539,0x58f,0x5e5,0x63b,0x691,0x6e7,0x73d,0x793,0x7e9 },
+       { 0x030,0x086,0x0dc,0x132,0x188,0x1de,0x234,0x28a,0x2e0,0x336,0x38c,0x3e2,0x438,0x48e,0x4e4,0x53a,0x590,0x5e6,0x63c,0x692,0x6e8,0x73e,0x794,0x7ea },
+       { 0x031,0x087,0x0dd,0x133,0x189,0x1df,0x235,0x28b,0x2e1,0x337,0x38d,0x3e3,0x439,0x48f,0x4e5,0x53b,0x591,0x5e7,0x63d,0x693,0x6e9,0x73f,0x795,0x7eb },
+       { 0x032,0x088,0x0de,0x134,0x18a,0x1e0,0x236,0x28c,0x2e2,0x338,0x38e,0x3e4,0x43a,0x490,0x4e6,0x53c,0x592,0x5e8,0x63e,0x694,0x6ea,0x740,0x796,0x7ec },
+       { 0x033,0x089,0x0df,0x135,0x18b,0x1e1,0x237,0x28d,0x2e3,0x339,0x38f,0x3e5,0x43b,0x491,0x4e7,0x53d,0x593,0x5e9,0x63f,0x695,0x6eb,0x741,0x797,0x7ed },
+       { 0x034,0x08a,0x0e0,0x136,0x18c,0x1e2,0x238,0x28e,0x2e4,0x33a,0x390,0x3e6,0x43c,0x492,0x4e8,0x53e,0x594,0x5ea,0x640,0x696,0x6ec,0x742,0x798,0x7ee },
+       { 0x035,0x08b,0x0e1,0x137,0x18d,0x1e3,0x239,0x28f,0x2e5,0x33b,0x391,0x3e7,0x43d,0x493,0x4e9,0x53f,0x595,0x5eb,0x641,0x697,0x6ed,0x743,0x799,0x7ef },
+       { 0x036,0x08c,0x0e2,0x138,0x18e,0x1e4,0x23a,0x290,0x2e6,0x33c,0x392,0x3e8,0x43e,0x494,0x4ea,0x540,0x596,0x5ec,0x642,0x698,0x6ee,0x744,0x79a,0x7f0 },
+       { 0x037,0x08d,0x0e3,0x139,0x18f,0x1e5,0x23b,0x291,0x2e7,0x33d,0x393,0x3e9,0x43f,0x495,0x4eb,0x541,0x597,0x5ed,0x643,0x699,0x6ef,0x745,0x79b,0x7f1 },
+       { 0x038,0x08e,0x0e4,0x13a,0x190,0x1e6,0x23c,0x292,0x2e8,0x33e,0x394,0x3ea,0x440,0x496,0x4ec,0x542,0x598,0x5ee,0x644,0x69a,0x6f0,0x746,0x79c,0x7f2 },
+       { 0x039,0x08f,0x0e5,0x13b,0x191,0x1e7,0x23d,0x293,0x2e9,0x33f,0x395,0x3eb,0x441,0x497,0x4ed,0x543,0x599,0x5ef,0x645,0x69b,0x6f1,0x747,0x79d,0x7f3 },
+       { 0x03a,0x090,0x0e6,0x13c,0x192,0x1e8,0x23e,0x294,0x2ea,0x340,0x396,0x3ec,0x442,0x498,0x4ee,0x544,0x59a,0x5f0,0x646,0x69c,0x6f2,0x748,0x79e,0x7f4 },
+       { 0x03b,0x091,0x0e7,0x13d,0x193,0x1e9,0x23f,0x295,0x2eb,0x341,0x397,0x3ed,0x443,0x499,0x4ef,0x545,0x59b,0x5f1,0x647,0x69d,0x6f3,0x749,0x79f,0x7f5 },
+       { 0x03c,0x092,0x0e8,0x13e,0x194,0x1ea,0x240,0x296,0x2ec,0x342,0x398,0x3ee,0x444,0x49a,0x4f0,0x546,0x59c,0x5f2,0x648,0x69e,0x6f4,0x74a,0x7a0,0x7f6 },
+       { 0x03d,0x093,0x0e9,0x13f,0x195,0x1eb,0x241,0x297,0x2ed,0x343,0x399,0x3ef,0x445,0x49b,0x4f1,0x547,0x59d,0x5f3,0x649,0x69f,0x6f5,0x74b,0x7a1,0x7f7 },
+       { 0x03e,0x094,0x0ea,0x140,0x196,0x1ec,0x242,0x298,0x2ee,0x344,0x39a,0x3f0,0x446,0x49c,0x4f2,0x548,0x59e,0x5f4,0x64a,0x6a0,0x6f6,0x74c,0x7a2,0x7f8 },
+       { 0x03f,0x095,0x0eb,0x141,0x197,0x1ed,0x243,0x299,0x2ef,0x345,0x39b,0x3f1,0x447,0x49d,0x4f3,0x549,0x59f,0x5f5,0x64b,0x6a1,0x6f7,0x74d,0x7a3,0x7f9 },
+       { 0x040,0x096,0x0ec,0x142,0x198,0x1ee,0x244,0x29a,0x2f0,0x346,0x39c,0x3f2,0x448,0x49e,0x4f4,0x54a,0x5a0,0x5f6,0x64c,0x6a2,0x6f8,0x74e,0x7a4,0x7fa },
+       { 0x041,0x097,0x0ed,0x143,0x199,0x1ef,0x245,0x29b,0x2f1,0x347,0x39d,0x3f3,0x449,0x49f,0x4f5,0x54b,0x5a1,0x5f7,0x64d,0x6a3,0x6f9,0x74f,0x7a5,0x7fb },
+       { 0x042,0x098,0x0ee,0x144,0x19a,0x1f0,0x246,0x29c,0x2f2,0x348,0x39e,0x3f4,0x44a,0x4a0,0x4f6,0x54c,0x5a2,0x5f8,0x64e,0x6a4,0x6fa,0x750,0x7a6,0x7fc },
+       { 0x043,0x099,0x0ef,0x145,0x19b,0x1f1,0x247,0x29d,0x2f3,0x349,0x39f,0x3f5,0x44b,0x4a1,0x4f7,0x54d,0x5a3,0x5f9,0x64f,0x6a5,0x6fb,0x751,0x7a7,0x7fd },
+       { 0x044,0x09a,0x0f0,0x146,0x19c,0x1f2,0x248,0x29e,0x2f4,0x34a,0x3a0,0x3f6,0x44c,0x4a2,0x4f8,0x54e,0x5a4,0x5fa,0x650,0x6a6,0x6fc,0x752,0x7a8,0x7fe },
+       { 0x045,0x09b,0x0f1,0x147,0x19d,0x1f3,0x249,0x29f,0x2f5,0x34b,0x3a1,0x3f7,0x44d,0x4a3,0x4f9,0x54f,0x5a5,0x5fb,0x651,0x6a7,0x6fd,0x753,0x7a9,0x7ff },
+       { 0x046,0x09c,0x0f2,0x148,0x19e,0x1f4,0x24a,0x2a0,0x2f6,0x34c,0x3a2,0x3f8,0x44e,0x4a4,0x4fa,0x550,0x5a6,0x5fc,0x652,0x6a8,0x6fe,0x754,0x7aa,0x800 },
+       { 0x047,0x09d,0x0f3,0x149,0x19f,0x1f5,0x24b,0x2a1,0x2f7,0x34d,0x3a3,0x3f9,0x44f,0x4a5,0x4fb,0x551,0x5a7,0x5fd,0x653,0x6a9,0x6ff,0x755,0x7ab,0x801 },
+       { 0x048,0x09e,0x0f4,0x14a,0x1a0,0x1f6,0x24c,0x2a2,0x2f8,0x34e,0x3a4,0x3fa,0x450,0x4a6,0x4fc,0x552,0x5a8,0x5fe,0x654,0x6aa,0x700,0x756,0x7ac,0x802 },
+       { 0x049,0x09f,0x0f5,0x14b,0x1a1,0x1f7,0x24d,0x2a3,0x2f9,0x34f,0x3a5,0x3fb,0x451,0x4a7,0x4fd,0x553,0x5a9,0x5ff,0x655,0x6ab,0x701,0x757,0x7ad,0x803 },
+       { 0x04a,0x0a0,0x0f6,0x14c,0x1a2,0x1f8,0x24e,0x2a4,0x2fa,0x350,0x3a6,0x3fc,0x452,0x4a8,0x4fe,0x554,0x5aa,0x600,0x656,0x6ac,0x702,0x758,0x7ae,0x804 },
+       { 0x04b,0x0a1,0x0f7,0x14d,0x1a3,0x1f9,0x24f,0x2a5,0x2fb,0x351,0x3a7,0x3fd,0x453,0x4a9,0x4ff,0x555,0x5ab,0x601,0x657,0x6ad,0x703,0x759,0x7af,0x805 },
+       { 0x04c,0x0a2,0x0f8,0x14e,0x1a4,0x1fa,0x250,0x2a6,0x2fc,0x352,0x3a8,0x3fe,0x454,0x4aa,0x500,0x556,0x5ac,0x602,0x658,0x6ae,0x704,0x75a,0x7b0,0x806 },
+       { 0x04d,0x0a3,0x0f9,0x14f,0x1a5,0x1fb,0x251,0x2a7,0x2fd,0x353,0x3a9,0x3ff,0x455,0x4ab,0x501,0x557,0x5ad,0x603,0x659,0x6af,0x705,0x75b,0x7b1,0x807 },
+       { 0x04e,0x0a4,0x0fa,0x150,0x1a6,0x1fc,0x252,0x2a8,0x2fe,0x354,0x3aa,0x400,0x456,0x4ac,0x502,0x558,0x5ae,0x604,0x65a,0x6b0,0x706,0x75c,0x7b2,0x808 },
+       { 0x04f,0x0a5,0x0fb,0x151,0x1a7,0x1fd,0x253,0x2a9,0x2ff,0x355,0x3ab,0x401,0x457,0x4ad,0x503,0x559,0x5af,0x605,0x65b,0x6b1,0x707,0x75d,0x7b3,0x809 },
+       { 0x050,0x0a6,0x0fc,0x152,0x1a8,0x1fe,0x254,0x2aa,0x300,0x356,0x3ac,0x402,0x458,0x4ae,0x504,0x55a,0x5b0,0x606,0x65c,0x6b2,0x708,0x75e,0x7b4,0x80a },
+       { 0x051,0x0a7,0x0fd,0x153,0x1a9,0x1ff,0x255,0x2ab,0x301,0x357,0x3ad,0x403,0x459,0x4af,0x505,0x55b,0x5b1,0x607,0x65d,0x6b3,0x709,0x75f,0x7b5,0x80b },
+       { 0x052,0x0a8,0x0fe,0x154,0x1aa,0x200,0x256,0x2ac,0x302,0x358,0x3ae,0x404,0x45a,0x4b0,0x506,0x55c,0x5b2,0x608,0x65e,0x6b4,0x70a,0x760,0x7b6,0x80c },
+       { 0x053,0x0a9,0x0ff,0x155,0x1ab,0x201,0x257,0x2ad,0x303,0x359,0x3af,0x405,0x45b,0x4b1,0x507,0x55d,0x5b3,0x609,0x65f,0x6b5,0x70b,0x761,0x7b7,0x80d },
+       { 0x054,0x0aa,0x100,0x156,0x1ac,0x202,0x258,0x2ae,0x304,0x35a,0x3b0,0x406,0x45c,0x4b2,0x508,0x55e,0x5b4,0x60a,0x660,0x6b6,0x70c,0x762,0x7b8,0x80e },
+       { 0x055,0x0ab,0x101,0x157,0x1ad,0x203,0x259,0x2af,0x305,0x35b,0x3b1,0x407,0x45d,0x4b3,0x509,0x55f,0x5b5,0x60b,0x661,0x6b7,0x70d,0x763,0x7b9,0x80f }
+};
+
+/**
+ * @brief   -------------------------------------------------
+ *            qoffsets - each row represents the addresses used to calculate a byte of the ECC Q
+ *            data 52 (*2) ECC Q bytes, 43 values represented by each
+ *          -------------------------------------------------.
+ */
+
+static const uint16_t qoffsets[ECC_Q_NUM_BYTES][ECC_Q_COMP] =
+{
+       { 0x000,0x058,0x0b0,0x108,0x160,0x1b8,0x210,0x268,0x2c0,0x318,0x370,0x3c8,0x420,0x478,0x4d0,0x528,0x580,0x5d8,0x630,0x688,0x6e0,0x738,0x790,0x7e8,0x840,0x898,0x034,0x08c,0x0e4,0x13c,0x194,0x1ec,0x244,0x29c,0x2f4,0x34c,0x3a4,0x3fc,0x454,0x4ac,0x504,0x55c,0x5b4 },
+       { 0x001,0x059,0x0b1,0x109,0x161,0x1b9,0x211,0x269,0x2c1,0x319,0x371,0x3c9,0x421,0x479,0x4d1,0x529,0x581,0x5d9,0x631,0x689,0x6e1,0x739,0x791,0x7e9,0x841,0x899,0x035,0x08d,0x0e5,0x13d,0x195,0x1ed,0x245,0x29d,0x2f5,0x34d,0x3a5,0x3fd,0x455,0x4ad,0x505,0x55d,0x5b5 },
+       { 0x056,0x0ae,0x106,0x15e,0x1b6,0x20e,0x266,0x2be,0x316,0x36e,0x3c6,0x41e,0x476,0x4ce,0x526,0x57e,0x5d6,0x62e,0x686,0x6de,0x736,0x78e,0x7e6,0x83e,0x896,0x032,0x08a,0x0e2,0x13a,0x192,0x1ea,0x242,0x29a,0x2f2,0x34a,0x3a2,0x3fa,0x452,0x4aa,0x502,0x55a,0x5b2,0x60a },
+       { 0x057,0x0af,0x107,0x15f,0x1b7,0x20f,0x267,0x2bf,0x317,0x36f,0x3c7,0x41f,0x477,0x4cf,0x527,0x57f,0x5d7,0x62f,0x687,0x6df,0x737,0x78f,0x7e7,0x83f,0x897,0x033,0x08b,0x0e3,0x13b,0x193,0x1eb,0x243,0x29b,0x2f3,0x34b,0x3a3,0x3fb,0x453,0x4ab,0x503,0x55b,0x5b3,0x60b },
+       { 0x0ac,0x104,0x15c,0x1b4,0x20c,0x264,0x2bc,0x314,0x36c,0x3c4,0x41c,0x474,0x4cc,0x524,0x57c,0x5d4,0x62c,0x684,0x6dc,0x734,0x78c,0x7e4,0x83c,0x894,0x030,0x088,0x0e0,0x138,0x190,0x1e8,0x240,0x298,0x2f0,0x348,0x3a0,0x3f8,0x450,0x4a8,0x500,0x558,0x5b0,0x608,0x660 },
+       { 0x0ad,0x105,0x15d,0x1b5,0x20d,0x265,0x2bd,0x315,0x36d,0x3c5,0x41d,0x475,0x4cd,0x525,0x57d,0x5d5,0x62d,0x685,0x6dd,0x735,0x78d,0x7e5,0x83d,0x895,0x031,0x089,0x0e1,0x139,0x191,0x1e9,0x241,0x299,0x2f1,0x349,0x3a1,0x3f9,0x451,0x4a9,0x501,0x559,0x5b1,0x609,0x661 },
+       { 0x102,0x15a,0x1b2,0x20a,0x262,0x2ba,0x312,0x36a,0x3c2,0x41a,0x472,0x4ca,0x522,0x57a,0x5d2,0x62a,0x682,0x6da,0x732,0x78a,0x7e2,0x83a,0x892,0x02e,0x086,0x0de,0x136,0x18e,0x1e6,0x23e,0x296,0x2ee,0x346,0x39e,0x3f6,0x44e,0x4a6,0x4fe,0x556,0x5ae,0x606,0x65e,0x6b6 },
+       { 0x103,0x15b,0x1b3,0x20b,0x263,0x2bb,0x313,0x36b,0x3c3,0x41b,0x473,0x4cb,0x523,0x57b,0x5d3,0x62b,0x683,0x6db,0x733,0x78b,0x7e3,0x83b,0x893,0x02f,0x087,0x0df,0x137,0x18f,0x1e7,0x23f,0x297,0x2ef,0x347,0x39f,0x3f7,0x44f,0x4a7,0x4ff,0x557,0x5af,0x607,0x65f,0x6b7 },
+       { 0x158,0x1b0,0x208,0x260,0x2b8,0x310,0x368,0x3c0,0x418,0x470,0x4c8,0x520,0x578,0x5d0,0x628,0x680,0x6d8,0x730,0x788,0x7e0,0x838,0x890,0x02c,0x084,0x0dc,0x134,0x18c,0x1e4,0x23c,0x294,0x2ec,0x344,0x39c,0x3f4,0x44c,0x4a4,0x4fc,0x554,0x5ac,0x604,0x65c,0x6b4,0x70c },
+       { 0x159,0x1b1,0x209,0x261,0x2b9,0x311,0x369,0x3c1,0x419,0x471,0x4c9,0x521,0x579,0x5d1,0x629,0x681,0x6d9,0x731,0x789,0x7e1,0x839,0x891,0x02d,0x085,0x0dd,0x135,0x18d,0x1e5,0x23d,0x295,0x2ed,0x345,0x39d,0x3f5,0x44d,0x4a5,0x4fd,0x555,0x5ad,0x605,0x65d,0x6b5,0x70d },
+       { 0x1ae,0x206,0x25e,0x2b6,0x30e,0x366,0x3be,0x416,0x46e,0x4c6,0x51e,0x576,0x5ce,0x626,0x67e,0x6d6,0x72e,0x786,0x7de,0x836,0x88e,0x02a,0x082,0x0da,0x132,0x18a,0x1e2,0x23a,0x292,0x2ea,0x342,0x39a,0x3f2,0x44a,0x4a2,0x4fa,0x552,0x5aa,0x602,0x65a,0x6b2,0x70a,0x762 },
+       { 0x1af,0x207,0x25f,0x2b7,0x30f,0x367,0x3bf,0x417,0x46f,0x4c7,0x51f,0x577,0x5cf,0x627,0x67f,0x6d7,0x72f,0x787,0x7df,0x837,0x88f,0x02b,0x083,0x0db,0x133,0x18b,0x1e3,0x23b,0x293,0x2eb,0x343,0x39b,0x3f3,0x44b,0x4a3,0x4fb,0x553,0x5ab,0x603,0x65b,0x6b3,0x70b,0x763 },
+       { 0x204,0x25c,0x2b4,0x30c,0x364,0x3bc,0x414,0x46c,0x4c4,0x51c,0x574,0x5cc,0x624,0x67c,0x6d4,0x72c,0x784,0x7dc,0x834,0x88c,0x028,0x080,0x0d8,0x130,0x188,0x1e0,0x238,0x290,0x2e8,0x340,0x398,0x3f0,0x448,0x4a0,0x4f8,0x550,0x5a8,0x600,0x658,0x6b0,0x708,0x760,0x7b8 },
+       { 0x205,0x25d,0x2b5,0x30d,0x365,0x3bd,0x415,0x46d,0x4c5,0x51d,0x575,0x5cd,0x625,0x67d,0x6d5,0x72d,0x785,0x7dd,0x835,0x88d,0x029,0x081,0x0d9,0x131,0x189,0x1e1,0x239,0x291,0x2e9,0x341,0x399,0x3f1,0x449,0x4a1,0x4f9,0x551,0x5a9,0x601,0x659,0x6b1,0x709,0x761,0x7b9 },
+       { 0x25a,0x2b2,0x30a,0x362,0x3ba,0x412,0x46a,0x4c2,0x51a,0x572,0x5ca,0x622,0x67a,0x6d2,0x72a,0x782,0x7da,0x832,0x88a,0x026,0x07e,0x0d6,0x12e,0x186,0x1de,0x236,0x28e,0x2e6,0x33e,0x396,0x3ee,0x446,0x49e,0x4f6,0x54e,0x5a6,0x5fe,0x656,0x6ae,0x706,0x75e,0x7b6,0x80e },
+       { 0x25b,0x2b3,0x30b,0x363,0x3bb,0x413,0x46b,0x4c3,0x51b,0x573,0x5cb,0x623,0x67b,0x6d3,0x72b,0x783,0x7db,0x833,0x88b,0x027,0x07f,0x0d7,0x12f,0x187,0x1df,0x237,0x28f,0x2e7,0x33f,0x397,0x3ef,0x447,0x49f,0x4f7,0x54f,0x5a7,0x5ff,0x657,0x6af,0x707,0x75f,0x7b7,0x80f },
+       { 0x2b0,0x308,0x360,0x3b8,0x410,0x468,0x4c0,0x518,0x570,0x5c8,0x620,0x678,0x6d0,0x728,0x780,0x7d8,0x830,0x888,0x024,0x07c,0x0d4,0x12c,0x184,0x1dc,0x234,0x28c,0x2e4,0x33c,0x394,0x3ec,0x444,0x49c,0x4f4,0x54c,0x5a4,0x5fc,0x654,0x6ac,0x704,0x75c,0x7b4,0x80c,0x864 },
+       { 0x2b1,0x309,0x361,0x3b9,0x411,0x469,0x4c1,0x519,0x571,0x5c9,0x621,0x679,0x6d1,0x729,0x781,0x7d9,0x831,0x889,0x025,0x07d,0x0d5,0x12d,0x185,0x1dd,0x235,0x28d,0x2e5,0x33d,0x395,0x3ed,0x445,0x49d,0x4f5,0x54d,0x5a5,0x5fd,0x655,0x6ad,0x705,0x75d,0x7b5,0x80d,0x865 },
+       { 0x306,0x35e,0x3b6,0x40e,0x466,0x4be,0x516,0x56e,0x5c6,0x61e,0x676,0x6ce,0x726,0x77e,0x7d6,0x82e,0x886,0x022,0x07a,0x0d2,0x12a,0x182,0x1da,0x232,0x28a,0x2e2,0x33a,0x392,0x3ea,0x442,0x49a,0x4f2,0x54a,0x5a2,0x5fa,0x652,0x6aa,0x702,0x75a,0x7b2,0x80a,0x862,0x8ba },
+       { 0x307,0x35f,0x3b7,0x40f,0x467,0x4bf,0x517,0x56f,0x5c7,0x61f,0x677,0x6cf,0x727,0x77f,0x7d7,0x82f,0x887,0x023,0x07b,0x0d3,0x12b,0x183,0x1db,0x233,0x28b,0x2e3,0x33b,0x393,0x3eb,0x443,0x49b,0x4f3,0x54b,0x5a3,0x5fb,0x653,0x6ab,0x703,0x75b,0x7b3,0x80b,0x863,0x8bb },
+       { 0x35c,0x3b4,0x40c,0x464,0x4bc,0x514,0x56c,0x5c4,0x61c,0x674,0x6cc,0x724,0x77c,0x7d4,0x82c,0x884,0x020,0x078,0x0d0,0x128,0x180,0x1d8,0x230,0x288,0x2e0,0x338,0x390,0x3e8,0x440,0x498,0x4f0,0x548,0x5a0,0x5f8,0x650,0x6a8,0x700,0x758,0x7b0,0x808,0x860,0x8b8,0x054 },
+       { 0x35d,0x3b5,0x40d,0x465,0x4bd,0x515,0x56d,0x5c5,0x61d,0x675,0x6cd,0x725,0x77d,0x7d5,0x82d,0x885,0x021,0x079,0x0d1,0x129,0x181,0x1d9,0x231,0x289,0x2e1,0x339,0x391,0x3e9,0x441,0x499,0x4f1,0x549,0x5a1,0x5f9,0x651,0x6a9,0x701,0x759,0x7b1,0x809,0x861,0x8b9,0x055 },
+       { 0x3b2,0x40a,0x462,0x4ba,0x512,0x56a,0x5c2,0x61a,0x672,0x6ca,0x722,0x77a,0x7d2,0x82a,0x882,0x01e,0x076,0x0ce,0x126,0x17e,0x1d6,0x22e,0x286,0x2de,0x336,0x38e,0x3e6,0x43e,0x496,0x4ee,0x546,0x59e,0x5f6,0x64e,0x6a6,0x6fe,0x756,0x7ae,0x806,0x85e,0x8b6,0x052,0x0aa },
+       { 0x3b3,0x40b,0x463,0x4bb,0x513,0x56b,0x5c3,0x61b,0x673,0x6cb,0x723,0x77b,0x7d3,0x82b,0x883,0x01f,0x077,0x0cf,0x127,0x17f,0x1d7,0x22f,0x287,0x2df,0x337,0x38f,0x3e7,0x43f,0x497,0x4ef,0x547,0x59f,0x5f7,0x64f,0x6a7,0x6ff,0x757,0x7af,0x807,0x85f,0x8b7,0x053,0x0ab },
+       { 0x408,0x460,0x4b8,0x510,0x568,0x5c0,0x618,0x670,0x6c8,0x720,0x778,0x7d0,0x828,0x880,0x01c,0x074,0x0cc,0x124,0x17c,0x1d4,0x22c,0x284,0x2dc,0x334,0x38c,0x3e4,0x43c,0x494,0x4ec,0x544,0x59c,0x5f4,0x64c,0x6a4,0x6fc,0x754,0x7ac,0x804,0x85c,0x8b4,0x050,0x0a8,0x100 },
+       { 0x409,0x461,0x4b9,0x511,0x569,0x5c1,0x619,0x671,0x6c9,0x721,0x779,0x7d1,0x829,0x881,0x01d,0x075,0x0cd,0x125,0x17d,0x1d5,0x22d,0x285,0x2dd,0x335,0x38d,0x3e5,0x43d,0x495,0x4ed,0x545,0x59d,0x5f5,0x64d,0x6a5,0x6fd,0x755,0x7ad,0x805,0x85d,0x8b5,0x051,0x0a9,0x101 },
+       { 0x45e,0x4b6,0x50e,0x566,0x5be,0x616,0x66e,0x6c6,0x71e,0x776,0x7ce,0x826,0x87e,0x01a,0x072,0x0ca,0x122,0x17a,0x1d2,0x22a,0x282,0x2da,0x332,0x38a,0x3e2,0x43a,0x492,0x4ea,0x542,0x59a,0x5f2,0x64a,0x6a2,0x6fa,0x752,0x7aa,0x802,0x85a,0x8b2,0x04e,0x0a6,0x0fe,0x156 },
+       { 0x45f,0x4b7,0x50f,0x567,0x5bf,0x617,0x66f,0x6c7,0x71f,0x777,0x7cf,0x827,0x87f,0x01b,0x073,0x0cb,0x123,0x17b,0x1d3,0x22b,0x283,0x2db,0x333,0x38b,0x3e3,0x43b,0x493,0x4eb,0x543,0x59b,0x5f3,0x64b,0x6a3,0x6fb,0x753,0x7ab,0x803,0x85b,0x8b3,0x04f,0x0a7,0x0ff,0x157 },
+       { 0x4b4,0x50c,0x564,0x5bc,0x614,0x66c,0x6c4,0x71c,0x774,0x7cc,0x824,0x87c,0x018,0x070,0x0c8,0x120,0x178,0x1d0,0x228,0x280,0x2d8,0x330,0x388,0x3e0,0x438,0x490,0x4e8,0x540,0x598,0x5f0,0x648,0x6a0,0x6f8,0x750,0x7a8,0x800,0x858,0x8b0,0x04c,0x0a4,0x0fc,0x154,0x1ac },
+       { 0x4b5,0x50d,0x565,0x5bd,0x615,0x66d,0x6c5,0x71d,0x775,0x7cd,0x825,0x87d,0x019,0x071,0x0c9,0x121,0x179,0x1d1,0x229,0x281,0x2d9,0x331,0x389,0x3e1,0x439,0x491,0x4e9,0x541,0x599,0x5f1,0x649,0x6a1,0x6f9,0x751,0x7a9,0x801,0x859,0x8b1,0x04d,0x0a5,0x0fd,0x155,0x1ad },
+       { 0x50a,0x562,0x5ba,0x612,0x66a,0x6c2,0x71a,0x772,0x7ca,0x822,0x87a,0x016,0x06e,0x0c6,0x11e,0x176,0x1ce,0x226,0x27e,0x2d6,0x32e,0x386,0x3de,0x436,0x48e,0x4e6,0x53e,0x596,0x5ee,0x646,0x69e,0x6f6,0x74e,0x7a6,0x7fe,0x856,0x8ae,0x04a,0x0a2,0x0fa,0x152,0x1aa,0x202 },
+       { 0x50b,0x563,0x5bb,0x613,0x66b,0x6c3,0x71b,0x773,0x7cb,0x823,0x87b,0x017,0x06f,0x0c7,0x11f,0x177,0x1cf,0x227,0x27f,0x2d7,0x32f,0x387,0x3df,0x437,0x48f,0x4e7,0x53f,0x597,0x5ef,0x647,0x69f,0x6f7,0x74f,0x7a7,0x7ff,0x857,0x8af,0x04b,0x0a3,0x0fb,0x153,0x1ab,0x203 },
+       { 0x560,0x5b8,0x610,0x668,0x6c0,0x718,0x770,0x7c8,0x820,0x878,0x014,0x06c,0x0c4,0x11c,0x174,0x1cc,0x224,0x27c,0x2d4,0x32c,0x384,0x3dc,0x434,0x48c,0x4e4,0x53c,0x594,0x5ec,0x644,0x69c,0x6f4,0x74c,0x7a4,0x7fc,0x854,0x8ac,0x048,0x0a0,0x0f8,0x150,0x1a8,0x200,0x258 },
+       { 0x561,0x5b9,0x611,0x669,0x6c1,0x719,0x771,0x7c9,0x821,0x879,0x015,0x06d,0x0c5,0x11d,0x175,0x1cd,0x225,0x27d,0x2d5,0x32d,0x385,0x3dd,0x435,0x48d,0x4e5,0x53d,0x595,0x5ed,0x645,0x69d,0x6f5,0x74d,0x7a5,0x7fd,0x855,0x8ad,0x049,0x0a1,0x0f9,0x151,0x1a9,0x201,0x259 },
+       { 0x5b6,0x60e,0x666,0x6be,0x716,0x76e,0x7c6,0x81e,0x876,0x012,0x06a,0x0c2,0x11a,0x172,0x1ca,0x222,0x27a,0x2d2,0x32a,0x382,0x3da,0x432,0x48a,0x4e2,0x53a,0x592,0x5ea,0x642,0x69a,0x6f2,0x74a,0x7a2,0x7fa,0x852,0x8aa,0x046,0x09e,0x0f6,0x14e,0x1a6,0x1fe,0x256,0x2ae },
+       { 0x5b7,0x60f,0x667,0x6bf,0x717,0x76f,0x7c7,0x81f,0x877,0x013,0x06b,0x0c3,0x11b,0x173,0x1cb,0x223,0x27b,0x2d3,0x32b,0x383,0x3db,0x433,0x48b,0x4e3,0x53b,0x593,0x5eb,0x643,0x69b,0x6f3,0x74b,0x7a3,0x7fb,0x853,0x8ab,0x047,0x09f,0x0f7,0x14f,0x1a7,0x1ff,0x257,0x2af },
+       { 0x60c,0x664,0x6bc,0x714,0x76c,0x7c4,0x81c,0x874,0x010,0x068,0x0c0,0x118,0x170,0x1c8,0x220,0x278,0x2d0,0x328,0x380,0x3d8,0x430,0x488,0x4e0,0x538,0x590,0x5e8,0x640,0x698,0x6f0,0x748,0x7a0,0x7f8,0x850,0x8a8,0x044,0x09c,0x0f4,0x14c,0x1a4,0x1fc,0x254,0x2ac,0x304 },
+       { 0x60d,0x665,0x6bd,0x715,0x76d,0x7c5,0x81d,0x875,0x011,0x069,0x0c1,0x119,0x171,0x1c9,0x221,0x279,0x2d1,0x329,0x381,0x3d9,0x431,0x489,0x4e1,0x539,0x591,0x5e9,0x641,0x699,0x6f1,0x749,0x7a1,0x7f9,0x851,0x8a9,0x045,0x09d,0x0f5,0x14d,0x1a5,0x1fd,0x255,0x2ad,0x305 },
+       { 0x662,0x6ba,0x712,0x76a,0x7c2,0x81a,0x872,0x00e,0x066,0x0be,0x116,0x16e,0x1c6,0x21e,0x276,0x2ce,0x326,0x37e,0x3d6,0x42e,0x486,0x4de,0x536,0x58e,0x5e6,0x63e,0x696,0x6ee,0x746,0x79e,0x7f6,0x84e,0x8a6,0x042,0x09a,0x0f2,0x14a,0x1a2,0x1fa,0x252,0x2aa,0x302,0x35a },
+       { 0x663,0x6bb,0x713,0x76b,0x7c3,0x81b,0x873,0x00f,0x067,0x0bf,0x117,0x16f,0x1c7,0x21f,0x277,0x2cf,0x327,0x37f,0x3d7,0x42f,0x487,0x4df,0x537,0x58f,0x5e7,0x63f,0x697,0x6ef,0x747,0x79f,0x7f7,0x84f,0x8a7,0x043,0x09b,0x0f3,0x14b,0x1a3,0x1fb,0x253,0x2ab,0x303,0x35b },
+       { 0x6b8,0x710,0x768,0x7c0,0x818,0x870,0x00c,0x064,0x0bc,0x114,0x16c,0x1c4,0x21c,0x274,0x2cc,0x324,0x37c,0x3d4,0x42c,0x484,0x4dc,0x534,0x58c,0x5e4,0x63c,0x694,0x6ec,0x744,0x79c,0x7f4,0x84c,0x8a4,0x040,0x098,0x0f0,0x148,0x1a0,0x1f8,0x250,0x2a8,0x300,0x358,0x3b0 },
+       { 0x6b9,0x711,0x769,0x7c1,0x819,0x871,0x00d,0x065,0x0bd,0x115,0x16d,0x1c5,0x21d,0x275,0x2cd,0x325,0x37d,0x3d5,0x42d,0x485,0x4dd,0x535,0x58d,0x5e5,0x63d,0x695,0x6ed,0x745,0x79d,0x7f5,0x84d,0x8a5,0x041,0x099,0x0f1,0x149,0x1a1,0x1f9,0x251,0x2a9,0x301,0x359,0x3b1 },
+       { 0x70e,0x766,0x7be,0x816,0x86e,0x00a,0x062,0x0ba,0x112,0x16a,0x1c2,0x21a,0x272,0x2ca,0x322,0x37a,0x3d2,0x42a,0x482,0x4da,0x532,0x58a,0x5e2,0x63a,0x692,0x6ea,0x742,0x79a,0x7f2,0x84a,0x8a2,0x03e,0x096,0x0ee,0x146,0x19e,0x1f6,0x24e,0x2a6,0x2fe,0x356,0x3ae,0x406 },
+       { 0x70f,0x767,0x7bf,0x817,0x86f,0x00b,0x063,0x0bb,0x113,0x16b,0x1c3,0x21b,0x273,0x2cb,0x323,0x37b,0x3d3,0x42b,0x483,0x4db,0x533,0x58b,0x5e3,0x63b,0x693,0x6eb,0x743,0x79b,0x7f3,0x84b,0x8a3,0x03f,0x097,0x0ef,0x147,0x19f,0x1f7,0x24f,0x2a7,0x2ff,0x357,0x3af,0x407 },
+       { 0x764,0x7bc,0x814,0x86c,0x008,0x060,0x0b8,0x110,0x168,0x1c0,0x218,0x270,0x2c8,0x320,0x378,0x3d0,0x428,0x480,0x4d8,0x530,0x588,0x5e0,0x638,0x690,0x6e8,0x740,0x798,0x7f0,0x848,0x8a0,0x03c,0x094,0x0ec,0x144,0x19c,0x1f4,0x24c,0x2a4,0x2fc,0x354,0x3ac,0x404,0x45c },
+       { 0x765,0x7bd,0x815,0x86d,0x009,0x061,0x0b9,0x111,0x169,0x1c1,0x219,0x271,0x2c9,0x321,0x379,0x3d1,0x429,0x481,0x4d9,0x531,0x589,0x5e1,0x639,0x691,0x6e9,0x741,0x799,0x7f1,0x849,0x8a1,0x03d,0x095,0x0ed,0x145,0x19d,0x1f5,0x24d,0x2a5,0x2fd,0x355,0x3ad,0x405,0x45d },
+       { 0x7ba,0x812,0x86a,0x006,0x05e,0x0b6,0x10e,0x166,0x1be,0x216,0x26e,0x2c6,0x31e,0x376,0x3ce,0x426,0x47e,0x4d6,0x52e,0x586,0x5de,0x636,0x68e,0x6e6,0x73e,0x796,0x7ee,0x846,0x89e,0x03a,0x092,0x0ea,0x142,0x19a,0x1f2,0x24a,0x2a2,0x2fa,0x352,0x3aa,0x402,0x45a,0x4b2 },
+       { 0x7bb,0x813,0x86b,0x007,0x05f,0x0b7,0x10f,0x167,0x1bf,0x217,0x26f,0x2c7,0x31f,0x377,0x3cf,0x427,0x47f,0x4d7,0x52f,0x587,0x5df,0x637,0x68f,0x6e7,0x73f,0x797,0x7ef,0x847,0x89f,0x03b,0x093,0x0eb,0x143,0x19b,0x1f3,0x24b,0x2a3,0x2fb,0x353,0x3ab,0x403,0x45b,0x4b3 },
+       { 0x810,0x868,0x004,0x05c,0x0b4,0x10c,0x164,0x1bc,0x214,0x26c,0x2c4,0x31c,0x374,0x3cc,0x424,0x47c,0x4d4,0x52c,0x584,0x5dc,0x634,0x68c,0x6e4,0x73c,0x794,0x7ec,0x844,0x89c,0x038,0x090,0x0e8,0x140,0x198,0x1f0,0x248,0x2a0,0x2f8,0x350,0x3a8,0x400,0x458,0x4b0,0x508 },
+       { 0x811,0x869,0x005,0x05d,0x0b5,0x10d,0x165,0x1bd,0x215,0x26d,0x2c5,0x31d,0x375,0x3cd,0x425,0x47d,0x4d5,0x52d,0x585,0x5dd,0x635,0x68d,0x6e5,0x73d,0x795,0x7ed,0x845,0x89d,0x039,0x091,0x0e9,0x141,0x199,0x1f1,0x249,0x2a1,0x2f9,0x351,0x3a9,0x401,0x459,0x4b1,0x509 },
+       { 0x866,0x002,0x05a,0x0b2,0x10a,0x162,0x1ba,0x212,0x26a,0x2c2,0x31a,0x372,0x3ca,0x422,0x47a,0x4d2,0x52a,0x582,0x5da,0x632,0x68a,0x6e2,0x73a,0x792,0x7ea,0x842,0x89a,0x036,0x08e,0x0e6,0x13e,0x196,0x1ee,0x246,0x29e,0x2f6,0x34e,0x3a6,0x3fe,0x456,0x4ae,0x506,0x55e },
+       { 0x867,0x003,0x05b,0x0b3,0x10b,0x163,0x1bb,0x213,0x26b,0x2c3,0x31b,0x373,0x3cb,0x423,0x47b,0x4d3,0x52b,0x583,0x5db,0x633,0x68b,0x6e3,0x73b,0x793,0x7eb,0x843,0x89b,0x037,0x08f,0x0e7,0x13f,0x197,0x1ef,0x247,0x29f,0x2f7,0x34f,0x3a7,0x3ff,0x457,0x4af,0x507,0x55f }
+};
+
+/*-------------------------------------------------
+ *  ecc_source_byte - return data from the sector
+ *  at the given offset, masking anything
+ *  particular to a mode
+ *-------------------------------------------------
+ */
+
+static inline uint8_t ecc_source_byte(const uint8_t *sector, uint32_t offset)
+{
+       /* in mode 2 always treat these as 0 bytes */
+       return (sector[MODE_OFFSET] == 2 && offset < 4) ? 0x00 : sector[SYNC_OFFSET + SYNC_NUM_BYTES + offset];
+}
+
+/**
+ * @fn  void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t &val1, uint8_t &val2)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_compute_bytes - calculate an ECC value (P or Q)
+ *          -------------------------------------------------.
+ *
+ * @param   sector          The sector.
+ * @param   row             The row.
+ * @param   rowlen          The rowlen.
+ * @param [in,out]  val1    The first value.
+ * @param [in,out]  val2    The second value.
+ */
+
+void ecc_compute_bytes(const uint8_t *sector, const uint16_t *row, int rowlen, uint8_t *val1, uint8_t *val2)
+{
+       int component;
+       *val1 = *val2 = 0;
+       for (component = 0; component < rowlen; component++)
+       {
+               *val1 ^= ecc_source_byte(sector, row[component]);
+               *val2 ^= ecc_source_byte(sector, row[component]);
+               *val1 = ecclow[*val1];
+       }
+       *val1 = ecchigh[ecclow[*val1] ^ *val2];
+       *val2 ^= *val1;
+}
+
+/**
+ * @fn  int ecc_verify(const uint8_t *sector)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_verify - verify the P and Q ECC codes in a sector
+ *          -------------------------------------------------.
+ *
+ * @param   sector  The sector.
+ *
+ * @return  true if it succeeds, false if it fails.
+ */
+
+int ecc_verify(const uint8_t *sector)
+{
+       int byte;
+       /* first verify P bytes */
+       for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
+       {
+               uint8_t val1, val2;
+               ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &val1, &val2);
+               if (sector[ECC_P_OFFSET + byte] != val1 || sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte] != val2)
+                       return 0;
+       }
+
+       /* then verify Q bytes */
+       for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
+       {
+               uint8_t val1, val2;
+               ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &val1, &val2);
+               if (sector[ECC_Q_OFFSET + byte] != val1 || sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte] != val2)
+                       return 0;
+       }
+       return 1;
+}
+
+/**
+ * @fn  void ecc_generate(uint8_t *sector)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_generate - generate the P and Q ECC codes for a sector, overwriting any
+ *            existing codes
+ *          -------------------------------------------------.
+ *
+ * @param [in,out]  sector  If non-null, the sector.
+ */
+
+void ecc_generate(uint8_t *sector)
+{
+       int byte;
+       /* first verify P bytes */
+       for (byte = 0; byte < ECC_P_NUM_BYTES; byte++)
+               ecc_compute_bytes(sector, poffsets[byte], ECC_P_COMP, &sector[ECC_P_OFFSET + byte], &sector[ECC_P_OFFSET + ECC_P_NUM_BYTES + byte]);
+
+       /* then verify Q bytes */
+       for (byte = 0; byte < ECC_Q_NUM_BYTES; byte++)
+               ecc_compute_bytes(sector, qoffsets[byte], ECC_Q_COMP, &sector[ECC_Q_OFFSET + byte], &sector[ECC_Q_OFFSET + ECC_Q_NUM_BYTES + byte]);
+}
+
+/**
+ * @fn  void ecc_clear(uint8_t *sector)
+ *
+ * @brief   -------------------------------------------------
+ *            ecc_clear - erase the ECC P and Q cods to 0 within a sector
+ *          -------------------------------------------------.
+ *
+ * @param [in,out]  sector  If non-null, the sector.
+ */
+
+void ecc_clear(uint8_t *sector)
+{
+       memset(&sector[ECC_P_OFFSET], 0, 2 * ECC_P_NUM_BYTES);
+       memset(&sector[ECC_Q_OFFSET], 0, 2 * ECC_Q_NUM_BYTES);
+}
+
+#endif /* WANT_RAW_DATA_SECTOR */
diff --git a/deps/libchdr/src/libchdr_chd.c b/deps/libchdr/src/libchdr_chd.c
new file mode 100644 (file)
index 0000000..c5cc179
--- /dev/null
@@ -0,0 +1,2737 @@
+/***************************************************************************
+
+    chd.c
+
+    MAME Compressed Hunks of Data file format
+
+****************************************************************************
+
+    Copyright Aaron Giles
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are
+    met:
+
+        * Redistributions of source code must retain the above copyright
+          notice, this list of conditions and the following disclaimer.
+        * Redistributions in binary form must reproduce the above copyright
+          notice, this list of conditions and the following disclaimer in
+          the documentation and/or other materials provided with the
+          distribution.
+        * Neither the name 'MAME' nor the names of its contributors may be
+          used to endorse or promote products derived from this software
+          without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+    IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+    POSSIBILITY OF SUCH DAMAGE.
+
+***************************************************************************/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <libchdr/chd.h>
+#include <libchdr/cdrom.h>
+#include <libchdr/flac.h>
+#include <libchdr/huffman.h>
+
+#include "LzmaEnc.h"
+#include "LzmaDec.h"
+#include "zlib.h"
+
+#undef TRUE
+#undef FALSE
+#define TRUE 1
+#define FALSE 0
+
+#undef MAX
+#undef MIN
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+
+#define SHA1_DIGEST_SIZE 20
+
+/***************************************************************************
+    DEBUGGING
+***************************************************************************/
+
+#define PRINTF_MAX_HUNK                                (0)
+
+/***************************************************************************
+    CONSTANTS
+***************************************************************************/
+
+#define MAP_STACK_ENTRIES                      512                     /* max number of entries to use on the stack */
+#define MAP_ENTRY_SIZE                         16                      /* V3 and later */
+#define OLD_MAP_ENTRY_SIZE                     8                       /* V1-V2 */
+#define METADATA_HEADER_SIZE           16                      /* metadata header size */
+
+#define MAP_ENTRY_FLAG_TYPE_MASK       0x0f            /* what type of hunk */
+#define MAP_ENTRY_FLAG_NO_CRC          0x10            /* no CRC is present */
+
+#define CHD_V1_SECTOR_SIZE                     512                     /* size of a "sector" in the V1 header */
+
+#define COOKIE_VALUE                           0xbaadf00d
+#define MAX_ZLIB_ALLOCS                                64
+
+#define END_OF_LIST_COOKIE                     "EndOfListCookie"
+
+#define NO_MATCH                                       (~0)
+
+#ifdef WANT_RAW_DATA_SECTOR
+static const uint8_t s_cd_sync_header[12] = { 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00 };
+#endif
+
+/* V3-V4 entry types */
+enum
+{
+       V34_MAP_ENTRY_TYPE_INVALID = 0,             /* invalid type */
+       V34_MAP_ENTRY_TYPE_COMPRESSED = 1,          /* standard compression */
+       V34_MAP_ENTRY_TYPE_UNCOMPRESSED = 2,        /* uncompressed data */
+       V34_MAP_ENTRY_TYPE_MINI = 3,                /* mini: use offset as raw data */
+       V34_MAP_ENTRY_TYPE_SELF_HUNK = 4,           /* same as another hunk in this file */
+       V34_MAP_ENTRY_TYPE_PARENT_HUNK = 5,         /* same as a hunk in the parent file */
+       V34_MAP_ENTRY_TYPE_2ND_COMPRESSED = 6       /* compressed with secondary algorithm (usually FLAC CDDA) */
+};
+
+/* V5 compression types */
+enum
+{
+       /* codec #0
+        * these types are live when running */
+       COMPRESSION_TYPE_0 = 0,
+       /* codec #1 */
+       COMPRESSION_TYPE_1 = 1,
+       /* codec #2 */
+       COMPRESSION_TYPE_2 = 2,
+       /* codec #3 */
+       COMPRESSION_TYPE_3 = 3,
+       /* no compression; implicit length = hunkbytes */
+       COMPRESSION_NONE = 4,
+       /* same as another block in this chd */
+       COMPRESSION_SELF = 5,
+       /* same as a hunk's worth of units in the parent chd */
+       COMPRESSION_PARENT = 6,
+
+       /* start of small RLE run (4-bit length)
+        * these additional pseudo-types are used for compressed encodings: */
+       COMPRESSION_RLE_SMALL,
+       /* start of large RLE run (8-bit length) */
+       COMPRESSION_RLE_LARGE,
+       /* same as the last COMPRESSION_SELF block */
+       COMPRESSION_SELF_0,
+       /* same as the last COMPRESSION_SELF block + 1 */
+       COMPRESSION_SELF_1,
+       /* same block in the parent */
+       COMPRESSION_PARENT_SELF,
+       /* same as the last COMPRESSION_PARENT block */
+       COMPRESSION_PARENT_0,
+       /* same as the last COMPRESSION_PARENT block + 1 */
+       COMPRESSION_PARENT_1
+};
+
+/***************************************************************************
+    MACROS
+***************************************************************************/
+
+#define EARLY_EXIT(x)                          do { (void)(x); goto cleanup; } while (0)
+
+/***************************************************************************
+    TYPE DEFINITIONS
+***************************************************************************/
+
+/* interface to a codec */
+typedef struct _codec_interface codec_interface;
+struct _codec_interface
+{
+       UINT32          compression;                                                            /* type of compression */
+       const char *compname;                                                                   /* name of the algorithm */
+       UINT8           lossy;                                                                          /* is this a lossy algorithm? */
+       chd_error       (*init)(void *codec, UINT32 hunkbytes);         /* codec initialize */
+       void            (*free)(void *codec);                                           /* codec free */
+       chd_error       (*decompress)(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen); /* decompress data */
+       chd_error       (*config)(void *codec, int param, void *config); /* configure */
+};
+
+/* a single map entry */
+typedef struct _map_entry map_entry;
+struct _map_entry
+{
+       UINT64                                  offset;                 /* offset within the file of the data */
+       UINT32                                  crc;                    /* 32-bit CRC of the data */
+       UINT32                                  length;                 /* length of the data */
+       UINT8                                   flags;                  /* misc flags */
+};
+
+/* a single metadata entry */
+typedef struct _metadata_entry metadata_entry;
+struct _metadata_entry
+{
+       UINT64                                  offset;                 /* offset within the file of the header */
+       UINT64                                  next;                   /* offset within the file of the next header */
+       UINT64                                  prev;                   /* offset within the file of the previous header */
+       UINT32                                  length;                 /* length of the metadata */
+       UINT32                                  metatag;                /* metadata tag */
+       UINT8                                   flags;                  /* flag bits */
+};
+
+/* codec-private data for the ZLIB codec */
+
+typedef struct _zlib_allocator zlib_allocator;
+struct _zlib_allocator
+{
+       UINT32 *                                allocptr[MAX_ZLIB_ALLOCS];
+       UINT32 *                                allocptr2[MAX_ZLIB_ALLOCS];
+};
+
+typedef struct _zlib_codec_data zlib_codec_data;
+struct _zlib_codec_data
+{
+       z_stream                                inflater;
+       zlib_allocator                  allocator;
+};
+
+/* codec-private data for the LZMA codec */
+#define MAX_LZMA_ALLOCS 64
+
+typedef struct _lzma_allocator lzma_allocator;
+struct _lzma_allocator
+{
+       void *(*Alloc)(void *p, size_t size);
+       void (*Free)(void *p, void *address); /* address can be 0 */
+       void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
+       uint32_t*       allocptr[MAX_LZMA_ALLOCS];
+       uint32_t*       allocptr2[MAX_LZMA_ALLOCS];
+};
+
+typedef struct _lzma_codec_data lzma_codec_data;
+struct _lzma_codec_data
+{
+       CLzmaDec                decoder;
+       lzma_allocator  allocator;
+};
+
+/* codec-private data for the CDZL codec */
+typedef struct _cdzl_codec_data cdzl_codec_data;
+struct _cdzl_codec_data {
+       /* internal state */
+       zlib_codec_data         base_decompressor;
+#ifdef WANT_SUBCODE
+       zlib_codec_data         subcode_decompressor;
+#endif
+       uint8_t*                        buffer;
+};
+
+/* codec-private data for the CDLZ codec */
+typedef struct _cdlz_codec_data cdlz_codec_data;
+struct _cdlz_codec_data {
+       /* internal state */
+       lzma_codec_data         base_decompressor;
+#ifdef WANT_SUBCODE
+       zlib_codec_data         subcode_decompressor;
+#endif
+       uint8_t*                        buffer;
+};
+
+/* codec-private data for the CDFL codec */
+typedef struct _cdfl_codec_data cdfl_codec_data;
+struct _cdfl_codec_data {
+       /* internal state */
+       int             swap_endian;
+       flac_decoder    decoder;
+#ifdef WANT_SUBCODE
+       zlib_codec_data         subcode_decompressor;
+#endif
+       uint8_t*        buffer;
+};
+
+/* internal representation of an open CHD file */
+struct _chd_file
+{
+       UINT32                                  cookie;                 /* cookie, should equal COOKIE_VALUE */
+
+       core_file *                             file;                   /* handle to the open core file */
+       UINT8                                   owns_file;              /* flag indicating if this file should be closed on chd_close() */
+       chd_header                              header;                 /* header, extracted from file */
+
+       chd_file *                              parent;                 /* pointer to parent file, or NULL */
+
+       map_entry *                             map;                    /* array of map entries */
+
+#ifdef NEED_CACHE_HUNK
+       UINT8 *                                 cache;                  /* hunk cache pointer */
+       UINT32                                  cachehunk;              /* index of currently cached hunk */
+
+       UINT8 *                                 compare;                /* hunk compare pointer */
+       UINT32                                  comparehunk;    /* index of current compare data */
+#endif
+
+       UINT8 *                                 compressed;             /* pointer to buffer for compressed data */
+       const codec_interface * codecintf[4];   /* interface to the codec */
+
+       zlib_codec_data                 zlib_codec_data;                /* zlib codec data */
+       cdzl_codec_data                 cdzl_codec_data;                /* cdzl codec data */
+       cdlz_codec_data                 cdlz_codec_data;                /* cdlz codec data */
+       cdfl_codec_data                 cdfl_codec_data;                /* cdfl codec data */
+
+#ifdef NEED_CACHE_HUNK
+       UINT32                                  maxhunk;                /* maximum hunk accessed */
+#endif
+
+       UINT8 *                                 file_cache;             /* cache of underlying file */
+};
+
+
+/***************************************************************************
+    GLOBAL VARIABLES
+***************************************************************************/
+
+static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
+static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
+
+/***************************************************************************
+    PROTOTYPES
+***************************************************************************/
+
+/* internal header operations */
+static chd_error header_validate(const chd_header *header);
+static chd_error header_read(chd_file *chd, chd_header *header);
+
+/* internal hunk read/write */
+#ifdef NEED_CACHE_HUNK
+static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
+#endif
+static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest);
+
+/* internal map access */
+static chd_error map_read(chd_file *chd);
+
+/* metadata management */
+static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
+
+/* zlib compression codec */
+static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes);
+static void zlib_codec_free(void *codec);
+static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);
+static void zlib_fast_free(voidpf opaque, voidpf address);
+static void zlib_allocator_free(voidpf opaque);
+
+/* lzma compression codec */
+static chd_error lzma_codec_init(void *codec, uint32_t hunkbytes);
+static void lzma_codec_free(void *codec);
+static chd_error lzma_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+/* cdzl compression codec */
+static chd_error cdzl_codec_init(void* codec, uint32_t hunkbytes);
+static void cdzl_codec_free(void* codec);
+static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+/* cdlz compression codec */
+static chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes);
+static void cdlz_codec_free(void* codec);
+static chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+/* cdfl compression codec */
+static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);
+static void cdfl_codec_free(void* codec);
+static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
+
+/***************************************************************************
+ *  LZMA ALLOCATOR HELPER
+ ***************************************************************************
+ */
+
+static void *lzma_fast_alloc(void *p, size_t size);
+static void lzma_fast_free(void *p, void *address);
+
+/*-------------------------------------------------
+ *  lzma_allocator_init
+ *-------------------------------------------------
+ */
+
+static void lzma_allocator_init(void* p)
+{
+       lzma_allocator *codec = (lzma_allocator *)(p);
+
+       /* reset pointer list */
+       memset(codec->allocptr, 0, sizeof(codec->allocptr));
+       memset(codec->allocptr2, 0, sizeof(codec->allocptr2));
+       codec->Alloc = lzma_fast_alloc;
+       codec->Free = lzma_fast_free;
+}
+
+/*-------------------------------------------------
+ *  lzma_allocator_free
+ *-------------------------------------------------
+ */
+
+static void lzma_allocator_free(void* p )
+{
+       int i;
+       lzma_allocator *codec = (lzma_allocator *)(p);
+
+       /* free our memory */
+       for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++)
+       {
+               if (codec->allocptr[i] != NULL)
+                       free(codec->allocptr[i]);
+       }
+}
+
+/*-------------------------------------------------
+ *  lzma_fast_alloc - fast malloc for lzma, which
+ *  allocates and frees memory frequently
+ *-------------------------------------------------
+ */
+
+/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
+#define LZMA_MIN_ALIGNMENT_BITS 512
+#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)
+
+static void *lzma_fast_alloc(void *p, size_t size)
+{
+       int scan;
+       uint32_t *addr        = NULL;
+       lzma_allocator *codec = (lzma_allocator *)(p);
+       uintptr_t vaddr = 0;
+
+       /* compute the size, rounding to the nearest 1k */
+       size = (size + 0x3ff) & ~0x3ff;
+
+       /* reuse a hunk if we can */
+       for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
+       {
+               uint32_t *ptr = codec->allocptr[scan];
+               if (ptr != NULL && size == *ptr)
+               {
+                       /* set the low bit of the size so we don't match next time */
+                       *ptr |= 1;
+
+                       /* return aligned address of the block */
+                       return codec->allocptr2[scan];
+               }
+       }
+
+       /* alloc a new one and put it into the list */
+       addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
+       if (addr==NULL)
+               return NULL;
+       for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
+       {
+               if (codec->allocptr[scan] == NULL)
+               {
+                       /* store block address */
+                       codec->allocptr[scan] = addr;
+
+                       /* compute aligned address, store it */
+                       vaddr = (uintptr_t)addr;
+                       vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));
+                       codec->allocptr2[scan] = (uint32_t*)vaddr;
+                       break;
+               }
+       }
+
+       /* set the low bit of the size so we don't match next time */
+       *addr = size | 1;
+
+       /* return aligned address */
+       return (void*)vaddr;
+}
+
+/*-------------------------------------------------
+ *  lzma_fast_free - fast free for lzma, which
+ *  allocates and frees memory frequently
+ *-------------------------------------------------
+ */
+
+static void lzma_fast_free(void *p, void *address)
+{
+       int scan;
+       uint32_t *ptr = NULL;
+       lzma_allocator *codec = NULL;
+
+       if (address == NULL)
+               return;
+
+       codec = (lzma_allocator *)(p);
+
+       /* find the hunk */
+       ptr = (uint32_t *)address;
+       for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
+       {
+               if (ptr == codec->allocptr2[scan])
+               {
+                       /* clear the low bit of the size to allow matches */
+                       *codec->allocptr[scan] &= ~1;
+                       return;
+               }
+       }
+}
+
+/***************************************************************************
+ *  LZMA DECOMPRESSOR
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ *  lzma_codec_init - constructor
+ *-------------------------------------------------
+ */
+
+static chd_error lzma_codec_init(void* codec, uint32_t hunkbytes)
+{
+       CLzmaEncHandle enc;
+       CLzmaEncProps encoder_props;
+       Byte decoder_props[LZMA_PROPS_SIZE];
+       SizeT props_size;
+       lzma_allocator* alloc;
+       lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
+
+       /* construct the decoder */
+       LzmaDec_Construct(&lzma_codec->decoder);
+
+       /* FIXME: this code is written in a way that makes it impossible to safely upgrade the LZMA SDK
+        * This code assumes that the current version of the encoder imposes the same requirements on the
+        * decoder as the encoder used to produce the file.  This is not necessarily true.  The format
+        * needs to be changed so the encoder properties are written to the file.
+
+        * configure the properties like the compressor did */
+       LzmaEncProps_Init(&encoder_props);
+       encoder_props.level = 9;
+       encoder_props.reduceSize = hunkbytes;
+       LzmaEncProps_Normalize(&encoder_props);
+
+       /* convert to decoder properties */
+       alloc = &lzma_codec->allocator;
+       lzma_allocator_init(alloc);
+       enc = LzmaEnc_Create((ISzAlloc*)alloc);
+       if (!enc)
+               return CHDERR_DECOMPRESSION_ERROR;
+       if (LzmaEnc_SetProps(enc, &encoder_props) != SZ_OK)
+       {
+               LzmaEnc_Destroy(enc, (ISzAlloc*)&alloc, (ISzAlloc*)&alloc);
+               return CHDERR_DECOMPRESSION_ERROR;
+       }
+       props_size = sizeof(decoder_props);
+       if (LzmaEnc_WriteProperties(enc, decoder_props, &props_size) != SZ_OK)
+       {
+               LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
+               return CHDERR_DECOMPRESSION_ERROR;
+       }
+       LzmaEnc_Destroy(enc, (ISzAlloc*)alloc, (ISzAlloc*)alloc);
+
+       /* do memory allocations */
+       if (LzmaDec_Allocate(&lzma_codec->decoder, decoder_props, LZMA_PROPS_SIZE, (ISzAlloc*)alloc) != SZ_OK)
+               return CHDERR_DECOMPRESSION_ERROR;
+
+       /* Okay */
+       return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+ *  lzma_codec_free
+ *-------------------------------------------------
+ */
+
+static void lzma_codec_free(void* codec)
+{
+       lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
+
+       /* free memory */
+       LzmaDec_Free(&lzma_codec->decoder, (ISzAlloc*)&lzma_codec->allocator);
+       lzma_allocator_free(&lzma_codec->allocator);
+}
+
+/*-------------------------------------------------
+ *  decompress - decompress data using the LZMA
+ *  codec
+ *-------------------------------------------------
+ */
+
+static chd_error lzma_codec_decompress(void* codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+       ELzmaStatus status;
+       SRes res;
+       SizeT consumedlen, decodedlen;
+       /* initialize */
+       lzma_codec_data* lzma_codec = (lzma_codec_data*) codec;
+       LzmaDec_Init(&lzma_codec->decoder);
+
+       /* decode */
+       consumedlen = complen;
+       decodedlen = destlen;
+       res = LzmaDec_DecodeToBuf(&lzma_codec->decoder, dest, &decodedlen, src, &consumedlen, LZMA_FINISH_END, &status);
+       if ((res != SZ_OK && res != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) || consumedlen != complen || decodedlen != destlen)
+               return CHDERR_DECOMPRESSION_ERROR;
+       return CHDERR_NONE;
+}
+
+/* cdlz */
+static chd_error cdlz_codec_init(void* codec, uint32_t hunkbytes)
+{
+       chd_error ret;
+       cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
+
+       /* allocate buffer */
+       cdlz->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
+       if (cdlz->buffer == NULL)
+               return CHDERR_OUT_OF_MEMORY;
+
+       /* make sure the CHD's hunk size is an even multiple of the frame size */
+       ret = lzma_codec_init(&cdlz->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+
+#ifdef WANT_SUBCODE
+       ret = zlib_codec_init(&cdlz->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+#endif
+
+       if (hunkbytes % CD_FRAME_SIZE != 0)
+               return CHDERR_CODEC_ERROR;
+
+       return CHDERR_NONE;
+}
+
+static void cdlz_codec_free(void* codec)
+{
+       cdlz_codec_data* cdlz = (cdlz_codec_data*) codec;
+       free(cdlz->buffer);
+       lzma_codec_free(&cdlz->base_decompressor);
+#ifdef WANT_SUBCODE
+       zlib_codec_free(&cdlz->subcode_decompressor);
+#endif
+}
+
+static chd_error cdlz_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+       uint32_t framenum;
+       cdlz_codec_data* cdlz = (cdlz_codec_data*)codec;
+
+       /* determine header bytes */
+       uint32_t frames = destlen / CD_FRAME_SIZE;
+       uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
+       uint32_t ecc_bytes = (frames + 7) / 8;
+       uint32_t header_bytes = ecc_bytes + complen_bytes;
+
+       /* extract compressed length of base */
+       uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
+       if (complen_bytes > 2)
+               complen_base = (complen_base << 8) | src[ecc_bytes + 2];
+
+       /* reset and decode */
+       lzma_codec_decompress(&cdlz->base_decompressor, &src[header_bytes], complen_base, &cdlz->buffer[0], frames * CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+       zlib_codec_decompress(&cdlz->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdlz->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
+#endif
+
+       /* reassemble the data */
+       for (framenum = 0; framenum < frames; framenum++)
+       {
+               uint8_t *sector;
+
+               memcpy(&dest[framenum * CD_FRAME_SIZE], &cdlz->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+               memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdlz->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
+#endif
+
+#ifdef WANT_RAW_DATA_SECTOR
+               /* reconstitute the ECC data and sync header */
+               sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
+               if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
+               {
+                       memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
+                       ecc_generate(sector);
+               }
+#endif
+       }
+       return CHDERR_NONE;
+}
+
+/* cdzl */
+
+static chd_error cdzl_codec_init(void *codec, uint32_t hunkbytes)
+{
+       chd_error ret;
+       cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
+
+       /* make sure the CHD's hunk size is an even multiple of the frame size */
+       if (hunkbytes % CD_FRAME_SIZE != 0)
+               return CHDERR_CODEC_ERROR;
+
+       cdzl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
+       if (cdzl->buffer == NULL)
+               return CHDERR_OUT_OF_MEMORY;
+
+       ret = zlib_codec_init(&cdzl->base_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+
+#ifdef WANT_SUBCODE
+       ret = zlib_codec_init(&cdzl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SUBCODE_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+#endif
+
+       return CHDERR_NONE;
+}
+
+static void cdzl_codec_free(void *codec)
+{
+       cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
+       zlib_codec_free(&cdzl->base_decompressor);
+#ifdef WANT_SUBCODE
+       zlib_codec_free(&cdzl->subcode_decompressor);
+#endif
+       free(cdzl->buffer);
+}
+
+static chd_error cdzl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+       uint32_t framenum;
+       cdzl_codec_data* cdzl = (cdzl_codec_data*)codec;
+
+       /* determine header bytes */
+       uint32_t frames = destlen / CD_FRAME_SIZE;
+       uint32_t complen_bytes = (destlen < 65536) ? 2 : 3;
+       uint32_t ecc_bytes = (frames + 7) / 8;
+       uint32_t header_bytes = ecc_bytes + complen_bytes;
+
+       /* extract compressed length of base */
+       uint32_t complen_base = (src[ecc_bytes + 0] << 8) | src[ecc_bytes + 1];
+       if (complen_bytes > 2)
+               complen_base = (complen_base << 8) | src[ecc_bytes + 2];
+
+       /* reset and decode */
+       zlib_codec_decompress(&cdzl->base_decompressor, &src[header_bytes], complen_base, &cdzl->buffer[0], frames * CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+       zlib_codec_decompress(&cdzl->subcode_decompressor, &src[header_bytes + complen_base], complen - complen_base - header_bytes, &cdzl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
+#endif
+
+       /* reassemble the data */
+       for (framenum = 0; framenum < frames; framenum++)
+       {
+               uint8_t *sector;
+
+               memcpy(&dest[framenum * CD_FRAME_SIZE], &cdzl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+               memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdzl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
+#endif
+
+#ifdef WANT_RAW_DATA_SECTOR
+               /* reconstitute the ECC data and sync header */
+               sector = (uint8_t *)&dest[framenum * CD_FRAME_SIZE];
+               if ((src[framenum / 8] & (1 << (framenum % 8))) != 0)
+               {
+                       memcpy(sector, s_cd_sync_header, sizeof(s_cd_sync_header));
+                       ecc_generate(sector);
+               }
+#endif
+       }
+       return CHDERR_NONE;
+}
+
+/***************************************************************************
+ *  CD FLAC DECOMPRESSOR
+ ***************************************************************************
+ */
+
+/*------------------------------------------------------
+ *  cdfl_codec_blocksize - return the optimal block size
+ *------------------------------------------------------
+ */
+
+static uint32_t cdfl_codec_blocksize(uint32_t bytes)
+{
+       /* determine FLAC block size, which must be 16-65535
+        * clamp to 2k since that's supposed to be the sweet spot */
+       uint32_t hunkbytes = bytes / 4;
+       while (hunkbytes > 2048)
+               hunkbytes /= 2;
+       return hunkbytes;
+}
+
+static chd_error cdfl_codec_init(void *codec, uint32_t hunkbytes)
+{
+#ifdef WANT_SUBCODE
+       chd_error ret;
+#endif
+       uint16_t native_endian = 0;
+       cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
+
+       /* make sure the CHD's hunk size is an even multiple of the frame size */
+       if (hunkbytes % CD_FRAME_SIZE != 0)
+               return CHDERR_CODEC_ERROR;
+
+       cdfl->buffer = (uint8_t*)malloc(sizeof(uint8_t) * hunkbytes);
+       if (cdfl->buffer == NULL)
+               return CHDERR_OUT_OF_MEMORY;
+
+       /* determine whether we want native or swapped samples */
+       *(uint8_t *)(&native_endian) = 1;
+       cdfl->swap_endian = (native_endian & 1);
+
+#ifdef WANT_SUBCODE
+       /* init zlib inflater */
+       ret = zlib_codec_init(&cdfl->subcode_decompressor, (hunkbytes / CD_FRAME_SIZE) * CD_MAX_SECTOR_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+#endif
+
+       /* flac decoder init */
+       if (flac_decoder_init(&cdfl->decoder))
+               return CHDERR_OUT_OF_MEMORY;
+
+       return CHDERR_NONE;
+}
+
+static void cdfl_codec_free(void *codec)
+{
+       cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
+       flac_decoder_free(&cdfl->decoder);
+#ifdef WANT_SUBCODE
+       zlib_codec_free(&cdfl->subcode_decompressor);
+#endif
+       if (cdfl->buffer)
+               free(cdfl->buffer);
+}
+
+static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+       uint32_t framenum;
+       uint8_t *buffer;
+#ifdef WANT_SUBCODE
+       uint32_t offset;
+       chd_error ret;
+#endif
+       cdfl_codec_data *cdfl = (cdfl_codec_data*)codec;
+
+       /* reset and decode */
+       uint32_t frames = destlen / CD_FRAME_SIZE;
+
+       if (!flac_decoder_reset(&cdfl->decoder, 44100, 2, cdfl_codec_blocksize(frames * CD_MAX_SECTOR_DATA), src, complen))
+               return CHDERR_DECOMPRESSION_ERROR;
+       buffer = &cdfl->buffer[0];
+       if (!flac_decoder_decode_interleaved(&cdfl->decoder, (int16_t *)(buffer), frames * CD_MAX_SECTOR_DATA/4, cdfl->swap_endian))
+               return CHDERR_DECOMPRESSION_ERROR;
+
+#ifdef WANT_SUBCODE
+       /* inflate the subcode data */
+       offset = flac_decoder_finish(&cdfl->decoder);
+       ret = zlib_codec_decompress(&cdfl->subcode_decompressor, src + offset, complen - offset, &cdfl->buffer[frames * CD_MAX_SECTOR_DATA], frames * CD_MAX_SUBCODE_DATA);
+       if (ret != CHDERR_NONE)
+               return ret;
+#else
+       flac_decoder_finish(&cdfl->decoder);
+#endif
+
+       /* reassemble the data */
+       for (framenum = 0; framenum < frames; framenum++)
+       {
+               memcpy(&dest[framenum * CD_FRAME_SIZE], &cdfl->buffer[framenum * CD_MAX_SECTOR_DATA], CD_MAX_SECTOR_DATA);
+#ifdef WANT_SUBCODE
+               memcpy(&dest[framenum * CD_FRAME_SIZE + CD_MAX_SECTOR_DATA], &cdfl->buffer[frames * CD_MAX_SECTOR_DATA + framenum * CD_MAX_SUBCODE_DATA], CD_MAX_SUBCODE_DATA);
+#endif
+       }
+
+       return CHDERR_NONE;
+}
+/***************************************************************************
+    CODEC INTERFACES
+***************************************************************************/
+
+static const codec_interface codec_interfaces[] =
+{
+       /* "none" or no compression */
+       {
+               CHDCOMPRESSION_NONE,
+               "none",
+               FALSE,
+               NULL,
+               NULL,
+               NULL,
+               NULL
+       },
+
+       /* standard zlib compression */
+       {
+               CHDCOMPRESSION_ZLIB,
+               "zlib",
+               FALSE,
+               zlib_codec_init,
+               zlib_codec_free,
+               zlib_codec_decompress,
+               NULL
+       },
+
+       /* zlib+ compression */
+       {
+               CHDCOMPRESSION_ZLIB_PLUS,
+               "zlib+",
+               FALSE,
+               zlib_codec_init,
+               zlib_codec_free,
+               zlib_codec_decompress,
+               NULL
+       },
+
+       /* V5 zlib compression */
+       {
+               CHD_CODEC_ZLIB,
+               "zlib (Deflate)",
+               FALSE,
+               zlib_codec_init,
+               zlib_codec_free,
+               zlib_codec_decompress,
+               NULL
+       },
+
+       /* V5 CD zlib compression */
+       {
+               CHD_CODEC_CD_ZLIB,
+               "cdzl (CD Deflate)",
+               FALSE,
+               cdzl_codec_init,
+               cdzl_codec_free,
+               cdzl_codec_decompress,
+               NULL
+       },
+
+       /* V5 CD lzma compression */
+       {
+               CHD_CODEC_CD_LZMA,
+               "cdlz (CD LZMA)",
+               FALSE,
+               cdlz_codec_init,
+               cdlz_codec_free,
+               cdlz_codec_decompress,
+               NULL
+       },
+
+       /* V5 CD flac compression */
+       {
+               CHD_CODEC_CD_FLAC,
+               "cdfl (CD FLAC)",
+               FALSE,
+               cdfl_codec_init,
+               cdfl_codec_free,
+               cdfl_codec_decompress,
+               NULL
+       },
+};
+
+/***************************************************************************
+    INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+    get_bigendian_uint64 - fetch a UINT64 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline UINT64 get_bigendian_uint64(const UINT8 *base)
+{
+       return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) |
+                       ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7];
+}
+
+/*-------------------------------------------------
+    put_bigendian_uint64 - write a UINT64 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline void put_bigendian_uint64(UINT8 *base, UINT64 value)
+{
+       base[0] = value >> 56;
+       base[1] = value >> 48;
+       base[2] = value >> 40;
+       base[3] = value >> 32;
+       base[4] = value >> 24;
+       base[5] = value >> 16;
+       base[6] = value >> 8;
+       base[7] = value;
+}
+
+/*-------------------------------------------------
+    get_bigendian_uint48 - fetch a UINT48 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline UINT64 get_bigendian_uint48(const UINT8 *base)
+{
+       return  ((UINT64)base[0] << 40) | ((UINT64)base[1] << 32) |
+                       ((UINT64)base[2] << 24) | ((UINT64)base[3] << 16) | ((UINT64)base[4] << 8) | (UINT64)base[5];
+}
+
+/*-------------------------------------------------
+    put_bigendian_uint48 - write a UINT48 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline void put_bigendian_uint48(UINT8 *base, UINT64 value)
+{
+       value &= 0xffffffffffff;
+       base[0] = value >> 40;
+       base[1] = value >> 32;
+       base[2] = value >> 24;
+       base[3] = value >> 16;
+       base[4] = value >> 8;
+       base[5] = value;
+}
+/*-------------------------------------------------
+    get_bigendian_uint32 - fetch a UINT32 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline UINT32 get_bigendian_uint32(const UINT8 *base)
+{
+       return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
+}
+
+/*-------------------------------------------------
+    put_bigendian_uint32 - write a UINT32 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline void put_bigendian_uint32(UINT8 *base, UINT32 value)
+{
+       base[0] = value >> 24;
+       base[1] = value >> 16;
+       base[2] = value >> 8;
+       base[3] = value;
+}
+
+/*-------------------------------------------------
+    put_bigendian_uint24 - write a UINT24 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline void put_bigendian_uint24(UINT8 *base, UINT32 value)
+{
+       value &= 0xffffff;
+       base[0] = value >> 16;
+       base[1] = value >> 8;
+       base[2] = value;
+}
+
+/*-------------------------------------------------
+    get_bigendian_uint24 - fetch a UINT24 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline UINT32 get_bigendian_uint24(const UINT8 *base)
+{
+       return (base[0] << 16) | (base[1] << 8) | base[2];
+}
+
+/*-------------------------------------------------
+    get_bigendian_uint16 - fetch a UINT16 from
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline UINT16 get_bigendian_uint16(const UINT8 *base)
+{
+       return (base[0] << 8) | base[1];
+}
+
+/*-------------------------------------------------
+    put_bigendian_uint16 - write a UINT16 to
+    the data stream in bigendian order
+-------------------------------------------------*/
+
+static inline void put_bigendian_uint16(UINT8 *base, UINT16 value)
+{
+       base[0] = value >> 8;
+       base[1] = value;
+}
+
+/*-------------------------------------------------
+    map_extract - extract a single map
+    entry from the datastream
+-------------------------------------------------*/
+
+static inline void map_extract(const UINT8 *base, map_entry *entry)
+{
+       entry->offset = get_bigendian_uint64(&base[0]);
+       entry->crc = get_bigendian_uint32(&base[8]);
+       entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16);
+       entry->flags = base[15];
+}
+
+/*-------------------------------------------------
+    map_assemble - write a single map
+    entry to the datastream
+-------------------------------------------------*/
+
+static inline void map_assemble(UINT8 *base, map_entry *entry)
+{
+       put_bigendian_uint64(&base[0], entry->offset);
+       put_bigendian_uint32(&base[8], entry->crc);
+       put_bigendian_uint16(&base[12], entry->length);
+       base[14] = entry->length >> 16;
+       base[15] = entry->flags;
+}
+
+/*-------------------------------------------------
+    map_size_v5 - calculate CHDv5 map size
+-------------------------------------------------*/
+static inline int map_size_v5(chd_header* header)
+{
+       return header->hunkcount * header->mapentrybytes;
+}
+
+/*-------------------------------------------------
+    crc16 - calculate CRC16 (from hashing.cpp)
+-------------------------------------------------*/
+uint16_t crc16(const void *data, uint32_t length)
+{
+       uint16_t crc = 0xffff;
+
+       static const uint16_t s_table[256] =
+       {
+               0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+               0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+               0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+               0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+               0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+               0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+               0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+               0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+               0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+               0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+               0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+               0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+               0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+               0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+               0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+               0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+               0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+               0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+               0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+               0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+               0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+               0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+               0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+               0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+               0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+               0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+               0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+               0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+               0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+               0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+               0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+               0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+       };
+
+       const uint8_t *src = (uint8_t*)data;
+
+       /* fetch the current value into a local and rip through the source data */
+       while (length-- != 0)
+               crc = (crc << 8) ^ s_table[(crc >> 8) ^ *src++];
+       return crc;
+}
+
+/*-------------------------------------------------
+       compressed - test if CHD file is compressed
++-------------------------------------------------*/
+static inline int chd_compressed(chd_header* header) {
+       return header->compression[0] != CHD_CODEC_NONE;
+}
+
+/*-------------------------------------------------
+       decompress_v5_map - decompress the v5 map
+-------------------------------------------------*/
+
+static chd_error decompress_v5_map(chd_file* chd, chd_header* header)
+{
+       int result = 0;
+       int hunknum;
+       int repcount = 0;
+       uint8_t lastcomp = 0;
+       uint32_t last_self = 0;
+       uint64_t last_parent = 0;
+       struct bitstream* bitbuf;
+       uint32_t mapbytes;
+       uint64_t firstoffs;
+       uint16_t mapcrc;
+       uint8_t lengthbits;
+       uint8_t selfbits;
+       uint8_t parentbits;
+       uint8_t *compressed_ptr;
+       uint8_t rawbuf[16];
+       struct huffman_decoder* decoder;
+       enum huffman_error err;
+       uint64_t curoffset;     
+       int rawmapsize = map_size_v5(header);
+
+       if (!chd_compressed(header))
+       {
+               header->rawmap = (uint8_t*)malloc(rawmapsize);
+               core_fseek(chd->file, header->mapoffset, SEEK_SET);
+               result = core_fread(chd->file, header->rawmap, rawmapsize);
+               return CHDERR_NONE;
+       }
+
+       /* read the reader */
+       core_fseek(chd->file, header->mapoffset, SEEK_SET);
+       result = core_fread(chd->file, rawbuf, sizeof(rawbuf));
+       mapbytes = get_bigendian_uint32(&rawbuf[0]);
+       firstoffs = get_bigendian_uint48(&rawbuf[4]);
+       mapcrc = get_bigendian_uint16(&rawbuf[10]);
+       lengthbits = rawbuf[12];
+       selfbits = rawbuf[13];
+       parentbits = rawbuf[14];
+
+       /* now read the map */
+       compressed_ptr = (uint8_t*)malloc(sizeof(uint8_t) * mapbytes);
+       core_fseek(chd->file, header->mapoffset + 16, SEEK_SET);
+       result = core_fread(chd->file, compressed_ptr, mapbytes);
+       bitbuf = create_bitstream(compressed_ptr, sizeof(uint8_t) * mapbytes);
+       header->rawmap = (uint8_t*)malloc(rawmapsize);
+
+       /* first decode the compression types */
+       decoder = create_huffman_decoder(16, 8);
+       if (decoder == NULL)
+       {
+               free(compressed_ptr);
+               free(bitbuf);
+               return CHDERR_OUT_OF_MEMORY;
+       }
+
+       err = huffman_import_tree_rle(decoder, bitbuf);
+       if (err != HUFFERR_NONE)
+       {
+               free(compressed_ptr);
+               free(bitbuf);
+               delete_huffman_decoder(decoder);
+               return CHDERR_DECOMPRESSION_ERROR;
+       }
+
+       for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
+       {
+               uint8_t *rawmap = header->rawmap + (hunknum * 12);
+               if (repcount > 0)
+                       rawmap[0] = lastcomp, repcount--;
+               else
+               {
+                       uint8_t val = huffman_decode_one(decoder, bitbuf);
+                       if (val == COMPRESSION_RLE_SMALL)
+                               rawmap[0] = lastcomp, repcount = 2 + huffman_decode_one(decoder, bitbuf);
+                       else if (val == COMPRESSION_RLE_LARGE)
+                               rawmap[0] = lastcomp, repcount = 2 + 16 + (huffman_decode_one(decoder, bitbuf) << 4), repcount += huffman_decode_one(decoder, bitbuf);
+                       else
+                               rawmap[0] = lastcomp = val;
+               }
+       }
+
+       /* then iterate through the hunks and extract the needed data */
+       curoffset = firstoffs;
+       for (hunknum = 0; hunknum < header->hunkcount; hunknum++)
+       {
+               uint8_t *rawmap = header->rawmap + (hunknum * 12);
+               uint64_t offset = curoffset;
+               uint32_t length = 0;
+               uint16_t crc = 0;
+               switch (rawmap[0])
+               {
+                       /* base types */
+                       case COMPRESSION_TYPE_0:
+                       case COMPRESSION_TYPE_1:
+                       case COMPRESSION_TYPE_2:
+                       case COMPRESSION_TYPE_3:
+                               curoffset += length = bitstream_read(bitbuf, lengthbits);
+                               crc = bitstream_read(bitbuf, 16);
+                               break;
+
+                       case COMPRESSION_NONE:
+                               curoffset += length = header->hunkbytes;
+                               crc = bitstream_read(bitbuf, 16);
+                               break;
+
+                       case COMPRESSION_SELF:
+                               last_self = offset = bitstream_read(bitbuf, selfbits);
+                               break;
+
+                       case COMPRESSION_PARENT:
+                               offset = bitstream_read(bitbuf, parentbits);
+                               last_parent = offset;
+                               break;
+
+                       /* pseudo-types; convert into base types */
+                       case COMPRESSION_SELF_1:
+                               last_self++;
+                       case COMPRESSION_SELF_0:
+                               rawmap[0] = COMPRESSION_SELF;
+                               offset = last_self;
+                               break;
+
+                       case COMPRESSION_PARENT_SELF:
+                               rawmap[0] = COMPRESSION_PARENT;
+                               last_parent = offset = ( ((uint64_t)hunknum) * ((uint64_t)header->hunkbytes) ) / header->unitbytes;
+                               break;
+
+                       case COMPRESSION_PARENT_1:
+                               last_parent += header->hunkbytes / header->unitbytes;
+                       case COMPRESSION_PARENT_0:
+                               rawmap[0] = COMPRESSION_PARENT;
+                               offset = last_parent;
+                               break;
+               }
+               /* UINT24 length */
+               put_bigendian_uint24(&rawmap[1], length);
+
+               /* UINT48 offset */
+               put_bigendian_uint48(&rawmap[4], offset);
+
+               /* crc16 */
+               put_bigendian_uint16(&rawmap[10], crc);
+       }
+
+       /* free memory */
+       free(compressed_ptr);
+       free(bitbuf);
+       delete_huffman_decoder(decoder);
+
+       /* verify the final CRC */
+       if (crc16(&header->rawmap[0], header->hunkcount * 12) != mapcrc)
+               return CHDERR_DECOMPRESSION_ERROR;
+
+       return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+    map_extract_old - extract a single map
+    entry in old format from the datastream
+-------------------------------------------------*/
+
+static inline void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes)
+{
+       entry->offset = get_bigendian_uint64(&base[0]);
+       entry->crc = 0;
+       entry->length = entry->offset >> 44;
+       entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? V34_MAP_ENTRY_TYPE_UNCOMPRESSED : V34_MAP_ENTRY_TYPE_COMPRESSED);
+#ifdef __MWERKS__
+       entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
+#else
+       entry->offset = (entry->offset << 20) >> 20;
+#endif
+}
+
+/***************************************************************************
+    CHD FILE MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_open_file - open a CHD file for access
+-------------------------------------------------*/
+
+CHD_EXPORT chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd)
+{
+       chd_file *newchd = NULL;
+       chd_error err;
+       int intfnum;
+
+       /* verify parameters */
+       if (file == NULL)
+               EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+       /* punt if invalid parent */
+       if (parent != NULL && parent->cookie != COOKIE_VALUE)
+               EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+       /* allocate memory for the final result */
+       newchd = (chd_file *)malloc(sizeof(**chd));
+       if (newchd == NULL)
+               EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
+       memset(newchd, 0, sizeof(*newchd));
+       newchd->cookie = COOKIE_VALUE;
+       newchd->parent = parent;
+       newchd->file = file;
+
+       /* now attempt to read the header */
+       err = header_read(newchd, &newchd->header);
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+
+       /* validate the header */
+       err = header_validate(&newchd->header);
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+
+       /* make sure we don't open a read-only file writeable */
+       if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE))
+               EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);
+
+       /* also, never open an older version writeable */
+       if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION)
+               EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);
+
+       /* if we need a parent, make sure we have one */
+       if (parent == NULL)
+       {
+               /* Detect parent requirement for versions below 5 */
+               if (newchd->header.version < 5 && newchd->header.flags & CHDFLAGS_HAS_PARENT)
+                       EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
+               /* Detection for version 5 and above - if parentsha1 != 0, we have a parent */
+               else if (newchd->header.version >= 5 && memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
+                       EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
+       }
+
+       /* make sure we have a valid parent */
+       if (parent != NULL)
+       {
+               /* check MD5 if it isn't empty */
+               if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 &&
+                       memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 &&
+                       memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0)
+                       EARLY_EXIT(err = CHDERR_INVALID_PARENT);
+
+               /* check SHA1 if it isn't empty */
+               if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 &&
+                       memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 &&
+                       memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
+                       EARLY_EXIT(err = CHDERR_INVALID_PARENT);
+       }
+
+       /* now read the hunk map */
+       if (newchd->header.version < 5)
+       {
+               err = map_read(newchd);
+               if (err != CHDERR_NONE)
+                       EARLY_EXIT(err);
+       }
+       else
+       {
+               err = decompress_v5_map(newchd, &(newchd->header));
+       }
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+
+#ifdef NEED_CACHE_HUNK
+       /* allocate and init the hunk cache */
+       newchd->cache = (UINT8 *)malloc(newchd->header.hunkbytes);
+       newchd->compare = (UINT8 *)malloc(newchd->header.hunkbytes);
+       if (newchd->cache == NULL || newchd->compare == NULL)
+               EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
+       newchd->cachehunk = ~0;
+       newchd->comparehunk = ~0;
+#endif
+
+       /* allocate the temporary compressed buffer */
+       newchd->compressed = (UINT8 *)malloc(newchd->header.hunkbytes);
+       if (newchd->compressed == NULL)
+               EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
+
+       /* find the codec interface */
+       if (newchd->header.version < 5)
+       {
+               for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
+               {
+                       if (codec_interfaces[intfnum].compression == newchd->header.compression[0])
+                       {
+                               newchd->codecintf[0] = &codec_interfaces[intfnum];
+                               break;
+                       }
+               }
+
+               if (intfnum == ARRAY_LENGTH(codec_interfaces))
+                       EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
+
+               /* initialize the codec */
+               if (newchd->codecintf[0]->init != NULL)
+               {
+                       err = (*newchd->codecintf[0]->init)(&newchd->zlib_codec_data, newchd->header.hunkbytes);
+                       if (err != CHDERR_NONE)
+                               EARLY_EXIT(err);
+               }
+       }
+       else
+       {
+               int decompnum;
+               /* verify the compression types and initialize the codecs */
+               for (decompnum = 0; decompnum < ARRAY_LENGTH(newchd->header.compression); decompnum++)
+               {
+                       int i;
+                       for (i = 0 ; i < ARRAY_LENGTH(codec_interfaces) ; i++)
+                       {
+                               if (codec_interfaces[i].compression == newchd->header.compression[decompnum])
+                               {
+                                       newchd->codecintf[decompnum] = &codec_interfaces[i];
+                                       break;
+                               }
+                       }
+
+                       if (newchd->codecintf[decompnum] == NULL && newchd->header.compression[decompnum] != 0)
+                               EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
+
+                       /* initialize the codec */
+                       if (newchd->codecintf[decompnum]->init != NULL)
+                       {
+                               void* codec = NULL;
+                               switch (newchd->header.compression[decompnum])
+                               {
+                                       case CHD_CODEC_ZLIB:
+                                               codec = &newchd->zlib_codec_data;
+                                               break;
+
+                                       case CHD_CODEC_CD_ZLIB:
+                                               codec = &newchd->cdzl_codec_data;
+                                               break;
+
+                                       case CHD_CODEC_CD_LZMA:
+                                               codec = &newchd->cdlz_codec_data;
+                                               break;
+
+                                       case CHD_CODEC_CD_FLAC:
+                                               codec = &newchd->cdfl_codec_data;
+                                               break;
+                               }
+
+                               if (codec == NULL)
+                                       EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
+
+                               err = (*newchd->codecintf[decompnum]->init)(codec, newchd->header.hunkbytes);
+                               if (err != CHDERR_NONE)
+                                       EARLY_EXIT(err);
+                       }
+               }
+       }
+
+       /* all done */
+       *chd = newchd;
+       return CHDERR_NONE;
+
+cleanup:
+       if (newchd != NULL)
+               chd_close(newchd);
+       return err;
+}
+
+/*-------------------------------------------------
+    chd_precache - precache underlying file in
+    memory
+-------------------------------------------------*/
+
+CHD_EXPORT chd_error chd_precache(chd_file *chd)
+{
+#ifdef _MSC_VER
+       size_t size, count;
+#else
+       ssize_t size, count;
+#endif
+
+       if (chd->file_cache == NULL)
+       {
+               core_fseek(chd->file, 0, SEEK_END);
+               size = core_ftell(chd->file);
+               if (size <= 0)
+                       return CHDERR_INVALID_DATA;
+               chd->file_cache = malloc(size);
+               if (chd->file_cache == NULL)
+                       return CHDERR_OUT_OF_MEMORY;
+               core_fseek(chd->file, 0, SEEK_SET);
+               count = core_fread(chd->file, chd->file_cache, size);
+               if (count != size)
+               {
+                       free(chd->file_cache);
+                       chd->file_cache = NULL;
+                       return CHDERR_READ_ERROR;
+               }
+       }
+
+       return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+    chd_open - open a CHD file by
+    filename
+-------------------------------------------------*/
+
+CHD_EXPORT chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
+{
+       chd_error err;
+       core_file *file = NULL;
+
+       /* choose the proper mode */
+       switch(mode)
+       {
+               case CHD_OPEN_READ:
+                       break;
+
+               default:
+                       err = CHDERR_INVALID_PARAMETER;
+                       goto cleanup;
+       }
+
+       /* open the file */
+       file = core_fopen(filename);
+       if (file == 0)
+       {
+               err = CHDERR_FILE_NOT_FOUND;
+               goto cleanup;
+       }
+
+       /* now open the CHD */
+       err = chd_open_file(file, mode, parent, chd);
+       if (err != CHDERR_NONE)
+               goto cleanup;
+
+       /* we now own this file */
+       (*chd)->owns_file = TRUE;
+
+cleanup:
+       if ((err != CHDERR_NONE) && (file != NULL))
+               core_fclose(file);
+       return err;
+}
+
+/*-------------------------------------------------
+    chd_close - close a CHD file for access
+-------------------------------------------------*/
+
+CHD_EXPORT void chd_close(chd_file *chd)
+{
+       /* punt if NULL or invalid */
+       if (chd == NULL || chd->cookie != COOKIE_VALUE)
+               return;
+
+       /* deinit the codec */
+       if (chd->header.version < 5)
+       {
+               if (chd->codecintf[0] != NULL && chd->codecintf[0]->free != NULL)
+                       (*chd->codecintf[0]->free)(&chd->zlib_codec_data);
+       }
+       else
+       {
+               int i;
+               /* Free the codecs */
+               for (i = 0 ; i < ARRAY_LENGTH(chd->codecintf); i++)
+               {
+                       void* codec = NULL;
+
+                       if (chd->codecintf[i] == NULL)
+                               continue;
+
+                       switch (chd->codecintf[i]->compression)
+                       {
+                               case CHD_CODEC_CD_LZMA:
+                                       codec = &chd->cdlz_codec_data;
+                                       break;
+
+                               case CHD_CODEC_ZLIB:
+                                       codec = &chd->zlib_codec_data;
+                                       break;
+
+                               case CHD_CODEC_CD_ZLIB:
+                                       codec = &chd->cdzl_codec_data;
+                                       break;
+
+                               case CHD_CODEC_CD_FLAC:
+                                       codec = &chd->cdfl_codec_data;
+                                       break;
+                       }
+
+                       if (codec)
+                       {
+                               (*chd->codecintf[i]->free)(codec);
+                       }
+               }
+
+               /* Free the raw map */
+               if (chd->header.rawmap != NULL)
+                       free(chd->header.rawmap);
+       }
+
+       /* free the compressed data buffer */
+       if (chd->compressed != NULL)
+               free(chd->compressed);
+
+#ifdef NEED_CACHE_HUNK
+       /* free the hunk cache and compare data */
+       if (chd->compare != NULL)
+               free(chd->compare);
+       if (chd->cache != NULL)
+               free(chd->cache);
+#endif
+
+       /* free the hunk map */
+       if (chd->map != NULL)
+               free(chd->map);
+
+       /* close the file */
+       if (chd->owns_file && chd->file != NULL)
+               core_fclose(chd->file);
+
+#ifdef NEED_CACHE_HUNK
+       if (PRINTF_MAX_HUNK) printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
+#endif
+       if (chd->file_cache)
+               free(chd->file_cache);
+
+       if (chd->parent)
+               chd_close(chd->parent);
+
+       /* free our memory */
+       free(chd);
+}
+
+/*-------------------------------------------------
+    chd_core_file - return the associated
+    core_file
+-------------------------------------------------*/
+
+CHD_EXPORT core_file *chd_core_file(chd_file *chd)
+{
+       return chd->file;
+}
+
+/*-------------------------------------------------
+    chd_error_string - return an error string for
+    the given CHD error
+-------------------------------------------------*/
+
+CHD_EXPORT const char *chd_error_string(chd_error err)
+{
+       switch (err)
+       {
+               case CHDERR_NONE:                                               return "no error";
+               case CHDERR_NO_INTERFACE:                               return "no drive interface";
+               case CHDERR_OUT_OF_MEMORY:                              return "out of memory";
+               case CHDERR_INVALID_FILE:                               return "invalid file";
+               case CHDERR_INVALID_PARAMETER:                  return "invalid parameter";
+               case CHDERR_INVALID_DATA:                               return "invalid data";
+               case CHDERR_FILE_NOT_FOUND:                             return "file not found";
+               case CHDERR_REQUIRES_PARENT:                    return "requires parent";
+               case CHDERR_FILE_NOT_WRITEABLE:                 return "file not writeable";
+               case CHDERR_READ_ERROR:                                 return "read error";
+               case CHDERR_WRITE_ERROR:                                return "write error";
+               case CHDERR_CODEC_ERROR:                                return "codec error";
+               case CHDERR_INVALID_PARENT:                             return "invalid parent";
+               case CHDERR_HUNK_OUT_OF_RANGE:                  return "hunk out of range";
+               case CHDERR_DECOMPRESSION_ERROR:                return "decompression error";
+               case CHDERR_COMPRESSION_ERROR:                  return "compression error";
+               case CHDERR_CANT_CREATE_FILE:                   return "can't create file";
+               case CHDERR_CANT_VERIFY:                                return "can't verify file";
+               case CHDERR_NOT_SUPPORTED:                              return "operation not supported";
+               case CHDERR_METADATA_NOT_FOUND:                 return "can't find metadata";
+               case CHDERR_INVALID_METADATA_SIZE:              return "invalid metadata size";
+               case CHDERR_UNSUPPORTED_VERSION:                return "unsupported CHD version";
+               case CHDERR_VERIFY_INCOMPLETE:                  return "incomplete verify";
+               case CHDERR_INVALID_METADATA:                   return "invalid metadata";
+               case CHDERR_INVALID_STATE:                              return "invalid state";
+               case CHDERR_OPERATION_PENDING:                  return "operation pending";
+               case CHDERR_NO_ASYNC_OPERATION:                 return "no async operation in progress";
+               case CHDERR_UNSUPPORTED_FORMAT:                 return "unsupported format";
+               default:                                                                return "undocumented error";
+       }
+}
+
+/***************************************************************************
+    CHD HEADER MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_get_header - return a pointer to the
+    extracted header data
+-------------------------------------------------*/
+
+CHD_EXPORT const chd_header *chd_get_header(chd_file *chd)
+{
+       /* punt if NULL or invalid */
+       if (chd == NULL || chd->cookie != COOKIE_VALUE)
+               return NULL;
+
+       return &chd->header;
+}
+
+/*-------------------------------------------------
+    chd_read_header - read CHD header data
+       from file into the pointed struct
+-------------------------------------------------*/
+CHD_EXPORT chd_error chd_read_header(const char *filename, chd_header *header)
+{
+       chd_error err = CHDERR_NONE;
+       chd_file chd;
+
+       /* punt if NULL */
+       if (filename == NULL || header == NULL)
+               EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+       /* open the file */
+       chd.file = core_fopen(filename);
+       if (chd.file == NULL)
+               EARLY_EXIT(err = CHDERR_FILE_NOT_FOUND);
+
+       /* attempt to read the header */
+       err = header_read(&chd, header);
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+
+       /* validate the header */
+       err = header_validate(header);
+       if (err != CHDERR_NONE)
+               EARLY_EXIT(err);
+
+cleanup:
+       if (chd.file != NULL)
+               core_fclose(chd.file);
+
+       return err;
+}
+
+/***************************************************************************
+    CORE DATA READ/WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_read - read a single hunk from the CHD
+    file
+-------------------------------------------------*/
+
+CHD_EXPORT chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer)
+{
+       /* punt if NULL or invalid */
+       if (chd == NULL || chd->cookie != COOKIE_VALUE)
+               return CHDERR_INVALID_PARAMETER;
+
+       /* if we're past the end, fail */
+       if (hunknum >= chd->header.totalhunks)
+               return CHDERR_HUNK_OUT_OF_RANGE;
+
+       /* perform the read */
+       return hunk_read_into_memory(chd, hunknum, (UINT8 *)buffer);
+}
+
+/***************************************************************************
+    METADATA MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_get_metadata - get the indexed metadata
+    of the given type
+-------------------------------------------------*/
+
+CHD_EXPORT chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag, UINT8 *resultflags)
+{
+       metadata_entry metaentry;
+       chd_error err;
+       UINT32 count;
+
+       /* if we didn't find it, just return */
+       err = metadata_find_entry(chd, searchtag, searchindex, &metaentry);
+       if (err != CHDERR_NONE)
+       {
+               /* unless we're an old version and they are requesting hard disk metadata */
+               if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0)
+               {
+                       char faux_metadata[256];
+                       UINT32 faux_length;
+
+                       /* fill in the faux metadata */
+                       sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd->header.obsolete_cylinders, chd->header.obsolete_heads, chd->header.obsolete_sectors, chd->header.hunkbytes / chd->header.obsolete_hunksize);
+                       faux_length = (UINT32)strlen(faux_metadata) + 1;
+
+                       /* copy the metadata itself */
+                       memcpy(output, faux_metadata, MIN(outputlen, faux_length));
+
+                       /* return the length of the data and the tag */
+                       if (resultlen != NULL)
+                               *resultlen = faux_length;
+                       if (resulttag != NULL)
+                               *resulttag = HARD_DISK_METADATA_TAG;
+                       return CHDERR_NONE;
+               }
+               return err;
+       }
+
+       /* read the metadata */
+       outputlen = MIN(outputlen, metaentry.length);
+       core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
+       count = core_fread(chd->file, output, outputlen);
+       if (count != outputlen)
+               return CHDERR_READ_ERROR;
+
+       /* return the length of the data and the tag */
+       if (resultlen != NULL)
+               *resultlen = metaentry.length;
+       if (resulttag != NULL)
+               *resulttag = metaentry.metatag;
+       if (resultflags != NULL)
+               *resultflags = metaentry.flags;
+       return CHDERR_NONE;
+}
+
+/***************************************************************************
+    CODEC INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+    chd_codec_config - set internal codec
+    parameters
+-------------------------------------------------*/
+
+CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config)
+{
+       return CHDERR_INVALID_PARAMETER;
+}
+
+/*-------------------------------------------------
+    chd_get_codec_name - get the name of a
+    particular codec
+-------------------------------------------------*/
+
+CHD_EXPORT const char *chd_get_codec_name(UINT32 codec)
+{
+       return "Unknown";
+}
+
+/***************************************************************************
+    INTERNAL HEADER OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+    header_validate - check the validity of a
+    CHD header
+-------------------------------------------------*/
+
+static chd_error header_validate(const chd_header *header)
+{
+       int intfnum;
+
+       /* require a valid version */
+       if (header->version == 0 || header->version > CHD_HEADER_VERSION)
+               return CHDERR_UNSUPPORTED_VERSION;
+
+       /* require a valid length */
+       if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
+               (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
+               (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
+               (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
+               (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
+               return CHDERR_INVALID_PARAMETER;
+
+       /* Do not validate v5 header */
+       if (header->version <= 4)
+       {
+               /* require valid flags */
+               if (header->flags & CHDFLAGS_UNDEFINED)
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* require a supported compression mechanism */
+               for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
+                       if (codec_interfaces[intfnum].compression == header->compression[0])
+                               break;
+
+               if (intfnum == ARRAY_LENGTH(codec_interfaces))
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* require a valid hunksize */
+               if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* require a valid hunk count */
+               if (header->totalhunks == 0)
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* require a valid MD5 and/or SHA1 if we're using a parent */
+               if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0)
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* if we're V3 or later, the obsolete fields must be 0 */
+               if (header->version >= 3 &&
+                       (header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 ||
+                        header->obsolete_heads != 0 || header->obsolete_hunksize != 0))
+                       return CHDERR_INVALID_PARAMETER;
+
+               /* if we're pre-V3, the obsolete fields must NOT be 0 */
+               if (header->version < 3 &&
+                       (header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 ||
+                        header->obsolete_heads == 0 || header->obsolete_hunksize == 0))
+                       return CHDERR_INVALID_PARAMETER;
+       }
+
+       return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+    header_guess_unitbytes - for older CHD formats,
+    guess at the bytes/unit based on metadata
+-------------------------------------------------*/
+
+static UINT32 header_guess_unitbytes(chd_file *chd)
+{
+       /* look for hard disk metadata; if found, then the unit size == sector size */
+       char metadata[512];
+       int i0, i1, i2, i3;
+       if (chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE &&
+               sscanf(metadata, HARD_DISK_METADATA_FORMAT, &i0, &i1, &i2, &i3) == 4)
+               return i3;
+
+       /* look for CD-ROM metadata; if found, then the unit size == CD frame size */
+       if (chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, CDROM_TRACK_METADATA2_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, GDROM_OLD_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE ||
+               chd_get_metadata(chd, GDROM_TRACK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL, NULL) == CHDERR_NONE)
+               return CD_FRAME_SIZE;
+
+       /* otherwise, just map 1:1 with the hunk size */
+       return chd->header.hunkbytes;
+}
+
+/*-------------------------------------------------
+    header_read - read a CHD header into the
+    internal data structure
+-------------------------------------------------*/
+
+static chd_error header_read(chd_file *chd, chd_header *header)
+{
+       UINT8 rawheader[CHD_MAX_HEADER_SIZE];
+       UINT32 count;
+
+       /* punt if NULL */
+       if (header == NULL)
+               return CHDERR_INVALID_PARAMETER;
+
+       /* punt if invalid file */
+       if (chd->file == NULL)
+               return CHDERR_INVALID_FILE;
+
+       /* seek and read */
+       core_fseek(chd->file, 0, SEEK_SET);
+       count = core_fread(chd->file, rawheader, sizeof(rawheader));
+       if (count != sizeof(rawheader))
+               return CHDERR_READ_ERROR;
+
+       /* verify the tag */
+       if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
+               return CHDERR_INVALID_DATA;
+
+       /* extract the direct data */
+       memset(header, 0, sizeof(*header));
+       header->length        = get_bigendian_uint32(&rawheader[8]);
+       header->version       = get_bigendian_uint32(&rawheader[12]);
+
+       /* make sure it's a version we understand */
+       if (header->version == 0 || header->version > CHD_HEADER_VERSION)
+               return CHDERR_UNSUPPORTED_VERSION;
+
+       /* make sure the length is expected */
+       if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
+               (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
+               (header->version == 3 && header->length != CHD_V3_HEADER_SIZE) ||
+               (header->version == 4 && header->length != CHD_V4_HEADER_SIZE) ||
+               (header->version == 5 && header->length != CHD_V5_HEADER_SIZE))
+
+               return CHDERR_INVALID_DATA;
+
+       /* extract the common data */
+       header->flags           = get_bigendian_uint32(&rawheader[16]);
+       header->compression[0]  = get_bigendian_uint32(&rawheader[20]);
+       header->compression[1]  = CHD_CODEC_NONE;
+       header->compression[2]  = CHD_CODEC_NONE;
+       header->compression[3]  = CHD_CODEC_NONE;
+
+       /* extract the V1/V2-specific data */
+       if (header->version < 3)
+       {
+               int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]);
+               header->obsolete_hunksize  = get_bigendian_uint32(&rawheader[24]);
+               header->totalhunks         = get_bigendian_uint32(&rawheader[28]);
+               header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]);
+               header->obsolete_heads     = get_bigendian_uint32(&rawheader[36]);
+               header->obsolete_sectors   = get_bigendian_uint32(&rawheader[40]);
+               memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
+               memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
+               header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen;
+               header->hunkbytes = seclen * header->obsolete_hunksize;
+               header->unitbytes          = header_guess_unitbytes(chd);
+               header->unitcount          = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
+               header->metaoffset = 0;
+       }
+
+       /* extract the V3-specific data */
+       else if (header->version == 3)
+       {
+               header->totalhunks   = get_bigendian_uint32(&rawheader[24]);
+               header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
+               header->metaoffset   = get_bigendian_uint64(&rawheader[36]);
+               memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
+               memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
+               header->hunkbytes    = get_bigendian_uint32(&rawheader[76]);
+               header->unitbytes    = header_guess_unitbytes(chd);
+               header->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
+               memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
+               memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
+       }
+
+       /* extract the V4-specific data */
+       else if (header->version == 4)
+       {
+               header->totalhunks   = get_bigendian_uint32(&rawheader[24]);
+               header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
+               header->metaoffset   = get_bigendian_uint64(&rawheader[36]);
+               header->hunkbytes    = get_bigendian_uint32(&rawheader[44]);
+               header->unitbytes    = header_guess_unitbytes(chd);
+               header->unitcount    = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
+               memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
+               memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
+               memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
+       }
+
+       /* extract the V5-specific data */
+       else if (header->version == 5)
+       {
+               /* TODO */
+               header->compression[0]  = get_bigendian_uint32(&rawheader[16]);
+               header->compression[1]  = get_bigendian_uint32(&rawheader[20]);
+               header->compression[2]  = get_bigendian_uint32(&rawheader[24]);
+               header->compression[3]  = get_bigendian_uint32(&rawheader[28]);
+               header->logicalbytes    = get_bigendian_uint64(&rawheader[32]);
+               header->mapoffset       = get_bigendian_uint64(&rawheader[40]);
+               header->metaoffset      = get_bigendian_uint64(&rawheader[48]);
+               header->hunkbytes       = get_bigendian_uint32(&rawheader[56]);
+               header->hunkcount       = (header->logicalbytes + header->hunkbytes - 1) / header->hunkbytes;
+               header->unitbytes       = get_bigendian_uint32(&rawheader[60]);
+               header->unitcount       = (header->logicalbytes + header->unitbytes - 1) / header->unitbytes;
+               memcpy(header->sha1, &rawheader[84], CHD_SHA1_BYTES);
+               memcpy(header->parentsha1, &rawheader[104], CHD_SHA1_BYTES);
+               memcpy(header->rawsha1, &rawheader[64], CHD_SHA1_BYTES);
+
+               /* determine properties of map entries */
+               header->mapentrybytes = chd_compressed(header) ? 12 : 4;
+
+               /* hack */
+               header->totalhunks              = header->hunkcount;
+       }
+
+       /* Unknown version */
+       else
+       {
+               /* TODO */
+       }
+
+       /* guess it worked */
+       return CHDERR_NONE;
+}
+
+/***************************************************************************
+    INTERNAL HUNK READ/WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+    hunk_read_compressed - read a compressed
+    hunk
+-------------------------------------------------*/
+
+static UINT8* hunk_read_compressed(chd_file *chd, UINT64 offset, size_t size)
+{
+#ifdef _MSC_VER
+       size_t bytes;
+#else
+       ssize_t bytes;
+#endif
+       if (chd->file_cache != NULL)
+       {
+               return chd->file_cache + offset;
+       }
+       else
+       {
+               core_fseek(chd->file, offset, SEEK_SET);
+               bytes = core_fread(chd->file, chd->compressed, size);
+               if (bytes != size)
+                       return NULL;
+               return chd->compressed;
+       }
+}
+
+/*-------------------------------------------------
+    hunk_read_uncompressed - read an uncompressed
+    hunk
+-------------------------------------------------*/
+
+static chd_error hunk_read_uncompressed(chd_file *chd, UINT64 offset, size_t size, UINT8 *dest)
+{
+#ifdef _MSC_VER
+       size_t bytes;
+#else
+       ssize_t bytes;
+#endif
+       if (chd->file_cache != NULL)
+       {
+               memcpy(dest, chd->file_cache + offset, size);
+       }
+       else
+       {
+               core_fseek(chd->file, offset, SEEK_SET);
+               bytes = core_fread(chd->file, dest, size);
+               if (bytes != size)
+                       return CHDERR_READ_ERROR;
+       }
+       return CHDERR_NONE;
+}
+
+#ifdef NEED_CACHE_HUNK
+/*-------------------------------------------------
+    hunk_read_into_cache - read a hunk into
+    the CHD's hunk cache
+-------------------------------------------------*/
+
+static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
+{
+       chd_error err;
+
+       /* track the max */
+       if (hunknum > chd->maxhunk)
+               chd->maxhunk = hunknum;
+
+       /* if we're already in the cache, we're done */
+       if (chd->cachehunk == hunknum)
+               return CHDERR_NONE;
+       chd->cachehunk = ~0;
+
+       /* otherwise, read the data */
+       err = hunk_read_into_memory(chd, hunknum, chd->cache);
+       if (err != CHDERR_NONE)
+               return err;
+
+       /* mark the hunk successfully cached in */
+       chd->cachehunk = hunknum;
+       return CHDERR_NONE;
+}
+#endif
+
+/*-------------------------------------------------
+    hunk_read_into_memory - read a hunk into
+    memory at the given location
+-------------------------------------------------*/
+
+static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest)
+{
+       chd_error err;
+
+       /* punt if no file */
+       if (chd->file == NULL)
+               return CHDERR_INVALID_FILE;
+
+       /* return an error if out of range */
+       if (hunknum >= chd->header.totalhunks)
+               return CHDERR_HUNK_OUT_OF_RANGE;
+
+       if (dest == NULL)
+               return CHDERR_INVALID_PARAMETER;
+
+       if (chd->header.version < 5)
+       {
+               map_entry *entry = &chd->map[hunknum];
+               UINT32 bytes;
+               UINT8* compressed_bytes;
+
+               /* switch off the entry type */
+               switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
+               {
+                       /* compressed data */
+                       case V34_MAP_ENTRY_TYPE_COMPRESSED:
+            {
+               void *codec = NULL;
+
+                               /* read it into the decompression buffer */
+                               compressed_bytes = hunk_read_compressed(chd, entry->offset, entry->length);
+                               if (compressed_bytes == NULL)
+                                       return CHDERR_READ_ERROR;
+
+                               /* now decompress using the codec */
+                               err = CHDERR_NONE;
+                               codec = &chd->zlib_codec_data;
+                               if (chd->codecintf[0]->decompress != NULL)
+                                       err = (*chd->codecintf[0]->decompress)(codec, compressed_bytes, entry->length, dest, chd->header.hunkbytes);
+                               if (err != CHDERR_NONE)
+                                       return err;
+                               break;
+                       }
+
+                       /* uncompressed data */
+                       case V34_MAP_ENTRY_TYPE_UNCOMPRESSED:
+                               err = hunk_read_uncompressed(chd, entry->offset, chd->header.hunkbytes, dest);
+                               if (err != CHDERR_NONE)
+                                       return err;
+                               break;
+
+                       /* mini-compressed data */
+                       case V34_MAP_ENTRY_TYPE_MINI:
+                               put_bigendian_uint64(&dest[0], entry->offset);
+                               for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
+                                       dest[bytes] = dest[bytes - 8];
+                               break;
+
+                       /* self-referenced data */
+                       case V34_MAP_ENTRY_TYPE_SELF_HUNK:
+#ifdef NEED_CACHE_HUNK
+                               if (chd->cachehunk == entry->offset && dest == chd->cache)
+                                       break;
+#endif
+                               return hunk_read_into_memory(chd, entry->offset, dest);
+
+                       /* parent-referenced data */
+                       case V34_MAP_ENTRY_TYPE_PARENT_HUNK:
+                               err = hunk_read_into_memory(chd->parent, entry->offset, dest);
+                               if (err != CHDERR_NONE)
+                                       return err;
+                               break;
+               }
+               return CHDERR_NONE;
+       }
+       else
+       {
+               void* codec = NULL;
+               /* get a pointer to the map entry */
+               uint64_t blockoffs;
+               uint32_t blocklen;
+#ifdef VERIFY_BLOCK_CRC
+               uint16_t blockcrc;
+#endif
+               uint8_t *rawmap = &chd->header.rawmap[chd->header.mapentrybytes * hunknum];
+               UINT8* compressed_bytes;
+
+               /* uncompressed case */
+               if (!chd_compressed(&chd->header))
+               {
+                       blockoffs = (uint64_t)get_bigendian_uint32(rawmap) * (uint64_t)chd->header.hunkbytes;
+                       if (blockoffs != 0) {
+                               core_fseek(chd->file, blockoffs, SEEK_SET);
+                               int result = core_fread(chd->file, dest, chd->header.hunkbytes);
+                       /* TODO
+                       else if (m_parent_missing)
+                               throw CHDERR_REQUIRES_PARENT; */
+                       } else if (chd->parent) {
+                               err = hunk_read_into_memory(chd->parent, hunknum, dest);
+                               if (err != CHDERR_NONE)
+                                       return err;
+                       } else {
+                               memset(dest, 0, chd->header.hunkbytes);
+                       }
+
+                       return CHDERR_NONE;
+               }
+
+               /* compressed case */
+               blocklen = get_bigendian_uint24(&rawmap[1]);
+               blockoffs = get_bigendian_uint48(&rawmap[4]);
+#ifdef VERIFY_BLOCK_CRC
+               blockcrc = get_bigendian_uint16(&rawmap[10]);
+#endif
+               codec = NULL;
+               switch (rawmap[0])
+               {
+                       case COMPRESSION_TYPE_0:
+                       case COMPRESSION_TYPE_1:
+                       case COMPRESSION_TYPE_2:
+                       case COMPRESSION_TYPE_3:
+                               compressed_bytes = hunk_read_compressed(chd, blockoffs, blocklen);
+                               if (compressed_bytes == NULL)
+                                       return CHDERR_READ_ERROR;
+                               switch (chd->codecintf[rawmap[0]]->compression)
+                               {
+                                       case CHD_CODEC_CD_LZMA:
+                                               codec = &chd->cdlz_codec_data;
+                                               break;
+
+                                       case CHD_CODEC_ZLIB:
+                                               codec = &chd->zlib_codec_data;
+                                               break;
+
+                                       case CHD_CODEC_CD_ZLIB:
+                                               codec = &chd->cdzl_codec_data;
+                                               break;
+
+                                       case CHD_CODEC_CD_FLAC:
+                                               codec = &chd->cdfl_codec_data;
+                                               break;
+                               }
+                               if (codec==NULL)
+                                       return CHDERR_CODEC_ERROR;
+                               err = chd->codecintf[rawmap[0]]->decompress(codec, compressed_bytes, blocklen, dest, chd->header.hunkbytes);
+                               if (err != CHDERR_NONE)
+                                       return err;
+#ifdef VERIFY_BLOCK_CRC
+                               if (crc16(dest, chd->header.hunkbytes) != blockcrc)
+                                       return CHDERR_DECOMPRESSION_ERROR;
+#endif
+                               return CHDERR_NONE;
+
+                       case COMPRESSION_NONE:
+                               err = hunk_read_uncompressed(chd, blockoffs, blocklen, dest);
+                               if (err != CHDERR_NONE)
+                                       return err;
+#ifdef VERIFY_BLOCK_CRC
+                               if (crc16(dest, chd->header.hunkbytes) != blockcrc)
+                                       return CHDERR_DECOMPRESSION_ERROR;
+#endif
+                               return CHDERR_NONE;
+
+                       case COMPRESSION_SELF:
+                               return hunk_read_into_memory(chd, blockoffs, dest);
+
+                       case COMPRESSION_PARENT:
+                               if (chd->parent == NULL)
+                                       return CHDERR_REQUIRES_PARENT;
+                               UINT8 units_in_hunk = chd->header.hunkbytes / chd->header.unitbytes;
+
+                               /* blockoffs is aligned to units_in_hunk */
+                               if (blockoffs % units_in_hunk == 0) {
+                                       return hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, dest);
+                               /* blockoffs is not aligned to units_in_hunk */
+                               } else {
+                                       UINT32 unit_in_hunk = blockoffs % units_in_hunk;
+                                       UINT8 *buf = malloc(chd->header.hunkbytes);
+                                       /* Read first half of hunk which contains blockoffs */
+                                       err = hunk_read_into_memory(chd->parent, blockoffs / units_in_hunk, buf);
+                                       if (err != CHDERR_NONE) {
+                                               free(buf);
+                                               return err;
+                                       }
+                                       memcpy(dest, buf + unit_in_hunk * chd->header.unitbytes, (units_in_hunk - unit_in_hunk) * chd->header.unitbytes);
+                                       /* Read second half of hunk which contains blockoffs */
+                                       err = hunk_read_into_memory(chd->parent, (blockoffs / units_in_hunk) + 1, buf);
+                                       if (err != CHDERR_NONE) {
+                                               free(buf);
+                                               return err;
+                                       }
+                                       memcpy(dest + (units_in_hunk - unit_in_hunk) * chd->header.unitbytes, buf, unit_in_hunk * chd->header.unitbytes);
+                                       free(buf);
+                               }
+               }
+               return CHDERR_NONE;
+       }
+
+       /* We should not reach this code */
+       return CHDERR_DECOMPRESSION_ERROR;
+}
+
+/***************************************************************************
+    INTERNAL MAP ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+    map_read - read the initial sector map
+-------------------------------------------------*/
+
+static chd_error map_read(chd_file *chd)
+{
+       UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;
+       UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
+       UINT64 fileoffset, maxoffset = 0;
+       UINT8 cookie[MAP_ENTRY_SIZE];
+       UINT32 count;
+       chd_error err;
+       int i;
+
+       /* first allocate memory */
+       chd->map = (map_entry *)malloc(sizeof(chd->map[0]) * chd->header.totalhunks);
+       if (!chd->map)
+               return CHDERR_OUT_OF_MEMORY;
+
+       /* read the map entries in in chunks and extract to the map list */
+       fileoffset = chd->header.length;
+       for (i = 0; i < chd->header.totalhunks; i += MAP_STACK_ENTRIES)
+       {
+               /* compute how many entries this time */
+               int entries = chd->header.totalhunks - i, j;
+               if (entries > MAP_STACK_ENTRIES)
+                       entries = MAP_STACK_ENTRIES;
+
+               /* read that many */
+               core_fseek(chd->file, fileoffset, SEEK_SET);
+               count = core_fread(chd->file, raw_map_entries, entries * entrysize);
+               if (count != entries * entrysize)
+               {
+                       err = CHDERR_READ_ERROR;
+                       goto cleanup;
+               }
+               fileoffset += entries * entrysize;
+
+               /* process that many */
+               if (entrysize == MAP_ENTRY_SIZE)
+               {
+                       for (j = 0; j < entries; j++)
+                               map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);
+               }
+               else
+               {
+                       for (j = 0; j < entries; j++)
+                               map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes);
+               }
+
+               /* track the maximum offset */
+               for (j = 0; j < entries; j++)
+                       if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_COMPRESSED ||
+                               (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == V34_MAP_ENTRY_TYPE_UNCOMPRESSED)
+                               maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);
+       }
+
+       /* verify the cookie */
+       core_fseek(chd->file, fileoffset, SEEK_SET);
+       count = core_fread(chd->file, &cookie, entrysize);
+       if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize))
+       {
+               err = CHDERR_INVALID_FILE;
+               goto cleanup;
+       }
+
+       /* verify the length */
+       if (maxoffset > core_fsize(chd->file))
+       {
+               err = CHDERR_INVALID_FILE;
+               goto cleanup;
+       }
+       return CHDERR_NONE;
+
+cleanup:
+       if (chd->map)
+               free(chd->map);
+       chd->map = NULL;
+       return err;
+}
+
+/***************************************************************************
+    INTERNAL METADATA ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+    metadata_find_entry - find a metadata entry
+-------------------------------------------------*/
+
+static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry)
+{
+       /* start at the beginning */
+       metaentry->offset = chd->header.metaoffset;
+       metaentry->prev = 0;
+
+       /* loop until we run out of options */
+       while (metaentry->offset != 0)
+       {
+               UINT8   raw_meta_header[METADATA_HEADER_SIZE];
+               UINT32  count;
+
+               /* read the raw header */
+               core_fseek(chd->file, metaentry->offset, SEEK_SET);
+               count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
+               if (count != sizeof(raw_meta_header))
+                       break;
+
+               /* extract the data */
+               metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]);
+               metaentry->length = get_bigendian_uint32(&raw_meta_header[4]);
+               metaentry->next = get_bigendian_uint64(&raw_meta_header[8]);
+
+               /* flags are encoded in the high byte of length */
+               metaentry->flags = metaentry->length >> 24;
+               metaentry->length &= 0x00ffffff;
+
+               /* if we got a match, proceed */
+               if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)
+                       if (metaindex-- == 0)
+                               return CHDERR_NONE;
+
+               /* no match, fetch the next link */
+               metaentry->prev = metaentry->offset;
+               metaentry->offset = metaentry->next;
+       }
+
+       /* if we get here, we didn't find it */
+       return CHDERR_METADATA_NOT_FOUND;
+}
+
+/***************************************************************************
+    ZLIB COMPRESSION CODEC
+***************************************************************************/
+
+/*-------------------------------------------------
+    zlib_codec_init - initialize the ZLIB codec
+-------------------------------------------------*/
+
+static chd_error zlib_codec_init(void *codec, uint32_t hunkbytes)
+{
+       int zerr;
+       chd_error err;
+       zlib_codec_data *data = (zlib_codec_data*)codec;
+
+       /* clear the buffers */
+       memset(data, 0, sizeof(zlib_codec_data));
+
+       /* init the inflater first */
+       data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */
+       data->inflater.avail_in = 0;
+       data->inflater.zalloc = zlib_fast_alloc;
+       data->inflater.zfree = zlib_fast_free;
+       data->inflater.opaque = &data->allocator;
+       zerr = inflateInit2(&data->inflater, -MAX_WBITS);
+
+       /* convert errors */
+       if (zerr == Z_MEM_ERROR)
+               err = CHDERR_OUT_OF_MEMORY;
+       else if (zerr != Z_OK)
+               err = CHDERR_CODEC_ERROR;
+       else
+               err = CHDERR_NONE;
+
+       /* handle an error */
+       if (err != CHDERR_NONE)
+               free(data);
+
+       return err;
+}
+
+/*-------------------------------------------------
+    zlib_codec_free - free data for the ZLIB
+    codec
+-------------------------------------------------*/
+
+static void zlib_codec_free(void *codec)
+{
+       zlib_codec_data *data = (zlib_codec_data *)codec;
+
+       /* deinit the streams */
+       if (data != NULL)
+       {
+               int i;
+
+               inflateEnd(&data->inflater);
+
+               /* free our fast memory */
+               zlib_allocator_free(&data->allocator);
+       }
+}
+
+/*-------------------------------------------------
+    zlib_codec_decompress - decompress data using
+    the ZLIB codec
+-------------------------------------------------*/
+
+static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen)
+{
+       zlib_codec_data *data = (zlib_codec_data *)codec;
+       int zerr;
+
+       /* reset the decompressor */
+       data->inflater.next_in = (Bytef *)src;
+       data->inflater.avail_in = complen;
+       data->inflater.total_in = 0;
+       data->inflater.next_out = (Bytef *)dest;
+       data->inflater.avail_out = destlen;
+       data->inflater.total_out = 0;
+       zerr = inflateReset(&data->inflater);
+       if (zerr != Z_OK)
+               return CHDERR_DECOMPRESSION_ERROR;
+
+       /* do it */
+       zerr = inflate(&data->inflater, Z_FINISH);
+       if (data->inflater.total_out != destlen)
+               return CHDERR_DECOMPRESSION_ERROR;
+
+       return CHDERR_NONE;
+}
+
+/*-------------------------------------------------
+    zlib_fast_alloc - fast malloc for ZLIB, which
+    allocates and frees memory frequently
+-------------------------------------------------*/
+
+/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
+#define ZLIB_MIN_ALIGNMENT_BITS 512
+#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)
+
+static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
+{
+       zlib_allocator *alloc = (zlib_allocator *)opaque;
+       uintptr_t paddr = 0;
+       UINT32 *ptr;
+       int i;
+
+       /* compute the size, rounding to the nearest 1k */
+       size = (size * items + 0x3ff) & ~0x3ff;
+
+       /* reuse a hunk if we can */
+       for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+       {
+               ptr = alloc->allocptr[i];
+               if (ptr && size == *ptr)
+               {
+                       /* set the low bit of the size so we don't match next time */
+                       *ptr |= 1;
+
+                       /* return aligned block address */
+                       return (voidpf)(alloc->allocptr2[i]);
+               }
+       }
+
+       /* alloc a new one */
+    ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES);
+       if (!ptr)
+               return NULL;
+
+       /* put it into the list */
+       for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+               if (!alloc->allocptr[i])
+               {
+                       alloc->allocptr[i] = ptr;
+                       paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
+                       alloc->allocptr2[i] = (uint32_t*)paddr;
+                       break;
+               }
+
+       /* set the low bit of the size so we don't match next time */
+       *ptr = size | 1;
+
+       /* return aligned block address */
+       return (voidpf)paddr;
+}
+
+/*-------------------------------------------------
+    zlib_fast_free - fast free for ZLIB, which
+    allocates and frees memory frequently
+-------------------------------------------------*/
+
+static void zlib_fast_free(voidpf opaque, voidpf address)
+{
+       zlib_allocator *alloc = (zlib_allocator *)opaque;
+       UINT32 *ptr = (UINT32 *)address;
+       int i;
+
+       /* find the hunk */
+       for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+               if (ptr == alloc->allocptr2[i])
+               {
+                       /* clear the low bit of the size to allow matches */
+                       *(alloc->allocptr[i]) &= ~1;
+                       return;
+               }
+}
+
+/*-------------------------------------------------
+    zlib_allocator_free
+-------------------------------------------------*/
+static void zlib_allocator_free(voidpf opaque)
+{
+       zlib_allocator *alloc = (zlib_allocator *)opaque;
+       int i;
+
+       for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+               if (alloc->allocptr[i])
+                       free(alloc->allocptr[i]);
+}
diff --git a/deps/libchdr/src/libchdr_flac.c b/deps/libchdr/src/libchdr_flac.c
new file mode 100644 (file)
index 0000000..54d374f
--- /dev/null
@@ -0,0 +1,302 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+***************************************************************************
+
+    flac.c
+
+    FLAC compression wrappers
+
+***************************************************************************/
+
+#include <assert.h>
+#include <string.h>
+
+#include <libchdr/flac.h>
+#define DR_FLAC_IMPLEMENTATION
+#include <dr_libs/dr_flac.h>
+
+/***************************************************************************
+ *  FLAC DECODER
+ ***************************************************************************
+ */
+
+static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes);
+static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin);
+static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata);
+static void flac_decoder_write_callback(void *userdata, void *buffer, size_t len);
+
+
+/* getters (valid after reset) */
+static uint32_t sample_rate(flac_decoder *decoder)  { return decoder->sample_rate; }
+static uint8_t channels(flac_decoder *decoder)  { return decoder->channels; }
+static uint8_t bits_per_sample(flac_decoder *decoder) { return decoder->bits_per_sample; }
+
+/*-------------------------------------------------
+ *  flac_decoder - constructor
+ *-------------------------------------------------
+ */
+
+int flac_decoder_init(flac_decoder *decoder)
+{
+       decoder->decoder = NULL;
+       decoder->sample_rate = 0;
+       decoder->channels = 0;
+       decoder->bits_per_sample = 0;
+       decoder->compressed_offset = 0;
+       decoder->compressed_start = NULL;
+       decoder->compressed_length = 0;
+       decoder->compressed2_start = NULL;
+       decoder->compressed2_length = 0;
+       decoder->uncompressed_offset = 0;
+       decoder->uncompressed_length = 0;
+       decoder->uncompressed_swap = 0;
+       return 0;
+}
+
+/*-------------------------------------------------
+ *  flac_decoder - destructor
+ *-------------------------------------------------
+ */
+
+void flac_decoder_free(flac_decoder* decoder)
+{
+       if ((decoder != NULL) && (decoder->decoder != NULL))
+               drflac_close(decoder->decoder);
+       decoder->decoder = NULL;
+}
+
+/*-------------------------------------------------
+ *  reset - reset state with the original
+ *  parameters
+ *-------------------------------------------------
+ */
+
+static int flac_decoder_internal_reset(flac_decoder* decoder)
+{
+       decoder->compressed_offset = 0;
+       flac_decoder_free(decoder);
+       decoder->decoder = drflac_open_with_metadata(
+               flac_decoder_read_callback, flac_decoder_seek_callback,
+               flac_decoder_metadata_callback, decoder, NULL);
+       return (decoder->decoder != NULL);
+}
+
+/*-------------------------------------------------
+ *  reset - reset state with new memory parameters
+ *  and a custom-generated header
+ *-------------------------------------------------
+ */
+
+int flac_decoder_reset(flac_decoder* decoder, uint32_t sample_rate, uint8_t num_channels, uint32_t block_size, const void *buffer, uint32_t length)
+{
+       /* modify the template header with our parameters */
+       static const uint8_t s_header_template[0x2a] =
+       {
+               0x66, 0x4C, 0x61, 0x43,                         /* +00: 'fLaC' stream header */
+               0x80,                                           /* +04: metadata block type 0 (STREAMINFO), */
+                                                               /*      flagged as last block */
+               0x00, 0x00, 0x22,                               /* +05: metadata block length = 0x22 */
+               0x00, 0x00,                                     /* +08: minimum block size */
+               0x00, 0x00,                                     /* +0A: maximum block size */
+               0x00, 0x00, 0x00,                               /* +0C: minimum frame size (0 == unknown) */
+               0x00, 0x00, 0x00,                               /* +0F: maximum frame size (0 == unknown) */
+               0x0A, 0xC4, 0x42, 0xF0, 0x00, 0x00, 0x00, 0x00, /* +12: sample rate (0x0ac44 == 44100), */
+                                                               /*      numchannels (2), sample bits (16), */
+                                                               /*      samples in stream (0 == unknown) */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* +1A: MD5 signature (0 == none) */
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /* +2A: start of stream data */
+       };
+       memcpy(decoder->custom_header, s_header_template, sizeof(s_header_template));
+       decoder->custom_header[0x08] = decoder->custom_header[0x0a] = (block_size*num_channels) >> 8;
+       decoder->custom_header[0x09] = decoder->custom_header[0x0b] = (block_size*num_channels) & 0xff;
+       decoder->custom_header[0x12] = sample_rate >> 12;
+       decoder->custom_header[0x13] = sample_rate >> 4;
+       decoder->custom_header[0x14] = (sample_rate << 4) | ((num_channels - 1) << 1);
+
+       /* configure the header ahead of the provided buffer */
+       decoder->compressed_start = (const uint8_t *)(decoder->custom_header);
+       decoder->compressed_length = sizeof(decoder->custom_header);
+       decoder->compressed2_start = (const uint8_t *)(buffer);
+       decoder->compressed2_length = length;
+       return flac_decoder_internal_reset(decoder);
+}
+
+/*-------------------------------------------------
+ *  decode_interleaved - decode to an interleaved
+ *  sound stream
+ *-------------------------------------------------
+ */
+
+int flac_decoder_decode_interleaved(flac_decoder* decoder, int16_t *samples, uint32_t num_samples, int swap_endian)
+{
+       /* configure the uncompressed buffer */
+       memset(decoder->uncompressed_start, 0, sizeof(decoder->uncompressed_start));
+       decoder->uncompressed_start[0] = samples;
+       decoder->uncompressed_offset = 0;
+       decoder->uncompressed_length = num_samples;
+       decoder->uncompressed_swap = swap_endian;
+
+#define        BUFFER  2352    /* bytes per CD audio sector */
+       int16_t buffer[BUFFER];
+       uint32_t buf_samples = BUFFER / channels(decoder);
+       /* loop until we get everything we want */
+       while (decoder->uncompressed_offset < decoder->uncompressed_length) {
+               uint32_t frames = (num_samples < buf_samples ? num_samples : buf_samples);
+               if (!drflac_read_pcm_frames_s16(decoder->decoder, frames, buffer))
+                       return 0;
+               flac_decoder_write_callback(decoder, buffer, frames*sizeof(*buffer)*channels(decoder));
+               num_samples -= frames;
+       }
+       return 1;
+}
+
+/*-------------------------------------------------
+ *  finish - finish up the decode
+ *-------------------------------------------------
+ */
+
+uint32_t flac_decoder_finish(flac_decoder* decoder)
+{
+       /* get the final decoding position and move forward */
+       drflac *flac = decoder->decoder;
+       uint64_t position = decoder->compressed_offset;
+
+       /* ugh... there's no function to obtain bytes used in drflac :-/ */
+       position -= DRFLAC_CACHE_L2_LINES_REMAINING(&flac->bs) * sizeof(drflac_cache_t);
+       position -= DRFLAC_CACHE_L1_BITS_REMAINING(&flac->bs) / 8;
+       position -= flac->bs.unalignedByteCount;
+
+       /* adjust position if we provided the header */
+       if (position == 0)
+               return 0;
+       if (decoder->compressed_start == (const uint8_t *)(decoder->custom_header))
+               position -= decoder->compressed_length;
+
+       flac_decoder_free(decoder);
+       return position;
+}
+
+/*-------------------------------------------------
+ *  read_callback - handle reads from the input
+ *  stream
+ *-------------------------------------------------
+ */
+
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+static size_t flac_decoder_read_callback(void *userdata, void *buffer, size_t bytes)
+{
+       flac_decoder* decoder = (flac_decoder*)userdata;
+       uint8_t *dst = buffer;
+
+       /* copy from primary buffer first */
+       uint32_t outputpos = 0;
+       if (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length)
+       {
+               uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed_length - decoder->compressed_offset);
+               memcpy(&dst[outputpos], decoder->compressed_start + decoder->compressed_offset, bytes_to_copy);
+               outputpos += bytes_to_copy;
+               decoder->compressed_offset += bytes_to_copy;
+       }
+
+       /* once we're out of that, copy from the secondary buffer */
+       if (outputpos < bytes && decoder->compressed_offset < decoder->compressed_length + decoder->compressed2_length)
+       {
+               uint32_t bytes_to_copy = MIN(bytes - outputpos, decoder->compressed2_length - (decoder->compressed_offset - decoder->compressed_length));
+               memcpy(&dst[outputpos], decoder->compressed2_start + decoder->compressed_offset - decoder->compressed_length, bytes_to_copy);
+               outputpos += bytes_to_copy;
+               decoder->compressed_offset += bytes_to_copy;
+       }
+
+       return outputpos;
+}
+
+/*-------------------------------------------------
+ *  metadata_callback - handle STREAMINFO metadata
+ *-------------------------------------------------
+ */
+
+static void flac_decoder_metadata_callback(void *userdata, drflac_metadata *metadata)
+{
+       flac_decoder *decoder = userdata;
+
+       /* ignore all but STREAMINFO metadata */
+       if (metadata->type != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO)
+               return;
+
+       /* parse out the data we care about */
+       decoder->sample_rate = metadata->data.streaminfo.sampleRate;
+       decoder->bits_per_sample = metadata->data.streaminfo.bitsPerSample;
+       decoder->channels = metadata->data.streaminfo.channels;
+}
+
+/*-------------------------------------------------
+ *  write_callback - handle writes to the output
+ *  stream
+ *-------------------------------------------------
+ */
+
+static void flac_decoder_write_callback(void *userdata, void *buffer, size_t bytes)
+{
+       int sampnum, chan;
+       int shift, blocksize;
+       flac_decoder * decoder = (flac_decoder *)userdata;
+       int16_t *sampbuf = (int16_t *)buffer;
+       int sampch = channels(decoder);
+       uint32_t offset = decoder->uncompressed_offset;
+       uint16_t usample;
+
+       /* interleaved case */
+       shift = decoder->uncompressed_swap ? 8 : 0;
+       blocksize = bytes / (sampch * sizeof(sampbuf[0]));
+       if (decoder->uncompressed_start[1] == NULL)
+       {
+               int16_t *dest = decoder->uncompressed_start[0] + offset * sampch;
+               for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)
+                       for (chan = 0; chan < sampch; chan++) {
+                               usample = (uint16_t)*sampbuf++;
+                               *dest++ = (int16_t)((usample << shift) | (usample >> shift));
+                       }
+       }
+
+       /* non-interleaved case */
+       else
+       {
+               for (sampnum = 0; sampnum < blocksize && offset < decoder->uncompressed_length; sampnum++, offset++)
+                       for (chan = 0; chan < sampch; chan++) {
+                               usample = (uint16_t)*sampbuf++;
+                               if (decoder->uncompressed_start[chan] != NULL)
+                                       decoder->uncompressed_start[chan][offset] = (int16_t) ((usample << shift) | (usample >> shift));
+                       }
+       }
+       decoder->uncompressed_offset = offset;
+}
+
+
+/*-------------------------------------------------
+ *  seek_callback - handle seeks on the output
+ *  stream
+ *-------------------------------------------------
+ */
+
+static drflac_bool32 flac_decoder_seek_callback(void *userdata, int offset, drflac_seek_origin origin)
+{
+       flac_decoder * decoder = (flac_decoder *)userdata;
+       uint32_t length = decoder->compressed_length + decoder->compressed2_length;
+
+       if (origin == drflac_seek_origin_start) {
+               uint32_t pos = offset;
+               if (pos <= length) {
+                       decoder->compressed_offset = pos;
+                       return 1;
+               }
+       } else if (origin == drflac_seek_origin_current) {
+               uint32_t pos = decoder->compressed_offset + offset;
+               if (pos <= length) {
+                       decoder->compressed_offset = pos;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
diff --git a/deps/libchdr/src/libchdr_huffman.c b/deps/libchdr/src/libchdr_huffman.c
new file mode 100644 (file)
index 0000000..6a50f13
--- /dev/null
@@ -0,0 +1,544 @@
+/* license:BSD-3-Clause
+ * copyright-holders:Aaron Giles
+****************************************************************************
+
+    huffman.c
+
+    Static Huffman compression and decompression helpers.
+
+****************************************************************************
+
+    Maximum codelength is officially (alphabetsize - 1). This would be 255 bits
+    (since we use 1 byte values). However, it is also dependent upon the number
+    of samples used, as follows:
+
+         2 bits -> 3..4 samples
+         3 bits -> 5..7 samples
+         4 bits -> 8..12 samples
+         5 bits -> 13..20 samples
+         6 bits -> 21..33 samples
+         7 bits -> 34..54 samples
+         8 bits -> 55..88 samples
+         9 bits -> 89..143 samples
+        10 bits -> 144..232 samples
+        11 bits -> 233..376 samples
+        12 bits -> 377..609 samples
+        13 bits -> 610..986 samples
+        14 bits -> 987..1596 samples
+        15 bits -> 1597..2583 samples
+        16 bits -> 2584..4180 samples   -> note that a 4k data size guarantees codelength <= 16 bits
+        17 bits -> 4181..6764 samples
+        18 bits -> 6765..10945 samples
+        19 bits -> 10946..17710 samples
+        20 bits -> 17711..28656 samples
+        21 bits -> 28657..46367 samples
+        22 bits -> 46368..75024 samples
+        23 bits -> 75025..121392 samples
+        24 bits -> 121393..196417 samples
+        25 bits -> 196418..317810 samples
+        26 bits -> 317811..514228 samples
+        27 bits -> 514229..832039 samples
+        28 bits -> 832040..1346268 samples
+        29 bits -> 1346269..2178308 samples
+        30 bits -> 2178309..3524577 samples
+        31 bits -> 3524578..5702886 samples
+        32 bits -> 5702887..9227464 samples
+
+    Looking at it differently, here is where powers of 2 fall into these buckets:
+
+          256 samples -> 11 bits max
+          512 samples -> 12 bits max
+           1k samples -> 14 bits max
+           2k samples -> 15 bits max
+           4k samples -> 16 bits max
+           8k samples -> 18 bits max
+          16k samples -> 19 bits max
+          32k samples -> 21 bits max
+          64k samples -> 22 bits max
+         128k samples -> 24 bits max
+         256k samples -> 25 bits max
+         512k samples -> 27 bits max
+           1M samples -> 28 bits max
+           2M samples -> 29 bits max
+           4M samples -> 31 bits max
+           8M samples -> 32 bits max
+
+****************************************************************************
+
+    Delta-RLE encoding works as follows:
+
+    Starting value is assumed to be 0. All data is encoded as a delta
+    from the previous value, such that final[i] = final[i - 1] + delta.
+    Long runs of 0s are RLE-encoded as follows:
+
+        0x100 = repeat count of 8
+        0x101 = repeat count of 9
+        0x102 = repeat count of 10
+        0x103 = repeat count of 11
+        0x104 = repeat count of 12
+        0x105 = repeat count of 13
+        0x106 = repeat count of 14
+        0x107 = repeat count of 15
+        0x108 = repeat count of 16
+        0x109 = repeat count of 32
+        0x10a = repeat count of 64
+        0x10b = repeat count of 128
+        0x10c = repeat count of 256
+        0x10d = repeat count of 512
+        0x10e = repeat count of 1024
+        0x10f = repeat count of 2048
+
+    Note that repeat counts are reset at the end of a row, so if a 0 run
+    extends to the end of a row, a large repeat count may be used.
+
+    The reason for starting the run counts at 8 is that 0 is expected to
+    be the most common symbol, and is typically encoded in 1 or 2 bits.
+
+***************************************************************************/
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libchdr/huffman.h>
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+/***************************************************************************
+ *  MACROS
+ ***************************************************************************
+ */
+
+#define MAKE_LOOKUP(code,bits)  (((code) << 5) | ((bits) & 0x1f))
+
+/***************************************************************************
+ *  IMPLEMENTATION
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ *  huffman_context_base - create an encoding/
+ *  decoding context
+ *-------------------------------------------------
+ */
+
+struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)
+{
+       struct huffman_decoder* decoder = NULL;
+
+       /* limit to 24 bits */
+       if (maxbits > 24)
+               return NULL;
+
+       decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder));
+       decoder->numcodes = numcodes;
+       decoder->maxbits = maxbits;
+       decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits));
+       decoder->huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes);
+       decoder->datahisto = NULL;
+       decoder->prevdata = 0;
+       decoder->rleremaining = 0;
+       return decoder;
+}
+
+void delete_huffman_decoder(struct huffman_decoder* decoder)
+{
+       if (decoder != NULL)
+       {
+               if (decoder->lookup != NULL)
+                       free(decoder->lookup);
+               if (decoder->huffnode != NULL)
+                       free(decoder->huffnode);
+               free(decoder);
+       }
+}
+
+/*-------------------------------------------------
+ *  decode_one - decode a single code from the
+ *  huffman stream
+ *-------------------------------------------------
+ */
+
+uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf)
+{
+       /* peek ahead to get maxbits worth of data */
+       uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits);
+
+       /* look it up, then remove the actual number of bits for this code */
+       lookup_value lookup = decoder->lookup[bits];
+       bitstream_remove(bitbuf, lookup & 0x1f);
+
+       /* return the value */
+       return lookup >> 5;
+}
+
+/*-------------------------------------------------
+ *  import_tree_rle - import an RLE-encoded
+ *  huffman tree from a source data stream
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)
+{
+       int numbits, curnode;
+       enum huffman_error error;
+
+       /* bits per entry depends on the maxbits */
+       if (decoder->maxbits >= 16)
+               numbits = 5;
+       else if (decoder->maxbits >= 8)
+               numbits = 4;
+       else
+               numbits = 3;
+
+       /* loop until we read all the nodes */
+       for (curnode = 0; curnode < decoder->numcodes; )
+       {
+               /* a non-one value is just raw */
+               int nodebits = bitstream_read(bitbuf, numbits);
+               if (nodebits != 1)
+                       decoder->huffnode[curnode++].numbits = nodebits;
+
+               /* a one value is an escape code */
+               else
+               {
+                       /* a double 1 is just a single 1 */
+                       nodebits = bitstream_read(bitbuf, numbits);
+                       if (nodebits == 1)
+                               decoder->huffnode[curnode++].numbits = nodebits;
+
+                       /* otherwise, we need one for value for the repeat count */
+                       else
+                       {
+                               int repcount = bitstream_read(bitbuf, numbits) + 3;
+                               while (repcount--)
+                                       decoder->huffnode[curnode++].numbits = nodebits;
+                       }
+               }
+       }
+
+       /* make sure we ended up with the right number */
+       if (curnode != decoder->numcodes)
+               return HUFFERR_INVALID_DATA;
+
+       /* assign canonical codes for all nodes based on their code lengths */
+       error = huffman_assign_canonical_codes(decoder);
+       if (error != HUFFERR_NONE)
+               return error;
+
+       /* build the lookup table */
+       huffman_build_lookup_table(decoder);
+
+       /* determine final input length and report errors */
+       return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ *  import_tree_huffman - import a huffman-encoded
+ *  huffman tree from a source data stream
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)
+{
+       int start;
+       int last = 0;
+       int count = 0;
+       int index;
+       int curcode;
+       uint8_t rlefullbits = 0;
+       uint32_t temp;
+       enum huffman_error error;
+       /* start by parsing the lengths for the small tree */
+       struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);
+       smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);
+       start = bitstream_read(bitbuf, 3) + 1;
+       for (index = 1; index < 24; index++)
+       {
+               if (index < start || count == 7)
+                       smallhuff->huffnode[index].numbits = 0;
+               else
+               {
+                       count = bitstream_read(bitbuf, 3);
+                       smallhuff->huffnode[index].numbits = (count == 7) ? 0 : count;
+               }
+       }
+
+       /* then regenerate the tree */
+       error = huffman_assign_canonical_codes(smallhuff);
+       if (error != HUFFERR_NONE)
+               return error;
+       huffman_build_lookup_table(smallhuff);
+
+       /* determine the maximum length of an RLE count */
+       temp = decoder->numcodes - 9;
+       while (temp != 0)
+               temp >>= 1, rlefullbits++;
+
+       /* now process the rest of the data */
+       for (curcode = 0; curcode < decoder->numcodes; )
+       {
+               int value = huffman_decode_one(smallhuff, bitbuf);
+               if (value != 0)
+                       decoder->huffnode[curcode++].numbits = last = value - 1;
+               else
+               {
+                       int count = bitstream_read(bitbuf, 3) + 2;
+                       if (count == 7+2)
+                               count += bitstream_read(bitbuf, rlefullbits);
+                       for ( ; count != 0 && curcode < decoder->numcodes; count--)
+                               decoder->huffnode[curcode++].numbits = last;
+               }
+       }
+
+       /* make sure we ended up with the right number */
+       if (curcode != decoder->numcodes)
+               return HUFFERR_INVALID_DATA;
+
+       /* assign canonical codes for all nodes based on their code lengths */
+       error = huffman_assign_canonical_codes(decoder);
+       if (error != HUFFERR_NONE)
+               return error;
+
+       /* build the lookup table */
+       huffman_build_lookup_table(decoder);
+
+       /* determine final input length and report errors */
+       return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+/*-------------------------------------------------
+ *  compute_tree_from_histo - common backend for
+ *  computing a tree based on the data histogram
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)
+{
+       int i;
+       uint32_t lowerweight;
+       uint32_t upperweight;
+       /* compute the number of data items in the histogram */
+       uint32_t sdatacount = 0;
+       for (i = 0; i < decoder->numcodes; i++)
+               sdatacount += decoder->datahisto[i];
+
+       /* binary search to achieve the optimum encoding */
+       lowerweight = 0;
+       upperweight = sdatacount * 2;
+       while (1)
+       {
+               /* build a tree using the current weight */
+               uint32_t curweight = (upperweight + lowerweight) / 2;
+               int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight);
+
+               /* apply binary search here */
+               if (curmaxbits <= decoder->maxbits)
+               {
+                       lowerweight = curweight;
+
+                       /* early out if it worked with the raw weights, or if we're done searching */
+                       if (curweight == sdatacount || (upperweight - lowerweight) <= 1)
+                               break;
+               }
+               else
+                       upperweight = curweight;
+       }
+
+       /* assign canonical codes for all nodes based on their code lengths */
+       return huffman_assign_canonical_codes(decoder);
+}
+
+/***************************************************************************
+ *  INTERNAL FUNCTIONS
+ ***************************************************************************
+ */
+
+/*-------------------------------------------------
+ *  tree_node_compare - compare two tree nodes
+ *  by weight
+ *-------------------------------------------------
+ */
+
+static int huffman_tree_node_compare(const void *item1, const void *item2)
+{
+       const struct node_t *node1 = *(const struct node_t **)item1;
+       const struct node_t *node2 = *(const struct node_t **)item2;
+       if (node2->weight != node1->weight)
+               return node2->weight - node1->weight;
+       if (node2->bits - node1->bits == 0)
+               fprintf(stderr, "identical node sort keys, should not happen!\n");
+       return (int)node1->bits - (int)node2->bits;
+}
+
+/*-------------------------------------------------
+ *  build_tree - build a huffman tree based on the
+ *  data distribution
+ *-------------------------------------------------
+ */
+
+int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)
+{
+       int curcode;
+       int nextalloc;
+       int listitems = 0;
+       int maxbits = 0;
+       /* make a list of all non-zero nodes */
+       struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2);
+       memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0]));
+       for (curcode = 0; curcode < decoder->numcodes; curcode++)
+               if (decoder->datahisto[curcode] != 0)
+               {
+                       list[listitems++] = &decoder->huffnode[curcode];
+                       decoder->huffnode[curcode].count = decoder->datahisto[curcode];
+                       decoder->huffnode[curcode].bits = curcode;
+
+                       /* scale the weight by the current effective length, ensuring we don't go to 0 */
+                       decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);
+                       if (decoder->huffnode[curcode].weight == 0)
+                               decoder->huffnode[curcode].weight = 1;
+               }
+
+#if 0
+        fprintf(stderr, "Pre-sort:\n");
+        for (int i = 0; i < listitems; i++) {
+            fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
+        }
+#endif
+
+       /* sort the list by weight, largest weight first */
+       qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);
+
+#if 0
+        fprintf(stderr, "Post-sort:\n");
+        for (int i = 0; i < listitems; i++) {
+            fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
+        }
+        fprintf(stderr, "===================\n");
+#endif
+
+       /* now build the tree */
+       nextalloc = decoder->numcodes;
+       while (listitems > 1)
+       {
+               int curitem;
+               /* remove lowest two items */
+               struct node_t* node1 = &(*list[--listitems]);
+               struct node_t* node0 = &(*list[--listitems]);
+
+               /* create new node */
+               struct node_t* newnode = &decoder->huffnode[nextalloc++];
+               newnode->parent = NULL;
+               node0->parent = node1->parent = newnode;
+               newnode->weight = node0->weight + node1->weight;
+
+               /* insert into list at appropriate location */
+               for (curitem = 0; curitem < listitems; curitem++)
+                       if (newnode->weight > list[curitem]->weight)
+                       {
+                               memmove(&list[curitem+1], &list[curitem], (listitems - curitem) * sizeof(list[0]));
+                               break;
+                       }
+               list[curitem] = newnode;
+               listitems++;
+       }
+
+       /* compute the number of bits in each code, and fill in another histogram */
+       for (curcode = 0; curcode < decoder->numcodes; curcode++)
+       {
+               struct node_t *curnode;
+               struct node_t* node = &decoder->huffnode[curcode];
+               node->numbits = 0;
+               node->bits = 0;
+
+               /* if we have a non-zero weight, compute the number of bits */
+               if (node->weight > 0)
+               {
+                       /* determine the number of bits for this node */
+                       for (curnode = node; curnode->parent != NULL; curnode = curnode->parent)
+                               node->numbits++;
+                       if (node->numbits == 0)
+                               node->numbits = 1;
+
+                       /* keep track of the max */
+                       maxbits = MAX(maxbits, ((int)node->numbits));
+               }
+       }
+       return maxbits;
+}
+
+/*-------------------------------------------------
+ *  assign_canonical_codes - assign canonical codes
+ *  to all the nodes based on the number of bits
+ *  in each
+ *-------------------------------------------------
+ */
+
+enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)
+{
+       int curcode, codelen;
+       uint32_t curstart = 0;
+       /* build up a histogram of bit lengths */
+       uint32_t bithisto[33] = { 0 };
+       for (curcode = 0; curcode < decoder->numcodes; curcode++)
+       {
+               struct node_t* node = &decoder->huffnode[curcode];
+               if (node->numbits > decoder->maxbits)
+                       return HUFFERR_INTERNAL_INCONSISTENCY;
+               if (node->numbits <= 32)
+                       bithisto[node->numbits]++;
+       }
+
+       /* for each code length, determine the starting code number */
+       for (codelen = 32; codelen > 0; codelen--)
+       {
+               uint32_t nextstart = (curstart + bithisto[codelen]) >> 1;
+               if (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen]))
+                       return HUFFERR_INTERNAL_INCONSISTENCY;
+               bithisto[codelen] = curstart;
+               curstart = nextstart;
+       }
+
+       /* now assign canonical codes */
+       for (curcode = 0; curcode < decoder->numcodes; curcode++)
+       {
+               struct node_t* node = &decoder->huffnode[curcode];
+               if (node->numbits > 0)
+                       node->bits = bithisto[node->numbits]++;
+       }
+       return HUFFERR_NONE;
+}
+
+/*-------------------------------------------------
+ *  build_lookup_table - build a lookup table for
+ *  fast decoding
+ *-------------------------------------------------
+ */
+
+void huffman_build_lookup_table(struct huffman_decoder* decoder)
+{
+       int curcode;
+       /* iterate over all codes */
+       for (curcode = 0; curcode < decoder->numcodes; curcode++)
+       {
+               /* process all nodes which have non-zero bits */
+               struct node_t* node = &decoder->huffnode[curcode];
+               if (node->numbits > 0)
+               {
+         int shift;
+         lookup_value *dest;
+         lookup_value *destend;
+                       /* set up the entry */
+                       lookup_value value = MAKE_LOOKUP(curcode, node->numbits);
+
+                       /* fill all matching entries */
+                       shift = decoder->maxbits - node->numbits;
+                       dest = &decoder->lookup[node->bits << shift];
+                       destend = &decoder->lookup[((node->bits + 1) << shift) - 1];
+                       while (dest <= destend)
+                               *dest++ = value;
+               }
+       }
+}
diff --git a/deps/libchdr/src/link.T b/deps/libchdr/src/link.T
new file mode 100644 (file)
index 0000000..ea37716
--- /dev/null
@@ -0,0 +1,5 @@
+{
+   global: chd_*;
+   local: *;
+};
+
diff --git a/deps/libchdr/tests/benchmark.c b/deps/libchdr/tests/benchmark.c
new file mode 100644 (file)
index 0000000..5c10bae
--- /dev/null
@@ -0,0 +1,49 @@
+#include <libchdr/chd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+int main(int argc, char** argv)
+{
+  chd_error err;
+  chd_file* file;
+  const chd_header* header;
+  void* buffer;
+  int i;
+  unsigned int totalbytes;
+  clock_t start, end;
+  double time_taken;
+
+  printf("\nlibchdr benchmark tool....");
+
+  /* Recording the starting clock tick.*/
+  start = clock(); 
+  
+  /* Sequential read all hunks */
+  err = chd_open(argv[1], CHD_OPEN_READ, NULL, &file);
+  if (err)
+       printf("\nchd_open() error: %s", chd_error_string(err));
+  header = chd_get_header(file);
+  totalbytes = header->hunkbytes * header->totalhunks;
+  buffer = malloc(header->hunkbytes);
+  for (i = 0 ; i < header->totalhunks ; i++)
+  {
+    err = chd_read(file, i, buffer);
+    if (err)
+      printf("\nchd_read() error: %s", chd_error_string(err));
+  }
+  free(buffer);
+  chd_close(file);
+
+  /* Recording the end clock tick. */
+  end = clock();
+
+  /* Calculating total time taken by the program. */
+  time_taken = ((double)(end - start)) / ((double)CLOCKS_PER_SEC);
+
+  /* Print results */
+  printf("\nRead %d bytes in %lf seconds", totalbytes, time_taken);
+  printf("\nRate is %lf MB/s", (((double)totalbytes)/(1024*1024)) / time_taken);
+  printf("\n\n");
+  return 0;
+}
diff --git a/deps/libchdr/tests/build_tests.sh b/deps/libchdr/tests/build_tests.sh
new file mode 100755 (executable)
index 0000000..8d9af6f
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+gcc benchmark.c -lchdr -o benchmark
diff --git a/deps/lightning/.gitattributes b/deps/lightning/.gitattributes
new file mode 100644 (file)
index 0000000..e8495d5
--- /dev/null
@@ -0,0 +1 @@
+ChangeLog merge=merge-changelog
diff --git a/deps/lightning/.gitignore b/deps/lightning/.gitignore
new file mode 100644 (file)
index 0000000..62ca42a
--- /dev/null
@@ -0,0 +1,33 @@
++*
+autom4te.cache
+aclocal.m4
+depcomp
+INSTALL
+Makefile
+Makefile.in
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+install-sh
+libtool
+lightning-*.tar.*
+ltmain.sh
+missing
+size
+stamp-h1
+test-driver
+check/.deps
+doc/.deps
+lib/.deps
+m4/libtool.m4
+m4/lt~obsolete.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+doc/mdate-sh
+doc/texinfo.tex
+lightning.pc
diff --git a/deps/lightning/.gitrepo b/deps/lightning/.gitrepo
new file mode 100644 (file)
index 0000000..bb1106e
--- /dev/null
@@ -0,0 +1,12 @@
+; DO NOT EDIT (unless you know what you are doing)
+;
+; This subdirectory is a git "subrepo", and this file is maintained by the
+; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
+;
+[subrepo]
+       remote = https://git.savannah.gnu.org/git/lightning.git
+       branch = master
+       commit = b0b8eb5e856c0d29053dc842e1919a2eb58c8cda
+       parent = 819f3dfc11f81f58cb52bd7b1f7cc5025791af62
+       method = merge
+       cmdver = 0.4.1
diff --git a/deps/lightning/AUTHORS b/deps/lightning/AUTHORS
new file mode 100644 (file)
index 0000000..2097c63
--- /dev/null
@@ -0,0 +1,14 @@
+Paulo Cesar Pereira de Andrade <pcpa@gnu.org>
+
+Paolo Bonzini <bonzini@gnu.org>
+
+PPC assembler by Ian Piumarta <piumarta@inria.fr>
+
+i386 assembler by Ian Piumarta <piumarta@inria.fr>
+and Gwenole Beauchesne <gb.public@free.fr>
+
+x86-64 backend by Matthew Flatt <mflatt@cs.utah.edu>
+
+Major PPC contributions by Laurent Michel <ldm@thorgal.homelinux.org>
+
+Major SPARC contributions by Ludovic Courtes <ludo@chbouib.org>
diff --git a/deps/lightning/COPYING b/deps/lightning/COPYING
new file mode 100644 (file)
index 0000000..4432540
--- /dev/null
@@ -0,0 +1,676 @@
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                      TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+  
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                    END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
diff --git a/deps/lightning/COPYING.DOC b/deps/lightning/COPYING.DOC
new file mode 100644 (file)
index 0000000..1a86456
--- /dev/null
@@ -0,0 +1,355 @@
+               GNU Free Documentation License
+                  Version 1.1, March 2000
+
+ Copyright (C) 2000  Free Software Foundation, Inc.
+     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+written document "free" in the sense of freedom: to assure everyone
+the effective freedom to copy and redistribute it, with or without
+modifying it, either commercially or noncommercially.  Secondarily,
+this License preserves for the author and publisher a way to get
+credit for their work, while not being considered responsible for
+modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work that contains a
+notice placed by the copyright holder saying it can be distributed
+under the terms of this License.  The "Document", below, refers to any
+such manual or work.  Any member of the public is a licensee, and is
+addressed as "you".
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject.  (For example, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, whose contents can be viewed and edited directly and
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup has been designed to thwart or discourage
+subsequent modification by readers is not Transparent.  A copy that is
+not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML designed for human modification.  Opaque formats include
+PostScript, PDF, proprietary formats that can be read and edited only
+by proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML produced by some word processors for output
+purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies of the Document numbering more than 100,
+and the Document's license notice requires Cover Texts, you must enclose
+the copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a publicly-accessible computer-network location containing a complete
+Transparent copy of the Document, free of added material, which the
+general network-using public has access to download anonymously at no
+charge using public-standard network protocols.  If you use the latter
+option, you must take reasonably prudent steps, when you begin
+distribution of Opaque copies in quantity, to ensure that this
+Transparent copy will remain thus accessible at the stated location
+until at least one year after the last time you distribute an Opaque
+copy (directly or through your agents or retailers) of that edition to
+the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+   from that of the Document, and from those of previous versions
+   (which should, if there were any, be listed in the History section
+   of the Document).  You may use the same title as a previous version
+   if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+   responsible for authorship of the modifications in the Modified
+   Version, together with at least five of the principal authors of the
+   Document (all of its principal authors, if it has less than five).
+C. State on the Title page the name of the publisher of the
+   Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+   adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+   giving the public permission to use the Modified Version under the
+   terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+   and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section entitled "History", and its title, and add to
+   it an item stating at least the title, year, new authors, and
+   publisher of the Modified Version as given on the Title Page.  If
+   there is no section entitled "History" in the Document, create one
+   stating the title, year, authors, and publisher of the Document as
+   given on its Title Page, then add an item describing the Modified
+   Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+   public access to a Transparent copy of the Document, and likewise
+   the network locations given in the Document for previous versions
+   it was based on.  These may be placed in the "History" section.
+   You may omit a network location for a work that was published at
+   least four years before the Document itself, or if the original
+   publisher of the version it refers to gives permission.
+K. In any section entitled "Acknowledgements" or "Dedications",
+   preserve the section's title, and preserve in the section all the
+   substance and tone of each of the contributor acknowledgements
+   and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+   unaltered in their text and in their titles.  Section numbers
+   or the equivalent are not considered part of the section titles.
+M. Delete any section entitled "Endorsements".  Such a section
+   may not be included in the Modified Version.
+N. Do not retitle any existing section as "Endorsements"
+   or to conflict in title with any Invariant Section.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections entitled "History"
+in the various original documents, forming one section entitled
+"History"; likewise combine any sections entitled "Acknowledgements",
+and any sections entitled "Dedications".  You must delete all sections
+entitled "Endorsements."
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, does not as a whole count as a Modified Version
+of the Document, provided no compilation copyright is claimed for the
+compilation.  Such a compilation is called an "aggregate", and this
+License does not apply to the other self-contained works thus compiled
+with the Document, on account of their being thus compiled, if they
+are not themselves derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one quarter
+of the entire aggregate, the Document's Cover Texts may be placed on
+covers that surround only the Document within the aggregate.
+Otherwise they must appear on covers around the whole aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License provided that you also include the
+original English version of this License.  In case of a disagreement
+between the translation and the original English version of this
+License, the original English version will prevail.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License.  Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License.  However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.  See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+      Copyright (c)  YEAR  YOUR NAME.
+      Permission is granted to copy, distribute and/or modify this document
+      under the terms of the GNU Free Documentation License, Version 1.1
+      or any later version published by the Free Software Foundation;
+      with the Invariant Sections being LIST THEIR TITLES, with the
+      Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+      A copy of the license is included in the section entitled "GNU
+      Free Documentation License".
+
+If you have no Invariant Sections, write "with no Invariant Sections"
+instead of saying which ones are invariant.  If you have no
+Front-Cover Texts, write "no Front-Cover Texts" instead of
+"Front-Cover Texts being LIST"; likewise for Back-Cover Texts.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/deps/lightning/COPYING.LESSER b/deps/lightning/COPYING.LESSER
new file mode 100644 (file)
index 0000000..fc8a5de
--- /dev/null
@@ -0,0 +1,165 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions. 
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version. 
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/deps/lightning/ChangeLog b/deps/lightning/ChangeLog
new file mode 100644 (file)
index 0000000..76cac91
--- /dev/null
@@ -0,0 +1,4148 @@
+2020-23-01 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Add a proper fix to the condition of considering
+       a register dead at entry of a block when it modifies the register
+       !after! a branch to a target where it is live.
+       The correction is just to split blocks on branches. It uses an
+       extra label per branch, but makes following the code simpler and
+       avoid costly searches.
+
+2020-22-01 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Correct a special condition of a register
+       only assigned in a block, and incorrectly marked as dead before
+       a jump where the register is live.
+
+2019-10-04 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c, include/lightning/jit_private.h,
+       include/lightning/jit_x86.h, lib/jit_x86-cpu.c, lib/jit_x86-sz.c,
+       lib/jit_x86.c: Correct issues with MinGW64 that defines _WIN32
+       and needs long long for jit_word_t.
+
+2019-09-16 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Do not add registers that are never modified
+       to the set of registers to scan for live range, what might
+       consume a lot of cpu time, doing nothing.
+
+2019-09-16 Marc Nieper-WiÃkirchen <marc@nieper-wisskirchen.de>
+
+       * include/lightning/jit_x86.h, lib/jit_x86.c: Correct x86_64
+       backend, made %r12 a callee-save register as dictated by the
+       System V AMD64 ABI.
+
+2019-09-16 Paulo Andrade <pcpa@gnu.org>
+
+       * Makefile.am: Do not force CFLAGS for the get_jit_size target.
+       * check/lightning.c: Drop __ppc__ check.
+       * include/lightning.h.in: Drop __ppc__ check. Add new
+       jit_flag_vararg flag, for special case in powerpc 32 bit using
+        the SYSV abi, and need to pass an extra argument during code
+       generation.
+       * include/lightning/jit_ppc.c: Drop __ppc_ check. Remove the
+       ABI_ELFv2 macro, as it now directly checks for the _CALL_ELF
+       value when/if appropriate.
+       * include/lightning/jit_private.h: Drop __ppc_ check. Check for
+       _CALL_AIXDESC to define extra data to handle function
+       descriptors.
+       * lib/jit_ppc-cpu.c: Update to check for _CALL_SYSV; assume
+       !_CALL_SYSV == (_CALL_AIX || _CALL_LINUX). Significant code
+       rework for the SYSV abi.
+       * lib/jit_ppc-sz.c: Update for the SYSV abi.
+       * lib/jit_ppc.c: Update for the SYSV abi. Add matching va_list
+       type. Drop __ppc__ check.
+       * lib/jit_size.c: Drop __ppc_ check.
+       * lib/lightning.c: Drop __ppc__ check. Add proper check for
+       __powerpc__ and _CALL_AIXDESC to manage function descriptors.
+       * lib/size.c: Update to drop __pppc_ check and SYSV abi.
+
+2019-08-30 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_mips-cpu.c: Use JALR to get the same effect as JR, as
+       in mips32r6 JR generates an illegal instruction. Thanks to
+       Bruno Haible for providing a patch and the information, reported at
+       https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=925129
+       * THANKS: update.
+
+2019-08-29 Marc Nieper-WiÃkirchen <marc@nieper-wisskirchen.de>
+
+       * include/lightning/jit_private.h: Move definition of offsetof
+       from the public header file here.
+
+       * configure.ac, include/Makefile.am, include/lightning.h,
+       include/lightning.h.in: Generate lightning.h from lightning.in.h
+       and remove the dependence on config.h from the public header file.
+
+2019-06-04 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_riscv.h, lib/jit_riscv-cpu.c,
+       lib/jit_riscv-fpu.c, lib/jit_riscv-sz.c, lib/jit_riscv.c:
+       Implement riscv port. Only 64 bit Linux supported. Built on
+       Fedora 28 image.
+
+       * check/all.tst, check/float.tst, configure.ac, include/lightning.h,
+       include/lightning/Makefile.am, include/lightning/jit_private.h,
+       lib/Makefile.am, lib/jit_disasm.c, lib/jit_size.c, lib/lightning.c:
+       Minor updates for the new riscv port.
+
+2019-06-04 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_alpha.c lib/jit_ia64.c lib/jit_mips.c lib/jit_sparc.c:
+       Correct assertion of _jitc->regarg after emiting an instruction.
+       jit_carry may be set, but not an argument to the current instruction.
+
+2019-06-01 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Correct assertion on jit_unget_reg when the
+       argument is jit_carry, and jit_carry was not used in the
+       instruction.
+
+2019-06-01 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h: Remove no longer need
+       setmask field of jit_block_t and blockmask from jit_compiler_t.
+
+       * lib/lightning.c: Rework of register live and unknown state
+       information during jit generation. It no longer recurses nor
+       do dangerous bit unset of registers in unknown state. The
+       only pitfall known, that must be taken care now is that jmpr
+       (or jmpi to not a jit node) is treated as a function call, as
+       otherwise it would need to consider all registers live, and
+       spill/reload during all jit generation.
+
+2018-12-28 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_disasm.c: Release bfd handle. Thanks for patch to
+       Marc Nieper-Wißkirchen.
+
+2018-08-30 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_disasm.c: Add hints to select hppa disassembler.
+
+       * lib/jit_hppa-cpu.c: Correct address of vastart when all
+       argument registers were used as non vararg arguments.
+
+       * lib/jit_hppa-fpu.c: Disable load/store of rv,ix,rb where
+       rv is the value, ix is an register or integer offset and rb
+       is a base register. These should be better tested, as they do
+       not work on all environments (fail on qemu-hppa).
+
+2018-04-20 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h: Add new register classes to
+       flag float registers and double only registers, required for sparc64
+       where only low 32 bit fpr registers can be used for single precision
+       operations.
+       Add new 128 bit jit_regset_t type for sparc64 register set.
+
+       * include/lightning/jit_sparc.h, lib/jit_sparc-cpu.c, lib/jit_sparc-fpu.c,
+       lib/jit_sparc-sz.c, lib/jit_sparc.c: Update for 64 bits sparc.
+
+       * lib/lightning.c: Update for new jit_regset_t required for sparc64.
+
+2018-02-26 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c, include/lightning.h: Add the new jit_va_push
+       interface. That should be called when passing a va_list to a C
+       function. This is required because on Alpha a va_list is passed
+       by value, and lightning does not know about data types, so, cannot
+       understand it is pushing a va_list as argument.
+
+       * lib/jit_names.c, lib/lightning.c: Minor changes for the new
+       jit_code_va_push.
+
+       * check/cva_list.c: Update only test case using jit_va_push, to
+       pass a va_list to a C function.
+
+       doc/body.texi: Better documentation of the varargs interface.
+
+       * jit_alpha.c, jit_alpha-cpu.c: Update to properly push a
+       C va_list and correctly calculate varargs offset.
+
+       * lib/jit_aarch64-sz.c, lib/jit_aarch64.c, lib/jit_alpha-sz.c,
+       lib/jit_arm-sz.c, lib/jit_arm.c, lib/jit_hppa-sz.c, lib/jit_hppa.c,
+       lib/jit_ia64-sz.c, lib/jit_ia64.c, lib/jit_mips-sz.c, lib/jit_mips.c,
+       lib/jit_ppc-sz.c, lib/jit_ppc.c, lib/jit_s390-sz.c, lib/jit_s390.c,
+       lib/jit_sparc-sz.c, lib/jit_sparc.c, lib/jit_x86-sz.c, lib/jit_x86.c:
+       Update for the new jit_va_push interface.
+
+2018-02-22 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_alpha-cpu.c: Always set t12 to the address of the
+       current function, to properly work on all systems. Previously
+       the shortcut did only work on Tru64. For Linux and glibc the
+       change is required.
+
+2018-02-22 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64.c, lib/jit_alpha.c, lib/jit_arm.c,
+       lib/jit_mips.c, lib/jit_ppc.c, lib/jit_sparc.c, lib/jit_x86.c:
+       Correct wrong logic in usage of jit_live in jit_retr. The
+       problem is that if a temporary is required during epilog,
+       the return register might be allocated, so, jit_live must always
+       be used.
+
+2018-01-31 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Avoid deep recursions when computing live
+       register ranges.
+
+2018-01-31 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_mips-cpu.c: Correct frame size and varargs
+       initialization for the n32 abi.
+       * lib/jit_mips.c, lib/jit_mips-fpu.c: Correct 32 bit abis
+       in big-endian.
+
+2017-09-13 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac: Add check for binutils 2.29 prototype to the
+       disassembler function.
+       * lib/jit_disasm.c: Adapt for binutils 2.29 change.
+
+2017-06-09 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h, lib/lightning.c: Add a
+       second pass from start when computing register live ranges.
+       This should be used temporarily, and is required for certain
+       loop constructs, with several consecutive blocks not referencing
+       a live register.
+
+2016-05-05 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Correct wrong movr simplification,
+       remove no longer needed code to set return registers live
+       and update live register set when reaching a label boundary,
+       but do not descend if the block has been already visited.
+       The later need some tuning for complex code generation, where
+       it will still have issues.
+
+2015-11-30 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Change documentation to no longer say
+       it is a variant of the Fibonacci sequence, and document
+       a proper implementation.
+       Thanks to Jon Arintok for pointing out that the Fibonacci
+       sequence generation was incorrect. It was documented, but
+       still confusing.
+
+       * check/fib.tst, check/fib.ok, check/bp.tst, check/bp.ok,
+       doc/ifib.c, doc/rbif.c: Implement a proper Fibonacci
+       sequence implementation.
+
+2015-07-03 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_mips-cpu.c: Correct definition of htonr_ul.
+       Correct prolog/epilog/va* routines to work on o64 abi.
+
+       * lib/jit_mips-fpu.c: Correct load of double literal
+       argument when not using a data buffer.
+       Remove alignment correction in vaarg_d if using the
+       new mips abi.
+
+       * lib/jit_mips.c: Correct code to allow creating variadic
+       jit functions when using the new mips abi.
+
+       * lib/jit_rewind.c: Minor adjust for rewind when using
+       the new mips abi, if there are varargs arguments in
+       registers.
+
+2015-06-06 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64-cpu.c: Search backward for the last output
+       register used, otherwise would stop too early if a float
+       argument used the slot.
+       Correct offset of first va_list argument, and use proper
+       va_list abi.
+
+       * lib/jit_ia64-fpu.c: Add new functions to move a gpr
+       to a fpr register, to counterpart the ones that move a
+       fpr to a gpr. These are required to properly implement
+       jit_getarg*_{f,d} on complex prototypes, or variadic
+       jit functions.
+
+       * lib/jit_ia64-sz.c: Update for support to jit variadic
+       functions.
+
+       * lib/jit_ia64.c: Implement proper abi for variadic
+       jit functions.
+
+2015-06-04 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_rewind.c: New file implementing generic functions
+       to "rewind", or rewrite IR code sequences.
+
+       * include/lightning.h: Add several new codes, that previously
+       were a function call, that would synthesize the operation.
+       Now, there is a code for the operation, and a new flag to
+       know an operation is synthesized.
+
+       * include/lightning/jit_private.h: Add several new macros to
+       help construct synthesized IR code sequences.
+
+       * lib/Makefile.am: Update for lib/jit_rewind.c.
+
+       * lib/jit_disasm.c: Update for a small rework on jit_node_t,
+       so that --enable-devel-disassembler does not need a change
+       in the layout of jit_node_t.
+
+       * lib/jit_names.c: Update for the new codes.
+
+       * lib/jit_print.c: Update to print more readable output, and
+       flag synthesized IR code sequences.
+
+       * lib/jit_aarch64-sz.c, lib/jit_aarch64.c,
+       lib/jit_arm-sz.c, lib/jit_arm.c, lib/jit_x86-sz.c,
+       lib/jit_x86.c: Update for new synthesized IR code sequences.
+
+       * lib/jit_ppc-cpu.c, lib/jit_ppc-fpu., lib/jit_ppc-sz.c,
+       lib/jit_ppc.c, lib/jit_mips-cpu.c, lib/jit_mips-fpu.c,
+       lib/jit_mips-sz.c, lib/jit_mips.c, lib/jit_s390-fpu.c,
+       lib/jit_s390-sz.c, lib/jit_s390.c: Update for new synthesized
+       IR code sequences and correct bugs in the initial varargs
+       implementation support.
+
+       * lib/jit_alpha-sz.c, lib/jit_alpha.c, lib/jit_hppa-sz.c,
+       lib/jit_hppa.c, lib/jit_ia64-sz.c, lib/jit_ia64.c,
+       lib/jit_sparc-sz.c, lib/jit_sparc.c: Add generic, untested
+       support for the new synthesized IR code sequences. Known
+       most likely broken right now, and should be corrected once
+       access to these hosts is available.
+
+       * lib/lightning.c: Update for new IR codes, and add support
+       for not yet existing instructions that change third argument.
+
+       * size.c: Change to use different tables for LE and BE PowerPC.
+       Correct a wrong endif for x32.
+
+2015-05-25 Paulo Andrade <pcpa@gnu.org>
+
+       * check/cva_list.c: New file implementing a test to ensure
+       the value returned by jit_va_start is a valid C va_list.
+
+       * check/va_list.ok: New simple helper file, as now the
+       va_list.tst test is enabled.
+
+       * check/va_list.tst: Rewritten for an extensive variadic
+       jit functions test.
+
+       * check/Makefile.am: Update for the new tests.
+
+       * lib/jit_arm-cpu.c, lib/jit_arm-swf.c, lib/jit_arm-vfp.c,
+       lib/jit_arm.c: Correct broken software float in a previous
+       commit. Note that the hard float abi implementation is known
+       broken at this time, for special cases involving variadic
+       functions, and should be corrected next.
+
+       lib/jit_x86-cpu.c, lib/jit_x86-sz.c, lib/jit_x86.c: Correct
+       the jit_va_list_t semantics to match C va_list.
+
+2015-05-24 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/Makefile.am: Bump library major. This is a preparation
+       for a rework that was due for quite some time, but that is
+       now required to properly implement variadic jit functions.
+       The rework is mainly required to know at prolog parsing, if
+       a function is variadic or not. This will benefit a few
+       backends, and is mandatory for the hard float arm abi.
+       The rework was already planned for quite some time, to
+       be able to use a variable stack framesize, and for leaf
+       functions optimization where applicable.
+       The change will be source compatible, but will change
+       some internals, and jit_code_t values, as some new will
+       be added.
+       The only behavior change is that, jit_arg_register_p may
+       change return value on hard float arm abi, if called before
+       or after jit_ellipsis. Common sense anyway, would say to
+       make that call after jit_ellipsis, but documentation
+       should be updated for it.
+
+2015-05-24 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64-fpu.c, lib/jit_aarch64.c: Correct base
+       aarch64 varargs code.
+
+2015-05-24 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c: Clearly run check if clang is the system
+       compiler.
+
+2015-05-20 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_sparc-cpu.c, lib/jit_sparc-fpu.c, lib/jit_sparc.c:
+       Add base support to jit vararg functions to the sparc backend.
+
+2015-05-20 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_alpha-cpu.c, lib/jit_alpha-fpu.c, lib/jit_alpha.c:
+       Add base support to jit vararg functions to the alpha backend.
+
+2015-05-19 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_hppa-cpu.c, lib/jit_hppa-fpu.c, lib/jit_hppa.c:
+       Add base support to jit vararg functions to the hppa backend.
+
+2015-05-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64-cpu.c, lib/jit_ia64-fpu.c, lib/jit_ia64.c:
+       Add base support to jit vararg functions to the ia64 backend.
+
+2015-05-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64-fpu.c, lib/jit_ia64.c: Correct movi_d_w
+       and movi_f_w implementation to work when not using a
+       data buffer. This causes the check varargs.tst to
+       work when passing "-d" to the lightning test tool.
+
+2015-05-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64.c: Implement inline assembly cache flush,
+       required on multiprocessor systems.
+
+2015-05-06 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_mips-cpu.c, lib/jit_mips-fpu.c, lib/jit_mips.c:
+       Add base support to jit vararg functions to the mips backend.
+       Currently only supported on the o32 abi, until access to a
+       n32 system is arranged.
+
+2015-05-05 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ppc-cpu.c, lib/jit_ppc-fpu.c, lib/jit_ppc.c:
+       Add base support to jit vararg functions to the PowerPC backend.
+
+2015-05-02 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_s390-cpu.c, lib/jit_s390-fpu.c, lib/jit_s390.c:
+       Add base support to jit vararg functions to the s390 backend.
+
+2015-05-01 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm-cpu.c, lib/jit_arm-swf.c, lib/jit_arm-vfp.c,
+       lib/jit_arm.c: Add base support to jit vararg
+       functions to the arm backend.
+
+2015-04-30 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64-cpu.c, lib/jit_aarch64-fpu.c,
+       lib/jit_aarch64.c: Add base support to jit vararg
+       functions to the aarch64 backend.
+
+2015-04-27 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, include/lightning/jit_private.h,
+       lib/jit_names.c, lib/lightning.c: Add initial support
+       for the new jit_va_start, jit_va_arg, jit_va_arg_d, and
+       jit_va_end interfaces. The jit_va_start call is supposed
+       to return a va_list compatible pointer, but not yet
+       decided if it will be "declared" stdarg compatible,
+       as for now only x86 support has been added (and should
+       be compatible), but issues may arise on other backends.
+
+       * check/lightning.c: Add wrappers to call the new jit_va_*
+       interfaces.
+
+       * lib/jit_x86-cpu.c, lib/jit_x86.c: Implement the new
+       jit_va_* for x86.
+
+       * lib/jit_x86-sz.c: Add fields, but not yet fully updated,
+       as this is an intermediate commit.
+
+       * lib/jit_aarch64-sz.c, lib/jit_aarch64.c,
+       lib/jit_alpha-sz.c, lib/jit_alpha.c,
+       lib/jit_arm-sz.c, lib/jit_arm.c,
+       lib/jit_hppa-sz.c, lib/jit_hppa.c,
+       lib/jit_ia64-sz.c, lib/jit_ia64.c,
+       lib/jit_mips-sz.c, lib/jit_mips.c,
+       lib/jit_ppc-sz.c, lib/jit_ppc.c,
+       lib/jit_s390-sz.c, lib/jit_s390.c,
+       lib/jit_sparc-sz.c, lib/jit_sparc.c: Prepare for the
+       new jit_va_* interfaces. Not yet implemented, and will
+       cause an assertion if used.
+
+       * check/va_list.tst: Simple early test case, that works
+       on x86_64, x32, ix86, cygwin, and cygwin64.
+
+2015-02-17 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, include/lightning/jit_private.h,
+       lib/jit_aarch64-cpu.c, lib/jit_aarch64.c,
+       lib/jit_alpha-cpu.c, lib/jit_alpha.c,
+       lib/jit_arm-cpu.c, lib/jit_arm.c,
+       lib/jit_hppa-cpu.c, lib/jit_hppa.c,
+       lib/jit_ia64-cpu.c, lib/jit_ia64.c,
+       lib/jit_mips-cpu.c, lib/jit_mips.c,
+       lib/jit_ppc-cpu.c, lib/jit_ppc.c,
+       lib/jit_s390-cpu.c, lib/jit_s390.c,
+       lib/jit_sparc-cpu.c, lib/jit_sparc.c,
+       lib/jit_x86-cpu.c, lib/jit_x86.c: Implement the new
+       jit_allocar(offs, size) interface, that receives
+       two integer registers arguments, allocates space
+       dynamically in the stack, returns the offset in
+       the first argument, and uses the second argument
+       for the size in bytes of the memory to be allocated.
+
+       * check/allocar.ok, check/allocar.tst: New files
+       implementing test cases for the new jit_allocar
+       interface.
+
+       * check/Makefile.am, check/lightning.c: Update for
+       the new test case and interface.
+
+       * doc/body.texi: Add documentation of the new
+       interface.
+
+2015-02-17 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_x86.h, lib/jit_x86-cpu.c,
+       lib/jit_x86-x87.c: No longer make st(7) available.
+       Need to keep one x87 slots empty to avoid exceptions.
+       This has the side effect of no longer needing the
+       hackish emms instruction before a function call.
+
+2015-02-16 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Remove the jit_regno_patch bitfield
+       register fields before actual emit, as it is only really
+       used before emit, otherwise, on special conditions it
+       may consider live registers as dead during code emit.
+
+2015-02-15 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-cpu.c, lib/jit_x86-sse.c, lib/jit_x86-x87.c:
+       Correct encoding of ldxr* stxr* in the x32 abi. If the
+       displacement register is negative, it would generate
+       a 64 bit instruction with a 32 bit unsigned displacement.
+
+       * check/ranger.tst, check/ranger.ok: New files, implementing
+       a test case for negative loads and stores. This is range.tst
+       converted to use registers instead of immediate offsets.
+
+       check/Makefile.am: Update for the new test case.
+
+2015-02-07 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_size.c: Preventively use at least 144 bytes
+       if JIT_INSTR_MAX is less than it. The logic is not
+       guaranteed to be 100% precise, it is mostly heuristics
+       to allocate a buffer with as close as possible size,
+       but a wrong value may cause code generation to write
+       past the end of the buffer.
+
+2015-02-03 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Correct the reason the bug in
+       simplify_stxi was not triggered before, it was due to
+       incorrectly resetting the value->code field, what was
+       causing it to never properly optimize:
+               stxi Im0 Rb0 Rt0
+               ldxi Rt1 Rb1 Im1
+       when Rb0 == Rb1, Rt0 == Rt1 and Im0 == Im1
+       There was another possible issue, that has been also
+       addressed in this commit, that would be the case of
+       Rbn == Rtn, where no redundancy removal is possible.
+
+2015-02-03 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Correct wrong check in simplify_stxi.
+       The test was incorrectly comparing the target register
+       and the displacement offset. This was a time bomb bug,
+       that would trigger in code like:
+               stxi Im0 Rb0 Rt0
+               stxi Im1 Rb1 Rt1
+       if Rb0 == Rb1 && Rt0 == Rt1 && Im0 == Rt1, that is,
+       the wrong check was Im0 == Rt1, instead of the supposed
+       Im0 == Imm1 (that was what the code mean't to do). It
+       was removing the second stxi assuming it was redundantly
+       generated; as that is not uncommon pattern on
+       translators generating jit.
+
+2015-02-02 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac, include/lightning/jit_private.h,
+       lib/jit_aarch64.c, lib/jit_alpha.c, lib/jit_arm.c,
+       lib/jit_disasm.c, lib/jit_hppa.c, lib/jit_ia64.c,
+       lib/jit_mips.c, lib/jit_ppc.c, lib/jit_print.c,
+       lib/jit_s390.c, lib/jit_sparc.c, lib/jit_x86.c: Add a new
+       --enable-devel-disassembler option, that should be used
+       during development, or lightning debug. This option
+       intermixes previous jit_print and jit_disassemble
+       output, making it easier to visualize what lightning
+       call was used, and what code was generated.
+
+2015-01-31 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm-cpu.c, lib/jit_arm.c: Only limit to 24 bit
+       displacement non conditional jump in the same jit_state_t.
+
+2015-01-19 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Reorder documentation, making jit_frame
+       and jit_tramp the lightning response to the need of
+       trampolines, continuations and tail call optimizations.
+       A pseudo code example of a factorial function was added.
+       Also added a section for description of the available
+       predicates.
+
+       * doc/fact.c: New file, implementing a simple example of
+       a translation of a trivial, recursive, tail call optimization
+       into lightning calls. This is the conversion to functional C
+       code of the example in doc/body.texi.
+
+       * doc/Makefile.am: Update for the next test case.
+
+2015-01-17 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/jit_aarch64.c,
+       lib/jit_alpha.c, lib/jit_arm-vfp.c, lib/jit_arm.c,
+       lib/jit_hppa.c, lib/jit_ia64.c, lib/jit_mips.c,
+       lib/jit_ppc.c, lib/jit_s390.c, lib/jit_sparc.c,
+       lib/jit_x86.c: Add the new jit_arg_register_p predicate.
+       The predicate is expected to be used to know if an
+       argument is in a register, what would need special
+       handling if code that can overwrite non callee save
+       registers is executed.
+
+       * check/carg.c: New test case to check consistency and
+       expected usage of jit_arg_register_p.
+
+       * check/Makefile.am: Update for new test case.
+
+2015-01-17 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_aarch64.h,
+       include/lightning/jit_alpha.h,
+       include/lightning/jit_arm.h,
+       include/lightning/jit_hppa.h,
+       include/lightning/jit_mips.h,
+        include/lightning/jit_ppc.h,
+       include/lightning/jit_s390.h,
+       include/lightning/jit_sparc.h,
+       include/lightning/jit_x86.h,
+       lib/jit_aarch64.c, lib/jit_alpha.c,
+       lib/jit_arm.c, lib/jit_hppa.c,
+       lib/jit_ia64.c, lib/jit_mips.c,
+       lib/jit_ppc.c, lib/jit_s390.c,
+       lib/jit_sparc.c, lib/jit_x86.c: Remove jit_arg_reg_p and
+       jit_arg_f_reg_p from a public header, and define it only
+       on port specific files where an integer offset is used
+       to qualify an argument identifier. Exported code expects
+       an opaque pointer (but of jit_node_t* type) to "qualify"
+       an argument identifier.
+       This patch, and the code review/simplification done during
+       it also corrected some bugs:
+       o Inconsistent jit_arg_d value of double argument after 3
+         integer arguments in arm for jit_functions; tested, C
+         functions were being properly called.
+       o Inconsistent use of getarg_{f,d} and putarg*_{f,d} on
+         s390 (32-bit) that happened to not have a proper test
+         case, as it would only happen for jit functions, and
+         tested, called C functions had proper arguments.
+       o Corrected a "last minute" correction that did not go
+         to the committed version, and would not compile on hppa,
+         due to bad _jit_putargi_d prototype definition.
+
+2015-01-17 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Correct wrong/outdated information for
+       hton*, pusharg* and ret*, and add missing documentation
+       for rsb*, qmul*, qdvi* and putarg*.
+
+2015-01-15 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac, lib/jit_disasm.c: Rewrite workaround
+       to apparent problem to initialize powerpc disassembler.
+
+2015-01-15 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/jit_aarch64.c,
+       lib/jit_alpha.c, lib/jit_arm.c, lib/jit_hppa.c,
+       lib/jit_ia64.c, lib/jit_mips.c, lib/jit_ppc.c,
+       lib/jit_s390.c, lib/jit_sparc.c, lib/jit_x86.c:
+       Implement jit_putarg*. It works as a mix of jit_getarg*
+       and jit_pusharg*, in the way that the first argument is
+       a register or immediate, and the second is a pointer
+       returned by jit_arg*. The use of the interface is to change
+       values of arguments to the current jit function.
+
+       * check/put.ok, check/put.tst: New test cases exercising
+       the new jit_putarg* interface.
+
+       * check/Makefile.am, check/lightning.c: Update for the
+       new test case and interface.
+
+2015-01-08 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_s390.h, lib/jit_s390-cpu.c,
+       lib/jit_s390-fpu.c, lib/jit_s390-sz.c, lib/jit_s390.c:
+       Renamed s390x* files to s390*.
+
+       * check/float.tst, check/lightning.c, configure.ac,
+       include/lightning.h, include/lightning/Makefile.am,
+       lib/Makefile.am, lib/jit_s390.c, lib/jit_size.c,
+       lib/lightning.c: Update for renamed files.
+
+2015-01-08 Paulo Andrade <pcpa@gnu.org>
+
+        * include/lightning.h, include/lightning/jit_private.h,
+        include/lightning/jit_s390x.h, lib/jit_disasm.c,
+        lib/jit_s390x-cpu.c, lib/jit_s390x-fpu.c, lib/jit_s390x-sz.c,
+        lib/jit_s390x.c, lib/jit_size.c, lib/lightning.c:
+       Add support for generating jit for s390 32 bit. This change
+       also removed %f15 from the list of temporaries fpr registers;
+       it was not being used, but if were, it would corrupt the
+       stack frame because the spill address would overwrite grp
+       offsets.
+
+2014-12-26 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ppc-cpu.c, lib/jit_ppc.c: Correct some endianess issues
+       on the powerpc le backend.
+
+2014-12-26 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ppc-cpu.c: Add mcrxr instruction emulation,
+       as this instruction has been phased out, and should be
+       implemented as a kernel trap.
+
+2014-12-26 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm.c: Better check for need to flush constants
+       before the pool being no longer reachable.
+
+2014-12-25 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h: Split jit_htonr in the new 3 interfaces
+       jit_htonr_us, jit_htonr_ui and jit_htonr_ul, the later only
+       available on 64 bit. The plain/untyped jit_htonr macro call
+       maps to the wordsize one.
+       * lib/jit_aarch64-cpu.c,  lib/jit_aarch64-sz.c, lib/jit_aarch64.c,
+       lib/jit_alpha-cpu.c, lib/jit_alpha-sz.c, lib/jit_alpha.c,
+       lib/jit_arm-cpu.c, lib/jit_arm-sz.c, lib/jit_arm.c,
+       lib/jit_hppa-cpu.c, lib/jit_hppa-sz.c, lib/jit_hppa.c,
+       lib/jit_ia64-cpu.c, lib/jit_ia64-sz.c, lib/jit_ia64.c,
+       lib/jit_mips-cpu.c, lib/jit_mips-sz.c, lib/jit_mips.c,
+       lib/jit_ppc-cpu.c, lib/jit_ppc-sz.c, lib/jit_ppc.c,
+       lib/jit_s390x-cpu.c, lib/jit_s390x-sz.c, lib/jit_s390x.c,
+       lib/jit_sparc-cpu.c, lib/jit_sparc-sz.c, lib/jit_sparc.c,
+       lib/jit_x86-cpu.c, lib/jit_x86-sz.c, lib/jit_x86.c:
+       Update backends for the new jit_htonr*.
+       * check/lightning.c, lib/jit_names.c, lib/lightning.c:
+       Update for the new jit_htonr* interfaces.
+       * check/Makefile.am: Update for new test cases.
+       * check/hton.ok, check/hton.tst: New test cases.
+
+2014-12-24 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h, include/lightning/jit_x86.h,
+       lib/jit_disasm.c, lib/jit_x86-cpu.c, lib/jit_x86-sse.c,
+       lib/jit_x86-sz.c, lib/jit_x86-x87.c, lib/jit_x86.c,
+       size.c: Implement support for the x32 abi. Built and
+       tested on Gentoo default/linux/amd64/13.0/x32 profile.
+
+2014-12-24 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_names.c: Add missing rsbi_f and rsbi_d strings.
+
+2014-12-21 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm.c: Call __clear_cache for every page.
+       This should only be required for older boards or
+       toolchain setup, but has been reported to be required
+       for lightning at some point.
+
+2014-12-21 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm.c: Correct check to guard overflow of index
+       of constants from program counter.
+
+2014-11-24 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Remove an optimization to calee save
+       registers that may incorrectly remove a jit_movr under
+       special conditions.
+
+2014-11-20 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_ppc.h, lib/jit_ppc-cpu.c,
+       lib/jit_ppc.c: Add initial powerpc le support.
+
+2014-11-20 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_disasm.c: Change thumb or arm disassemble based on
+       jit code before disassembly.
+
+       * lib/jit_arm-cpu.c: Correct reversed arguments to LDRD and
+       STRD instructions, and correct checking for support of those.
+
+       * lib/jit_arm-swf.c: Correct wrong use of LDRD and STRD and
+       only use those if the register is even.
+
+       * check/check.arm.swf.sh, check/check.arm4.swf.sh: New files
+       to test LDRD and STRD, as well as the alternate code path
+       when those are not available, in the .arm4. test case.
+
+       * check/Makefile.am: Update for the new test cases.
+
+2014-11-08 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h, lib/jit_aarch64.c,
+       lib/jit_alpha.c, lib/jit_arm.c, lib/jit_hppa.c,
+       lib/jit_ia64.c, lib/jit_mips.c, lib/jit_ppc.c,
+       lib/jit_s390x.c, lib/jit_sparc.c, lib/jit_x86.c:
+       Implement a private jit_flush call, that flushes
+       the cache, if applicable, aligning down to the
+       previous and up to the next page boundary.
+
+2014-11-08 Paulo Andrade <pcpa@gnu.org>
+
+       * check/ctramp.c: New file. It just repeats the test
+       of tramp.tst, but using two jit_state_t, what should
+       test possible issues with two contexts, and also validate
+       jit_tramp works on backends with function descriptions.
+
+       * check/Makefile.am: Update for new test case.
+
+2014-11-03 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_mips.h: Do not make the t9 register
+       JIT_R11 (or JIT_R7 for n32 or n64 abi) available. Previously
+       it cause problems if one expects it to not be changed in a
+       function call. For example, calling a jit function, where it
+       really does not need to be changed.
+
+2014-10-26 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64.c, lib/jit_alpha.c, lib/jit_arm.c,
+       lib/jit_hppa.c, lib/jit_ia64.c, lib/jit_mips.c, lib/jit_ppc.c,
+       lib/jit_s390x.c, lib/jit_sparc.c, lib/jit_x86.c: Add an
+       assertion to all code generation "drivers" to ensure
+       _jitc->regarg is empty or in an expected state, after
+       translation of a lightning instruction to native code.
+       This change was a brute force test to find out other cases
+       of a temporary not being release (like was happening with
+       _bmsi and _bmci on x86), but no other case was found,
+       after running make check, with assertions enabled, on all
+       backends.
+
+2014-10-26 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-cpu.c: Correct a register allocation leak in
+       _bmsi and _bmci.
+
+2014-10-25 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_disasm.c: Do not cause an fatal error if init_jit
+       fails in the jit_init_debug call.
+
+2014-10-24 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64.c, lib/jit_ppc.c: Correct handling of function
+       descriptor when first prolog is a jit_tramp prolog. The
+       test case was using the same jit_context_t, so was not
+       triggering this condition.
+
+       * lib/jit_ppc-cpu.c: Properly handle jump displacements that
+       do not fit on 24 powerpc. This required changing from previous
+       "mtlr reg, blr" to "mtctr reg, bctr" to properly handle
+       the logic to "hide" function descriptors, but that would
+       also be required as the proper jit_jmpr when/if implementing
+       optimizations to leaf functions (was working with blr because
+       it is saved/reloaded in prolog/epilog).
+
+2014-10-21 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/lightning.c: Add three predicates
+       to query information about labels. jit_forward_p(label)
+       will return non zero if the label is "forward", that is
+       need a call to jit_link(label), jit_indirect_p(label)
+       that returns non zero if the label was created with the
+       jit_indirect() call, and jit_target_p(label) that will
+       return non zero if there is at least one jump patched
+       to land at that label.
+
+2014-10-18 Paulo Andrade <pcpa@gnu.org>
+
+       * check/range.ok, check/range.tst: New test case designed
+       to catch incorrect code generation, usually due to incorrect
+       test of immediate size. The test checks a large amount of
+       encodings in "power of two" boundaries. This test exorcises
+       a significant amount of code paths that was previously not
+       tested.
+
+       * check/Makefile.am: Add range test to make check target.
+
+       * lib/jit_aarch64-cpu.c: Correct wrong address calculation
+       for stxi_c, stxi_s, stxi_i and stxi_l when the offset is
+       too large.
+
+        * lib/jit_mips-fpu.c: Correct wrong size test to check if
+       an immediate can be encoded in a float or double store.
+
+       * lib/jit_s390x-cpu.c: Correct inverted encoding to stxi_s
+       when the offset cannot be encoded, and fallbacks to an
+       alternate encoding in 2 instructions.
+
+2014-10-17 Paulo Andrade <pcpa@gnu.org>
+
+       * check/alu_rsb.ok, check/alu_rsb.tst: New files implementing
+       tests for jit_rsb*.
+
+       * check/Makefile.am, check/lightning.c, include/lightning.h,
+       lib/jit_aarch64-cpu.c, lib/jit_aarch64-fpu.c, lib/jit_aarch64-sz.c,
+       lib/jit_aarch64.c, lib/jit_alpha-cpu.c, lib/jit_alpha-fpu.c,
+       lib/jit_alpha-sz.c, lib/jit_alpha.c, lib/jit_arm-cpu.c,
+       lib/jit_arm-swf.c, lib/jit_arm-sz.c, lib/jit_arm-vfp.c,
+       lib/jit_arm.c, lib/jit_hppa-cpu.c, lib/jit_hppa-fpu.c,
+       lib/jit_hppa-sz.c, lib/jit_hppa.c, lib/jit_ia64-cpu.c,
+       lib/jit_ia64-fpu.c, lib/jit_ia64-sz.c, lib/jit_ia64.c,
+       lib/jit_mips-cpu.c, lib/jit_mips-fpu.c, lib/jit_mips-sz.c,
+       lib/jit_mips.c, lib/jit_names.c, lib/jit_ppc-cpu.c,
+       lib/jit_ppc-fpu.c, lib/jit_ppc-sz.c, lib/jit_ppc.c,
+       lib/jit_s390x-cpu.c, lib/jit_s390x-fpu.c, lib/jit_s390x-sz.c,
+       lib/jit_s390x.c, lib/jit_sparc-cpu.c, lib/jit_sparc-fpu.c,
+       lib/jit_sparc-sz.c, lib/jit_sparc.c, lib/jit_x86-cpu.c,
+       lib/jit_x86-sse.c, lib/jit_x86-sz.c, lib/jit_x86-x87.c,
+       lib/jit_x86.c, lib/lightning.c: Implement jit_rsb*. This
+       was a missing lightning 1.x interface, that on most
+       backends is synthesized, but on a few backends (hppa and ia64),
+       it can generate better code as on those there is, or the
+       only instruction with an immediate is in "rsb" format
+       (left operand).
+
+2014-10-17 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_names.c: New file with single definition of string
+       representation of lightning IR codes.
+
+       * size.c: Modified to append the code name in a C comment
+       after the maximum instruction size.
+
+       * lib/jit_print.c: Minor change to not duplicate jit_names.c
+       contents.
+
+       * lib/jit_aarch64-sz.c, lib/jit_alpha-sz.c, lib/jit_arm-sz.c,
+       lib/jit_hppa-sz.c, lib/jit_ia64-sz.c, lib/jit_mips-sz.c,
+       lib/jit_ppc-sz.c, lib/jit_s390x-sz.c, lib/jit_sparc-sz.c,
+       lib/jit_x86-sz.c: Rewritten to add string representation of
+       IR codes in a C comment.
+
+2014-10-14 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64-cpu.c, lib/jit_alpha-cpu.c, lib/jit_arm-cpu.c,
+       lib/jit_hppa-cpu.c, lib/jit_mips-cpu.c, lib/jit_ppc-cpu.c,
+       lib/jit_sparc-cpu.c: Implement or correct the internal
+       nop(count) call that receives an argument that tells the
+       modulo bytes to align the code for the next instruction.
+
+       * include/lightning.h, lib/lightning.c, lib/jit_aarch64.c,
+       lib/jit_alpha.c, lib/jit_arm.c, lib/jit_hppa.c, lib/jit_ia64.c,
+       lib/jit_mips.c, lib/jit_ppc.c, lib/jit_s390x.c, lib/jit_sparc.c,
+       lib/jit_x86.c: Implement the new jit_align() call that receive
+       an argument, that tells the modulo, in bytes, to align the
+       next instruction. In most backends the only value that makes
+       a difference is a value that matches sizeof(void*), as all
+       other values usually are already automatically aligned in
+       labels, but not guaranteed to be aligned at word size bytes.
+
+       * check/align.ok, check/align.tst: New files, implementing
+       a simple test for the new jit_align() interface.
+
+       * check/Makefile.am, check/lightning.c, lib/jit_aarch64-sz.c,
+       lib/jit_alpha-sz.c, lib/jit_arm-sz.c, lib/jit_hppa-sz.c,
+       lib/jit_ia64-sz.c, lib/jit_mips-sz.c, lib/jit_ppc-sz.c,
+       lib/jit_print.c, lib/jit_s390x-sz.c, lib/jit_sparc-sz.c,
+       lib/jit_x86-sz.c: Update for the new jit_code_align code and
+       the jit_align() interface.
+
+2014-10-13 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/jit_size.c, size.c: Use a
+       symbolic value for the last IR code.
+
+2014-10-12 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, include/lightning/jit_private.h,
+       lib/jit_aarch64-cpu.c, lib/jit_alpha-cpu.c, lib/jit_arm-cpu.c,
+       lib/jit_hppa-cpu.c, lib/jit_ia64-cpu.c, lib/jit_mips-cpu.c,
+       lib/jit_ppc-cpu.c, lib/jit_s390x-cpu.c, lib/jit_sparc-cpu.c,
+       lib/jit_x86-cpu.c, lib/lightning.c: Implement the new
+       jit_frame and jit_tramp interfaces, that allow writing
+       trampoline like calls, where a single dispatcher jit buffer
+       is written, and later other jit buffers are created, with
+       the same stack frame layout as the dispatcher. This is the
+       logic that GNU Smalltalk used in lightning 1.x, and is required
+       to make a sane port for lighting 2.x.
+
+       * jit_ia64-cpu.c: Implement support for jit_frame and jit_tramp,
+       and also correct wrong encoding for B4 instructions, that
+       implement jmpr, as well as correct reverse logic in _jmpr,
+       that was moving the branch register to the jump register,
+       and not vice-versa.
+       Also, if a stack frame is to be assumed, always assume it may
+       call a function with up to 8 arguments, regardless of the
+       hint frame argument.
+
+       * lib/jit_arm.c: Add a new must_align_p() interface to ensure
+       function prologs are always aligned. This condition was
+       previously always true, somewhat by accident, but with
+       jit_tramp it is not guaranteed.
+
+       * jit_ia64-cpu.c: lib/jit_ppc.c: Add minor special handling
+       required to implement jit_tramp, where a function descriptor
+       should not be added before a prolog, as jit_tramp means omit
+       prolog.
+
+       * check/lightning.c: Update test driver for the new interfaces.
+
+       * check/Makefile.am, check/tramp.tst, check/tramp.ok: Add
+       a simple test and example of the jit_frame and jit_tramp
+       usage implementing a simple Fibonacci function using a
+       simulation of an interpreter stack and how it would handle
+       state in language specific variables.
+
+       * doc/body.texi: Add documentation for jit_frame and
+       jit_tramp.
+
+2014-09-29 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64.c, lib/jit_alpha.c, lib/jit_arm.c,
+       lib/jit_hppa.c, lib/jit_ia64.c, lib/jit_mips.c,
+       lib/jit_ppc.c, lib/jit_s390x.c, lib/jit_sparc.c,
+       lib/jit_x86.c, lib/lightning.c: Allow jit_jmpi on a
+       target that is not a node. This may lead to hard to
+       debug code generation, but is a required feature for
+       certain generators, like the ones that used lightning
+       1.2x. Note that previously, but not really well
+       documented, it was instructed to use:
+       jit_movi(rn, addr); jit_jmpr(rn);
+       but now, plain:
+       jit_patch_abs(jit_jmpi(), addr);
+       should also work.
+
+2014-09-24 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-sz.c: Generate information about instruction
+       lengths for more precise calculation of buffer size on
+       Windows x64. This change is specially important because
+       the maximum instruction length is larger than other
+       systems, what could cause an out of bounds write on
+       special conditions without this update.
+
+2014-09-24 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c: Add workaround to conflicting global
+       optind variable in cygwin binutils that have an internal
+       getopt* implementation.
+
+       * lib/jit_x86-cpu.c: Add a simple define ffsl ffs if building
+       for 32 bit and there is no ffsl function.
+
+2014-09-24 Paulo Andrade <pcpa@gnu.org>
+
+        * check/lightning.c: Add a hopefully temporary kludge to not use
+       sprintf and sscanf returned by dlsym. This is required to pass
+       the varargs test.
+
+        * include/lightning/jit_private.h: Use symbolic name for first
+       integer register argument, as this is different in sysv and
+       win64 abi.
+
+        * include/lightning/jit_x86.h: Add conditionals and definitions
+       for Windows x64 (under __CYGWIN__ preprocessor conditional).
+
+        * lib/jit_x86-cpu.c: Correct one instruction encoding bug, that
+       was working by accident. Only use rax to rdx for some byte
+       operations to work on compatibility mode (that is, to generate
+       the proper encoding, instead of actually generating encoding
+       for high byte registers, e.g. %bh).
+       Add proper prolog and epilog for windows x64.
+
+        * lib/jit_x86-sse.c: Correct a swapped rex prefix for float
+       operations.
+
+        * lib/jit_x86.c: Adjust to support Windows x64 abi.
+
+       * check/check.x87.nodata.sh: New file, previously used but that
+       was missing git.
+
+2014-09-07 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Mark all registers advertised as live, as
+       per jit_callee_save_p as live whenever reaching a jump that
+       cannot be tracked. This is a rethink of the previous commit,
+       and is a better approach, otherwise there would not be much
+       sense on relying on jit_callee_save_p if it could not be
+       trusted.
+
+       * check/jmpr.tst, check/jmpr.ok: New files implementing a very
+       simple test case, that would actually cause an assertion on
+       code before the change to only mark as live when reaching a
+       jump that could not tracked, the actually advertised as callee
+       save registers.
+
+       check/Makefile.am: Update for new jmpr test case.
+
+2014-09-01 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Do not mark all registers in unknown state
+       as live on jit_jmpr, or jit_jmpi to an absolute address. Instead,
+       treat it as a function call, and only consider JIT_Vn registers
+       as possibly live.
+
+2014-08-29 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Add a proper info menu entry for
+       GNU lightning.
+
+       * doc/version.texi: Regenerate.
+
+2014-08-16 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64-cpu.c, lib/jit_aarch64-fpu.c,
+       lib/jit_arm-cpu.c, lib/jit_arm-vfp.c,
+       lib/jit_hppa-cpu.c, lib/jit_hppa-fpu.c,
+       lib/jit_ia64-cpu.c, lib/jit_ia64-fpu.c,
+       lib/jit_mips-cpu.c, lib/jit_mips-fpu.c,
+       lib/jit_ppc-cpu.c, lib/jit_ppc-fpu.c,
+       lib/jit_s390x-cpu.c, lib/jit_s390x-fpu.c,
+       lib/jit_s390x.c, lib/jit_sparc-cpu.c,
+       lib/jit_x86-cpu.c, lib/jit_x86-sse.c,
+       lib/jit_x86-x87.c: Review generation of all branch
+       instructions and always adds the jit_class_nospill
+       bitfield for temporary registers that cannot be spilled
+       because the reload would be after a conditional jump; the
+       patch only adds an extra assertion. These conditions do
+       not happen on documented lightning usage, but can happen
+       if one uses the not exported jit_get_reg and jit_unget_reg
+       calls and cause enough register starvation.
+
+2014-08-16 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_alpha.c: Correct wrong bitmask of most argument
+       float register arguments, that were being set as callee
+       save instead of argument registers class.
+
+2014-08-16 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm-sz.c: Regenerate table of known maximum
+       instruction sizes for the software float fallback,
+       that implements "virtual" float registers in the stack
+       and operations as calls to libgcc.
+
+       * size.c: Correct typo in the generated jit_arm-sz.c file.
+
+2014-08-10 Paulo Andrade <pcpa@gnu.org>
+
+        * include/lightning/jit_alpha.h, lib/jit_alpha-cpu.c,
+        lib/jit_alpha-fpu.c, lib/jit_alpha-sz.c, lib/jit_alpha.c:
+       New files implementing a lightning Alpha port. Thanks
+       to Trent Nelson and snakebit.net staff for providing access
+       to an Alpha system.
+
+        * check/float.tst, check/lightning.c, configure.ac,
+        include/lightning.h, include/lightning/Makefile.am,
+        include/lightning/jit_private.h, lib/Makefile.am,
+        lib/jit_disasm.c, lib/jit_size.c, lib/lightning.c:
+       Minor changes to adapt for the new Alpha port.
+
+2014-08-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Always mark JIT_RET and JIT_FRET as
+       live in a function epilog. This is required because
+       on some ports a complex sequence, allocating one or more
+       registers, may be required to jump from a ret* to the
+       epilog, and the lightning api does not have annotations
+       to know if a function returns a value, or the type of
+       the return value.
+
+2014-08-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Change the correct live bitmask of
+       return registers after a function call in jit_update.
+
+2014-08-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Change assertions to have an int
+       result and correct a bad bit mask assertion.
+
+2014-08-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64.c: Correct bad setup for assertion
+       of consistency before a patch.
+
+2014-08-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_mips-cpu.c: Correct typo in the jit_bmsr
+       implementation that was using the wrong test result
+       register.
+
+2014-07-28 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_memory.c: Do not call free on NULL pointers.
+
+       * include/lightning/jit_private.h, lib/jit_note.c,
+       lib/lightning.c: Add a wrapper to memcpy and memmove
+       to not actually call those functions with a zero size
+       argument, and likely also a null src or dst.
+
+2014-07-27 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h, lib/jit_disasm.c,
+       lib/lightning.c: Remove the global jit_progname variable.
+       It was being only used in jit_init_debug, that is called
+       from init_jit, so, just pass an argument.
+
+2014-07-27 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Add note that jit_set_memory_functions
+       should be called before init_jit, because init_jit
+       itself may call the memory wrappers.
+
+2014-04-22 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm.c: Do not get confused with default settings
+       if /proc is not mounted on Linux specific code path.
+
+2014-04-09 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_aarch64.h, include/lightning/jit_arm.h,
+       include/lightning/jit_hppa.h, include/lightning/jit_ia64.h,
+       include/lightning/jit_mips.h, include/lightning/jit_ppc.h,
+       include/lightning/jit_private.h, include/lightning/jit_s390x.h,
+       include/lightning/jit_sparc.h, include/lightning/jit_x86.h:
+       Do not add jit_regset_t, JIT_RA0, and JIT_FA0 to the installed
+       header file. These types and definitions are supposed to be
+       only used internally.
+
+2014-04-05 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm-cpu.c: Only adjust stack pointer in prolog if
+       need stack space, that is, do not emit a nop instruction
+       subtracting zero from the stack pointer.
+
+2014-04-04 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_disasm.c: Correct a crash in the doc/printf example
+       on arm due to releasing the data_info information in
+       jit_clear_state. This is a special case for arm only, and
+       actually, only armv5 or older uses the data_info buffer,
+       or when forcing arm instruction set mode besides thumb
+       available.
+
+2014-12-03 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Write detailed description and examples for
+       jit_get_memory_functions, jit_set_memory_functions,
+       jit_get_code, jit_set_code, jit_get_data and jit_set_data.
+
+2014-12-03 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, include/lightning/jit_private.h,
+       lib/lightning.c: Implement the new jit_set_data() interface,
+       and the new jit_get_data() helper. Like jit_set_code(),
+       jit_realize() should be called before jit_set_data().
+       The most common usage should be jit_set_data(JIT_DISABLE_DATA
+       | JIT_DISABLE_NOTE), to force synthesize any float/double
+       constant in the stack and not generate any debug information.
+
+       * lib/jit_note.c: Minor change to debug note generation as
+       now it uses an alternate temporary data buffer during constants
+       and debug generation to accommodate the possibility of the user
+       setting an alternate data buffer.
+
+       * lib/jit_hppa-fpu.c, lib/jit_s390x.c, lib/jit_s390x-cpu.c,
+       lib/jit_s390x-fpu.c, lib/jit_sparc.c, lib/jit_sparc-fpu.c,
+       lib/jit_x86-sse.c, lib/jit_x86-x87.c: Implement jit_set_data.
+
+       * lib/jit_hppa-sz.c, lib/jit_sparc-sz.c, lib/jit_x86-sz.c,
+       lib/jit_s390x-sz.c: Update for several instructions that now
+       have a different maximum length due to jit_set_data.
+
+       * lib/jit_mips-fpu.c: Implement jit_set_data, but missing
+       validation on n32 and n64 abis (and/or big endian).
+
+       * lib/jit_mips-sz.c: Update for changes in o32.
+
+       * lib/jit_ppc-fpu.c: Implement jit_set_data, but missing
+       validation on Darwin PPC.
+
+       * lib/jit_ppc-sz.c: Update for changes in powerpc 32 and
+       64 bit.
+
+       * lib/jit_ia64-fpu.c: Implement untested jit_set_data.
+
+       * TODO: Add note to list ports that were not tested for the
+       new jit_set_data() feature, due to no longer having access
+       to them.
+
+       * check/nodata.c: New file implementing a simple test exercising
+       several different conditions created by jit_set_data().
+
+       * check/check.nodata.sh: New file implementing a wrapper
+       over the existing *.tst files, that runs all tests without
+       using a data buffer for constants; only meaningful (and
+       enabled) on architectures that used to store float/double
+       constants on a read only data buffer.
+
+       * configure.ac, check/Makefile.am: Update for the new test
+       cases.
+
+       * check/lightning.c: Implement the new "-d" option that
+       sets an internal flag to call jit_set_data() disable
+       constants and debug, that is, using only a pure code
+       buffer.
+
+2014-11-03 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, include/lightning/jit_private.h,
+       lib/lightning.c: Implement the new jit_set_code() interface,
+       that allows instructing lightning to use an alternate code
+       buffer. The new jit_realize() function should be called
+       before jit_set_code(), and usually call jit_get_code()
+       to query the amount of bytes expected to be required for
+       the code.
+
+       * lib/jit_size.c: Minor update to have less chances of
+       miscalculating the code buffer by starting the counter
+       with the size of the longest instruction instead of zero,
+       as code emit fails if at any moment less than the longest
+       instruction bytes are available.
+
+       * check/setcode.c: New file implementing some basic tests
+       of the new jit_set_code() interface.
+
+       * check/Makefile.am: Update for newer test case.
+
+2014-06-03 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/lightning.c: Add the new
+       jit_indirect() call, that returns a special label node,
+       and tells lightning that the label may be the target of
+       an indirect jump.
+
+       * doc/body.texi: Document the new jit_indirect() call, and
+       add examples of different ways to create labels and branches.
+
+2014-23-02 Paulo Andrade <pcpa@gnu.org>
+
+       *  lib/jit_x86.c: Rewrite previous patch to inline save/restore
+       because clobbering %ebx in x86 is treated as an error
+       (jit_x86.c:239:5: error: PIC register clobbered by 'ebx' in 'asm').
+
+2014-19-02 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86.c: Rewrite incorrect inline assembly that could
+       truncate a variable in a callee save register. Now it simply
+       tells gcc that the register is clobbered, instead of using a
+       *32 bit* swap with a temporary variable. The problem only
+       happens when compiling with optimization.
+
+2014-19-02 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_aarch64.h, include/lightning/jit_arm.h,
+       include/lightning/jit_hppa.h, include/lightning/jit_ia64.h,
+       include/lightning/jit_mips.h, include/lightning/jit_ppc.h,
+       include/lightning/jit_s390x.h, include/lightning/jit_sparc.h,
+       include/lightning/jit_x86.h: Change jit_regset_t to an
+       unsigned type, to allow safe right shift.
+
+       * lib/lightning.c: Rewrite jit_regset_scan1 to allow easier
+       compiler optimization.
+
+2013-12-03 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-x87.c: Correct wrong optimization when
+       loading the log(2) constant.
+
+2013-12-03 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-cpu.c: Use the emms instruction before
+       calling any function. This is particularly important
+       when using c99 complex functions as it can easily
+       overflow the x87 stack due to the way lightning uses
+       the x87 stack as a flat register file.
+
+2013-12-02 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-x87.c: Correct wrong code generation due
+       to comparing the base and not the value register with
+       %st(0) in stxi_f.
+
+2013-12-02 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-x87.c, lib/jit_x86.c: Use 8 bytes aligned
+       stack offset for float/double x87 to/from sse move.
+
+2013-11-27 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac, lib/jit_arm-swf.c, lib/jit_arm.c: Add
+       changes that should at least allow building lightning
+       on Apple iOS7.
+
+2013-10-08 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ppc-cpu.c: Correct wrong shortcut for ldxi_l with
+       a zero offset, that was calling ldr_i instead of ldr_l.
+
+2013-10-08 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_arm.h, lib/jit_arm-cpu.c: Do not use
+       by default load/store instructions that map to ldrt/strt.
+       There is already the long displacement version for positive
+       offsets, and when using a (shorter) negative offset it does
+       not map to ldrt/strt. At least on qemu strt may cause
+       reproducible, but unexpected SIGILL.
+
+2013-10-08 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm-vfp.c: Correct wrong load/store offset
+       calculation when the displacement is constant but too
+       large to use an instruction with an immediate offset.
+
+2013-10-07 Paulo Andrade <pcpa@gnu.org>
+
+       * check/self.c: Extend tests to validate jit_callee_save_p
+       does not cause an assertion on valid arguments, and test
+       extra registers defined on some backends.
+
+       * configure.ac: Do not ignore environment CFLAGS when
+       checking if need to test runtime configurable options,
+       like use x87 when sse2 is available, arm instruction set
+       instead of thumb, etc.
+
+       * include/lightning/jit_arm.h: Correct wrong jit_f macro
+       definition.
+
+       * include/lightning/jit_ia64.h, include/lightning/jit_ppc.h: 
+       Correct wrong jit_r macro definition.
+
+       * lib/jit_x86-x87.c, lib/jit_x86.c: Actually use the
+       reserved stack space for integer to/from float conversion.
+       The stack space was also changed to ensure it is 8 bytes
+       aligned. Also, for Solaris x86 in 32 bit mode, an alternate
+       truncr_d was implemented because for some reason it is
+       failing with SIGILL if using the "fisttpl" instructions,
+       that must be available on p6 or newer, but for the sake of
+       making all tests pass, implement a 486 or newer sequence
+       if "sun" is defined.
+
+2013-10-03 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_mips.h, lib/jit_mips-cpu.c,
+       lib/jit_mips-sz.c, lib/jit_mips.c, size: Build and
+       pass all test cases on Irix big endian mips using
+       the 64 bit abi.
+
+2013-10-02 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_mips.h: Add proper mips abi detection.
+
+2013-09-30 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_print.c: Do not crash if calling jit_print from
+       gdb before actually emitting code.
+
+       * lib/lightning.c: Correct misplaced check for already
+       visited blocks on conditional branches, what was preventing
+       proper merge live bit masks of forward blocks.
+
+2013-09-30 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-cpu.c: Correct not properly tested case of using
+       %r12 as index register, what was causing an invalid assertion.
+       %r12 is mapped to the "extra" JIT_R3 register, and test cases
+       only test "standard" lightning registers.
+
+2013-09-28 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64.c: Minor change to force collecting the maximum
+       instruction length in the --enable-devel-get-jit-size build
+       mode. The actual generated file did not change because the
+       sampling was large enough that it had already collected proper
+       information in the previously slightly buggy code (not forcing
+       a sync of the instructions that could be combined).
+
+2013-09-27 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm.c: Correct build when disassembler is
+       disabled.
+
+2013-09-25 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64-cpu.c, lib/jit_ia64-fpu.c: Correct some
+       off by one range checks (that were only accepting values
+       one less than the maximum allowed) and an invalid test
+       condition check that was forcing it to always use
+       indirect jumps even when reachable with an immediate
+       displacement.
+
+2013-09-24 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64-sz.c, lib/jit_arm-sz.c, lib/jit_hppa-sz.c,
+       lib/jit_ia64-sz.c, lib/jit_mips-sz.c, lib/jit_ppc-sz.c,
+       lib/jit_s390x-sz.c, lib/jit_size.c, lib/jit_sparc-sz.c,
+       lib/jit_x86-sz.c: New files implementing static tables
+       with longest known instructions length generated to match
+       a lightning instruction. These tables should make it easier
+       to make it very unlikely to ever miscalculate, or by too
+       much, the size of a code buffer.
+
+       * lib/jit_size.c: New file that aids to either collect
+       jit code size information, or use the information depending
+       on build options.
+
+       * size.c: New helper file that parses input for, and create
+       an initial jit_$arch-sz.c file, that needs some minor edit
+       for arches with multiple configurations.
+
+       * configure.ac, Makefile.am: Add the new, devel mode only
+       --enable-devel-get-jit-size configure option, that sets
+       compile time flags to collect jit code size information,
+       that will be used as input for the "noinst size program".
+
+       * lib/jit_aarch64.c, lib/jit_arm.c, lib/jit_disasm.c,
+       lib/jit_hppa.c, lib/jit_ia64.c, lib/jit_memory.c,
+       lib/jit_mips.c, lib/jit_ppc.c, lib/jit_s390x.c,
+       lib/jit_sparc.c, lib/jit_x86.c, lib/lightning.c: Minor
+       changes for the --enable-devel-get-jit-size build mode,
+       as well as the "production build mode" with jit code
+       size information.
+
+2013-09-14 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/lightning.c: Add the new
+       jit_pointer_p interface, that returns a boolean value
+       telling if the pointer argument is inside the jit
+       code buffer. This is useful to avoid the need to add
+       extra labels and calls to jit_address to figure bounds
+       of code buffer, and still keep internal data private.
+
+2013-09-13 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, include/lightning/jit_private.h,
+       lib/jit_note.c: Change the code argument of jit_get_note
+       to a jit_pointer_t and make jit_get_note a public interface.
+       It was intended so since start, as a way to map an offset
+       in the code to a function name, file name and line number
+       mapping.
+
+2013-09-11 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Correct reversed arguments in example of
+       usage in a (possibly) multi threaded, multiple jit_state_t
+       environments.
+
+       * include/lightning/jit_arm.h, include/lightning/jit_private.h,
+       lib/jit_arm-cpu.c, lib/jit_arm.c: Make a previously, non
+       documented, global state private to the related jit_state_t
+       generating code.
+
+2013-09-10 Paulo Andrade <pcpa@gnu.org>
+
+       * check/self.c, check/self.ok: New files implementing simple
+       consistency check assertions. At first validating some macros
+       that use values from different sources agree.
+
+       * check/Makefile.am: Update for the new test case.
+
+       * include/lightning.h,  lib/lightning.c: Add the new
+       jit_callee_save_p() call, that is intended to be used when
+       writing complex code using lightning, so that one does not
+       need to verify what backend is being used, or have access to
+       private data, to query if a register is callee save or not;
+       on several backends the scratch registers are actually callee
+       save.
+
+       * include/lightning/jit_aarch64.h, include/lightning/jit_arm.h,
+       include/lightning/jit_hppa.h, include/lightning/jit_mips.h,
+       include/lightning/jit_ppc.h, include/lightning/jit_sparc.h,
+       include/lightning/jit_x86.h: Add an explicit definition for
+       JIT_R3-JIT_Rn, JIT_V3-JIT_Vn and JIT_F6-JIT_Fn when applicable.
+       This allows one to write code based on "#if defined(JIT_XN)"
+       and therefore, not need to check what is the current backend
+       or have access to private data structures. This is particularly
+       useful when writing virtual machines with several specialized,
+       global registers.
+
+       * lib/jit_ia64.c: Properly flag the callee save general
+       purpose registers as such, so that jit_callee_save_p() works
+       as intended.
+
+2013-09-10 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c, configure.ac: Conditionally use the
+       code written to workaround a bug in the Hercules emulator,
+       as isnan and isinf are not available at least on HP-UX ia64.
+
+2013-09-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_s390x-cpu.c: Spill/reload correct callee save
+       float registers.
+
+2013-09-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_hppa-cpu.c: Correct code to call a function stored
+       in a register or a patched function address.
+
+2013-09-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64-cpu.c: Correct incorrect logic when restoring
+       the value of the "r2" callee save register.
+
+2013-08-29 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm-cpu.c, lib/jit_arm.c: Correct wrong test and update
+       of the thumb offset information, when checking if needing to
+       patch a jump from arm to thumb mode. The problem would happen when
+       remapping the code buffer, and the new address being lower than
+       the previous one.
+
+2013-08-26 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac: Extend FreeBSD test to also handle NetBSD.
+
+       * lib/jit_x86-cpu.c: Correct wrongly defined offset type of
+       ldxi_ui. Problem detected when building on NetBSD.
+
+       * lib/lightning.c: Adjust code to handle NetBSD mremap,
+       where arguments do not match Linux mremap.
+
+2013-08-26 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ppc.c: Correct C sequence point problem miscalculating
+       the actual function address in a function descriptor. Problem
+       happens with gcc 4.8.1 at least.
+
+2013-08-11 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_s390x-cpu.c: Correct code checking if immediate
+       fits instruction, but using the negated value.
+
+2013-07-28 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_s390x.h, lib/jit_s390x-cpu.c,
+       lib/jit_s390x-fpu.c, lib/jit_s390x.c: New files
+       implementing the new s390x port.
+
+       * configure.ac, include/lightning.h,
+       include/lightning/Makefile.am,
+       include/lightning/jit_private.h,
+       lib/Makefile.am, lib/jit_disasm.c, lib/lightning.c:
+       Minor adaptation for the new s390x backend.
+
+       * check/float.tst: Update for the s390x result of
+       truncating +Inf to integer.
+
+       * check/qalu_mul.tst: Add extra test cases to better test
+       high word of signed multiplication as the result is
+       adjust from unsigned multiplication on s390x.
+
+2013-07-28 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c: Do not assume casting a double NaN or
+       Inf to float will produce the expected float NaN or Inf.
+       This is not true at least under s390x.
+
+2013-07-28 Paulo Andrade <pcpa@gnu.org>
+
+       * check/check.arm.sh, check/check.sh, check/check.swf.sh,
+       check/check.x87.sh: Properly check test programs output,
+       not just rely on the test program self testing the results
+       and not crashing.
+
+2013-07-28 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_aarch64.c: Remove unused macros left from cut&paste
+       of jit_arm.c.
+
+2013-07-16 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_aarch64.h, lib/jit_aarch64-cpu.c,
+       lib/jit_aarch64-fpu.c, lib/jit_aarch64.c: New files
+       implementing the new aarch64 port, as a new architecture,
+       not as an expansion of the existing armv[4-7] port.
+
+       * check/lightning.c: Add aarch64 support and a small
+       change to recognize character constants as immediate
+       values.
+
+       * check/float.tst: Add aarch64 preprocessor conditionals
+       to select proper expected value when converting [+-]Inf
+       and NaN to integer.
+
+       * include/lightning/jit_arm.h, lib/jit_arm.c: Minor changes
+       to better match the new aarch64 files.
+
+       * configure.ac, include/lightning.h,
+       include/lightning/Makefile.am, include/lightning/jit_private.h,
+       lib/Makefile.am, lib/lightning.c: Minor adjustments
+       for the aarch64 port.
+
+2013-07-08 Paulo Andrade <pcpa@gnu.org>
+
+       * NEWS, THANKS, configure.ac, doc/version.texi: Update for
+       the 1.99a second alpha release.
+
+2013-06-25 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_mips.c: Correct cut&paste error that caused wrong
+       stack offset calculation for double arguments in stack in
+       the o32 abi.
+       Correct typo in the __LITTLE_ENDIAN macro name, that came
+       from cut&paste error in the original typo in lib/jit_ppc.c.
+
+       * lib/jit_ia64.c, lib/jit_ppc.c: Correct typo in the
+       __LITTLE_ENDIAN macro name.
+
+2013-06-22 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c, configure.ac, include/lightning.h,
+       lib/lightning.c: Add tests and quirks to build/detect
+       and/or work on Irix.
+
+       * include/lightning/jit_mips.h, lib/jit_mips-cpu.c,
+       lib/jit_mips-fpu.c, lib/jit_mips.c: Adapt code to run
+       in big endian mips, using the n32 abi.
+
+2013-06-18 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h: Minor extra preprocessor testing
+       to "detect" byte order on x86 solaris, that now builds
+       and pass all test cases.
+
+2013-06-18 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_sparc-cpu.c: Correct compiler warning of value
+       used before assignment. The usage is bogus as the api
+       requires always patching jumps, but the random value used
+       could cause an assertion due to invalid displacement.
+
+       * lib/jit_sparc.c: Always load and store double arguments
+       in stack as 2 float loads or stores, for safety, as unaligned
+       access is not allowed in Sparc Solaris.
+
+2013-06-14 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac: Force -mlp64 to CFLAGS on HP-UX ia64 port.
+       It is the only supported mode, and expects gcc as C compiler.
+
+       * include/lightning.h, lib/jit_ia64-cpu.c, lib/jit_ia64.c:
+       Correct ia64 port to work on HP-UX that runs it in big endian
+       mode.
+
+2013-06-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_hppa.c: Sanitize the cache synchronization inline
+       assembly code that was doing twice the work and redundantly
+       flushing the end address every loop iteration.
+
+2013-06-09 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac, check/Makefile.am, doc/Makefile.am: Do not
+       explicitly link to -ldl, but instead autodetect the library
+       with dlopen, dlsym, etc.
+
+       * check/lightning.c: Add workaround to apparently buggy
+       getopt in HP-UX that sets optind to the wrong index, and
+       use RTLD_NEXT on HP-UX instead of RTLD_DEFAULT to dlsym
+       global symbols.
+
+       * include/lightning.h: Rework definitions of wordsize and
+       byte order to detect proper values on HP-UX.
+
+       * lib/lightning.c: Minor correction to use MAP_ANONYMOUS
+       instead of MAP_ANON on HP-UX.
+
+       * lib/jit_hppa.c: Float arguments must be passed on integer
+       registers on HP-UX, not only for varargs functions.
+         Add code to properly clear instruction cache. This was
+       not required on Debian hppa port, but may have been working
+       by accident.
+
+       * lib/jit_hppa-cpu.c: Follow pattern of HP-UX binaries and
+       use bve,n instead of bv,n to return from functions.
+
+       * lib/jit_hppa-fpu.c: For some reason "fst? frX,rX,(rY)" did
+       not work on the tested computer (HP-UX B.11.23 U 9000/785 HP-UX)
+       so the code was changed, at first for __hpux only to add the
+       base and offset register and use the instruction with an
+       immediate (zero) offset.
+
+2013-06-07 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c, lib/jit_disasm.c, lib/jit_ppc-cpu.c,
+       lib/jit_ppc-fpu.c, lib/jit_ppc.c, include/lightning.h,
+       include/lightning/jit_ppc.h, include/lightning/jit_private.h:
+       Adapt code to work on 32 bit AIX ppc using gcc. Most changes
+       are basically to adapt the elf64 logic to 32 bit, as it does
+       not use the same convention of 32 bit Darwin ppc.
+
+       * check/stack.tst: Add a fake memcpy function to the test
+       case if running under AIX, as it is not available to dlsym.
+
+       * configure.ac: Check for getopt.h header, not available in
+       AIX.
+
+2013-06-01 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_hppa.h, lib/jit_hppa-cpu.c,
+       lib/jit_hppa-fpu.c, lib/jit_hppa.c: New files implementing
+       the hppa port. Built on Debian Linux PA-RISC 2.0, 32 bit.
+
+       * check/float.tst: Add preprocessor for hppa expected
+       values when converting NaN and +-Inf to an integer.
+
+       * check/ldst.inc: Ensure double load/store tests use an
+       8 byte aligned address by default.
+
+       * lib/lightning.c: Correct a bug found during tests in
+       the new port, where qmul* and qdiv* were not properly
+       setting one of the result registers as modified in the
+       function, what would be a problem if the only "write"
+       usage were the qmul* or qdiv*.
+
+       * check/varargs.tst, check/varargs.ok: Add one extra
+       interleaved integer/double test to validate proper code
+       generation in the extra case.
+
+       * check/lightning.c, configure.ac, include/lightning.h,
+       include/lightning/Makefile.am,
+       include/lightning/jit_private.h, lib/Makefile.am,
+       lib/jit_disasm.c: Update for the hppa port.
+
+2013-04-27 Paulo Andrade <pcpa@gnu.org>
+
+       * check/varargs.tst: Correct misplaced .align directive
+       that was causing the double buffer to not be aligned at
+       8 bytes.
+       * lib/jit_ia64-cpu.c:
+         Properly implement abi for excess arguments passed on
+       stack.
+         Simplify load/store with immediate displacement argument
+       with zero value.
+         Simplify some calls to "subi" changing to "addi" with
+       a negative argument.
+         Remove some #if 0'ed code, that could be useful in
+       special conditions, but the most useful one would be
+       to "optimize" "static" jit functions, but for the sake
+       of simplicity, jit functions are implemented in a way
+       that can be passed back to C code as C function pointers.
+         Add an attribute to prototypes of several unused functions.
+       These functions are defined for the sake of implementing all
+       Itanium documented instructions, but a significant amount of
+       them is not used by lightning.
+       * lib/jit_ia64-fpu.c: Simplify load/store with zero immediate
+       displacement and add unused attribute for functions not used
+       by lightning, but required to provide macros implementing all
+       Itanium documented instructions.
+       * lib/jit_ia64.c: Update for the properly implemented abi
+       for stack arguments.
+       * lib/lightning.c: Mark an unused function as such.
+
+2013-04-27 Paulo Andrade <pcpa@gnu.org>
+
+       lib/jit_ia64-cpu.c:
+         Correct immediate range check of integer comparisons when
+       inverting arguments.
+         Correct gei_u that was not decrementing immediate when
+       inverting arguments.
+         Correct b?add* and b?sub* that were not properly updating
+       the result register.
+
+2013-04-27 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64-cpu.c: Correct wrong mapping of 2 instructions
+       in "M-, stop, M-, stop" translation, that was ignoring the
+       last stop (implemented as a nop I- stop).
+
+       * lib/jit_ia64-fpu.c: Properly implement fnorm.s and fnorm.d,
+       as well as the proper integer to float or double conversion.
+
+2013-04-27 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64-cpu.c: Correct bogus implementation of ldr_T
+       for signed integers, that was using ld1.s, ld2.s and ld4.s.
+       The ".s" stands for speculative load, not sign extend.
+
+       * lib/jit_ia64-fpu.c: Correct bogus implementation of ldxr_T
+       for float and double. The third (actually, second) argument
+       is indeed added to the base register, but the base register
+       is modified. The actual M7 implementation was already correct,
+       just the ldxr_f and ldxr_d implementation that was kept in
+       a prototype state, misinterpreting what M7 does.
+
+2013-04-27 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64-cpu.c: Correct X2 pattern matching by preventing
+       it to attempt to require a stop between the L and the X
+       instruction; that is, check the registers and predicates
+       before emitting the L instruction, not after.
+
+       * lib/jit_ia64-fpu.c: Slightly simplify and correct
+       divr_f and divrd_d implementation.
+
+       * check/lightning.c: Add __ia64__ preprocessor define
+       on Itanium. 
+
+       * check/alu.inc, check/clobber.tst, check/float.tst: Define
+       several macros conditionally to __ia64__. This is required
+       because __ia64__ jit generation can use way too many memory,
+       due to not implementing instruction reordering to avoid
+       as much as possible "stops", what causes way too many nops
+       to be generated, as well as the fact that division and
+       remainder requires function calls, and float division
+       requires significant code to implement.
+
+2013-04-27 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h: Add new backend specific movr_w_d,
+       movr_d_w and movi_d_w codes as helpers to ia64 varargs
+       functions arguments.
+
+       * lib/jit_ia64-cpu.c:
+         Correct wrong encoding of A5 small integers.
+         Correct define of "mux" instruction modifiers.
+         Correct ordering of arguments and predicates of cmp_xy
+       implementation with immediate arguments; like most other
+       codes with an immediate, the immediate is the second, not
+       the third argument.
+
+       * lib/jit_ia64-fpu.c: Actual implementation of the code
+       to move to/from gpr to/from fpr, to implement varargs abi.
+
+       * lib/jit_ia64.c: Make fpr argument registers not allocatable
+       as temporaries, no need for the extra checks when there are
+       plenty registers.
+
+       * lib/jit_print.c, lib/lightning.c: Minor updates for the
+       new movr_w_d, movr_d_w and movi_d_w codes.
+
+2013-04-26 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ia64-cpu.c, lib/jit_ia64-fpu.c: Correct code to
+       also insert a stop to break an instruction group if a
+       register is written more than once in the same group.
+       This may happen if a register is argument and result of
+       some lightning call (not a real instruction). The most
+       common case should be code in the pattern:
+               movl rn=largenum
+               ...
+               mov rn=smallnum
+       where "rn" would end up holding "largenum".
+       But the problem possibly could happen in other circumstances.
+
+2013-04-26 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_ia64.h, lib/jit_ia64-cpu.c,
+       lib/jit_ia64-fpu.c, lib/jit_ia64.c:
+         Relocate JIT_Rn registers to the local registers, as, like
+       float registers, div/rem and sqrt are implemented as function
+       calls, and may overwrite non saved scratch registers.
+         Change patch_at to receive a jit_code_t instead of a
+       jit_node_t, so that it is easier to "inline" patches when
+       some instruction requires complex code to implement, e.g.
+       uneq and ltgt.
+         Correct arguments to FMA and FMA like instructions that,
+       due to a cut&paste error were passing the wrong argument
+       to the related F- implementation function.
+         Rewrite ltgt to return the proper result if one (or both)
+       of the arguments is unordered.
+
+2013-04-26 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_ia64.h, include/lightning/jit_private.h,
+       lib/jit_ia64-cpu.c, lib/jit_ia64-fpu.c, lib/jit_ia64.c,
+       lib/lightning.c: Rework code to detect need of a "stop" to
+       also handle predicates, as if a predicate is written, it
+       cannot be read in the same instruction group.
+         Use a single jit_regset_t variable for all registers when
+       checking need for a stop (increment value by 128 for
+       float registers).
+         Correct wrong "subi" implementation, as the code executed
+       is r0=im-r1, not r0=r1-im.
+         Use standard lightning 6 fpr registers, and rework to
+       use callee save float registers, that may be spill/reloaded
+       in prolog/epilog. This is required because some jit
+       instructions implementations need to call functions; currently
+       integer div/mod and float sqrt, what may change the value of
+       scratch float registers.
+         Rework point of "sync" of branches that need to return a
+       patch'able address, because the need for a "stop" before a
+       predicate read causes all branches to be the instruction
+       in slot 0, as there is no template to "stop" and branch
+       in the same instruction "bundle".
+
+2013-04-25 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_ia64.h, lib/jit_ia64-cpu.c,
+       lib/jit_ia64-fpu.c, lib/jit_ia64.c: New files implementing
+       the basic infrastructure of an Itanium port. The code
+       compiles and can generate jit for basic hello world like
+       functions.
+
+       * check/lightning.c, configure.ac, include/lightning.h,
+       include/lightning/Makefile.am, include/lightning/jit_private.h,
+       lib/Makefile.am, lib/lightning.c: Update for the Itanium
+       port.
+
+       * lib/jit_mips-cpu.c, lib/jit_mips.c: Correct typo and
+       make the jit_carry register local to the jit_state_t.
+       This matches code reviewed in the Itanium port, that
+       should use the same base logic to handle carry/borrow.
+
+2013-04-10 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h, lib/jit_arm.c,
+       lib/jit_mips-cpu.c, lib/jit_mips.c, lib/jit_ppc-cpu.c,
+       lib/jit_ppc.c, lib/jit_print.c, lib/jit_sparc-cpu.c,
+       lib/jit_sparc.c, lib/jit_x86-cpu.c, lib/jit_x86.c,
+       lib/lightning.c: Change all jit_regset macros to take
+       a pointer argument, to avoid structure copies when
+       adding a port to an architecture with more than 64
+       registers.
+
+2013-04-08 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm.c, lib/jit_ppc.c: Do not rely on __clear_cache
+       aligning to the next page boundary the end argument. It may
+       actually truncate it.
+
+2013-03-29 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h, lib/jit_arm.c, lib/jit_memory.c,
+       lib/jit_mips.c, lib/jit_ppc.c, lib/jit_sparc.c, lib/jit_x86.c,
+       lib/lightning.c: Do not start over jit generation if can grow
+       the code buffer with mremap without moving the base pointer.
+
+2013-03-29 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_memory.c: Implement a simple memory allocation wrapper
+       to allow overriding calls to malloc/calloc/realloc/free, as well
+       as ensuring all memory containing pointers is zero or points to
+       allocated memory.
+
+       * include/lightning.h, include/lightning/jit_private.h: Definitions
+       for the memory allocation wrapper.
+
+       * lib/Makefile.am: Update for new jit_memory.c file.
+
+       * lib/jit_arm.c, lib/jit_disasm.c, lib/jit_mips.c, lib/jit_note.c,
+       lib/jit_ppc.c, lib/jit_sparc.c, lib/jit_x86.c, lib/lightning.c:
+       Use the new memory allocation wrapper code.
+
+2013-03-22 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac, include/lightning/jit_private.h, lib/lightning.c:
+       Remove dependency on gmp. Only a simple bitmap was required, and
+       that was not enough reason to force linking to gmp and possible
+       complications caused by it.
+
+2013-03-10 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h: Add check for __powerpc__ defined
+       in Linux, while Darwin defines __ppc__.
+
+       * include/lightning/jit_ppc.h: Adjust register definitions
+       for Darwin 32 bit and Linux 64 bit ppc usage and/or ABI.
+
+       * include/lightning/jit_private.h: Add proper check for
+       Linux __powerpc__ and an data definition for an workaround
+       to properly handle code that starts with a jump to a "main"
+       label.
+
+       * lib/jit_disasm.c: Add extra disassembler initialization
+       for __powerpc64__.
+
+       * lib/jit_ppc-cpu.c: Add extra macros and functions, and
+       correct/adapt previous ones to handle powerpc64.
+
+       * lib/jit_ppc-fpu.c: Adapt for 64 bit wordsize. Basically
+       add conversion from/to int32/int64 and proper handling of
+       load/store offsets too large for 32 bit.
+
+       * lib/jit_ppc.c: Add calls to 64 bit codes and adaptation
+       for the PowerPC 64 bit Linux ABI.
+
+       * lib/jit_arm.c, lib/jit_mips.c, lib/jit_sparc, lib/jit_x86.c,
+       lib/lightning.c: Correct off by one error when restarting jit
+       of a function due to finding too late that needs to spill/reload
+       some register. Problem was found by accident on a very special
+       condition during PowerPC 64 code adaptation.
+
+2013-03-08 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c: Add missing ppc preprocessor definition.
+
+2013-03-06 Paulo Andrade <pcpa@gnu.org>
+
+       * check/float.tst: Comment out the int to negative infinity
+       test in mips for the moment because not all Loongson agrees
+       on the result.
+
+       * lib/jit_disasm.c: Add a test instead of an assertion
+       when loading symbols for disassembly due to a failure with
+       a simple binutils build in Debian mipsel64.
+
+2013-03-06 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h, lib/jit_arm-cpu.c,
+       lib/jit_arm.c, lib/jit_disasm.c, lib/jit_mips-cpu.c,
+       lib/jit_mips.c, lib/jit_note.c, lib/jit_ppc-cpu.c,
+       lib/jit_ppc.c, lib/jit_print.c, lib/jit_sparc-cpu.c,
+       lib/jit_sparc.c, lib/jit_x86-cpu.c, lib/jit_x86.c,
+       lib/lightning.c: Add an extra structure for data storage
+       during jit generation, and release it after generating
+       jit, to reduce a bit memory usage, and also to make it
+       easier to understand what data is available during
+       jit runtime.
+
+2013-03-06 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Make data and code buffer readonly.
+
+2013-02-20 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Fool proof validate the examples of what
+       an assembly-language programmer would write and correct the
+       wrong sparc example.
+
+2013-02-19 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Add back the SPARC code generation example.
+
+2013-02-19 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c: Remove state flag to work with partial
+       sparc port, by just disassembling if there was incomplete
+       code generation.
+
+       * jit_sparc-cpu.c: Correct wrong range check for immediate
+       integer constants (off by one bit shift).
+         Correct macro implementing equivalent "rd %y, rd" assembly.
+         Implement qmul* and qdiv*.
+
+       * jit_sparc.c: Update for qmul* and qdiv* and remove logic
+       to handle incomplete code generation during sparc port.
+
+2013-02-18 Paulo Andrade <pcpa@gnu.org>
+
+       * check/float.tst: Add sparc to list of known NaN and +-Inf
+       to integer conversion.
+
+       * check/lightning.c: Define __sparc__ to preprocessor in
+       the sparc backend.
+
+       * include/lightning/jit_private.h: Correct wrong definition
+       of emit_stxi_d, that has lived for a long time, but would
+       cause problems whenever needing to spill/reload a float
+       register.
+
+       * include/lightning/jit_sparc.h: Can only use %g2,%g3,%g4
+       for scratch variables, as other "global" registers are
+       reserved for the system, e.g. libc.
+         Reorder float register naming to make it easier to
+       access odd float registers, so that generating code for
+       pusharg and getarg is easier for the IR.
+
+       * lib/jit_mips-cpu.c, lib/jit_ppc-cpu.c: Update to match
+       new code in jit_sparc-cpu.c. It must call jit_get_reg
+       with jit_class_nospill if using the register to move
+       an unconditional branch address to it, as the reload
+       will not happen (actually could happen in the delay
+       slot...)
+
+       * lib/jit_sparc-cpu.c: Correct wrong macro definition for
+       ldxr_s.
+         Properly implement div* and implement rem. Div* needs
+       to use the y register, and rem* needs to be synthesized.
+         Correct b?sub* macro definitions.
+
+       * lib/jit_sparc-fpu.c: Correct reversed float to/from double
+       conversion.
+         Correct wrong jit_get_reg call asking for a gpr and then
+       using the fpr with that number.
+         Correct wrong branch displacement computation for
+       conditional branches.
+
+       * lib/jit_sparc.c: Correct getarg_d and pushargi_d implementation.
+         Add rem* entries to the switch converting IR to machine code.
+
+       * lib/lightning.c: Correct a problem detected when adding
+       the jit_class_nospill flag to jit_get_reg, that was caused
+       when having a branch to an "epilog" node, what would cause
+       the code to think all registers in unknown state were live,
+       while in truth, all registers in unknown state in the
+       "just after return" point are actually dead.
+
+2013-02-17 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_sparc.h, lib/jit_sparc-cpu.c,
+       lib/jit_sparc-fpu.c, lib/jit_sparc.c: New files implementing
+       the basic framework of the sparc port.
+
+       * configure.ac, include/lightning.h, include/lightning/Makefile.am,
+       include/lightning/jit_private.h, lib/jit_disasm.c: Update
+       for the sparc port framework.
+
+       * lib/jit_mips.c: Correct reversed retr/reti logic.
+
+       * lib/jit_ppc.c: Correct misspelled __LITTLE_ENDIAN.
+
+       * lib/lightning.c: Always do byte hashing in hash_data, because
+       the logic to "compress" strings causes large pointers to not
+       be guaranteed aligned at 4 byte boundaries.
+         Update for the sparc port framework.
+
+2013-02-11 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm.c: Correct jit_pushargi_f in the arm hardfp abi.
+       Most of the logic uses even numbered register numbers, so that
+       a float and a double can be used in the same register, but
+       the abi requires packing the float arguments, so jit_pushargi_f
+       needs to allocate a temporary register to modify only the
+       proper register argument (or be very smart to push two
+       immediate arguments if applicable).
+
+2013-02-11 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/lightning.c: Implement the new
+       jit_clear_state and jit_destroy_state calls. jit_clear_state
+       releases all memory not required during jit_execution; that
+       is, leaves only the mmap'ed data and code buffers allocated.
+       jit_destroy_state releases the mmap'ed buffers as well as
+       the jit_state_t object itself, that holds pointers to the
+       code and data buffers, as well as annotation pointers (for
+       disassembly or backtrace) in the data buffer.
+
+       * lib/jit_note.c: Correct invalid vector offset access.
+
+       * check/ccall.c, check/lightning.c, doc/ifib.c, doc/incr.c,
+       doc/printf.c, doc/rfib.c, doc/rpn.c: Use the new jit_clear_state
+       and jit_destroy_state calls, to demonstrate the new code to
+       release all jit memory.
+
+       * doc/body.texi: Add basic documentation and usage description
+       of jit_clear_state and jit_destroy_state.
+
+2013-02-11 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_private.h, lib/jit_note.c, lib/lightning.c:
+         Store all annotation information in the mmap'ed area reserved for
+       read only data. This adds code to not allocate memory for jit_note_t
+       objects, and to relocate jit_line_t objects and its contents after
+       calculating annotation information. The jit_line_t objects are
+       relocated because it is not possible to always calculate before
+       hand data layout because note information may be extended or
+       redundant entries removed, as well as allowed to be added in
+       non sequential order.
+         A bug was also corrected in _jit_set_note, that was causing it
+       to allocate new jit_line_t objects when not needed. It was still
+       working correctly, but allocating way more memory than required.
+
+2013-02-05 Paulo Andrade <pcpa@gnu.org>
+
+       *include/lightning.h, lib/lightning.c: Add the new jit_live code
+       to explicitly mark a register as live. It is required to avoid
+       assuming functions always return a value in the gpr and fpr return
+       register, and to avoid the need of some very specialized codes
+       that vary too much from backend to backend, to instruct the
+       optimization code the return register is live.
+
+       * lib/jit_arm.c, lib/jit_mips.c, lib/jit_ppc.c, lib/jit_print.c,
+       lib/jit_x86.c: Update for the new jit_live code.
+
+       * check/ret.ok, check/ret.tst: New files implementing a simple
+       test case that would previously fail at least in ix86/x86_64.
+
+       * check/Makefile.am: Update for new "ret" test case.
+
+2013-02-05 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ppc-cpu.c, lib/jit_ppc.c: Validate and correct
+       problems in the qmul and qdiv ppc implementation.
+
+2013-02-04 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, include/lightning/jit_private.h,
+       lib/jit_arm-cpu.c, lib/jit_arm.c, lib/jit_mips-cpu.c,
+       lib/jit_mips.c, lib/jit_ppc-cpu.c, lib/jit_ppc.c,
+       lib/jit_x86-cpu.c, lib/jit_x86.c, lib/lightning.c:
+       Implement the new qmul and qdiv instructions that return signed
+       and unsigned lo/hi multiplication result and div/rem division result.
+       These should be useful for jit translation of code that needs to
+       know if a multiplication overflows (no branch opcode added) or if
+       a division is exact (easy check if remainder is zero).
+
+       * check/lightning.c, lib/jit_print.c, check/Makefile.am,
+       check/all.tst: Update for the new qmul and qdiv instructions.
+
+       * check/qalu.inc, check/qalu_div.ok, check/qalu_div.tst,
+       check/qalu_mul.ok, check/qalu_mul.tst: New files implementing
+       simple test cases for qmul and qdiv.
+
+2013-01-30 Paulo Andrade <pcpa@gnu.org>
+
+       * doc/body.texi: Correct "jmpi" description that incorrectly
+       told it was possible to pass any address as jump target. The
+       only way to do that is "movi+jmpr".
+
+2013-01-30 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-cpu.c: Correct undefined behavior code.
+       http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56143
+
+2013-01-29 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac: Use AC_CONFIG_HEADERS instead of AC_CONFIG_HEADER
+       to have HAVE_CONFIG_H defined with latest aclocal.
+
+       * include/lightning/jit_private.h, lib/lightning.c: Add new
+       abstraction to use an heuristic to calculate amount of space
+       required for jit generation, and code to reallocate buffer if
+       did miscalculate it.
+
+       * lib/jit_arm.c, lib/jit_mips.c, lib/jit_ppc.c, lib/jit_x86.c:
+       Update to use new code to estimate and resize of required buffer
+       for jit code.
+
+       * lib/jit_x86-cpu.c: Minor cosmetic change to avoid adding a
+       non required rex prefix when calling a function pointer stored
+       in a register.
+
+2013-01-24 Paulo Andrade <pcpa@gnu.org>
+
+       * check/Makefile.am: "make debug" target should pass only
+       the main test tool program as argument for running gdb
+
+       * configure.ac: Add the --enable-assertions options.
+
+       * doc/Makefile.am, doc/body.texi, doc/lightning.texi:
+       Major rewrite of the documentation to match the current
+       implementation.
+
+       * doc/version.texi: Automatic date update.
+
+       * doc/ifib.c, doc/incr.c, doc/printf.c, doc/rfib.c, doc/rpn.c:
+       Implementation of the documentation examples, that are also
+       compiled during a normal build.
+
+       * doc/p-lightning.texi, doc/porting.texi, doc/toc.texi,
+       doc/u-lightning.texi, doc/using.texi: These files were
+       renamed in the documentation rewrite, as the documentation
+       was significantly trimmed due to full removal of the porting
+       chapters. Better porting documentation should be added but
+       for the moment it was just removed the documentation not
+       matching the implementation.
+
+2013-01-18 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_note.c: Correct bounds check and wrong code keeping
+       a pointer that could be changed after a realloc call.
+
+2013-01-18 Paulo Andrade <pcpa@gnu.org>
+
+       * check/3to2.tst, check/add.tst, check/allocai.tst, check/bp.tst,
+       check/call.tst, check/ccall.c, check/clobber.tst, check/divi.tst,
+       check/fib.tst, check/ldsti.tst, check/ldstr-c.tst, check/ldstr.tst,
+       check/ldstxi-c.tst, check/ldstxi.tst, check/ldstxr-c.tst,
+       check/ldstxr.tst, check/lightning.c, check/rpn.tst, check/stack.tst,
+       check/varargs.tst, include/lightning.h,
+       include/lightning/jit_private.h, lib/jit_arm.c, lib/jit_disasm.c,
+       lib/jit_mips.c, lib/jit_note.c, lib/jit_ppc.c, lib/jit_print.c,
+       lib/jit_x86.c, lib/lightning.c: Extend the "jit_note" abstraction
+       with the new "jit_name" call, that receives a string argument, and
+       should usually be called to mark boundaries of functions of code
+       generating jit (that is, it is not expected that the language
+       generating jit map its functions to jit functions).
+
+2013-01-17 Paulo Andrade <pcpa@gnu.org>
+
+       * check/add.tst, check/allocai.tst, check/bp.tst, check/divi.tst,
+       check/fib.tst, check/lightning.c, include/lightning/jit_arm.h,
+       include/lightning/jit_mips.h, include/lightning/jit_ppc.h,
+       include/lightning/jit_private.h, include/lightning/jit_x86.h:
+       Make JIT_RET, JIT_FRET and JIT_SP private. These should not be
+       used in any operations due to frequently having special
+       constraints (usually JIT_FRET). JIT_FP must be made available
+       because it must be used as the base register to access stack
+       space allocated with jit_allocai.
+
+2013-01-14 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/lightning.c: Add an extra align
+       argument to the jit_data call (that should be made private),
+       so that it should not align strings at 8 bytes.
+         Correct the jit_note call to include the null ending byte
+       when adding label/note names to the "jit data section".
+
+2013-01-11 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_note.c: New file implementing a simple string+integer
+       annotation, that should be used to map filename and line number
+       to offsets in the generated jit.
+
+       * include/lightning.h, lib/lightning.c: Update for the new
+       note code.
+         Add an extra mandatory argument to init_jit, that is used
+       as argument to bfd_openr.
+         Change from generic void* to char* the argument to jit_note
+       and add an extra integer argument, to map to filename and
+       line number.
+
+       * check/ccall.c, check/lightning.c, include/lightning/jit_private.h,
+       lib/jit_arm.c, lib/jit_disasm.c, lib/jit_mips.c, lib/jit_ppc.c,
+       lib/jit_print.c, lib/jit_x86.c: lib/Makefile.am: Update for the
+       new annotation code.
+
+       * configure.ac, check/Makefile.am: Update to work with latest
+       automake.
+
+2013-01-09 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/jit_arm.c, jit_mips-fpu.c,
+       lib/jit_mips.c, lib/jit_print.c, lib/jit_x86.c, lib/lightning.c:
+       Remove the jit_code_getarg_{f,d} and jit_code_pusharg{i,r}_{f,d}
+       calls, replacing them with the new, internal only, jit_movr_w_f,
+       jit_mov{r,i}_f_w, jit_movr_ww_d, and jit_mov{i,r}_d_ww, that
+       better describe the operation being done, and allow removing
+       the hackish code to detect special conditions for arm when
+       moving from/to vfp from/to a grp register pair.
+       Rename jit_code_retval_{f,d} to jit_code_x86_retval_{f,d} as
+       it is specific to 32 bit x86, and used to move abi return
+       value in x87 register to a sse register.
+
+2013-01-05 Paulo Andrade <pcpa@gnu.org>
+
+       * check/cccall.c, check/ccall.ok: New test case to validate
+       interleaved calls from/to C code and jit.
+
+       * check/Makefile.am: Update for the new ccall test case.
+
+       * include/lightning.h, lib/lightning.c: Add the new jit_address
+       call that returns the real/final address of a "note" in the
+       generated jit. It requires a jit_node_t as returned by the
+       jit_note call, and is only valid after calling jit_emit.
+         Add an intermediate solution to properly handle arm
+       soft and softfp modes that move a double to an integer register
+       pair. Currently it just adds extra tests for the condition,
+       but the proper solution should be to have extra lightning
+       codes for these conditions, codes which should be only used
+       by the backends that need it, and merged with the existing
+       jit_pusharg*_{f,d}.
+
+       * include/lightning/jit_private.h: Add new jit_state_t flag
+       to know it finished jit_emit, so that calls to jit_address
+       are valid.
+
+       * lib/jit_mips.c: Correct abi implementation so that the
+       new ccall test case pass. Major problem was using
+       _jit->function.self.arg{i,f} as boolean values, but that
+       would cause lightning.c:patch_registers() to incorrectly
+       assume only one register was used as argument when calling
+       jit_regarg_p(); _jit->function.self.arg{i,f} must be the
+       number of registers used as arguments (in all backends).
+
+       * lib/jit_x86.c: Add workaround, by marking %rax as used,
+       to a special condition, when running out of registers and the
+       allocator trying to spill and reload %rax, but %rax was used
+       as a pointer to a function, what would cause the reload to
+       destroy the return value. This condition can be better
+       generalized, but the current solution is good enough.
+
+       * include/lightning/jit_ppc.h, lib/jit_ppc-cpu.c, lib/jit_ppc.c:
+       Rewrite logic to handle arguments, as the original code was
+       written based on a SysV pdf about the generic powerpc ABI,
+       what did "invent" a new abi for the previous test cases, but
+       failed in the new ccall test in Darwin PPC. Now it properly
+       handles 13 float registers for arguments, as well as proper
+       computation of stack offsets when running out of registers
+       for arguments.
+
+2013-01-02 Paulo Andrade <pcpa@gnu.org>
+
+       * check/float.tst: Correct test case to match ppc also
+       converting positive infinity to 0x7fffffff.
+
+       * lib/jit_arm-swf.c: Correct typos with double underscores.
+
+       * lib/lightning.c: Correct remaining wrong reverse jump logic.
+
+2012-12-29 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Correct both, wrong and confusing logic
+       to compute the reverse of a jump. Now it properly matches
+       C semantics for "eq" (==) and "ne" (!=) and correct computation
+       of reverse of "uneq" as "gt".
+
+       * check/branch.tst: Update "ne" float branch check that
+       previously happened to be wrongly tested with a NaN argument.
+
+2012-12-29 Paulo Andrade <pcpa@gnu.org>
+
+       * check/float.ok, check/float.tst: New test cases implementing
+       extensive validation of float comparison and branch code
+       generation as well as integer conversion, involving NaN and
+       [+-]Inf.
+
+       * lib/jit_arm-swf.c, lib/jit_x86-sse.c, lib/jit_x86-x87.c:
+       Correct bugs found by new float test case.
+
+       * lib/jit_x86.c: Correct cut&paste error added in commit to
+       convert jit_arg* return value to a jit_node_t*, that would
+       cause it to not properly handle double arguments in ix86.
+
+       * check/Makefile.am: Update for the new test case.
+
+2012-12-28 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c, include/lightning.h, lib/jit_arm.c,
+       lib/jit_mips.c, lib/jit_ppc.c, lib/jit_print.c, lib/jit_x86.c,
+       lib/lightning.c: Change return value of jit_arg{,_f,_d} to
+       a jit_node_t* object, that should be used as argument to
+       jit_getarg_{c,uc,s,us,i,ui,l,f,d}. This just requires changing
+       from jit_int32_t to jit_pointer_t (or jit_node_t*) the "handle"
+       for the getarg calls, with the benefit that it makes it easy
+       to implement patching of the stack address of non register
+       arguments, this way allowing to implement variable size stack
+       frames if applicable; useful if there are too many registers and
+       jit functions uses only a few callee save registers.
+
+2012-12-27 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm.c, lib/jit_mips-cpu.c, lib/jit_mips.c: Correct
+       regressions when patching jit_calli for a forward function.
+
+       * lib/jit_ppc-cpu.c: Correct wrong arguments to ANDI opcode
+       in jit_getarg_u{c,s} implementation.
+
+2012-12-23 Paulo Andrade <pcpa@gnu.org>
+
+       * check/call.ok, check/call.tst: New test cases to validate
+       simple typed argument and return values in function calls.
+
+       * check/lightning.c: Properly handle jit_movi of labels for
+       backward and forward code labels.
+
+       * check/Makefile.am: Update for new test case.
+
+2012-12-23 Paulo Andrade <pcpa@gnu.org>
+
+       * check/carry.ok, check/carry.tst: New test case to validate
+       carry condition handling.
+
+       * check/Makefile.am: Update for new test case.
+
+2012-12-22 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ppc-cpu.c, lib/jit_ppc.c: Implement logic for
+       jit_htonr for big endian, so that ppc (big endian) pass the
+       new clobber.tst test case.
+
+2012-12-22 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm.c: Correct use of wrong argument offset
+       variable in armv7l or float/double argument for varargs
+       function in armv7hl.
+         Correct jit_getarg* logic in software float mode to
+       match expected behavior in other backends, that is, if
+       a function is not called, it is safe to use a few lightning
+       calls before a next jit_getarg* call, as done in the test
+       case check/stack.tst. The proper solution should be to
+       extend the parser in lib/lightning.c to check if there is
+       some float operation that will call some (libgcc?) function,
+       but software float arm should be a very uncommon backend for
+       lightning, so, just load the already in place arguments
+       saved to stack, assuming the register argument was clobbered
+       (what should not be the case most times...).
+
+2012-12-22 Paulo Andrade <pcpa@gnu.org>
+
+       * check/clobber.ok, check/clobber.tst: New test case doing
+       extensive validation tests to ensure registers not used in
+       a operation are not clobbered.
+
+       * check/Makefile.am: Update for new test case.
+
+2012-12-21 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/lightning.c: Partially rewrite/revert code to compute
+       initial register live state at the start of a basic block.
+       The original logic was corrupted when adding optimizations
+       to do as few computations as possible in jit_update. The
+       reglive field must be always a known set of live registers
+       at the start of a basic block. The value that was incorrect
+       was the regmask field, that must be the set of registers
+       that are in unknown state, because they are not known live,
+       neither set (or possibly not set) in the basic block, and
+       *must* store the state at the start of the basic block.
+
+2012-12-20 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_ppc.h: Correct mismatch of JIT_F{1,5}
+       with enum codes, that were correct, and returned by jit_f().
+
+       * lib/jit_ppc-cpu.c, lib/jit_ppc-fpu.c, lib/jit_ppc.c: Properly
+       implement and better describe values when generating stack
+       frames.
+
+2012-12-18 Paulo Andrade <pcpa@gnu.org>
+
+       * check/stack.ok, check/stack.tst: New files to test data
+       integrity on a deep chain of stack frames.
+
+       * lib/jit_arm.c, lib/jit_arm-cpu.c, lib/jit_mips.c,
+       lib/jit_mips-cpu.c, lib/jit_ppc.c, lib/jit_ppc-cpu.c,
+       lib/jit_x86.c, lib/jit_x86-cpu.c: Calculate _jit->function->stack
+       in the emit stage, otherwise it will calculate it wrong if
+       need to jit_allocai space to spill registers.
+
+       * lib/lightning.c: Correct wrong offset when updating the
+       "current" jit function pointer in the code that may need to
+       allocate stack space to spill registers.
+
+       * check/lightning.c: Correct off by one data space check.
+
+       * check/Makefile.am: Update for new test case.
+
+2012-12-17 Paulo Andrade <pcpa@gnu.org>
+
+       * check/fop_abs.ok, check/fop_abs.tst, check/fop_sqrt.ok,
+       check/fop_sqrt.tst: New files implementing simple test cases
+       for the extra float operations.
+
+       * check/Makefile.am: Update for new test cases.
+
+       * check/alu.inc: Add an extra macro to check for unordered
+       equality on tests where it is expected to use NaN as an
+       argument.
+
+       * check/lightning.c: Minor change for proper/common argument
+       syntax handling ommiting arguments to options.
+
+2012-12-17 Paulo Andrade <pcpa@gnu.org>
+
+       * check/Makefile.am: Automatically generate pattern list
+       of tests with alternate jit generation options. This should
+       prevent typos and needing to change multiple places after
+       a change.
+
+2012-12-14 Paulo Andrade <pcpa@gnu.org>
+
+       * check/lightning.c: Remove the ".cpu name value" syntax,
+       as it was not able to do proper changes before the jit
+       internal data structure was initialized. Now it supports
+       several getopt options to force using different jit
+       generation options, effectively replacing the previous
+       syntax.
+
+       * check/run-test: Add simple extra logic to handle differently
+       named test scripts, used to test things like x87 coprocessor
+       in ix86, and arm instruction set or software float in armv7l.
+
+       * configure.ac: Add some AC_RUN_IFELSE calls to figure at
+       compile time if can test different code generation options,
+       and update Makefile generation accordingly.
+
+       * check/Makefile.am, lib/jit_arm.c, lib/jit_x86.c: Update to
+       properly work with the test tool updating the jit_cpu global
+       information.
+
+       * check/check.arm.sh, check/check.swf.sh, check/check.x87.sh:
+       New wrapper files passing -mthumb=0, mvfp=0 and -mx87=1 to
+       the test tool, if applicable, so that it can validate alternate
+       code generation options on test hosts that support them.
+
+2012-12-14 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-x87.c, lib/jit_x86.c: Correct test cases in ix86
+       when using the x87 coprocessor instead of sse2+.
+
+2012-12-14 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, include/lightning/jit_private.h,
+       lib/jit_arm.c, lib/jit_mips.c, lib/jit_ppc.c, lib/jit_x86.c,
+       lib/lightning.c: Make jit_ellipsis implementation not
+       backend specific. It is not intended to handle va_list
+       like objects at runtime, as jit_arg* and jit_getarg*
+       return constant values resolved at parse time, so, effectively
+       it is not possible to create printf like jit functions, as
+       there is no va_start, va_arg, va_end, etc, abstraction. This
+       limitation should be kept for the sake of making new ports
+       easier.
+
+2012-12-14 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/lightning.c: Add two extra wrapper
+       functions to avoid need for excess pointer to/from word casts.
+
+       * check/lightning.c: Only need for pointer to/from word cast
+       now is jit_movi, update accordingly.
+
+2012-12-13 Paulo Andrade <pcpa@gnu.org>
+
+       * check/varargs.ok, check/varargs.tst: New test cases implementing
+       simple varargs calls with a large amount of arguments to exercise
+       excess arguments on stack.
+
+       * include/lightning.h: Include config.h if HAVE_CONFIG_H is
+       defined.
+
+       * lib/jit_arm.c: Allocate a fpr register, not a gpr one for
+       temporary when pushing varargs arguments in the stack.
+
+       * lib/jit_arm-swf.c: Correct code changing the wrong offset
+       in jit_absr_d and jit_negr_d in software float.
+
+       * lib/jit_mips.c: Correct calculation of offsets of arguments
+       on stack.
+
+       * lib/jit_ppc.c: Correct bogus logic for "next" offset of arguments
+       on stack and adjust for fixed offset of stack arguments.
+
+2012-12-12 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning.h, lib/jit_arm.c, lib/jit_mips.c,
+       lib/jit_ppc.c, lib/jit_x86.c, lib/lightning.c: Change jit_prepare
+       to no longer receive an argument. If receiving an argument, it
+       should be an ABI specifier, not a boolean if varargs or not,
+       and add the new jit_ellipsis call, to specify where the
+       ellipsis is in the C prototype of the function being called.
+       Note that currently it is not supported to define varargs
+       functions and it will be ignored if calling jit_ellipsis not
+       in a prepare/finish* block, but this should be addressed.
+
+       * check/allocai.tst, check/alu_add.tst, check/alu_and.tst,
+       check/alu_com.tst, check/alu_div.tst, check/alu_lsh.tst,
+       check/alu_mul.tst, check/alu_neg.tst, check/alu_or.tst,
+       check/alu_rem.tst, check/alu_rsh.tst, check/alu_sub.tst,
+       check/alu_xor.tst, check/alux_add.tst, check/alux_sub.tst,
+       check/bp.tst, check/branch.tst, check/cvt.tst, check/divi.tst,
+       check/fib.tst, check/ldsti.tst, check/ldstr-c.tst,
+       check/ldstr.tst, check/ldstxi-c.tst, check/ldstxi.tst,
+       check/ldstxr-c.tst, check/ldstxr.tst, check/rpn.tst,
+       check/lightning.c: Update for the change to jit_prepare and
+       addition of jit_ellipsis.
+
+2012-12-11 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ppc-cpu.c: Make movr a function that checks arguments
+       so that other code can safely assume it is a noop if src and dst
+       are the same register.
+         Implement rem{r,i}{,_u} as a div{,u}/mul/sub.
+         Correct ANDIS, ORIS and XORIS calls to cast the argument to
+       unsigned before the shift to avoid an assertion if the argument
+       had the topmost bit set.
+         Implement lshi, rshi and rshi_u as functions to test for a
+       zero argument, that would otherwise trigger an assertion when
+       computing the shift value.
+         Do a simple implementation of bm{s,c}{r,i} with a temporary,
+       "andr" of arguments and jump based on comparison with zero.
+         Correct typo in ldxi_c.
+
+       * lib/jit_ppc-fpu.c: Correct wrong arguments to FDIV* and STF*.
+
+       * lib/jit_ppc.c: Correct wrong check for 6 instead of 8 integer
+       arguments in registers. If calling a varargs function and
+       passing a float or double argument, also either store the
+       value in the stack or in integer registers, as varargs functions
+       do not fetch it from float registers.
+         Add "case" for new functions and incorrectly missing ones.
+         Call libgcc's __clear_cache, that should know what to do
+       if the hardware needs flushing cache before execution.
+
+       * lib/lightning.c: Do a simple/trivial logic in jit_regset_scan1,
+       that should make it easier for the compiler to optimize it, and
+       that also corrects the previously wrong code for big endian, and
+       that was causing problems in ppc due to not saving all callee save
+       registers as it was not "finding" them in the regset due to the
+       little endian assumption bug.
+
+2012-12-11 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac: Only default to using the builtin disassembler
+       if on GNU/Linux. This should be temporary, due to requiring
+       /proc/self/exe.
+         Correctly check $target_cpu for powerpc.
+
+       * include/lightning/jit_ppc.h: Correctly implement jit_v_num.
+
+       * include/lightning/jit_private.h: Declare proper prototype
+       for jit_init_debug and jit_finish_debug.
+
+       * lib/jit_ppc-cpu.c: Remove code to save/restore callee save
+       float registers, as it is not required since those float
+       registers are not usable currently.
+         Change prolog and epilog generation to, at least comparing
+       code, match what gcc generates in "gcc -O0", but it is still
+       failing in Darwin PPC, apparently due to the __clear_cache
+       call not being enough, as frequently it will also fail to
+       execute, and the code buffer is all zeroes.
+
+       * lib/lightning.c: Do not fail in jit_regset_scan1 calls due
+       to passing 64 as argument on computers with 64 registers.
+
+2012-12-10 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_mips-cpu.c: Correct all current test cases.
+         Call the "xori" not the "XORI" macro for jit_xori implementation,
+       as the XORI macro handles only 16 bit unsigned values.
+         Call the "movr" macro, not the "movi" macro in the special
+       case of adding or subtracting zero.
+         Use the proper temporary register in the jit_andr implementation.
+
+2012-12-09 Paulo Andrade <pcpa@gnu.org>
+
+       * check/alu.inc, check/alu_add.ok, check/alu_add.tst,
+       check/alu_and.ok, check/alu_and.tst, check/alu_com.ok,
+       check/alu_com.tst, check/alu_div.ok, check/alu_div.tst,
+       check/alu_lsh.ok, check/alu_lsh.tst, check/alu_mul.ok,
+       check/alu_mul.tst, check/alu_neg.ok, check/alu_neg.tst,
+       check/alu_or.ok, check/alu_or.tst, check/alu_rem.ok,
+       check/alu_rem.tst, check/alu_rsh.ok, check/alu_rsh.tst,
+       check/alu_sub.ok, check/alu_sub.tst, check/alu_xor.ok,
+       check/alu_xor.tst, check/alux_add.ok, check/alux_add.tst,
+       check/alux_sub.ok, check/alux_sub.tst, check/branch.ok,
+       check/branch.tst: New test cases for arithmetic and branch
+       tests.
+
+       * check/Makefile.am: Update for new test cases.
+
+       * include/lightning/jit_private.h: Make the jit_reg_free_p
+       macro shared by all backends. Previously was added for the
+       arm backend, but is useful in the x86_64 backend when checking
+       state of "special purpose register".
+       Also add the new jit_class_named register class, that must be
+       or'ed with the register value if calling jit_get_reg expecting
+       an specific value, because the specific register value may be
+       zero, that previously was treated as no register requested.
+
+       * lib/jit_arm-cpu.c: Correct argument order for T2_MVN.
+
+       * lib/jit_arm-swf.c: Call the proper function for double
+       divide. The "software float" implementation just calls
+       libgcc functions.
+
+       * lib/jit_arm.c: Return float/double values in the float
+       register if using the hard float ABI.
+
+       * lib/jit_x86-cpu.c: Change the can_sign_extend_int_p macro
+       to not include -0x80000000L, because there is code that
+       "abuses" it and thinks it can negate the immediate value
+       after calling that macro.
+         Correct implementation of jit_subi that had a wrong code
+       patch logic doing subtraction with reversed arguments.
+         Correct REX prefix calculation in the jit_muli implementation.
+         Correct logic to get/unget %*ax and %*dx registers in divremr
+       and divremi.
+         Correct divremi that was using the symbolic, unique %*ax
+       value in on place (not using the _REGNO name suffix).
+         Correct cut&paste error causing it to use "xor" instead of
+       "or" in one code path of the jit_ori implementation.
+         Correct several flaws when clobbering registers and/or when
+       one of the arguments was %*cx in the rotshr wrapper function
+       implementing most shift operations.
+
+       * lib/lightning.c: No longer expect that the backend be smart
+       enough to know what to do when asking for a named register
+       if that register is already an argument or is live. It fails
+       if it is an argument, or if register is live, fails if cannot
+       spill.
+         No longer incorrectly assume that eqr_{f,d} and ltgr_{f,d} are
+       safe to inverse value tests in jump thread optimization.
+
+2012-12-05 Paulo Andrade <pcpa@gnu.org>
+
+       * check/Makefile.am, check/cvt.ok, check/cvt.tst: Add new
+       "cvt" test case to test conversion from/to int/float types.
+
+       * check/lightning.c: Only define truncr_{f,d}_l in 64 bit mode.
+
+       * include/lightning.h: Correct typo that caused it to define
+       jit_truncr_{f,d}_l in 32 bit mode.
+
+       * lib/jit_arm-cpu.c: Avoid assertion failure in the signed/unsigned
+       extend opcodes generation as it shares an interface for 3 argument
+       opcode generation.
+
+       * lib/jit_x86-cpu.c: Correct wrong argument passed to
+       jit_unget_reg in the andi implementation and wrong byte
+       unsigned extend code generation.
+
+       * lib/jit_x86-sse.c: Correct conversion from "word" to float or
+       double as is dependent on wordsize.
+
+2012-12-05 Paulo Andrade <pcpa@gnu.org>
+
+       * check/ldstr-c.ok, check/ldstr-c.tst, check/ldstxi-c.ok,
+       check/ldstxi-c.tst, check/ldstxr-c.ok, check/ldstxr-c.tst:
+       New test case files testing load clobbering the base and/or
+       index register;
+
+       * check/ldst.inc: New file with common definition for all the
+       ldst* test cases.
+
+       check/Makefile.am, check/ldsti.tst, check/ldstr.tst,
+       check/ldstxi.tst, check/ldstxr.tst: Update for new common
+       definitions file and new register clobber ldst tests.
+
+2012-12-05 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_mips-fpu.c: Correct wrong register order in stxr_{f,d}
+       in the mips backend.
+
+2012-12-05 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_arm-vfp.c: Correct regression found in armv7l with
+       latest test cases.
+
+2012-12-05 Paulo Andrade <pcpa@gnu.org>
+
+       * check/ldstxi.tst, check/ldstxr.tst: Correct wrong argument
+       order for 32 bit mode tests.
+
+       * configure.ac: Correct check for ix86 target_cpu.
+
+2012-12-05 Paulo Andrade <pcpa@gnu.org>
+
+       * check/ldstr.ok, check/ldstr.tst, check/ldsti.ok,
+       check/ldsti.tst, check/ldstxr.ok, check/ldstxr.tst,
+       check/ldstxi.ok, check/ldstxi.tst:
+       New test case files exercising a very large amount of
+       register combinations to verify load/store implementation.
+
+       * check/Makefile.am: Update for new test cases.
+
+       * lib/jit_x86-cpu.c: Correct wrong argument order when
+       computing REX prefix for {ld,st}r_T codes;
+
+2012-12-04 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_mips-fpu.c, lib/jit_mips.c: Implement missing mips
+       jit_sqrtr_{f,d} codes.
+
+       * check/all.tst, include/lightning.h, lib/jit_print.c: Change
+       declaration order and call order in all.tst of {add,sub}c and
+       {add,sub}x. *c must be called before to set the carry and *x
+       second to use the carry and keep it set. The wrong call order
+       was causing all.tst to fail in mips, where a register is
+       allocated to keep a global carry state.
+
+2012-12-04 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_mips.h, lib/jit_mips-cpu.c,
+       lib/jit_mips-fpu.c, lib/jit_mips.c: Correct float/double
+       argument handling and make the mips backend pass the initial
+       test cases.
+
+       * include/lightning.h, ib/jit_print.c, lib/lightning.c:
+       Add extra enum values for argument handling functions that
+       could not be abstracted to the current codes, that is, when
+       float values need to move from/to gpr from/to fpr. It would
+       be more tempting to add such primitives, but they would have
+       wordsize limitations, and it is not expected to add codes
+       with one gpr argument for 64 bit and two for 32 bit.
+
+       * lib/jit_ppc.c: Check _jit->function before calling jit_epilog()
+       to avoid a runtime exception.
+
+2012-12-04 Paulo Andrade <pcpa@gnu.org>
+
+       * include/lightning/jit_mips.h, lib/jit_mips.c: Update to
+       make the mips backend compile in a qemu image.
+
+       * lib/jit_ppc.c: Minor adaptations to help in having the
+       ppc backend compilable.
+
+2012-12-03 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac, include/lightning/jit_private.h, lib/jit_arm-cpu.c,
+       lib/jit_arm-swf.c, lib/jit_arm.c, check/Makefile.am: Correct
+       implementation of the arm backend port to build and pass the
+       current test cases. Tested on armv7 with softfp abi.
+
+       * lib/jit_disasm.c: Rename and change prototype of static
+       disassemble function as in the arm backend it is required
+       to access state information stored in the jit_state_t object.
+
+       * check/3to2.tst, check/add.tst: Correct test case code assuming
+       JIT_RO and JIT_RET are the same, and even if they are the same,
+       the logic was incorrect because it must always call jit_retval*
+       to fetch a function call return before any other instruction.
+       The arm backend hash a special condition if jit_retval is not
+       called, because "r0" is not JIT_R0, but is JIT_RET and *also*
+       the first argument for a called function, so JIT_RET must be
+       only used as an argument to jit_retval.
+
+2012-12-03 Paulo Andrade <pcpa@gnu.org>
+
+       * check/all.tst, check/lightning.c: Only declare or use 64 bit
+       interfaces on 64 bit builds.
+
+       * check/fib.tst: Use simpler logic to not need preprocessor
+       conditionals for 32 or 64 bit.
+
+       * include/lightning.h: Only declare 64 bit macros on a 64 bit
+       build. Code using lightning must know about wordsize and the
+       jit generation limitations, also, this way it generates a
+       compile time failure, not a runtime assertion.
+
+       * include/lightning/jit_x86.h: Correct typo in macro name.
+
+       * lib/jit_arm.c, lib/jit_arm-cpu.c, lib/jit_mips.c,
+       lib/jit_mips-cpu.c, lib/jit_ppc.c, lib/jit_ppc-cpu.c, 
+       lib/jit_x86.c, lib/jit_x86-cpu.c: Correct wrong code to get
+       current jit function pointer.
+
+       * lib/lightning.c: Move call to the simplify() optimization
+       to after register liveness is known. Previous code did work
+       by accident but now with proper test cases the problem was
+       noticed.
+
+       * lib/jit_disasm.c: Always cast bfd_vma to long long when
+       passing it as printf argument.
+
+2012-12-03 Paulo Andrade <pcpa@gnu.org>
+
+       * configure.ac, check/Makefile.am, check/check.sh,
+       doc/Makefile.am, include/lightning/Makefile.am,
+       lib/Makefile.am: Correct make distcheck.
+
+2012-12-02 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_ppc.c: Assign copyright ownership to FSF.
+
+       * lib/jit_x86-cpu.c: Correct integer multiplication that was
+       generating code with reversed register arguments.
+
+       * check/rpn.ok, check/rpn.tst: New test case file.
+
+2012-12-02 Paulo Andrade <pcpa@gnu.org>
+
+       * lib/jit_x86-cpu.c, lib/jit_x86-sse.c, lib/jit_x86-x87.c:
+       Actually change copyright owner to FSF as avertised.
+
+       *  lib/jit_arm-cpu.c,  lib/jit_arm-swf.c,
+       lib/jit_arm-vfp.c, lib/jit_arm.c,
+       lib/jit_mips-cpu.c, lib/jit_mips-fpu.c, lib/jit_mips.c,
+       lib/jit_ppc-cpu.c, lib/jit_ppc-fpu.c, lib/jit_ppc.c: New
+       files implementing initial code different jit backends.
+
+       * include/lightning/jit_private.h: Add extra field to the
+       private jit_patch_t type, required by the arm port.
+
+       * lib/Makefile.am: Update for the new backend implementation
+       files.
+
+2012-12-02 Paulo Andrade <pcpa@gnu.org>
+
+       * check/Makefile.am: Add proper "make clean" rule and missing
+       check.sh to EXTRA_DIST.
+
+2012-12-02 Paulo Andrade <pcpa@gnu.org>
+
+       * .gitignore: Update pattern of ignored files.
+
+       * check/Makefile.am: Add rule to build liblightning.la dependency
+       in case of running "make check" before building the library.
+
+2012-12-02 Paulo Andrade <pcpa@gnu.org>
+
+       * lightning/Makefile.am, lightning/asm-common.h,
+       lightning/core-common.h, lightning/fp-common.h,
+       lightning/funcs-common.h, lightning/i386/Makefile.frag,
+       lightning/i386/asm-32.h, lightning/i386/asm-64.h,
+       lightning/i386/asm.h, lightning/i386/core-32.h,
+       lightning/i386/core-64.h, lightning/i386/core.h,
+       lightning/i386/fp-32.h, lightning/i386/fp-64.h,
+       lightning/i386/fp.h, lightning/i386/funcs.h,
+       lightning/ppc/asm.h, lightning/ppc/core.h,
+       lightning/ppc/fp.h, lightning/ppc/funcs.h,
+       lightning/sparc/asm.h, lightning/sparc/core.h,
+       lightning/sparc/fp.h, lightning/sparc/funcs.h:
+       Removed. The core logic is used in the new code, and new mips
+       and arm ports will be added. At first, sparc will not be
+       supported as it has not yet been ported to the new engine.
+
+2012-12-02 Paulo Andrade <pcpa@gnu.org>
+
+       * tests/Makefile.am, tests/3to2.c, tests/3to2.ok, tests/add.c,
+       tests/add.ok, tests/allocai.c, tests/allocai.ok, tests/bp.c,
+       tests/bp.ok, tests/divi.c, tests/divi.ok, tests/fib.c, tests/fib.ok,
+       tests/fibdelay.c, tests/fibdelay.ok, tests/fibit.c, tests/fibit.ok,
+       tests/funcfp.c, tests/funcfp.ok, tests/incr.c, tests/incr.ok,
+       tests/ldst.c, tests/ldst.ok, tests/ldxi.c, tests/ldxi.ok,
+       tests/modi.c, tests/modi.ok, tests/movi.c, tests/movi.ok,
+       tests/printf.c, tests/printf.ok, tests/printf2.c, tests/printf2.ok,
+       tests/ret.c, tests/ret.ok, tests/rpn.c, tests/rpn.ok, tests/rpnfp.c,
+       tests/rpnfp.ok, tests/sete.c, tests/sete.ok, tests/testfp.c,
+       tests/testfp.ok, tests-run-test: Removed previous test suite, in
+       favor of a newer one in the check subdirectory.
+
+       * check/3to2.ok, check/3to2.tst, check/add.ok, check/add.tst,
+       check/allocai.ok, check/allocai.tst, check/bp.ok, check/bp.tst,
+       check/divi.ok, check/divi.tst, check/fib.ok, check/fib.tst:
+       New sample input for the new test program, loosely matching
+       several of the previous test cases.
+
+       * check/Makefile.am: New test suite makefile.
+
+       * check/check.sh, check/run-test: New wrapper files for the
+       new test suite.
+
+       * check/lightning.c: New file. The main driver of the new test
+       suite, that compiles to a parser of a very simple assembly like
+       language, generates jit and executes it.
+
+       * check/all.tst: New file. A generic debug and sample test file
+       with a directive to prevent it from being executed, and useful to
+       read disassembly of all possible instructions, using a fixed set
+       of registers.
+
+       * include/Makefile.am, include/lightning.h,
+       include/lightning/Makefile.am, include/lightning/jit_arm.h,
+       include/lightning/jit_mips.h, include/lightning/jit_ppc.h,
+       include/lightning/jit_private.h, include/lightning/jit_x86.h,
+       lib/Makefile.am, lib/jit_disasm.c, lib/jit_print.c,
+       lib/jit_x86-cpu.c, lib/jit_x86-sse.c, lib/jit_x86-x87.c,
+       lib/jit_x86.c, lib/lightning.c: New files. These files are
+       written from scratch, only by <pcpa@gnu.org>, and have now
+       copyright assignment to the FSF. This is the core of the new
+       lightning rework. Previously it was integrated in code with
+       a garbage collector and several custom types like vectors and
+       hash tables, so this first code merge with lightning converts
+       that code into a library extracting only the jit bits, and at
+       first only for x86_64 GNU/Linux.
+
+       * lightning.h, m4/lightning.m4: Removed. These are no longer
+       required in the new lightning code.
+
+       .gitignore, Makefile.am, configure.ac: Update for the new
+       lightning code.
+
+2012-12-02 Paulo Andrade <pcpa@gnu.org>
+       * .cvsignore: Removed for extra cleanup.
+
+       * build-aux: Rename directory to m4.
+
+       * m4: Renamed to "default" name and for consistency with merge
+       with code rework to be imported in lightning.
+
+       * .gitignore, configure.ac, Makefile.am, doc/Makefile.am:
+       Update for build-aux to m4 rename.
+
+2012-12-01 Paulo Andrade <pcpa@gnu.org>
+
+       * opcode/Makefile.am, opcode/Makefile.in, opcode/ansidecl.h,
+       opcode/bfd.h, opcode/dis-asm.h, opcode/dis-buf.c, opcode/disass.c,
+       opcode/i386-dis.c, opcode/i386.h, opcode/ppc-dis.c, opcode/ppc-opc.c,
+       opcode/ppc.h, opcode/sparc-dis.c, opcode/sparc-opc.c, opcode/sparc.h,
+       opcode/sysdep.h: Removed. Do not bundle GNU binutils files.
+
+       * aclocal.m4, configure, Makefile.in, config.h.in, doc/Makefile.in,
+       lightning/Makefile.in, tests/Makefile.in: Removed. Do not maintain
+       autogenerated files that also generate too much diff noise when
+       regenerated in git.
+
+       * build-aux/help2man, build-aux/texinfo.tex, build-aux/texi2dvi:
+       Removed. Buildenvironment must have an up to date version from
+       upstream installed.
+
+       * build-aux/config.guess, build-aux/config.sub, build-aux/depcomp,
+       build-aux/install-sh build-aux/mdate-sh build-aux/missing: Removed.
+       Do not maintain a copy of automake files in git. Release tarballs
+       must use an up to date version.
+
+       * lightningize.in, doc/lightningize.1: Removed. Do not encourage
+       bundling lightning in other packages. It should use a system package
+       or a proper thirdy part subdirectory.
+
+       * INSTALL: Removed. Autoreconf removes it and creates a symlink
+       when regenerating files, so, avoid conflicts in git and let
+       automake create the symlink.
+
+       * .gitignore: Add INSTALL and autogenerated files.
+
+       * configure.ac, Makefile.am: Update for removal of opcode subdir,
+       auto generated files and lightningize.
+
+       * tests/Makefile.am, tests/3to2.c, tests/add.c, tests/bp.c,
+       tests/fib.c, tests/fibdelay.c, tests/fibit.c, tests/funcfp.c,
+       tests/incr.c, tests/printf.c, tests/rpn.c, tests/rpnfp.c,
+       tests/sete.c, tests/testfp.c: Update for removal of opcode subdir.
+
+       * doc/Makefile.am: Update for removal of lightningize.
+
+       * configure.ac, lightning/ppc/funcs.h, lightning/sparc/funcs.h,
+       lightning/i386/fp.h, lightning/i386/core.h, lightning/i386/asm.h,
+       tests/3to2.c, tests/add.c, tests/bp.c, tests/fib.c, tests/fibdelay.c,
+       tests/fibit.c, tests/funcfp.c, tests/incr.c, tests/printf.c,
+       tests/rpn.c, tests/rpnfp.c, tests/sete.c, tests/testfp.c:
+       Remove LIGHTNING_CROSS, it is half supported and incomplete.
+
+       * tests/3to2.c, tests/funcfp.c, tests/rpnfp.c: Remove preprocessor
+       check on JIT_FPR. If no hardware registers are available, the backend
+       must provide an alternative for software float.
+
+       * lightning/ppc/core.h, lightning/sparc/core.h, tests/Makefile.am:
+       Remove JIT_NEED_PUSH_POP. It is absolutely not trivial to implement
+       properly on some backends due to stack alignment constraints, and
+       whenever it is required, using jit_allocai and using a properly
+       aligned stack vector, or a heap buffer, is better.
+
+       * tests/push-pop.c, tests/push-pop.ok: Removed due to
+       JIT_NEED_PUSH_POP no longer available.
+
+2011-02-28  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-64.h: Add jit_add{c,x}{i,r}_l, jit_mulr_{l,ul}_,
+       fix jit_mul{i,r}_{l,ul}.
+
+2010-08-20  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/fp-64.h: Return patch address from jit_bXYr_{f,d}.
+       Reported by Paulo César Pereira de Andrade.
+       * lightning/ppc/fp.h: Likewise.
+       * lightning/sparc/fp.h: Implement FP branches.
+
+2010-08-18  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/fp-64.h: Fix jp in jit_bner_{f,d}.
+
+2010-08-18  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/fp-32.h: Fix -D_ASM_SAFETY compilation.
+       Reported by Paulo César Pereira de Andrade.
+
+2010-08-15  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/ldst.c: Update.
+       * tests/Makefile.am: Use -ffloat-store to compile it.
+
+2010-08-15  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core.h (jit_ldr_c, jit_ldxr_c, jit_ldr_s,
+       jit_ldxr_s): Move...
+       * lightning/i386/core-32.h: ... here.
+       * lightning/i386/core-64.h (jit_ldr_c, jit_ldxr_c, jit_ldr_s,
+       Use movsbq and movswq.
+
+2010-08-10  Paulo César Pereira de Andrade <pcpa@mandriva.com.br>
+
+       * lightning/i386/core-32.h (jit_replace): Use MOVLrr, not MOVLir.
+       (jit_movbrm): Check index register as well.
+       * lightning/i386/fp-64.h: Add jit_extr_f_d and jit_extr_d_f.
+       * lightning/fp-common.h: Add jit_extr_f_d and jit_extr_d_f.
+
+2010-07-28  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/Makefile.am: Add ldst test.
+       * tests/Makefile.in: Regenerate.
+       * tests/ldst.c: New.
+       * tests/ldst.ok: New.
+
+2010-07-28  Paolo Bonzini  <bonzini@gnu.org>
+
+       * THANKS: Add Paulo Cesar Pereira de Andrade.
+       * doc/porting.texi: Fix ordering of arguments in jit_stxi.
+       * lightning/i386/core-32.h (jit_replace): Remove cmp argument.
+       * lightning/i386/fp-64.h (jit_movi_f): Fix.
+
+2010-07-26  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-32.h (jit_replace): Move here (removed
+       2009-03-01).
+
+2010-07-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * build-aux/lightning.m4: Always set and replace lightning_frag.
+       * Makefile.in: Regenerate.
+       * aclocal.m4: Regenerate.
+       * config.h.in: Regenerate.
+       * configure: Regenerate.
+       * doc/Makefile.in: Regenerate.
+       * doc/lightningize.1: Regenerate.
+       * doc/version.texi: Regenerate.
+       * lightning/Makefile.in: Regenerate.
+       * opcode/Makefile.in: Regenerate.
+       * tests/Makefile.in: Regenerate.
+
+2009-03-01  Paolo Bonzini  <bonzini@gnu.org>
+
+        * lightning/i386/core-64.h: Use Mike's macros for x86-64 too.
+        * lightning/i386/core.h: Remove jit_replace.
+
+       2009-02-27  Mike Spivey  <mike@comlab.ox.ac.uk>
+
+        * lightning/i386/core.h: Rewrite shift-handling macros.
+        * lightning/fp-common.h: Fix jit_extr_{f_d,d_f}.
+
+2009-02-17  Mike Spivey  <mike@comlab.ox.ac.uk>
+
+       * lightning/i386/core.h: Fix blunder in operand order.
+
+2009-02-17  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/fp-32.h: Another fix to jit_fp_btest.
+
+2009-02-17  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/fp-common.h: Define double branches if missing.
+       * lightning/i386/asm.h: Define JC and JNC mnemonics.
+       * lightning/i386/fp-32.h: Fix jit_fp_btest.  All reported
+       by Mike Spivey.
+
+2008-10-09  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/funcs.h (jit_flush_code): Subtract 1 from end.
+       Reported by Eli Barzilay and Matthew Flatt.
+
+2008-08-23  Nix  <nix@esperi.org.uk>
+
+       * lightning/i386/Makefile.frag: fp-32.h and fp-64.h are target files.
+
+2008-07-02  Laurent Michel  <ldm@engr.uconn.edu>
+
+       * lightning/ppc/funcs.h (jit_flush_code): modified the computation
+       of start/end. The pointer arithmetic was done without casting. It
+       prevented compilation with recent gcc versions. 
+       * lightning/ppc/core.h (jit_pushr_i): The offset for the store was
+       incorrect. Should have been 4 bytes below SP (not above).
+       * lightning/ppc/core.h (jit_popr_i): The offset for the load was 
+       incorrect. Should have been 0 (not +8). 
+
+2008-06-17  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-64.h: Forward IMULQir to IMULQirr,
+       fix REXQ order for IMULQirr.
+
+2008-06-17  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core.h: Fix _rN vs. _rR.
+
+2008-06-16  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core.h: Use jit_save in jit_replace.  Move JIT_R
+       definition...
+       * lightning/i386/core-32.h: ... here; define jit_save so that
+       the core.h has no effect on the 32-bit backend.
+       * lightning/i386/core-64.h: Place JIT_R1/JIT_R2 in R10/R11,
+       place outgoing arguments in the right spot from the beginning,
+       define jit_save, fix jit_reg8/jit_reg16.
+
+2008-06-15  Paolo Bonzini  <bonzini@gnu.org>
+
+        * lightning/i386/core-64.h: Rewrite argument passing to
+       support up to 6 arguments and generate less code.
+
+2008-06-14  Laurent Michel  <ldm@thorgal.homelinux.org>
+
+       * lightning/i386/core-64.h (jit_movi_l): When the operand is 0,
+       the XOR should be on a quadword.
+       * lightning/i386/core-64.h (jit_prolog): Keep 16-byte stack
+       alignment.
+       (jit_ret): Always use LEAVE.
+
+2008-06-13  Laurent Michel  <ldm@thorgal.homelinux.org>
+
+       * lightning/i386/core-64.h: Add (void) casts for C++ compatibility.
+       * lightning/i386/asm.h: Likewise.
+
+2008-06-12  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core.h: Move JIT_V definition...
+       * lightning/i386/core-32.h: ... here.
+       * lightning/i386/core-64.h: ... and here.  Avoid dancing between
+       RSI/RDI and R12/R13, and place JIT_V1/JIT_V2 in R12/R13.
+
+2008-06-11  Paolo Bonzini  <bonzini@gnu.org>
+
+       * build-aux/lightning.m4: Adjust LIGHTNING_BACKENDS, don't
+       use suffix support to distinguish i386/x86_64.
+       * lightning/i386/Makefile.frag: Use LIGHTNING_TARGET_FILES
+       to distribute *-32.h and *-64.h files now.
+       * lightning/i386/asm-i386: Moved to...
+       * lightning/i386/asm.h: Include the appropriate subtarget file.
+       * lightning/i386/core-i386: Moved to...
+       * lightning/i386/core.h: Include the appropriate subtarget file.
+       * lightning/i386/fp.h: New, include the appropriate subtarget file.
+       * lightning/i386/asm-32: Do not include asm-i386.h.
+       * lightning/i386/asm-64.h: Likewise.
+       * lightning/i386/core-32: Do not include core-i386.h.
+       * lightning/i386/core-64.h: Likewise.
+       * lightning/Makefile.am: Adjust for renamed files.
+
+       * configure.ac: Define LIGHTNING_TARGET here.
+       * opcode/disass.c: Change list of valid LIGHTNING_TARGET values.
+
+       * lightningize.in: Robustify against missing subtarget files.
+
+2008-06-11  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-32.h: Use MOVLir instead of jit_movi_l
+       to implement jit_movi_p.
+
+2008-06-11  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-32.h: Use separate __APPLE__ and SysV
+       prolog/ret macros.  Subtract 12 bytes in __APPLE__ case to
+       keep stack aligned, and always use LEAVE in the epilog.
+
+2008-06-11  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-i386.h: Fix C++ incompatibility.
+
+2008-06-10  Laurent Michel  <ldm@engr.uconn.edu>
+
+       * lightning/i386/core-i386.h: Fix jit_replace8 for
+       case when one of the operands is _EAX.
+
+2008-05-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/run-test: Avoid CRLF issues on mingw.
+
+2008-03-21  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-64.h: Fix jit_{ld,st}{,x}i_{i,l}.
+       Remove jit_ld{,x}i_ul.
+       * lightning/core-common.h: Make jit_ld{,x}{i,r}_ul
+       always a synonym of the _l variant.
+       * doc/porting.texi: Document this.
+
+2008-03-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-64.h: Fix uses of jit_qop_.
+
+2008-03-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-64.h: Add boolean operations.
+
+2008-03-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-64.h: Add LEAQmr.
+
+2008-03-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-64.h: Misc bugfixes.
+
+2008-03-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-i386.c: Remove jit_ldr_i, jit_ldxr_i.
+       * lightning/i386/core-32.h: Add jit_ldr_i, jit_ldxr_i.
+       * lightning/i386/core-64.h: Add jit_ld{r,xr,i,xi}_{ui,l,ul};
+       move jit_ldr_i, jit_ldxr_i, jit_str_l, jit_stxr_l with others.
+
+2008-03-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/asm-common.h: Add _s32P.
+
+2008-03-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-64.h: Implement long mul/div/mod.
+
+2008-03-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-i386.h: Cast memory address to long for JCCim.
+
+2008-03-15  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/asm-common.h: Add underscores around __unused__
+       attribute.
+
+2008-03-15  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/core.h: Avoid some "value computed is not used"
+       warnings.
+       * lightnings/tests/allocai.c: Silence other warnings.
+
+2008-03-14  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightningize.in: Fix some problems (not all).
+
+2008-03-14  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-32.h: Avoid some "value computed is not used"
+       warnings; reported by Sam Steingold.
+
+2008-03-08  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-32.h: Fix stxr_c(_EAX, _EBX, _ESI).
+
+2008-02-13  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-32.h: Avoid redefinition of _r1, reported by
+       Sam Steingold.
+       * lightning/i386/asm-64.h: Likewise.
+
+2008-02-08  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-i386.h: Don't define _VOID, reported
+       by Reini Urban.
+
+2008-02-03  Paolo Bonzini  <bonzini@gnu.org>
+
+       * build-aux/lightning.m4: Add --with-lightning-prefix option, suggested
+       by Sam Steingold.
+
+2008-01-14  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-64.h: Use CALLsr, not CALLLsr.
+
+2008-01-13  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-i386.h: Move jit_calli and jit_callr...
+       * lightning/i386/core-32.h: ... here.
+       * lightning/i386/core-64.h: Redefine them.
+
+2008-01-05  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/fp-32.h: Fix sub(a,0,a).
+       * lightning/tests/3to2.c: Add new testcases.
+       * lightning/tests/3to2.ok: Add new testcases.
+
+2008-01-02  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/fp-32.h: Fix sub(a,b,a) with a ~= JIT_FPR0.
+       * lightning/tests/3to2.c: New.
+       * lightning/tests/3to2.ok: New.
+
+2007-11-07  Paolo Bonzini  <bonzini@gnu.org>
+
+       * opcode/Makefile.am: Fix AM_CPPFLAGS.
+
+2007-08-12  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-i386.h: Improve encoding of set* instructions.
+       * lightning/i386/core-64.h: Fix jit_bra_l.
+       * tests/sete.c: New.
+       * tests/sete.ok: New.
+
+2007-06-29  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/bp.c: Upgrade to GPL/LGPLv3.
+       * lightning/i386/asm-32.h: Upgrade to GPL/LGPLv3.
+       * lightning/i386/asm-64.h: Upgrade to GPL/LGPLv3.
+       * lightning/i386/core-32.h: Upgrade to GPL/LGPLv3.
+       * lightning/i386/core-64.h: Upgrade to GPL/LGPLv3.
+       * lightning/i386/fp-64.h: Upgrade to GPL/LGPLv3.
+       * lightning/sparc/asm.h: Upgrade to GPL/LGPLv3.
+       * lightning/sparc/core.h: Upgrade to GPL/LGPLv3.
+       * lightning/sparc/fp.h: Upgrade to GPL/LGPLv3.
+       * lightning/sparc/funcs.h: Upgrade to GPL/LGPLv3.
+       * lightning/i386/asm-i386.h: Upgrade to GPL/LGPLv3.
+       * lightning/i386/core-i386.h: Upgrade to GPL/LGPLv3.
+       * lightning/i386/fp-32.h: Upgrade to GPL/LGPLv3.
+       * lightning/i386/funcs.h: Upgrade to GPL/LGPLv3.
+       * lightning/ppc/asm.h: Upgrade to GPL/LGPLv3.
+       * lightning/ppc/core.h: Upgrade to GPL/LGPLv3.
+       * lightning/ppc/fp.h: Upgrade to GPL/LGPLv3.
+       * lightning/ppc/funcs.h: Upgrade to GPL/LGPLv3.
+       * lightning.h: Upgrade to GPL/LGPLv3.
+       * tests/add.c: Upgrade to GPL/LGPLv3.
+       * tests/fib.c: Upgrade to GPL/LGPLv3.
+       * tests/testfp.c: Upgrade to GPL/LGPLv3.
+       * tests/fibdelay.c: Upgrade to GPL/LGPLv3.
+       * tests/fibit.c: Upgrade to GPL/LGPLv3.
+       * tests/funcfp.c: Upgrade to GPL/LGPLv3.
+       * tests/incr.c: Upgrade to GPL/LGPLv3.
+       * tests/printf.c: Upgrade to GPL/LGPLv3.
+       * tests/printf2.c: Upgrade to GPL/LGPLv3.
+       * tests/rpn.c: Upgrade to GPL/LGPLv3.
+       * tests/rpnfp.c: Upgrade to GPL/LGPLv3.
+       * lightning/asm-common.h: Upgrade to GPL/LGPLv3.
+       * lightning/core-common.h: Upgrade to GPL/LGPLv3.
+       * lightning/fp-common.h: Upgrade to GPL/LGPLv3.
+       * lightning/funcs-common.h: Upgrade to GPL/LGPLv3.
+       * opcode/dis-buf.c: Upgrade to GPL/LGPLv3.
+       * opcode/disass.c: Upgrade to GPL/LGPLv3.
+       * opcode/i386-dis.c: Upgrade to GPL/LGPLv3.
+       * opcode/sparc-dis.c: Upgrade to GPL/LGPLv3.
+       * opcode/sparc-opc.c: Upgrade to GPL/LGPLv3.
+       * lightningize.in: Upgrade to GPL/LGPLv3.
+       * opcode/bfd.h: Upgrade to GPL/LGPLv3.
+       * opcode/i386.h: Upgrade to GPL/LGPLv3.
+       * opcode/sparc.h: Upgrade to GPL/LGPLv3.
+
+2007-01-26  Thomas Girard  <thomas.g.girard@free.fr>
+
+       * lightning/Makefile.am: Add clean-local target.
+
+2006-12-02  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-i386.h: Add CVTTS?2SIL.
+       * lightning/i386/asm-64.h: Add CVTTS?2SIQ.
+       * lightning/i386/fp-64.h: Use it.
+
+       * lightning/Makefile.am: Place files in nodist_lightning_HEADERS.
+
+2006-11-23  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/core-common.h: Add casts in "*i_p" variants.
+       * lightning/i386/asm-32.h: Add _r1.
+       * lightning/i386/asm-64.h: Likewise, and add SSE instructions.
+       * lightning/i386/asm-i386.h: Merge SSE instructions from Gwenole.
+       Use short form for 16-bit AX instructions.  Remove _r1
+       * lightning/i386/core-64.h: Add FP ABI support in its infancy.
+       * lightning/i386/core-i386.h: Move jit_arg_f and jit_arg_d...
+       * lightning/i386/core-32.h: ... and jit_prepare_f and jit_prepare_d...
+       * lightning/i386/fp-32.h: ... here.
+       * lightning/i386/fp-64.h: Write the code.
+       * lightning/sparc/fp.h: Fix jit_extr_{f_d,d_f} register order.
+       
+2006-11-22  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-i386.h: Move x86-64 instructions...
+       * lightning/i386/asm-64.h: ... here.
+       * lightning/i386/fp-32.h: Fix bugfixes worked around in froofyJIT.
+       Add JIT_FPRET.
+       * lightning/sparc/fp.h: Likewise.
+       * lightning/ppc/fp.h: Likewise.
+       * lightning/fp-common.h: Adjust for JIT_FPRET.
+       * tests/funcfp.c: Adjust for JIT_FPRET.
+       * tests/rpnfp.c: Adjust for JIT_FPRET.
+
+2006-11-20  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-i386.h:  Add an underscore to macros without
+       a parameter.
+
+2006-11-20  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core-i386.h: Move jit_movip, jit_check8, jit_reg8,
+       jit_reg16, jit_movbrm...
+       * lightning/i386/core-32.h: ... here.
+       * lightning/i386/core-64.h: Redefine them.  Fix other bugs.
+
+       * tests/printf.c: Do not do a varargs call.
+
+2006-11-20  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-i386.h: Check in rewrite from Basilisk II.
+       * lightning/i386/asm-32.h: Adjust.
+       * lightning/i386/asm-64.h: Adjust.
+       * lightning/i386/fp-32.h: Adjust.
+
+       * lightning/i386/core-32.h: Adjust.  Add jit_{ld,ldx,st,stx}i*.
+       * lightning/i386/core-64.h: Adjust.  Add jit_{ld,ldx,st,stx}i*.
+       * lightning/i386/core-i386.h: Adjust. Remove these patterns.
+
+2006-11-20  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm-i386.h: Merge 64-bit cleanliness changes from
+       mzscheme.
+       Add SSE.
+       * lightning/i386/asm-64.h: Likewise.
+
+2006-11-20  Paolo Bonzini  <bonzini@gnu.org>
+           Ludovic Courtes  <ludo@chbouib.org>
+
+       * lightning/i386/core-32.h: Disable jit_push and jit_pop if stack not
+       needed.
+       * lightning/i386/core-64.h: Disable jit_push and jit_pop if stack not
+       needed.
+       * lightning/sparc/core.h: Merge final implementation of jit_pushr and
+       jit_popr.
+       * lightning/ppc/core.h: Fix implementation of jit_pushr and jit_popr to
+       work (more or less) across function calls.
+
+       * tests/push-pop.c, tests/push-pop.ok: New test.
+       * tests/Makefile.am: Run it.
+
+2006-11-20  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/asm-common.h: Make 64-bit safe.
+       * lightning/i386/funcs.h: Make 64-bit safe.
+
+       * lightning/i386/asm-64.h: More merge from mzscheme.
+       * lightning/i386/asm-i386.h: More merge from mzscheme.
+       * lightning/i386/core-32.h: More merge from mzscheme.
+       * lightning/i386/core-64.h: More merge from mzscheme.
+       * lightning/i386/core-i386.h: More merge from mzscheme.
+
+       * tests/rpnfp.c, tests/testfp.c, tests/funcfp.c: Skip if no
+       floating-point support.
+
+2006-11-04  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/rpn.c: Remove pushr/popr.
+
+2006-11-04  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/core.h: Implement jit_allocai, define JIT_FP to be R1.
+       * lightning/ppc/funcs.h: Store frame size into _jitl.  Store R1 before
+       the STMW, so that the offset is unchanged when we patch the STMW.
+       * lightning/i386/core.h: Define JIT_FP to be EBP.
+       * lightning/i386/core-32.h: Implement jit_allocai, put LEAVE in the
+       epilog if jit_allocai was used.
+       * lightning/i386/core-64.h: Implement jit_allocai, put LEAVE in the
+       epilog if jit_allocai was used.
+
+2006-11-04  Ludovic Courtes  <ludo@chbouib.org>
+
+       * lightning/sparc/core.h: Implement jit_allocai.
+       * tests/allocai.c: New.
+       * tests/Makefile.am: Point to new tests.
+
+2006-11-03  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/core.h: Fix jit_bms using BNE rather than BGT.
+       "AND." does signed comparisons.
+
+2006-10-31  Paolo Bonzini  <bonzini@gnu.org>
+
+       * doc/porting.texi: Rename JIT_FP to JIT_AP.
+       * lightning/core-common.h: Likewise.
+       * lightning/i386/core-i386.h: Likewise.
+       * lightning/fp-common.h: Provide default versions of jit_getarg_[fd].
+       * lightning/i386/fp-32.h: Don't provide jit_getarg_[fd].
+       * lightning/ppc/fp.h: Likewise.
+
+2006-10-31  Ludovic Courtes  <ludo@chbouib.org>
+
+        * doc/using.texi (The instruction set): Clarified the use of `JIT_RET' and
+        documented `jit_retval'.
+        * tests/ret.c (generate_function_proxy): After `jit_finish', use
+        `jit_retval_i' to move FUNC's return value into the correct register.
+
+2006-10-31  Paolo Bonzini  <bonzini@gnu.org>
+           Ludovic Courtes  <ludo@chbouib.org>
+
+       * tests/divi.c, tests/divi.ok, tests/movi.c, tests/movi.ok: New.
+       * tests/ldxi.c: Ensure large pointer is generated.
+       * tests/Makefile.am: Point to new tests.
+       * lightning.h: Include funcs-common.h before funcs.h.
+       * lightning/sparc/core.h: Fix bugs in modi/divi.
+
+2006-10-30  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/Makefile.am: Use "ln -sf".
+       * lightning/core-common.h: Define jit_negr_l if necessary.
+
+2006-10-30  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm.h (MOVS*, MOVZ*): Use correct _r[124] macros.
+
+2006-10-29  Paolo Bonzini  <bonzini@gnu.org>
+
+       * configure.ac: Use lightning.m4 macros.
+       * lightning.m4: Refactor to use common code in configure.ac.  Move...
+       * build-aux/lightning.m4: ... here.
+       * lightningize.in: Support suffixes.
+       * opcode/disass.in: Adapt to changes in configure.ac.
+
+       * lightning/ppc/funcs.h: Use __APPLE__ instead of _CALL_DARWIN.
+       * lightning/i386/core-32.h: Likewise.
+
+2006-10-26  Paolo Bonzini  <bonzini@gnu.org>
+
+       * configure.ac: Fix compilation test.
+       * lightning/Makefile.am: Symlink LIGHTNING_TARGET_FILES in
+       non-distribution mode.
+       * lightning/i386/Makefile.frag: Use LIGHTNING_TARGET_FILES.
+
+2006-10-26  Paolo Bonzini  <bonzini@gnu.org>
+
+       * configure.ac: Subst cpu.
+       * lightning/core-common.h: Make tests pass on i386.
+       * lightning/i386/asm-32.h: Make tests pass on i386.
+       * lightning/i386/asm-64.h: Make tests pass on i386.
+       * lightning/i386/asm-i386.h: Make tests pass on i386.
+       * lightning/i386/core-32.h: Make tests pass on i386.
+       * lightning/i386/core-64.h: Make tests pass on i386.
+       * lightning/i386/core-i386.h: Make tests pass on i386.
+       * tests/Makefile.am: Include files from cpu directory.
+
+2006-10-26  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm.h: Move to asm-i386.h
+       * lightning/i386/asm-32.h: New, from Matthew Flatt.
+       * lightning/i386/asm-64.h: New, from Matthew Flatt.
+       * lightning/i386/core.h: Move to core-i386.h
+       * lightning/i386/core-32.h: New, from Matthew Flatt.
+       * lightning/i386/core-64.h: New, from Matthew Flatt.
+       * lightning/i386/fp.h: Move to fp-32.h
+       * lightning/i386/fp-64.h: New, dummy.
+       * lightning/i386/Makefile.frag: New.
+       * lightning/Makefile.am: Support per-target Makefile fragments.
+       * configure.ac: Support per-target Makefile fragments and CPU suffixes.
+
+2006-10-16  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/i386.h (jit_flush_code): Fix syntax error. :-(
+
+2006-07-06  Paolo Bonzini  <bonzini@gnu.org>
+           Ludovic Courtes  <ludovic.courtes@laas.fr>
+
+       * doc/using.texi: Clarify "Using autoconf" section
+       and rename it to "Bundling lightning"
+       * lightning.m4: Work also if lightning is not bundled.
+
+2006-07-06  Paolo Bonzini  <bonzini@gnu.org>
+           Ludovic Courtes  <ludovic.courtes@laas.fr>
+
+       * lightning/ppc/core.h (_jit_mod): Replace with...
+       (_jit_mod_big, _jit_mod_small): ... these.
+       (jit_modi_i, jit_modi_ui): Rewrite.
+       * tests/modi.c, tests/modi.ok: New tests.
+
+2006-05-18  Matthew Flatt  <mflatt@cs.utah.edu>
+
+       * lightning/i386/asm.h: Fix test for extending the mprotect area
+       towards lower addresses.
+
+2006-05-16  Bruno Haible  <bruno@clisp.org>
+
+       * lightning/asm-common.h: Don't use __func__ nor __FUNCTION__ if
+       not compiling with GNU C.
+
+2006-02-16  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/core.h: Fix jit_ldxi_* with big displacement.
+
+2006-01-23  Paolo Bonzini  <bonzini@gnu.org>
+
+       * configure.ac: Fix comments in config.h.in.
+       
+2005-11-25  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/sparc/fp.h: Fix header comment.
+       * lightning/ppc/fp.h: Fix header comment.
+
+2005-04-27  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/asm.h (JCm, JCSm, JNCm, JNCSm): New.
+
+2004-11-26  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/funcs.h (_jit_epilog): Remove unused variable.
+
+2004-11-13  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/funcs.h [__linux__]: Include sys/mman.h.
+
+2004-11-09  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/sparc/fp.h: Fix fp-to-integer conversions.
+       * lightning/ppc/testfp.c: Test fp-to-integer conversions
+       of integer numbers.
+       * lightning/ppc/testfp.ok: Adjust for the above.
+
+2004-11-08  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/testfp.c: Always flush code before
+       testing it.
+
+2004-11-08  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/fp.h: Do not clobber f31.
+
+2004-11-08  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning.h: New name of...
+       * lightning-inst.h: ... this file.
+       * lightning.h.in: Removed.
+
+       * opcodes/disass.c: Include config.h.
+       * tests/add.c: Include config.h.
+       * tests/bp.c: Include config.h.
+       * tests/fib.c: Include config.h.
+       * tests/fibdelay.c: Include config.h.
+       * tests/fibit.c: Include config.h.
+       * tests/funcfp.c: Include config.h.
+       * tests/incr.c: Include config.h.
+       * tests/printf.c: Include config.h.
+       * tests/printf2.c: Include config.h.
+       * tests/rpn.c: Include config.h.
+       * tests/rpnfp.c: Include config.h.
+       * tests/testfp.c: Include config.h.
+
+2004-10-12  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/fp.h: Fix bugs in conditional branches.
+
+2004-10-10  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/funcs.h: Fix pasto in jit_flush_code.
+
+2004-10-08  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/fp.h: Optimized conditional branches.
+
+2004-09-20  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/asm.h: Fix more typos.
+
+2004-09-20  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/asm.h: Fix typos, replace `26' with JIT_AUX.
+
+2004-09-20  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/fp.h: Added conditional branches.
+
+2004-09-18  Laurent Michel  <ldm@thorgal.homelinux.org>
+
+       * lightning/ppc/fp.h (jit_unler_d, jit_unltr_d, jit_unger_d,
+       jit_ungtr_d, jit_ltgt_d, jit_uneq_d): Implemented missing tests
+       to fully support testfp.
+       (jit_floorr_d_i, jit_ceilr_d_i, jit_roundr_d_i, jit_truncr_d_i):
+       New macros.
+       * lightning/ppc/asm.h: Added missing opcodes FCTIWZ and MTFSFI.
+       * lightning/ppc/funcs.h (_jit_prolog): Fixed minor mistake in
+       the initialization of _jitl.nextarg_geti, relying on the
+       JIT_AUX macro as well to get the register offset.
+
+2004-09-07  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/funcs.h: Fix typo.
+
+2004-09-06  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/funcfp.c: Use %g.  Remove C99 variable declarations.
+       * tests/testfp.c: Don't use __builtin_nan.
+
+       * lightning/ppc/core.h: Add three V registers.
+       * lightning/ppc/funcs.h: Adjust.
+
+       * lightning/sparc/core.h: Some fixes related to FP argument passing.
+       Move R0 to %g2, use %o7 for JIT_BIG2.
+       * lightning/sparc/fp.h: Some fixes related to FP argument passing.
+
+2004-09-02  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/sparc/core.h: Add another V register,
+       move R0 to %o7.
+
+2004-07-15  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/funcs.h: Implement jit_flush_code,
+       in order to support Fedora's exec-shield.
+
+2004-07-14  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/core-common.h: Add more jit_extr_*_* macros.
+       * lightning/doc/using.texi: Be clearer about the order
+       of arguments in jit_extr_*_*.
+       * lightning/doc/porting.texi: Add more jit_extr_*_* macros.
+       * lightning/i386/fp.h: Fix typo in jit_extr_i_d.
+
+2004-07-14  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/funcs.h: Adjust offset of LR into
+       stack frame if running under the Darwin ABI.
+
+2004-07-13  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/fp.h: Rename jit_exti_d to jit_extr_i_d.
+
+2004-07-13  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/core.h: Fix thinko.
+
+       * lightning/i386/core.h: Fix jit_lti_ui.
+       * lightning/core-common.h: Add missing macros.
+
+       * lightning/ppc/fp.h: Rename jit_neg_* to jit_negr_*.
+       * lightning/i386/fp.h: Rename jit_neg_* to jit_negr_*.
+       * lightning/sparc/fp.h: Rename jit_neg_* to jit_negr_*.
+       * lightning/fp-common.h: Rename jit_neg_* to jit_negr_*.
+       * doc/porting.texi: Add undocumented macros.
+
+2004-07-12  Paolo Bonzini  <bonzini@gnu.org>
+
+       * doc/porting.texi: Add missing macros.
+
+2004-07-12  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/funcs.h: Don't generate trampolines.
+       Separate prolog and epilog generation.
+       * lightning/ppc/core.h: Generate epilog explicitly.
+       Don't reserve r31 anymore.
+       * lightning/core-common.h: Remove call to jit_setup_code.
+
+2004-07-09  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/lightning.h.in: Avoid preprocessor warnings.
+       * lightning/lightning-inst.h: Likewise.
+
+       * lightning/i386/core.h: Define JIT_R, JIT_R_NUM, JIT_V,
+       JIT_V_NUM.
+       * lightning/ppc/core.h: Likewise.
+       * lightning/sparc/core.h: Likewise.
+       * lightning/i386/fp.h: Define JIT_FPR, JIT_FPR_NUM.
+       * lightning/ppc/fp.h: Likewise.
+       * lightning/sparc/fp.h: Likewise.
+       * lightning/core-common.h: Define fixed register names.
+       * lightning/fp-common.h: Likewise for FP regs.
+
+2004-07-09  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/ppc/funcs.h: Fix location where return address
+       is stored.
+       * lightning/i386/asm.h: Add a trailing _ to opcodes without
+       any parameter.
+       * lightning/i386/core.h: Adjust for the above.
+
+2004-04-15  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/fp.h: Change "and" to "_and"
+       to satisfy C++ compilers.
+
+2004-04-14  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/sparc/fp.h: Use memcpy to implement jit_movi.
+       * lightning/ppc/fp.h: Use memcpy to implement jit_movi.
+       Move floating-point opcodes...
+       * lightning/ppc/asm.h: ... here.
+
+2004-04-14  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/core-common.h: Add jit_finishr.
+       * lightning/ppc/core.h: Add jit_callr and jit_finishr.
+       * lightning/i386/core.h: Add jit_callr.
+       * lightning/sparc/core.h: Add jit_callr.  Fix typo.
+
+2004-04-14  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core.h: Fix pasto in jit_b*_ui.
+
+2004-03-30  Laurent Michel
+
+       * lightning/ppc: Implement PowerPC floating point
+       (ChangeLog entry missing).
+
+2004-03-12  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/fp-common.h: Load/store macros are not the
+       same for floats and doubles anywhere, but jit_retval may be.
+       * lightning/i386/asm.h: Fix = mistaken for == in ESCrri.
+       * lightning/i386/core.h: Fix typo in jit_prepare_[fd].
+       * lightning/i386/fp.h: Rewritten.
+       * tests/testfp.c: Add tests for unordered comparisons.
+       * tests/testfp.ok: Add results.
+
+2004-03-15  Paolo Bonzini  <bonzini@gnu.org>
+
+       Merge changes from Laurent Michel.
+
+       * lightning/asm-common.h: Add _jit_I_noinc.
+       * lightning/core-common.h: Support jit_init,
+       jit_setup_code, jit_patch_at.  Return patchable IP from
+       jit_movi_p.
+       * lightning/funcs-common.h: Provide defaults
+       for jit_setup_code, jit_start_pfx, jit_end_pfx
+       * lightning/i386/core.h: Add jit_patch_at, jit_patch_movi.
+       * lightning/ppc/core.h: Likewise.
+       * lightning/sparc/core.h: Likewise.
+       * lightning/ppc/asm.h: Fix generation of branch destination
+       displacements in _FB and _BB
+       * lightning/ppc/core.h: Generate trampolines in the user
+       area.
+       * lightning/ppc/funcs.h: Add a few casts.
+       * tests/bc.c: New testcase.
+
+       * lightning/i386/asm.h: Wrap into #ifndef LIGHTNING_DEBUG.
+       * lightning/ppc/asm.h: Wrap into #ifndef LIGHTNING_DEBUG.
+       * lightning/sparc/asm.h: Wrap into #ifndef LIGHTNING_DEBUG.
+
+
+2004-03-09  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/sparc/fp.h: Rewrite.  Move macros for
+       FP code generation...
+       * lightning/sparc/asm.h: ... here.
+       * lightning/sparc/core.h: Rename jit_prepare to
+       jit_prepare_i, jit_retval to jit_retval_i.
+       * lightning/ppc/core.h: Rename jit_prepare to
+       jit_prepare_i, jit_retval to jit_retval_i.
+       * lightning/i386/core.h: Rename jit_prepare to
+       jit_prepare_i, jit_retval to jit_retval_i.
+       * lightning/core-common.h: Provide backwards
+       compatible synonyms for the above.
+       * lightning/fp-common.h: Rewrite.
+       * lightning-inst.h: Include fp unconditionally.
+       * lightning.h.in: Include fp unconditionally.
+       * tests/Makefile.am: Enable fp tests.
+       * tests/fib.c: Use jit_retval_i.
+       * tests/fibit.c: Cast codeBuffer to char *.
+       * tests/funcfp.c: Use new fp macros.
+       * tests/printf.c: Use jit_retval_i.
+       * tests/rpnfp.c: Use new fp macros.
+       * tests/testfp.c: Use new fp macros.
+
+2004-03-02  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core.h: generate correct code when
+       doing lt/le/ge/etc. on ESI and EDI.  Use MOVZX/MOVSX
+       where possible.
+       * lightning/i386/asm.h: Add macros for MOVZX/MOVSX.
+       Move macros for x87 here, and add many of them.
+       * lightning/i386/fp.h: Use new macros for x87.
+
+2004-02-06  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core.h: avoid generating MOV reg, reg.
+       * lightning/sparc/core.h: fix several bugs.
+       * lightning/ppc/core.h: fix several bugs.
+       * tests/rpn.c: rewritten.
+
+2004-01-08  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/rpnfp.c: new example, suggested by Basile
+       Starynkevitch.
+       * tests/rpnfp.ok: new example.
+
+2003-12-12  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/add.c: new test, suggested by Steve Dekorte.
+       * tests/add.c: new test.
+
+2003-11-14  Paolo Bonzini  <bonzini@gnu.org>
+           John Redford <eirenik@hotmail.com>
+
+       * lightning/asm-common.h: change the 'pc' field of _jit to
+       be a union of various data types, because ISO C99 doesn't
+       permit using ++ on a = cast.  Change the incremented casts of
+       _jit.pc to be _jit.x.uc_pc, _jit.x.us_pc, etc.
+       * all files: change all non-cast instances of _jit.pc to be
+       _jit.x.pc.
+       * lightning/i386/core.h: remove casts from jit_might.
+
+2003-05-25  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core.h: use JITSORRY in jit_replace
+       * lightning/asm-common.h: define JITSORRY
+
+2003-05-14  Paolo Bonzini  <bonzini@gnu.org>
+
+       * lightning/i386/core.h: fix missing comma in several
+       load/store macros.
+       * lightning/core-common.h: fix long/unsigned long/pointer
+       jit_pushr/jit_popr.
+       * lightning/ppc/funcs.h: correctly align stack pointer
+
+No changelogs for the assemblers (lightning directory) until 1.0
+       
+2003-03-27  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/printf2.c: new test
+
+2001-05-03  Paolo Bonzini  <bonzini@gnu.org>
+
+       * tests/printf.c: made the message platform independent
+
+2001-01-19  Paolo Bonzini  <bonzini@gnu.org>
+
+       * configure.in: support cross-assembling
+       
+       * disass/bfd.h, disass/dis-asm.h, disass/dis-buf.c,
+       disass/i386-dis.c, disass/i386.h, disass/ppc-dis.c,
+       disass/ppc.h, disass/ppc-opc.c, disass/sparc-dis.c,
+       disass/sparc.h, disass/sparc-opc.c: new files, from GDB
+
+       * disass/disass.c, disass/Makefile.am: new files
+
+       * tests/fib.c, tests/fibit.c, tests/incr.c, tests/printf.c,
+       tests/rpn.c, tests/testfp.c, tests/Makefile.am: support
+       disassembling
diff --git a/deps/lightning/Makefile.am b/deps/lightning/Makefile.am
new file mode 100644 (file)
index 0000000..c921901
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# Copyright 2000, 2001, 2002, 2012-2019 Free Software Foundation, Inc.
+#
+# This file is part of GNU lightning.
+#
+# GNU lightning is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU lightning is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+#
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS =              \
+       check           \
+       doc             \
+       include         \
+       lib
+
+pkgconfiglibdir = $(libdir)/pkgconfig
+pkgconfiglib_DATA = lightning.pc
+
+if get_jit_size
+JIT_SIZE_PATH = "$(top_builddir)/jit_$(cpu)-sz.c"
+AM_CPPFLAGS=-DGET_JIT_SIZE=1 -DJIT_SIZE_PATH='$(JIT_SIZE_PATH)'
+AM_CFLAGS = -I$(top_srcdir)/include -D_GNU_SOURCE $(LIGHTNING_CFLAGS)
+
+noinst_PROGRAMS = size
+size_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+size_SOURCES = size.c
+
+get_jit_size:: $(JIT_SIZE_PATH)
+
+$(JIT_SIZE_PATH):
+       make clean
+       make check
+       $(top_builddir)/size
+
+CLEANFILES = $(JIT_SIZE_PATH)
+endif
diff --git a/deps/lightning/NEWS b/deps/lightning/NEWS
new file mode 100644 (file)
index 0000000..f56dd79
--- /dev/null
@@ -0,0 +1,199 @@
+NEWS FROM 1.99 TO 1.99a
+
+o   Lightning now builds and pass all test cases on AIX 7.1 powerpc,
+    HP-UX 11iv2 hppa, HP-UX 11iv3 ia64, Solaris 10 Sparc, Solaris 11
+    x86_64, and Irix 6.5.30 mips (using n32 abi).
+
+NEWS FROM VERSION 1.3 TO 1.99
+
+o   The 1.99 version is a major lightning redesign and an
+    alpha version.
+
+o   Unless for some special power users usage, the major
+    difference in the rework is that now function calls push
+    arguments from left to right, what is both, more natural for
+    programers, and also more natural to implement for architectures
+    that pass arguments in registers and have alignment constraints,
+    usually for 64 bit double arguments.
+
+o   Add mips backend, implementing the o32 abi.
+
+o   Added arm backend implementing all combinations of software float,
+    vfp, neon, arm and thumb instruction sets, softfp and hardp abis,
+    armv5, armv6, and armv7.
+
+o   Added sse2+ code generation for the 32 bit x86 backend.
+
+o   Added sse3 and sse4.x optional code generation for the 64 bit
+    x86 backend, code generation based on detected cpu.
+
+o   Reworked and added full lightning instruction set to ppc 32;
+    tested on ppc64 hardware and Darwin 32 operating system.
+
+o   Added ppc64 backend, built and tested on Fedora ppc.
+
+o   Reworked the sparc backend, built and tested on Debian sparc.
+
+o   Added an ia64 backend, built and tested on Debian ia64.
+
+o   Added an hppa backend, built and tested on Debian hppa.
+
+---
+
+NEWS FROM VERSION 1.2 TO 1.3
+
+o   Initial support for x86-64 back-end (mostly untested).
+
+o   lightning is more strict on casts from integer to pointer.
+    Be sure to use the _p variants when your immediates are
+    of pointer type.  This was done to ease 64-bit cleanliness
+    tests.
+
+o   Many bug fixes.
+
+o   JIT_FPRET is used as JIT_RET to move return values.
+    jit_retval_[fd] is used to retrieve return values.
+
+o   jit_pushr/jit_popr are deprecated, you need to #define
+    JIT_NEED_PUSH_POP prior to including lightning.h if you
+    want to use them.
+
+o   Support for stack-allocated variables.  Because of this,
+    backends defining JIT_FP should now rename it to JIT_AP.
+    JIT_FP is now a user-visible register used in ldxi/ldxr
+    to access stack-allocated variables.
+
+
+---
+
+NEWS FROM VERSION 1.1.2 TO 1.2
+
+o   Floating-point interface rewritten, uses a register file
+    architecture rather than a stack.
+
+o   Many bug fixes.
+
+o   jit_prepare and jit_retval are now jit_prepare_i and
+    jit_retval_i.
+
+o   Support for Fedora Core 1's exec-shield feature.
+
+o   PPC supports both SysV and Darwin ABIs.
+
+o   More (and more complete) examples provided.
+
+---
+
+NEWS FROM VERSION 1.1.1 TO 1.1.2
+
+o   This release fixes the bugs in PowerPC cache flushing and in
+    SPARC testing.
+
+---
+
+NEWS FROM VERSION 1.1 TO 1.1.1
+
+o   Merge changes from Debian
+
+This version was released to have a distributable version of lightning
+after the recent crack of the GNU FTP machines.  It does not fix
+outstanding bugs; I apologize for the inconvenience.
+
+---
+
+NEWS FROM VERSION 1.0 TO 1.1
+
+o   Several bug fixes
+
+o   improved infrastructure for embedding GNU lightning (lightningize
+    script)
+    
+---
+
+NEWS FROM VERSION 0.99 TO 1.0
+
+o   SPARC backend tested on GNU Smalltalk
+
+
+---
+
+NEWS FROM VERSION 0.98 TO 0.99
+
+o   Added floating point function support (thanks to Laurent Michel);
+    unfortunately this broke even more the PPC and SPARC floating point
+    stuff :-(
+
+---
+
+NEWS FROM VERSION 0.97 to 0.98
+
+o   PPC backend tested on GNU Smalltalk
+
+o   switched to autoconf 2.50
+
+o   new (much faster) PPC cache flushing code by John McIntosh
+
+---
+
+NEWS FROM VERSION 0.96 to 0.97
+
+o   support for cross-assembling and for disassembling the code that the tests
+    generate
+
+o   PPC microtests pass (tested directly by me), SPARC was said to work
+
+---
+
+NEWS FROM VERSION 0.95 to 0.96
+
+o   fixed implementation of delay slots to be coherent with the manual
+
+---
+
+NEWS FROM VERSION 0.94 to 0.95
+
+o   adc/sbc replaced with addc/addx/subc/subx to allow for more optimization
+    (inspired by the PPC instruction set).
+
+o   A few fixes and much less warnings from the compiler
+
+o   Automake-ized everything
+
+o   i386 backend generates smaller code for bms/bmc/or/xor by using byte
+    or word versions if possible
+
+o   Moved backends to separate directories
+
+---
+
+NEWS FROM VERSION 0.93 to 0.94
+
+o   Manual builds as DVI file.
+
+---
+
+NEWS FROM VERSION 0.92 to 0.93
+
+o   Floating-point front-end (began supporting PPC & SPARC).
+
+---
+
+NEWS FROM VERSION 0.91 to 0.92
+
+o   Floating-point front-end (only x86 supported).
+
+---
+
+NEWS FROM VERSION 0.9 to 0.91
+
+o   Carrying supported in addition/subtraction.
+
+o   insn type changed to jit_insn.
+
+o   Misc bug fixes.
+
+o   Reentrancy supported.
+
+o   SPARC run-time assembler rewritten.
+
+o   The run-time assembler can be disabled for debugging purposes.
diff --git a/deps/lightning/README b/deps/lightning/README
new file mode 100644 (file)
index 0000000..ae36ea5
--- /dev/null
@@ -0,0 +1,3 @@
+GNU lightning is a library to aid in making portable programs
+that compile assembly code at run time.  For more information,
+look at the info documentation.
diff --git a/deps/lightning/THANKS b/deps/lightning/THANKS
new file mode 100644 (file)
index 0000000..0e0f1a9
--- /dev/null
@@ -0,0 +1,21 @@
+Thanks to all the following people for their help in
+improving GNU lightning:
+
+Paolo Bonzini                   <bonzini@gnu.org>
+Eli Barzilay                    <eli@barzilay.org>
+Ludovic Courtes                 <ludo@chbouib.org>
+Matthew Flatt                  <mflatt@cs.utah.edu>
+Laurent Michel                  <ldm@thorgal.homelinux.org>
+Paulo Cesar Pereira de Andrade  <pcpa@gnu.org>
+Mike Spivey                     <mike@comlab.ox.ac.uk>
+Basile Starynkevitch            <basile@starynkevitch.net>
+Sam Steingold                  <sds@gnu.org>
+Jens Troeger                    <savage@light-speed.de>
+Tom Tromey                      <tromey@redhat.com>
+Trent Nelson                    <trent@snakebite.org>
+Vitaly Magerya                  <vmagerya@gmail.com>
+Brandon Invergo                 <brandon@gnu.org>
+Holger Hans Peter Freyther      <holger@moiji-mobile.com>
+Jon Arintok                     <jon.arintok@gmail.com>
+Bruno Haible                    <bruno@clisp.org>
+Marc Nieper-Wißkirchen                <marc@nieper-wisskirchen.de>
diff --git a/deps/lightning/TODO b/deps/lightning/TODO
new file mode 100644 (file)
index 0000000..676af02
--- /dev/null
@@ -0,0 +1,28 @@
+       * Validate that divrem in jit_x86-cpu.c is not modifying
+       the non result arguments. This is not verified by clobber.tst,
+       as it only checks registers not involved in the operation
+       (because it does not know about values being set as input
+       for the the operation).
+
+       * Write a simple higher level language implementation generating
+       jit with lightning, that could be some lisp or C like language.
+
+       * rerun ./configure --enable-devel-get-jit-size and regenerate
+       the related jit_$arch-sz.c for the ports where nodata is
+       meaningful:
+       hppa            (done)
+       i586            (done)
+       ia64
+       mips o32        (done)
+       mips n32
+       mips n64
+       powerpc 32      (done)
+       powerpc 64      (done)
+       ppc
+       s390x           (done)
+       sparc           (done)
+       x86_64          (done)
+       Missing ones are due to no longer (remote) access to such hosts
+       and may be broken with jit_set_data(..., JIT_DISABLE_DATA).
+       (ia64 hp-ux or linx), (irix mips for 32 or 64 abi), and
+       (darwin ppc).
diff --git a/deps/lightning/check/3to2.ok b/deps/lightning/check/3to2.ok
new file mode 100644 (file)
index 0000000..de2c040
--- /dev/null
@@ -0,0 +1,22 @@
+0
+1
+1
+1
+0
+1
+1
+1
+0
+1
+1
+0
+1
+1
+1
+0
+1
+1
+1
+0
+1
+1
diff --git a/deps/lightning/check/3to2.tst b/deps/lightning/check/3to2.tst
new file mode 100644 (file)
index 0000000..563cf85
--- /dev/null
@@ -0,0 +1,118 @@
+.data  32
+dfmt:
+.c     "%1.0f\n"
+ifmt:
+.c     "%d\n"
+
+.code
+       jmpi main
+
+#define def_test_double(a, b, c)               \
+       name test_double_##a##_##b##_##c        \
+test_double_##a##_##b##_##c:                   \
+       prolog                                  \
+       arg_d $d0                               \
+       arg_d $d1                               \
+       getarg_d %b $d0                         \
+       getarg_d %c $d1                         \
+       subr_d %a %b %c                         \
+       retr_d %a                               \
+       epilog
+#define test_double(a, b, c, x, y)             \
+       prepare                                 \
+               pushargi_d x                    \
+               pushargi_d y                    \
+       finishi test_double_##a##_##b##_##c     \
+       retval_d %f0                            \
+       prepare                                 \
+               pushargi dfmt                   \
+               ellipsis                        \
+               pushargr_d %f0                  \
+       finishi @printf
+
+#define def_test_int(a, b, c)                  \
+       name test_int_##a##_##b##_##c           \
+test_int_##a##_##b##_##c:                      \
+       prolog                                  \
+       arg $i0                                 \
+       arg $i1                                 \
+       getarg %b $i0                           \
+       getarg %c $i1                           \
+       subr %a %b %c                           \
+       retr %a                                 \
+       epilog
+#define test_int(a, b, c, x, y)                        \
+       prepare                                 \
+               pushargi x                      \
+               pushargi y                      \
+       finishi test_int_##a##_##b##_##c        \
+       retval %r0                              \
+       prepare                                 \
+               pushargi ifmt                   \
+               ellipsis                        \
+               pushargr %r0                    \
+       finishi @printf
+
+def_test_double(f0, f0, f0)
+def_test_double(f0, f0, f1)
+def_test_double(f0, f1, f0)
+def_test_double(f0, f1, f2)
+
+def_test_double(f3, f3, f3)
+def_test_double(f3, f3, f1)
+def_test_double(f3, f1, f3)
+def_test_double(f3, f1, f2)
+
+def_test_double(f3, f0, f0)
+def_test_double(f3, f0, f3)
+def_test_double(f3, f3, f0)
+
+def_test_int(r0, r0, r0)
+def_test_int(r0, r0, r1)
+def_test_int(r0, r1, r0)
+def_test_int(r0, r1, r2)
+
+def_test_int(v0, v0, v0)
+def_test_int(v0, v0, r1)
+def_test_int(v0, r1, v0)
+def_test_int(v0, r1, r2)
+
+def_test_int(v0, r0, r0)
+def_test_int(v0, r0, v0)
+def_test_int(v0, v0, r0)
+
+
+       name main
+main:
+       prolog
+
+       test_double(f0, f0, f0, 3.0, 2.0)
+       test_double(f0, f0, f1, 3.0, 2.0)
+       test_double(f0, f1, f0, 3.0, 2.0)
+       test_double(f0, f1, f2, 3.0, 2.0)
+
+       test_double(f3, f3, f3, 3.0, 2.0)
+       test_double(f3, f3, f1, 3.0, 2.0)
+       test_double(f3, f1, f3, 3.0, 2.0)
+       test_double(f3, f1, f2, 3.0, 2.0)
+
+       test_double(f3, f0, f0, 3.0, 2.0)
+       test_double(f3, f0, f3, 3.0, 2.0)
+       test_double(f3, f3, f0, 3.0, 2.0)
+
+       test_int(r0, r0, r0, 3, 2)
+       test_int(r0, r0, r1, 3, 2)
+       test_int(r0, r1, r0, 3, 2)
+       test_int(r0, r1, r2, 3, 2)
+
+       test_int(v0, v0, v0, 3, 2)
+       test_int(v0, v0, r1, 3, 2)
+       test_int(v0, r1, v0, 3, 2)
+       test_int(v0, r1, r2, 3, 2)
+
+       test_int(v0, r0, r0, 3, 2)
+       test_int(v0, r0, v0, 3, 2)
+       test_int(v0, v0, r0, 3, 2)
+
+       ret
+       epilog
diff --git a/deps/lightning/check/Makefile.am b/deps/lightning/check/Makefile.am
new file mode 100644 (file)
index 0000000..e04f7ac
--- /dev/null
@@ -0,0 +1,318 @@
+#
+# Copyright 2012-2019 Free Software Foundation, Inc.
+#
+# This file is part of GNU lightning.
+#
+# GNU lightning is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU lightning is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+#
+
+AM_CFLAGS = -I$(top_srcdir)/include -D_GNU_SOURCE
+
+check_PROGRAMS = lightning ccall self setcode nodata ctramp carg cva_list
+
+lightning_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+lightning_SOURCES = lightning.c
+
+ccall_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+ccall_SOURCES = ccall.c
+
+self_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+self_SOURCES = self.c
+
+setcode_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+setcode_SOURCES = setcode.c
+
+nodata_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+nodata_SOURCES = nodata.c
+
+ctramp_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+ctramp_SOURCES = ctramp.c
+
+carg_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+carg_SOURCES = carg.c
+
+cva_list_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+cva_list_SOURCES = cva_list.c
+
+$(top_builddir)/lib/liblightning.la:
+       cd $(top_builddir)/lib; $(MAKE) $(AM_MAKEFLAGS) liblightning.la
+
+EXTRA_DIST =                           \
+       3to2.tst        3to2.ok         \
+       add.tst         add.ok          \
+       align.tst       align.ok        \
+       allocai.tst     allocai.ok      \
+       allocar.tst     allocar.ok      \
+       bp.tst          bp.ok           \
+       divi.tst        divi.ok         \
+       fib.tst         fib.ok          \
+       rpn.tst         rpn.ok          \
+       ldst.inc                        \
+       ldstr.tst       ldstr.ok        \
+       ldsti.tst       ldsti.ok        \
+       ldstxr.tst      ldstxr.ok       \
+       ldstxi.tst      ldstxi.ok       \
+       ldstr-c.tst     ldstr-c.ok      \
+       ldstxr-c.tst    ldstxr-c.ok     \
+       ldstxi-c.tst    ldstxi-c.ok     \
+       cvt.tst         cvt.ok          \
+       hton.tst        hton.ok         \
+       branch.tst      branch.ok       \
+       alu.inc                         \
+       alu_add.tst     alu_add.ok      \
+       alux_add.tst    alux_add.ok     \
+       alu_sub.tst     alu_sub.ok      \
+       alux_sub.tst    alux_sub.ok     \
+       alu_rsb.tst     alu_rsb.ok      \
+       alu_mul.tst     alu_mul.ok      \
+       alu_div.tst     alu_div.ok      \
+       alu_rem.tst     alu_rem.ok      \
+       alu_and.tst     alu_and.ok      \
+       alu_or.tst      alu_or.ok       \
+       alu_xor.tst     alu_xor.ok      \
+       alu_lsh.tst     alu_lsh.ok      \
+       alu_rsh.tst     alu_rsh.ok      \
+       alu_com.tst     alu_com.ok      \
+       alu_neg.tst     alu_neg.ok      \
+       fop_abs.tst     fop_abs.ok      \
+       fop_sqrt.tst    fop_sqrt.ok     \
+       varargs.tst     varargs.ok      \
+       stack.tst       stack.ok        \
+       clobber.tst     clobber.ok      \
+       carry.tst       carry.ok        \
+       call.tst        call.ok         \
+       float.tst       float.ok        \
+       jmpr.tst        jmpr.ok         \
+       put.tst         put.ok          \
+       qalu.inc                        \
+       qalu_mul.tst    qalu_mul.ok     \
+       qalu_div.tst    qalu_div.ok     \
+       range.tst       range.ok        \
+       ranger.tst      ranger.ok       \
+       ret.tst         ret.ok          \
+       tramp.tst       tramp.ok        \
+       va_list.tst     va_list.ok      \
+       check.sh                        \
+       check.x87.sh                    \
+       check.arm.sh    check.swf.sh    \
+       check.arm.swf.sh                \
+       check.arm4.swf.sh               \
+       check.nodata.sh                 \
+       check.x87.nodata.sh             \
+       run-test        all.tst
+
+base_TESTS =                           \
+       3to2 add align allocai          \
+       allocar bp divi fib rpn         \
+       ldstr ldsti                     \
+       ldstxr ldstxi                   \
+       ldstr-c ldstxr-c ldstxi-c       \
+       cvt hton branch                 \
+       alu_add alux_add                \
+       alu_sub alux_sub alu_rsb        \
+       alu_mul alu_div alu_rem         \
+       alu_and alu_or alu_xor          \
+       alu_lsh alu_rsh                 \
+       alu_com alu_neg                 \
+       fop_abs fop_sqrt                \
+       varargs stack                   \
+       clobber carry call              \
+       float jmpr put                  \
+       qalu_mul qalu_div               \
+       range ranger ret tramp          \
+       va_list
+
+$(base_TESTS): check.sh
+       $(LN_S) $(srcdir)/check.sh $@
+
+TESTS = $(base_TESTS)
+
+if test_x86_x87
+#x87_TESTS = $(addsuffix .x87, $(base_TESTS))
+x87_TESTS =                                    \
+       3to2.x87 add.x87 allocai.x87            \
+       allocar.x87 bp.x87 divi.x87 fib.x87     \
+       rpn.x87 ldstr.x87 ldsti.x87             \
+       ldstxr.x87 ldstxi.x87                   \
+       ldstr-c.x87 ldstxr-c.x87 ldstxi-c.x87   \
+       cvt.x87 branch.x87                      \
+       alu_add.x87 alux_add.x87                \
+       alu_sub.x87 alux_sub.x87 alu_rsb.x87    \
+       alu_mul.x87 alu_div.x87 alu_rem.x87     \
+       alu_and.x87 alu_or.x87 alu_xor.x87      \
+       alu_lsh.x87 alu_rsh.x87                 \
+       alu_com.x87 alu_neg.x87                 \
+       fop_abs.x87 fop_sqrt.x87                \
+       varargs.x87 stack.x87                   \
+       clobber.x87 carry.x87 call.x87          \
+       float.x87 jmpr.x87 put.x87              \
+       va_list.x87
+$(x87_TESTS):  check.x87.sh
+       $(LN_S) $(srcdir)/check.x87.sh $@
+TESTS += $(x87_TESTS)
+
+#x87_nodata_TESTS = $(addsuffix .x87.nodata, $(base_TESTS))
+x87_nodata_TESTS =                                                     \
+       3to2.x87.nodata add.x87.nodata allocai.x87.nodata               \
+       allocar.x87.nodata bp.x87.nodata divi.x87.nodata fib.x87.nodata \
+       rpn.x87.nodata ldstr.x87.nodata ldsti.x87.nodata                \
+       ldstxr.x87.nodata ldstxi.x87.nodata                             \
+       ldstr-c.x87.nodata ldstxr-c.x87.nodata ldstxi-c.x87.nodata      \
+       cvt.x87.nodata branch.x87.nodata                                \
+       alu_add.x87.nodata alux_add.x87.nodata                          \
+       alu_sub.x87.nodata alux_sub.x87.nodata alu_rsb.x87.nodata       \
+       alu_mul.x87.nodata alu_div.x87.nodata alu_rem.x87.nodata        \
+       alu_and.x87.nodata alu_or.x87.nodata alu_xor.x87.nodata         \
+       alu_lsh.x87.nodata alu_rsh.x87.nodata                           \
+       alu_com.x87.nodata alu_neg.x87.nodata                           \
+       fop_abs.x87.nodata fop_sqrt.x87.nodata                          \
+       varargs.x87.nodata stack.x87.nodata                             \
+       clobber.x87.nodata carry.x87.nodata call.x87.nodata             \
+       float.x87.nodata jmpr.x87.nodata put.x87.nodata                 \
+       va_list.x87.nodata
+$(x87_nodata_TESTS):   check.x87.nodata.sh
+       $(LN_S) $(srcdir)/check.x87.nodata.sh $@
+TESTS += $(x87_nodata_TESTS)
+endif
+
+if test_arm_arm
+#arm_TESTS = $(addsuffix .arm, $(base_TESTS))
+arm_TESTS =                                    \
+       3to2.arm add.arm align.arm allocai.arm  \
+       allocar.arm bp.arm divi.arm fib.arm     \
+       rpn.arm ldstr.arm ldsti.arm             \
+       ldstxr.arm ldstxi.arm                   \
+       ldstr-c.arm ldstxr-c.arm ldstxi-c.arm   \
+       cvt.arm hton.arm branch.arm             \
+       alu_add.arm alux_add.arm                \
+       alu_sub.arm alux_sub.arm alu_rsb.arm    \
+       alu_mul.arm alu_div.arm alu_rem.arm     \
+       alu_and.arm alu_or.arm alu_xor.arm      \
+       alu_lsh.arm alu_rsh.arm                 \
+       alu_com.arm alu_neg.arm                 \
+       fop_abs.arm fop_sqrt.arm                \
+       varargs.arm stack.arm                   \
+       clobber.arm carry.arm call.arm          \
+       float.arm jmpr.arm tramp.arm range.arm  \
+       ranger.arm put.arm va_list.arm
+$(arm_TESTS):  check.arm.sh
+       $(LN_S) $(srcdir)/check.arm.sh $@
+TESTS += $(arm_TESTS)
+endif
+
+if test_arm_swf
+#swf_TESTS = $(addsuffix .swf, $(base_TESTS))
+swf_TESTS =                                    \
+       3to2.swf add.swf allocai.swf            \
+       allocar.swf bp.swf divi.swf fib.swf     \
+       rpn.swf ldstr.swf ldsti.swf             \
+       ldstxr.swf ldstxi.swf                   \
+       ldstr-c.swf ldstxr-c.swf ldstxi-c.swf   \
+       cvt.swf hton.swf branch.swf             \
+       alu_add.swf alux_add.swf                \
+       alu_sub.swf alux_sub.swf alu_rsb.swf    \
+       alu_mul.swf alu_div.swf alu_rem.swf     \
+       alu_and.swf alu_or.swf alu_xor.swf      \
+       alu_lsh.swf alu_rsh.swf                 \
+       alu_com.swf alu_neg.swf                 \
+       fop_abs.swf fop_sqrt.swf                \
+       varargs.swf stack.swf                   \
+       clobber.swf carry.swf call.swf          \
+       float.swf jmpr.swf tramp.swf range.swf  \
+       ranger.swf put.swf va_list.swf
+$(swf_TESTS):  check.swf.sh
+       $(LN_S) $(srcdir)/check.swf.sh $@
+TESTS += $(swf_TESTS)
+if test_arm_arm
+#arm_swf_TESTS = $(addsuffix .arm.swf, $(base_TESTS))
+arm_swf_TESTS =                                                        \
+       3to2.arm.swf add.arm.swf allocai.arm.swf                \
+       allocar.arm.swf bp.arm.swf divi.arm.swf fib.arm.swf     \
+       rpn.arm.swf ldstr.arm.swf ldsti.arm.swf                 \
+       ldstxr.arm.swf ldstxi.arm.swf                           \
+       ldstr-c.arm.swf ldstxr-c.arm.swf ldstxi-c.arm.swf       \
+       cvt.arm.swf hton.arm.swf branch.arm.swf                 \
+       alu_add.arm.swf alux_add.arm.swf                        \
+       alu_sub.arm.swf alux_sub.arm.swf alu_rsb.arm.swf        \
+       alu_mul.arm.swf alu_div.arm.swf alu_rem.arm.swf         \
+       alu_and.arm.swf alu_or.arm.swf alu_xor.arm.swf          \
+       alu_lsh.arm.swf alu_rsh.arm.swf                         \
+       alu_com.arm.swf alu_neg.arm.swf                         \
+       fop_abs.arm.swf fop_sqrt.arm.swf                        \
+       varargs.arm.swf stack.arm.swf                           \
+       clobber.arm.swf carry.arm.swf call.arm.swf              \
+       float.arm.swf jmpr.arm.swf tramp.arm.swf range.arm.swf  \
+       ranger.arm.swf put.arm.swf va_list.arm.swf
+$(arm_swf_TESTS):      check.arm.swf.sh
+       $(LN_S) $(srcdir)/check.arm.swf.sh $@
+TESTS += $(arm_swf_TESTS)
+endif
+if test_arm_arm
+#arm4_swf_TESTS = $(addsuffix .arm4.swf, $(base_TESTS))
+arm4_swf_TESTS =                                               \
+       3to2.arm4.swf add.arm4.swf allocai.arm4.swf             \
+       allocar.arm4.swf bp.arm4.swf divi.arm4.swf fib.arm4.swf \
+       rpn.arm4.swf ldstr.arm4.swf ldsti.arm4.swf              \
+       ldstxr.arm4.swf ldstxi.arm4.swf                         \
+       ldstr-c.arm4.swf ldstxr-c.arm4.swf ldstxi-c.arm4.swf    \
+       cvt.arm4.swf hton.arm4.swf branch.arm4.swf              \
+       alu_add.arm4.swf alux_add.arm4.swf                      \
+       alu_sub.arm4.swf alux_sub.arm4.swf alu_rsb.arm4.swf     \
+       alu_mul.arm4.swf alu_div.arm4.swf alu_rem.arm4.swf      \
+       alu_and.arm4.swf alu_or.arm4.swf alu_xor.arm4.swf       \
+       alu_lsh.arm4.swf alu_rsh.arm4.swf                       \
+       alu_com.arm4.swf alu_neg.arm4.swf                       \
+       fop_abs.arm4.swf fop_sqrt.arm4.swf                      \
+       varargs.arm4.swf stack.arm4.swf                         \
+       clobber.arm4.swf carry.arm4.swf call.arm4.swf           \
+       float.arm4.swf jmpr.arm4.swf tramp.arm4.swf             \
+       range.arm4.swf ranger.arm4.swf put.arm4.swf             \
+       va_list.arm4.swf
+$(arm4_swf_TESTS):     check.arm4.swf.sh
+       $(LN_S) $(srcdir)/check.arm4.swf.sh $@
+TESTS += $(arm4_swf_TESTS)
+endif
+endif
+
+if test_nodata
+#nodata_TESTS = $(addsuffix .nodata, $(base_TESTS))
+nodata_TESTS =                                         \
+       3to2.nodata add.nodata allocai.nodata           \
+       allocar.nodata bp.nodata divi.nodata fib.nodata \
+       rpn.nodata ldstr.nodata ldsti.nodata            \
+       ldstxr.nodata ldstxi.nodata                     \
+       ldstr-c.nodata ldstxr-c.nodata ldstxi-c.nodata  \
+       cvt.nodata branch.nodata                        \
+       alu_add.nodata alux_add.nodata                  \
+       alu_sub.nodata alux_sub.nodata alu_rsb.nodata   \
+       alu_mul.nodata alu_div.nodata alu_rem.nodata    \
+       alu_and.nodata alu_or.nodata alu_xor.nodata     \
+       alu_lsh.nodata alu_rsh.nodata                   \
+       alu_com.nodata alu_neg.nodata                   \
+       fop_abs.nodata fop_sqrt.nodata                  \
+       varargs.nodata stack.nodata                     \
+       clobber.nodata carry.nodata call.nodata         \
+       float.nodata jmpr.nodata tramp.nodata           \
+       range.nodata ranger.nodata put.nodata           \
+       va_list.nodata
+$(nodata_TESTS):       check.nodata.sh
+       $(LN_S) $(srcdir)/check.nodata.sh $@
+TESTS += $(nodata_TESTS)
+endif
+
+TESTS += ccall self setcode nodata ctramp carg cva_list
+CLEANFILES = $(TESTS)
+
+#TESTS_ENVIRONMENT=$(srcdir)/run-test;
+
+debug:         lightning
+       $(LIBTOOL) --mode=execute gdb lightning
+
diff --git a/deps/lightning/check/add.ok b/deps/lightning/check/add.ok
new file mode 100644 (file)
index 0000000..f5f322c
--- /dev/null
@@ -0,0 +1 @@
+5 + 4 = 9
diff --git a/deps/lightning/check/add.tst b/deps/lightning/check/add.tst
new file mode 100644 (file)
index 0000000..9fc054d
--- /dev/null
@@ -0,0 +1,35 @@
+.data  32
+fmt:
+.c     "%d + %d = %d\n"
+
+.code
+       jmpi main
+
+       name test
+test:
+       prolog
+       arg $i0
+       arg $i1
+       getarg %r0 $i0
+       getarg %r1 $i1
+       addr %r0 %r0 %r1
+       retr %r0
+       epilog
+
+       name main
+main:
+       prolog
+       prepare
+               pushargi 5
+               pushargi 4
+       finishi test
+       retval %r0
+       prepare
+               pushargi fmt
+               ellipsis
+               pushargi 5
+               pushargi 4
+               pushargr %r0
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/align.ok b/deps/lightning/check/align.ok
new file mode 100644 (file)
index 0000000..f599e28
--- /dev/null
@@ -0,0 +1 @@
+10
diff --git a/deps/lightning/check/align.tst b/deps/lightning/check/align.tst
new file mode 100644 (file)
index 0000000..5d5348c
--- /dev/null
@@ -0,0 +1,28 @@
+.data  32
+fmt:
+.c     "%d\n"
+.code
+       prolog
+       movi %r0 1
+       jmpi L1                         /* should not generate this */
+       align $(__WORDSIZE / 8)         /* possible nops */
+L1:
+       bgei L4 %r0 10
+       addi %r0 %r0 1
+       jmpi L2
+       movr %r1 %r0                    /* to force jump generation */
+       align $(__WORDSIZE / 8)         /* possible nops */
+L2:
+       bgti L4 %r0 10                  /* never executed */
+       align $(__WORDSIZE / 8)         /* possible nops */
+L3:
+       jmpi L1
+       align $(__WORDSIZE / 8)         /* possible nops */
+L4:
+       prepare
+               pushargi fmt
+               ellipsis
+               pushargr %r0
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/all.tst b/deps/lightning/check/all.tst
new file mode 100644 (file)
index 0000000..ac4fc97
--- /dev/null
@@ -0,0 +1,415 @@
+.disasm                // only disassemble
+.code
+       prolog
+       allocai 32 $buf
+       arg $c
+       arg $uc
+       arg $s
+       arg $us
+       arg $i
+#if __WORDSIZE == 64
+       arg $ui
+       arg $l
+#endif
+       getarg_c %r0 $c
+       getarg_uc %r0 $uc
+       getarg_s %r0 $s
+       getarg_us %r0 $us
+       getarg_i %r0 $i
+#if __WORDSIZE == 64
+       getarg_ui %r0 $ui
+       getarg_l %r0 $l
+#endif
+       addr %r0 %r1 %r2
+       addi %r0 %r1 2
+       addcr %r0 %r1 %r2
+       addci %r0 %r1 2
+       addxr %r0 %r1 %r2
+       addxi %r0 %r1 2
+       subr %r0 %r1 %r2
+       subi %r0 %r1 2
+       subcr %r0 %r1 %r2
+       subci %r0 %r1 2
+       subxr %r0 %r1 %r2
+       subxi %r0 %r1 2
+       mulr %r0 %r1 %r2
+       muli %r0 %r1 2
+       qmulr %r0 %r1 %r2 %v0
+       qmuli %r0 %r1 %r2 3
+       qmulr_u %r0 %r1 %r2 %v0
+       qmuli_u %r0 %r1 %r2 3
+       divr %r0 %r1 %r2
+       divi %r0 %r1 2
+       divr_u %r0 %r1 %r2
+       divi_u %r0 %r1 2
+       qdivr %r0 %r1 %r2 %v0
+       qdivi %r0 %r1 %r2 3
+       qdivr_u %r0 %r1 %r2 %v0
+       qdivi_u %r0 %r1 %r2 3
+       remr %r0 %r1 %r2
+       remi %r0 %r1 2
+       remr_u %r0 %r1 %r2
+       remi_u %r0 %r1 2
+       andr %r0 %r1 %r2
+       andi %r0 %r1 2
+       orr %r0 %r1 %r2
+       ori %r0 %r1 2
+       xorr %r0 %r1 %r2
+       xori %r0 %r1 2
+       lshr %r0 %r1 %r2
+       lshi %r0 %r1 2
+       rshr %r0 %r1 %r2
+       rshi %r0 %r1 2
+       rshr_u %r0 %r1 %r2
+       rshi_u %r0 %r1 2
+       negr %r0 %r1
+       comr %r0 %r1
+       ltr %r0 %r1 %r2
+       lti %r0 %r1 2
+       ltr_u %r0 %r1 %r2
+       lti_u %r0 %r1 2
+       ler %r0 %r1 %r2
+       lei %r0 %r1 2
+       ler_u %r0 %r1 %r2
+       lei_u %r0 %r1 2
+       eqr %r0 %r1 %r2
+       eqi %r0 %r1 2
+       ger %r0 %r1 %r2
+       gei %r0 %r1 2
+       ger_u %r0 %r1 %r2
+       gei_u %r0 %r1 2
+       gtr %r0 %r1 %r2
+       gti %r0 %r1 2
+       gtr_u %r0 %r1 %r2
+       gti_u %r0 %r1 2
+       ner %r0 %r1 %r2
+       nei %r0 %r1 2
+       movr %r0 %r1
+       movi %r0 1
+       extr_c %r0 %r1
+       extr_uc %r0 %r1
+       extr_s %r0 %r1
+       extr_us %r0 %r1
+#if __WORDSIZE == 64
+       extr_i %r0 %r1
+       extr_ui %r0 %r1
+#endif
+       htonr %r0 %r1
+       ntohr %r0 %r1
+       ldr_c %r0 %r1
+       ldi_c %r0 0x80000000
+       ldr_uc %r0 %r1
+       ldi_uc %r0 0x80000000
+       ldr_s %r0 %r1
+       ldi_s %r0 0x80000000
+       ldr_us %r0 %r1
+       ldi_us %r0 0x80000000
+       ldr_i %r0 %r1
+       ldi_i %r0 0x80000000
+#if __WORDSIZE == 64
+       ldr_ui %r0 %r1
+       ldi_ui %r0 0x80000000
+       ldr_l %r0 %r1
+       ldi_l %r0 0x80000000
+#endif
+       ldxr_c %r0 %r1 %r2
+       ldxi_c %r0 %r1 1
+       ldxr_uc %r0 %r1 %r2
+       ldxi_uc %r0 %r1 1
+       ldxr_s %r0 %r1 %r2
+       ldxi_s %r0 %r1 2
+       ldxr_us %r0 %r1 %r2
+       ldxi_us %r0 %r1 2
+       ldxr_i %r0 %r1 %r2
+       ldxi_i %r0 %r1 4
+#if __WORDSIZE == 64
+       ldxr_ui %r0 %r1 %r2
+       ldxi_ui %r0 %r1 4
+       ldxr_l %r0 %r1 %r2
+       ldxi_l %r0 %r1 8
+#endif
+       str_c %r1 %r0
+       sti_c 0x80000000 %r1
+       str_s %r1 %r0
+       sti_s 0x80000000 %r1
+       str_i %r1 %r0
+       sti_i 0x80000000 %r1
+#if __WORDSIZE == 64
+       str_l %r1 %r0
+       sti_l 0x80000000 %r1
+#endif
+       stxr_c %r2 %r1 %r0
+       stxi_c 1 %r1 %r0
+       stxr_s %r2 %r1 %r0
+       stxi_s 2 %r1 %r0
+       stxr_i %r2 %r1 %r0
+       stxi_i 4 %r1 %r0
+#if __WORDSIZE == 64
+       stxr_l %r2 %r1 %r0
+       stxi_l 8 %r1 %r0
+#endif
+cond:
+       bltr cond %r0 %r1
+condi:
+       blti condi %r0 1
+condu:
+       bltr_u condu %r0 %r1
+condiu:
+       blti_u condiu %r0 1
+       bler cond %r0 %r1
+       blei condi %r0 1
+       bler_u condu %r0 %r1
+       blei_u condiu %r0 1
+bool:
+       beqr bool %r0 %r1
+booli:
+       beqi booli %r0 1
+       bger cond %r0 %r1
+       bgei condi %r0 1
+       bger_u condu %r0 %r1
+       bgei_u condiu %r0 1
+       bgtr cond %r0 %r1
+       bgti condi %r0 1
+       bgtr_u condu %r0 %r1
+       bgti_u condiu %r0 1
+       bner bool %r0 %r1
+       bnei booli %r0 1
+mask:
+       bmsr mask %r0 %r1
+maski:
+       bmsi maski %r0 1
+       bmcr mask %r0 %r1
+       bmci maski %r0 1
+as:
+       boaddr as %r0 %r1
+asi:
+       boaddi asi %r0 1
+asu:
+       boaddr_u as %r0 %r1
+       boaddi_u asi %r0 1
+       bxaddr as %r0 %r1
+       bxaddi asi %r0 1
+       bxaddr_u as %r0 %r1
+       bxaddi_u asi %r0 1
+       bosubr as %r0 %r1
+       bosubi asi %r0 1
+       bosubr_u as %r0 %r1
+       bosubi_u asi %r0 1
+       bxsubr as %r0 %r1
+       bxsubi asi %r0 1
+       bxsubr_u as %r0 %r1
+       bxsubi_u asi %r0 1
+label:
+       jmpr %r0
+       jmpi label
+       callr %r0
+       calli label
+       prepare
+       pushargr %r0
+       finishr %r0
+       prepare
+       pushargi 1
+       ellipsis
+       finishi 0x80000000
+       ret
+       retr %r1
+       reti 2
+       retval_c %r1
+       retval_uc %r1
+       retval_s %r1
+       retval_us %r1
+       retval_i %r1
+#if __WORDSIZE == 64
+       retval_ui %r1
+       retval_l %r1
+#endif
+       arg_f $f
+       getarg_f %f1 $f
+       addr_f %f0 %f1 %f2
+       addi_f %f0 %f1 0.5
+       subr_f %f0 %f1 %f2
+       subi_f %f0 %f1 0.5
+       mulr_f %f0 %f1 %f2
+       muli_f %f0 %f1 0.5
+       divr_f %f0 %f1 %f2
+       divi_f %f0 %f1 0.5
+       negr_f %f0 %f1
+       absr_f %f0 %f1
+       sqrtr_f %f0 %f1
+       ltr_f %r0 %f0 %f1
+       lti_f %r0 %f0 0.5
+       ler_f %r0 %f0 %f1
+       lei_f %r0 %f0 0.5
+       eqr_f %r0 %f0 %f1
+       eqi_f %r0 %f0 0.5
+       ger_f %r0 %f0 %f1
+       gei_f %r0 %f0 0.5
+       gtr_f %r0 %f0 %f1
+       gti_f %r0 %f0 0.5
+       ner_f %r0 %f0 %f1
+       nei_f %r0 %f0 0.5
+       unltr_f %r0 %f0 %f1
+       unlti_f %r0 %f0 0.5
+       unler_f %r0 %f0 %f1
+       unlei_f %r0 %f0 0.5
+       uneqr_f %r0 %f0 %f1
+       uneqi_f %r0 %f0 0.5
+       unger_f %r0 %f0 %f1
+       ungei_f %r0 %f0 0.5
+       ungtr_f %r0 %f0 %f1
+       ungti_f %r0 %f0 0.5
+       ltgtr_f %r0 %f0 %f1
+       ltgti_f %r0 %f0 0.5
+       ordr_f %r0 %f0 %f1
+       ordi_f %r0 %f0 0.5
+       unordr_f %r0 %f0 %f1
+       unordi_f %r0 %f0 0.5
+       truncr_f_i %r0 %f0
+#if __WORDSIZE == 64
+       truncr_f_l %r0 %f0
+#endif
+       extr_f %f0 %r0
+       extr_d_f %f0 %f1
+       movr_f %f0 %f1
+       movi_f %f0 1.5
+       ldr_f %f0 %r0
+       ldi_f %f0 0x80000000
+       ldxr_f %f0 %r0 %r1
+       ldxi_f %f0 %r0 4
+       str_f %r0 %f0
+       sti_f 0x80000000 %f0
+       stxr_f %r1 %r0 %f0
+       stxi_f 4 %r0 %f0
+/* FIXME the bordr_d at the end will cause an assertion on riscv due to
+ * too distant jump (does not fit in a 12 bit signed int) */
+ord:
+       bltr_f ord %f0 %f1
+ordi:
+       blti_f ordi %f0 0.5
+       bler_f ord %f0 %f1
+       blei_f ordi %f0 0.5
+       beqr_f ord %f0 %f1
+       beqi_f ordi %f0 0.5
+       bger_f ord %f0 %f1
+       bgei_f ordi %f0 0.5
+       bgtr_f ord %f0 %f1
+       bgti_f ordi %f0 0.5
+       bner_f ord %f0 %f1
+       bnei_f ordi %f0 0.5
+unord:
+       bunltr_f unord %f0 %f1
+unordi:
+       bunlti_f unordi %f0 0.5
+       bunler_f unord %f0 %f1
+       bunlei_f unordi %f0 0.5
+       buneqr_f unord %f0 %f1
+       buneqi_f unordi %f0 0.5
+       bunger_f unord %f0 %f1
+       bungei_f unordi %f0 0.5
+       bungtr_f unord %f0 %f1
+       bungti_f unordi %f0 0.5
+       bltgtr_f unord %f0 %f1
+       bltgti_f unordi %f0 0.5
+       bordr_f unord %f0 %f1
+       bordi_f unordi %f0 0.5
+       bunordr_f unord %f0 %f1
+       bunordi_f unordi %f0 0.5
+       prepare
+       pushargr_f %f1
+       pushargi_f 0.5
+       finishi 0x80000000
+       retr_f %f1
+       reti_f 0.5
+       retval_f %f1
+       arg_d $f
+       getarg_d %f1 $f
+       addr_d %f0 %f1 %f2
+       addi_d %f0 %f1 0.5
+       subr_d %f0 %f1 %f2
+       subi_d %f0 %f1 0.5
+       mulr_d %f0 %f1 %f2
+       muli_d %f0 %f1 0.5
+       divr_d %f0 %f1 %f2
+       divi_d %f0 %f1 0.5
+       negr_d %f0 %f1
+       absr_d %f0 %f1
+       sqrtr_d %f0 %f1
+       ltr_d %r0 %f0 %f1
+       lti_d %r0 %f0 0.5
+       ler_d %r0 %f0 %f1
+       lei_d %r0 %f0 0.5
+       eqr_d %r0 %f0 %f1
+       eqi_d %r0 %f0 0.5
+       ger_d %r0 %f0 %f1
+       gei_d %r0 %f0 0.5
+       gtr_d %r0 %f0 %f1
+       gti_d %r0 %f0 0.5
+       ner_d %r0 %f0 %f1
+       nei_d %r0 %f0 0.5
+       unltr_d %r0 %f0 %f1
+       unlti_d %r0 %f0 0.5
+       unler_d %r0 %f0 %f1
+       unlei_d %r0 %f0 0.5
+       uneqr_d %r0 %f0 %f1
+       uneqi_d %r0 %f0 0.5
+       unger_d %r0 %f0 %f1
+       ungei_d %r0 %f0 0.5
+       ungtr_d %r0 %f0 %f1
+       ungti_d %r0 %f0 0.5
+       ltgtr_d %r0 %f0 %f1
+       ltgti_d %r0 %f0 0.5
+       ordr_d %r0 %f0 %f1
+       ordi_d %r0 %f0 0.5
+       unordr_d %r0 %f0 %f1
+       unordi_d %r0 %f0 0.5
+       truncr_d_i %r0 %f0
+#if __WORDSIZE == 64
+       truncr_d_l %r0 %f0
+#endif
+       extr_d %f0 %r0
+       extr_f_d %f0 %f1
+       movr_d %f0 %f1
+       movi_d %f0 1.5
+       ldr_d %f0 %r0
+       ldi_d %f0 0x80000000
+       ldxr_d %f0 %r0 %r1
+       ldxi_d %f0 %r0 8
+       str_d %r0 %f0
+       sti_d 0x80000000 %f0
+       stxr_d %r1 %r0 %f0
+       stxi_d 8 %r0 %f0
+       bltr_d ord %f0 %f1
+       blti_d ordi %f0 0.5
+       bler_d ord %f0 %f1
+       blei_d ordi %f0 0.5
+       beqr_d ord %f0 %f1
+       beqi_d ordi %f0 0.5
+       bger_d ord %f0 %f1
+       bgei_d ordi %f0 0.5
+       bgtr_d ord %f0 %f1
+       bgti_d ordi %f0 0.5
+       bner_d ord %f0 %f1
+       bnei_d ordi %f0 0.5
+       bunltr_d unord %f0 %f1
+       bunlti_d unordi %f0 0.5
+       bunler_d unord %f0 %f1
+       bunlei_d unordi %f0 0.5
+       buneqr_d unord %f0 %f1
+       buneqi_d unordi %f0 0.5
+       bunger_d unord %f0 %f1
+       bungei_d unordi %f0 0.5
+       bungtr_d unord %f0 %f1
+       bungti_d unordi %f0 0.5
+       bltgtr_d unord %f0 %f1
+       bltgti_d unordi %f0 0.5
+       bordr_d unord %f0 %f1
+       bordi_d unordi %f0 0.5
+       bunordr_d unord %f0 %f1
+       bunordi_d unordi %f0 0.5
+       prepare
+       pushargr_d %f1
+       pushargi_d 0.5
+       finishi 0x80000000
+       retr_d %f1
+       reti_d 0.5
+       retval_d %f1
diff --git a/deps/lightning/check/allocai.ok b/deps/lightning/check/allocai.ok
new file mode 100644 (file)
index 0000000..2962f7a
--- /dev/null
@@ -0,0 +1,2 @@
+received 7777
+succeeded
diff --git a/deps/lightning/check/allocai.tst b/deps/lightning/check/allocai.tst
new file mode 100644 (file)
index 0000000..c20cad0
--- /dev/null
@@ -0,0 +1,100 @@
+.data  128
+idfmt:
+.c     "received %d\n"
+failure_message:
+.c     "numbers don't add up to zero\n"
+report_message:
+.c     "failed: got %i instead of %i\n"
+succeeded_message:
+.c     "succeeded\n"
+
+.code
+       jmpi main
+
+/*
+static int
+identity (int arg)
+{
+  printf ("received %i\n", arg);
+  return arg;
+}
+ */
+       name identify
+identify:
+       prolog
+       arg $i
+       getarg %v0 $i
+       prepare
+               pushargi idfmt
+               ellipsis
+               pushargr %v0
+       finishi @printf
+       retr %v0
+       epilog
+
+       name identity_func
+identity_func:
+       prolog
+       arg $i
+       getarg %r1 $i
+
+       /* Store the argument on the stack.  */
+       allocai $(__WORDSIZE >> 3) $off
+       stxi $off %fp %r1
+
+       /* Store the negative of the argument on the stack.  */
+       allocai $(__WORDSIZE >> 3) $neg
+       negr %r2 %r1
+       stxi $neg %fp %r2
+
+       /* Invoke FUNC.  */
+       prepare
+               pushargr %r1
+       finishi identify
+
+       /* Ignore the result.  */
+
+       /* Restore the negative and the argument from the stack.  */
+       ldxi %r2 %fp $neg
+       ldxi %v1 %fp $off
+
+       /* Make sure they still add to zero.  */
+       addr %r0 %v1 %r2
+       bnei branch %r0 0
+
+       /* Return it.  */
+       retr %v1
+
+       /* Display a failure message.  */
+branch:
+       prepare
+               pushargi failure_message
+               ellipsis
+       finishi @printf
+
+       /* Leave.  */
+       retr %v1
+       epilog
+
+       name main
+main:
+       prolog
+       prepare
+               pushargi 7777
+       finishi identity_func
+       retval %r0
+       beqi succeeded %r0 7777
+       prepare
+               pushargi report_message
+               ellipsis
+               pushargr %r0
+               pushargi 7777
+       finishi @printf
+       reti 1
+succeeded:
+       prepare
+               pushargi succeeded_message
+               ellipsis
+       finishi @printf
+       reti 0
+       epilog
diff --git a/deps/lightning/check/allocar.ok b/deps/lightning/check/allocar.ok
new file mode 100644 (file)
index 0000000..516b1e7
--- /dev/null
@@ -0,0 +1,4 @@
+1 2 3
+3 4 5
+5 6 7
+7 8 9
diff --git a/deps/lightning/check/allocar.tst b/deps/lightning/check/allocar.tst
new file mode 100644 (file)
index 0000000..e3ee010
--- /dev/null
@@ -0,0 +1,403 @@
+#define szof_c                 1
+#define szof_uc                        szof_c
+#define szof_s                 2
+#define szof_us                        szof_s
+#define szof_i                 4
+#if __WORDSIZE == 64
+#  define szof_ui              szof_i
+#  define szof_l               8
+#endif
+#define szof_f                 4
+#define szof_d                 8
+
+#define FILL(T)                                                        \
+       name fill##T                                            \
+fill##T:                                                       \
+       prolog                                                  \
+       arg $argp                                               \
+       getarg %v0 $argp                                        \
+       arg $argi                                               \
+       getarg %r0 $argi                                        \
+       muli %r0 %r0 szof##T                                    \
+       addr %v1 %v0 %r0                                        \
+       movi %r0 0                                              \
+fill##T##loop:                                                 \
+       bger fill##T##done %v0 %v1                              \
+       str##T %v0 %r0                                          \
+       addi %r0 %r0 1                                          \
+       addi %v0 %v0 szof##T                                    \
+       jmpi fill##T##loop                                      \
+fill##T##done:                                                 \
+       ret                                                     \
+       epilog
+#define FILLF(T)                                               \
+       name fill##T                                            \
+fill##T:                                                       \
+       prolog                                                  \
+       arg $argp                                               \
+       getarg %v0 $argp                                        \
+       arg $argi                                               \
+       getarg %r0 $argi                                        \
+       muli %r0 %r0 szof##T                                    \
+       addr %v1 %v0 %r0                                        \
+       movi##T %f0 0.0                                         \
+fill##T##loop:                                                 \
+       bger fill##T##done %v0 %v1                              \
+       str##T %v0 %f0                                          \
+       addi##T %f0 %f0 1.0                                     \
+       addi %v0 %v0 szof##T                                    \
+       jmpi fill##T##loop                                      \
+fill##T##done:                                                 \
+       ret                                                     \
+       epilog
+
+#define fill_uc                fill_c
+#define fill_us                fill_s
+#define fill_ui                fill_i
+
+#define ARG(  T, N)                    arg    $arg##T##N
+#define ARGF( T, N)                    arg##T $arg##T##N
+#define ARG1( K, T)                    ARG##K(T, 0)
+#define ARG2( K, T)    ARG1( K, T)     ARG##K(T, 1)
+#define ARG3( K, T)    ARG2( K, T)     ARG##K(T, 2)
+#define ARG4( K, T)    ARG3( K, T)     ARG##K(T, 3)
+#define ARG5( K, T)    ARG4( K, T)     ARG##K(T, 4)
+#define ARG6( K, T)    ARG5( K, T)     ARG##K(T, 5)
+#define ARG7( K, T)    ARG6( K, T)     ARG##K(T, 6)
+#define ARG8( K, T)    ARG7( K, T)     ARG##K(T, 7)
+#define ARG9( K, T)    ARG8( K, T)     ARG##K(T, 8)
+#define ARG10(K, T)    ARG9( K, T)     ARG##K(T, 9)
+#define ARG11(K, T)    ARG10(K, T)     ARG##K(T, 10)
+#define ARG12(K, T)    ARG11(K, T)     ARG##K(T, 11)
+#define ARG13(K, T)    ARG12(K, T)     ARG##K(T, 12)
+#define ARG14(K, T)    ARG13(K, T)     ARG##K(T, 13)
+#define ARG15(K, T)    ARG14(K, T)     ARG##K(T, 14)
+#define ARG16(K, T)    ARG15(K, T)     ARG##K(T, 15)
+#define ARG_c(N)                       ARG##N( , _c)
+#define ARG_uc(N)                      ARG##N( , _uc)
+#define ARG_s(N)                       ARG##N( , _s)
+#define ARG_us(N)                      ARG##N( , _us)
+#define ARG_i(N)                       ARG##N( , _i)
+#define ARG_ui(N)                      ARG##N( , _ui)
+#define ARG_l(N)                       ARG##N( , _l)
+#define ARG_f(N)                       ARG##N(F, _f)
+#define ARG_d(N)                       ARG##N(F, _d)
+
+#define CHK(N, T, V)                                           \
+       getarg %r0 $arg##T##V                                   \
+       ldxi##T %r1 %v0 $(V * szof##T)                          \
+       beqr N##T##V %r0 %r1                                    \
+       calli @abort                                            \
+N##T##V:
+#define CHKF(N, T, V)                                          \
+       getarg##T %f0 $arg##T##V                                \
+       ldxi##T %f1 %v0 $(V * szof##T)                          \
+       beqr##T N##T##V %f0 %f1                                 \
+       calli @abort                                            \
+N##T##V:
+
+#define GET1( K, N, T, V)                              CHK##K(N, T, 0)
+#define GET2( K, N, T, V)      GET1( K, N, T, V)       CHK##K(N, T, 1)
+#define GET3( K, N, T, V)      GET2( K, N, T, V)       CHK##K(N, T, 2)
+#define GET4( K, N, T, V)      GET3( K, N, T, V)       CHK##K(N, T, 3)
+#define GET5( K, N, T, V)      GET4( K, N, T, V)       CHK##K(N, T, 4)
+#define GET6( K, N, T, V)      GET5( K, N, T, V)       CHK##K(N, T, 5)
+#define GET7( K, N, T, V)      GET6( K, N, T, V)       CHK##K(N, T, 6)
+#define GET8( K, N, T, V)      GET7( K, N, T, V)       CHK##K(N, T, 7)
+#define GET9( K, N, T, V)      GET8( K, N, T, V)       CHK##K(N, T, 8)
+#define GET10(K, N, T, V)      GET9( K, N, T, V)       CHK##K(N, T, 9)
+#define GET11(K, N, T, V)      GET10(K, N, T, V)       CHK##K(N, T, 10)
+#define GET12(K, N, T, V)      GET11(K, N, T, V)       CHK##K(N, T, 11)
+#define GET13(K, N, T, V)      GET12(K, N, T, V)       CHK##K(N, T, 12)
+#define GET14(K, N, T, V)      GET13(K, N, T, V)       CHK##K(N, T, 13)
+#define GET15(K, N, T, V)      GET14(K, N, T, V)       CHK##K(N, T, 14)
+#define GET16(K, N, T, V)      GET15(K, N, T, V)       CHK##K(N, T, 15)
+
+#define GET_c(N, M)            GET##N( , c##N,  _c,  M)
+#define GET_uc(N, M)           GET##N( , uc##N, _uc, M)
+#define GET_s(N, M)            GET##N( , s##N,  _s,  M)
+#define GET_us(N, M)           GET##N( , us##N, _us, M)
+#define GET_i(N, M)            GET##N( , i##N,  _i,  M)
+#define GET_ui(N, M)           GET##N( , ui##N, _ui, M)
+#define GET_l(N, M)            GET##N( , l##N,  _l,  M)
+#define GET_f(N, M)            GET##N(F, f##N,  _f,  M)
+#define GET_d(N, M)            GET##N(F, d##N,  _d,  M)
+
+#define PUSH(  T, V)           pushargi    V
+#define PUSHF( T, V)           pushargi##T V
+#define PUSH0( K, T)           /**/
+#define PUSH1( K, T)                                   PUSH##K(T, 0)
+#define PUSH2( K, T)           PUSH1( K, T)            PUSH##K(T, 1)
+#define PUSH3( K, T)           PUSH2( K, T)            PUSH##K(T, 2)
+#define PUSH4( K, T)           PUSH3( K, T)            PUSH##K(T, 3)
+#define PUSH5( K, T)           PUSH4( K, T)            PUSH##K(T, 4)
+#define PUSH6( K, T)           PUSH5( K, T)            PUSH##K(T, 5)
+#define PUSH7( K, T)           PUSH6( K, T)            PUSH##K(T, 6)
+#define PUSH8( K, T)           PUSH7( K, T)            PUSH##K(T, 7)
+#define PUSH9( K, T)           PUSH8( K, T)            PUSH##K(T, 8)
+#define PUSH10(K, T)           PUSH9( K, T)            PUSH##K(T, 9)
+#define PUSH11(K, T)           PUSH10(K, T)            PUSH##K(T, 10)
+#define PUSH12(K, T)           PUSH11(K, T)            PUSH##K(T, 11)
+#define PUSH13(K, T)           PUSH12(K, T)            PUSH##K(T, 12)
+#define PUSH14(K, T)           PUSH13(K, T)            PUSH##K(T, 13)
+#define PUSH15(K, T)           PUSH14(K, T)            PUSH##K(T, 14)
+#define PUSH16(K, T)           PUSH15(K, T)            PUSH##K(T, 15)
+
+#define PUSH_c( N)             PUSH##N( , _c)
+#define PUSH_uc(N)             PUSH##N( , _uc)
+#define PUSH_s( N)             PUSH##N( , _s)
+#define PUSH_us(N)             PUSH##N( , _us)
+#define PUSH_i( N)             PUSH##N( , _i)
+#define PUSH_ui(N)             PUSH##N( , _ui)
+#define PUSH_l( N)             PUSH##N( , _l)
+#define PUSH_f( N)             PUSH##N(F, _f)
+#define PUSH_d( N)             PUSH##N(F, _d)
+
+/* bottom function */
+#define DEF0(T)                                                        \
+       name test##T##_0                                        \
+test##T##_0:                                                   \
+       prolog                                                  \
+       ret                                                     \
+       epilog
+
+#define DEFN(N, M, T)                                          \
+       name test##T##_##N                                      \
+test##T##_##N:                                                 \
+       prolog                                                  \
+       arg $argp                                               \
+       /* stack buffer in %v0 */                               \
+       getarg %v0 $argp                                        \
+       ARG##T(N)                                               \
+       /* validate arguments */                                \
+       GET##T(N, M)                                            \
+       /* heap buffer in %v1 */                                \
+       prepare                                                 \
+               pushargi $(N * szof##T)                         \
+       finishi @malloc                                         \
+       retval %v1                                              \
+       /* copy stack bufer to heap buffer */                   \
+       prepare                                                 \
+               pushargr %v1                                    \
+               pushargr %v0                                    \
+               pushargi $(N * szof##T)                         \
+       finishi MEMCPY                                          \
+       /* stack buffer for next function in %v2 */             \
+       movi %r0 $(M * szof##T)                                 \
+       allocar %v2 %r0                                         \
+       addr %v2 %v2 %fp                                        \
+       /* fill stack buffer for next function */               \
+       prepare                                                 \
+               pushargr %v2                                    \
+               pushargi M                                      \
+       finishi fill##T                                         \
+       /* call next function */                                \
+       prepare                                                 \
+               pushargr %v2                                    \
+               PUSH##T(M)                                      \
+       finishi test##T##_##M                                   \
+       /* validate stack buffer */                             \
+       prepare                                                 \
+               pushargr %v1                                    \
+               pushargr %v0                                    \
+               pushargi $(N * szof##T)                         \
+       finishi @memcmp                                         \
+       retval %r0                                              \
+       beqi test##T##_##N##_done %r0 0                         \
+       calli @abort                                            \
+test##T##_##N##_done:                                          \
+       /* release heap bufer */                                \
+       prepare                                                 \
+               pushargr %v1                                    \
+       finishi @free                                           \
+       ret                                                     \
+       epilog
+
+/* top function */
+#define DEFX(T)                                                        \
+       name test##T##_17                                       \
+test##T##_17:                                                  \
+       prolog                                                  \
+       /* heap buffer in %v1 */                                \
+       prepare                                                 \
+               pushargi $(16 * szof##T)                        \
+       finishi @malloc                                         \
+       retval %v1                                              \
+       /* stack buffer for next function in %v2 */             \
+       movi %r0 $(16 * szof##T)                                \
+       allocar %v2 %r0                                         \
+       addr %v2 %v2 %fp                                        \
+       /* fill stack buffer for next function */               \
+       prepare                                                 \
+               pushargr %v2                                    \
+               pushargi 16                                     \
+       finishi fill##T                                         \
+       /* copy stack buffer to heap buffer */                  \
+       prepare                                                 \
+               pushargr %v1                                    \
+               pushargr %v2                                    \
+               pushargi $(16 * szof##T)                        \
+       finishi MEMCPY                                          \
+       /* call next function */                                \
+       prepare                                                 \
+               pushargr %v2                                    \
+               PUSH##T(16)                                     \
+       finishi test##T##_16                                    \
+       /* validate stack buffer */                             \
+       prepare                                                 \
+               pushargr %v1                                    \
+               pushargr %v2                                    \
+               pushargi $(16 * szof##T)                        \
+       finishi @memcmp                                         \
+       retval %r0                                              \
+       beqi test##T##_17_done %r0 0                            \
+       calli @abort                                            \
+test##T##_17_done:                                             \
+       /* release heap bufer */                                \
+       prepare                                                 \
+               pushargr %v1                                    \
+       finishi @free                                           \
+       ret                                                     \
+       epilog
+
+#define DEF(  T)                                               \
+       DEF0( T)                                                \
+       DEFN( 1,  0, T)                                         \
+       DEFN( 2,  1, T)                                         \
+       DEFN( 3,  2, T)                                         \
+       DEFN( 4,  3, T)                                         \
+       DEFN( 5,  4, T)                                         \
+       DEFN( 6,  5, T)                                         \
+       DEFN( 7,  6, T)                                         \
+       DEFN( 8,  7, T)                                         \
+       DEFN( 9,  8, T)                                         \
+       DEFN(10,  9, T)                                         \
+       DEFN(11, 10, T)                                         \
+       DEFN(12, 11, T)                                         \
+       DEFN(13, 12, T)                                         \
+       DEFN(14, 13, T)                                         \
+       DEFN(15, 14, T)                                         \
+       DEFN(16, 15, T)                                         \
+       DEFX(T)
+
+#define CALL(T)                        calli test##T##_17
+
+.data  16
+fmt:
+.c     "%d %d %d\n"
+.code
+       jmpi main
+
+#if _AIX
+#  define MEMCPY               memcpy
+/* error: Function not implemented (memcpy) */
+       name memcpy
+memcpy:
+       prolog
+       arg $dst
+       arg $src
+       arg $len
+       getarg %r0 $dst
+       getarg %r1 $src
+       getarg %r2 $len
+       movr %v1 %r0
+       blti memcpy_done %r2 1
+memcpy_loop:
+       subi %r2 %r2 1
+       ldxr_c %v0 %r1 %r2
+       stxr_c %r2 %r0 %v0
+       bgti memcpy_loop %r2 0
+memcpy_done:
+       retr %v1
+       epilog
+#else
+#  define MEMCPY               @memcpy
+#endif
+
+       FILL(_c)
+       FILL(_s)
+       FILL(_i)
+#if __WORDSIZE == 64
+       FILL(_l)
+#endif
+       FILLF(_f)
+       FILLF(_d)
+
+       DEF(_c)
+       DEF(_uc)
+       DEF(_s)
+       DEF(_us)
+       DEF(_i)
+#if __WORDSIZE == 64
+       DEF(_ui)
+       DEF(_l)
+#endif
+       DEF(_f)
+       DEF(_d)
+
+       name main
+main:
+       prolog
+
+       CALL(_c)
+       CALL(_uc)
+       CALL(_s)
+       CALL(_us)
+       CALL(_i)
+#if __WORDSIZE == 64
+       CALL(_ui)
+       CALL(_l)
+#endif
+       CALL(_f)
+       CALL(_d)
+
+       // loop control
+       movi %v2 1
+
+       // loop a few times calling allocar
+loop:
+       // allocate 12 bytes
+       movi %r0 12
+       allocar %v0 %r0
+
+       // offset
+       movr %v1 %v0
+
+       // 1
+       stxr_i %v1 %fp %v2
+
+       // 2
+       addi %v2 %v2 1
+       addi %v1 %v1 4
+       stxr_i %v1 %fp %v2
+
+       // 3
+       addi %v2 %v2 1
+       addi %v1 %v1 4
+       stxr_i %v1 %fp %v2
+
+       // reload
+       movr %v1 %v0
+
+       // 1
+       ldxr_i %r0 %fp %v1
+
+       // 2
+       addi %v1 %v1 4
+       ldxr_i %r1 %fp %v1
+
+       // 3
+       addi %v1 %v1 4
+       ldxr_i %r2 %fp %v1
+
+       prepare
+               pushargi fmt
+               ellipsis
+               pushargr %r0
+               pushargr %r1
+               pushargr %r2
+       finishi @printf
+       blti loop %v2 9
+
+       ret
+       epilog
diff --git a/deps/lightning/check/alu.inc b/deps/lightning/check/alu.inc
new file mode 100644 (file)
index 0000000..0c259ea
--- /dev/null
@@ -0,0 +1,360 @@
+.data  8
+ok:
+.c     "ok\n"
+
+/* ia64 code generation is not optimized for size, and also some
+ * codes generate quite long sequences due to need for stops causing
+ * no code template match and needing to add nops, and other cases
+ * are division/remainder that needs function calls, or float division
+ * that requires a quite long sequence.
+ * (the brute force tests of all register combinations can easily
+ *  generate several GB of jit).
+ */
+
+/* 3 operand */
+
+/* reg0 = reg1 op reg2 */
+#define ALUR(N, T, OP, I0, I1, V, R0, R1, R2)          \
+       movi %R1 I0                                     \
+       movi %R2 I1                                     \
+       OP##r##T %R0 %R1 %R2                            \
+       beqi OP##T##N##r_##R0##R1##R2 %R0 V             \
+       calli @abort                                    \
+OP##T##N##r_##R0##R1##R2:
+
+/* reg0 = reg1 op im */
+#define ALUI(N, T, OP, I0, I1, V, R0, R1, R2)          \
+       movi %R1 I0                                     \
+       movi %R2 V                                      \
+       OP##i##T %R0 %R1 I1                             \
+       beqr OP##T##N##i_##R0##R1##R2 %R0 %R2           \
+       calli @abort                                    \
+OP##T##N##i_##R0##R1##R2:
+
+/* reg0 = reg0 op reg1 */
+#define ALUR0(N, T, OP, I0, I1, V, R0, R1, R2)         \
+       movi %R0 I0                                     \
+       movi %R1 I1                                     \
+       movi %R2 V                                      \
+       OP##r##T %R0 %R0 %R1                            \
+       beqr OP##T##N##r_0##R0##R1##R2 %R0 %R2          \
+       calli @abort                                    \
+OP##T##N##r_0##R0##R1##R2:
+
+/* reg0 = reg1 op reg0 */
+#define ALUR1(N, T, OP, I0, I1, V, R0, R1, R2)         \
+       movi %R0 I1                                     \
+       movi %R1 I0                                     \
+       movi %R2 V                                      \
+       OP##r##T %R0 %R1 %R0                            \
+       beqr OP##T##N##r_1##R0##R1##R2 %R0 %R2          \
+       calli @abort                                    \
+OP##T##N##r_1##R0##R1##R2:
+
+/* reg0 = reg0 op im */
+#define ALUI0(N, T, OP, I0, I1, V, R0, R1, R2)         \
+       movi %R0 I0                                     \
+       movi %R1 V                                      \
+       OP##i##T %R0 %R0 I1                             \
+       beqr OP##T##N##i_0##R0##R1##R2 %R0 %R1          \
+       calli @abort                                    \
+OP##T##N##i_0##R0##R1##R2:
+
+#define ALU3(N, T, OP, I0, I1, V, R0, R1, R2)          \
+       ALUR(N, T, OP, I0, I1, V, R0, R1, R2)           \
+       ALUI(N, T, OP, I0, I1, V, R0, R1, R2)           \
+       ALUR0(N, T, OP, I0, I1, V, R0, R1, R2)          \
+       ALUR1(N, T, OP, I0, I1, V, R0, R1, R2)          \
+       ALUI0(N, T, OP, I0, I1, V, R0, R1, R2)
+
+#define ALU2(N, T, OP, I0, I1, V, R0, R1, R2)          \
+       ALU3(N, T, OP, I0, I1, V, R0, R1, R2)           \
+       ALU3(N, T, OP, I0, I1, V, R0, R2, R1)
+
+#define ALU1(N, T, OP, I0, I1, V, R0, R1, R2)          \
+       ALU2(N, T, OP, I0, I1, V, R0, R1, R2)           \
+       ALU2(N, T, OP, I0, I1, V, R1, R0, R2)           \
+       ALU2(N, T, OP, I0, I1, V, R2, R1, R0)
+
+#if __ia64__
+#  define ALU(N, T, OP, I0, I1, V)                     \
+       ALU3(N, T, OP, I0, I1, V, r0, r1, r2)           \
+       ALU3(N, T, OP, I0, I1, V, v0, v1, v2)
+#else
+#  define ALU(N, T, OP, I0, I1, V)                     \
+       ALU1(N, T, OP, I0, I1, V, v0, v1, v2)           \
+       ALU1(N, T, OP, I0, I1, V, v0, v1, r0)           \
+       ALU1(N, T, OP, I0, I1, V, v0, v1, r1)           \
+       ALU1(N, T, OP, I0, I1, V, v0, v1, r2)           \
+       ALU1(N, T, OP, I0, I1, V, v1, v2, r1)           \
+       ALU1(N, T, OP, I0, I1, V, v1, v2, r2)           \
+       ALU1(N, T, OP, I0, I1, V, v2, r0, r1)           \
+       ALU1(N, T, OP, I0, I1, V, v2, r0, r2)           \
+       ALU1(N, T, OP, I0, I1, V, r0, r1, r2)
+#endif
+
+/* 3 carry set/propagate */
+
+/*
+ * r0 = i0
+ * r1 = i1
+ * r2 = 0
+ * r0 = r0 opc r1      <only want carry>
+ * r2 = r2 opx r2      <r2 must match v>
+ */
+#define ALUXII(N, OP, I0, I1, V, R0, R1, R2)           \
+       movi %R0 I0                                     \
+       movi %R2 0                                      \
+       OP##ci %R0 %R0 I1                               \
+       OP##xi %R2 %R2 0                                \
+       beqi OP##N##ii##R0##R1##R2 %R2 V                \
+       calli @abort                                    \
+OP##N##ii##R0##R1##R2:
+
+#define ALUXIR(N, OP, I0, I1, V, R0, R1, R2)           \
+       movi %R0 I0                                     \
+       movi %R2 0                                      \
+       OP##ci %R0 %R0 I1                               \
+       OP##xr %R2 %R2 %R2                              \
+       beqi OP##N##ir##R0##R1##R2 %R2 V                \
+       calli @abort                                    \
+OP##N##ir##R0##R1##R2:
+
+#define ALUXRI(N, OP, I0, I1, V, R0, R1, R2)           \
+       movi %R0 I0                                     \
+       movi %R1 I1                                     \
+       movi %R2 0                                      \
+       OP##cr %R0 %R0 %R1                              \
+       OP##xi %R2 %R2 0                                \
+       beqi OP##N##ri##R0##R1##R2 %R2 V                \
+       calli @abort                                    \
+OP##N##ri##R0##R1##R2:
+
+#define ALUXRR(N, OP, I0, I1, V, R0, R1, R2)           \
+       movi %R0 I0                                     \
+       movi %R1 I1                                     \
+       movi %R2 0                                      \
+       OP##cr %R0 %R0 %R1                              \
+       OP##xr %R2 %R2 %R2                              \
+       beqi OP##N##rr##R0##R1##R2 %R2 V                \
+       calli @abort                                    \
+OP##N##rr##R0##R1##R2:
+
+#define ALUX2(N, OP, I0, I1, V, R0, R1, R2)            \
+        ALUXII(N, OP, I0, I1, V, R0, R1, R2)           \
+        ALUXIR(N, OP, I0, I1, V, R0, R1, R2)           \
+        ALUXRI(N, OP, I0, I1, V, R0, R1, R2)           \
+        ALUXRR(N, OP, I0, I1, V, R0, R1, R2)
+
+#define ALUX1(N, OP, I0, I1, V, R0, R1, R2)            \
+       ALUX2(N, OP, I0, I1, V, R0, R1, R2)             \
+       ALUX2(N, OP, I0, I1, V, R0, R2, R1)
+
+#define ALUX0(N, OP, I0, I1, V, R0, R1, R2)            \
+       ALUX1(N, OP, I0, I1, V, R0, R1, R2)             \
+       ALUX1(N, OP, I0, I1, V, R1, R0, R2)             \
+       ALUX1(N, OP, I0, I1, V, R2, R1, R0)
+
+#if __ia64__
+#  define ALUX(N, OP, I0, I1, V)                       \
+       ALUX2(N, OP, I0, I1, V, r0, r1, r2)             \
+       ALUX2(N, OP, I0, I1, V, v0, v1, v2)
+#else
+#  define ALUX(N, OP, I0, I1, V)                       \
+       ALUX0(N, OP, I0, I1, V, v0, v1, v2)             \
+       ALUX0(N, OP, I0, I1, V, v0, v1, r0)             \
+       ALUX0(N, OP, I0, I1, V, v0, v1, r1)             \
+       ALUX0(N, OP, I0, I1, V, v0, v1, r2)             \
+       ALUX0(N, OP, I0, I1, V, v1, v2, r0)             \
+       ALUX0(N, OP, I0, I1, V, v1, v2, r1)             \
+       ALUX0(N, OP, I0, I1, V, v1, v2, r2)             \
+       ALUX0(N, OP, I0, I1, V, v2, r0, r1)             \
+       ALUX0(N, OP, I0, I1, V, v2, r0, r2)             \
+       ALUX0(N, OP, I0, I1, V, r0, r1, r2)
+#endif
+
+/* unary int */
+
+#define UNR(N, OP, I, V, R0, R1)                       \
+       movi %R1 I                                      \
+       OP##r %R0 %R1                                   \
+       beqi OP##N##R0##R1 %R0 V                        \
+       calli @abort                                    \
+OP##N##R0##R1:
+
+#define UNRC(N, OP, I, V, R0, R1)                      \
+       movi %R0 I                                      \
+       OP##r %R0 %R0                                   \
+       beqi OP##N##c##R0##R1 %R0 V                     \
+       calli @abort                                    \
+OP##N##c##R0##R1:
+
+#define UN2(N, OP, I, V, R0, R1)                       \
+       UNR(N, OP, I, V, R0, R1)                        \
+       UNRC(N, OP, I, V, R0, R1)
+
+#define UN1(N, OP, I, V, R0, R1)                       \
+       UN2(N, OP, I, V, R0, R1)                        \
+       UN2(N, OP, I, V, R1, R0)
+
+#if __ia64__
+#  define UN(N, OP, I, V)                              \
+       UN2(N, OP, I, V, r0, r1)                        \
+       UN2(N, OP, I, V, v0, v1)
+#else
+#  define UN(N, OP, I, V)                              \
+       UN1(N, OP, I, V, v0, v1)                        \
+       UN1(N, OP, I, V, v0, v2)                        \
+       UN1(N, OP, I, V, v0, r0)                        \
+       UN1(N, OP, I, V, v0, r1)                        \
+       UN1(N, OP, I, V, v0, r2)                        \
+       UN1(N, OP, I, V, v1, v2)                        \
+       UN1(N, OP, I, V, v1, r0)                        \
+       UN1(N, OP, I, V, v1, r1)                        \
+       UN1(N, OP, I, V, v1, r2)                        \
+       UN1(N, OP, I, V, v2, r0)                        \
+       UN1(N, OP, I, V, v2, r1)                        \
+       UN1(N, OP, I, V, v2, r2)                        \
+       UN1(N, OP, I, V, r0, r1)                        \
+       UN1(N, OP, I, V, r0, r2)                        \
+       UN1(N, OP, I, V, r1, r2)
+#endif
+
+/* reg0 = reg1 op reg2 */
+#define FOPR(N, T, OP, I0, I1, V, F0, F1, F2)          \
+       movi##T %F1 I0                                  \
+       movi##T %F2 I1                                  \
+       OP##r##T %F0 %F1 %F2                            \
+       beqi##T OP##T##N##F0##F1##F2 %F0 V              \
+       calli @abort                                    \
+OP##T##N##F0##F1##F2:
+
+/* reg0 = reg0 op reg1 */
+#define FOPR0(N, T, OP, I0, I1, V, F0, F1, F2)         \
+       movi##T %F0 I0                                  \
+       movi##T %F1 I1                                  \
+       OP##r##T %F0 %F0 %F1                            \
+       beqi##T OP##T##N##0##F0##F1##F2 %F0 V           \
+       calli @abort                                    \
+OP##T##N##0##F0##F1##F2:
+
+/* reg1 = reg0 op reg1 */
+#define FOPR1(N, T, OP, I0, I1, V, F0, F1, F2)         \
+       movi##T %F0 I0                                  \
+       movi##T %F1 I1                                  \
+       OP##r##T %F1 %F0 %F1                            \
+       beqi##T OP##T##N##1##F0##F1##F2 %F1 V           \
+       calli @abort                                    \
+OP##T##N##1##F0##F1##F2:
+
+/* reg0 = reg1 op im */
+#define FOPI(N, T, OP, I0, I1, V, F0, F1, F2)          \
+       movi##T %F1 I0                                  \
+       movi##T %F2 V                                   \
+       OP##i##T %F0 %F1 I1                             \
+       beqr##T OP##T##N##i##F0##F1##F2 %F0 %F2         \
+       calli @abort                                    \
+OP##T##N##i##F0##F1##F2:
+
+/* reg0 = reg0 op im */
+#define FOPI0(N, T, OP, I0, I1, V, F0, F1, F2)         \
+       movi##T %F0 I0                                  \
+       movi##T %F2 V                                   \
+       OP##i##T %F0 %F0 I1                             \
+       beqr##T OP##T##N##i0##F0##F1##F2 %F0 %F2        \
+       calli @abort                                    \
+OP##T##N##i0##F0##F1##F2:
+
+#define FOP1(N, T, OP, I0, I1, V, F0, F1, F2)          \
+       FOPR(N, T, OP, I0, I1, V, F0, F1, F2)           \
+       FOPR0(N, T, OP, I0, I1, V, F0, F1, F2)          \
+       FOPR1(N, T, OP, I0, I1, V, F0, F1, F2)          \
+       FOPI(N, T, OP, I0, I1, V, F0, F1, F2)           \
+       FOPI0(N, T, OP, I0, I1, V, F0, F1, F2)
+
+#if __ia64__
+#  define  FOP(N, T, OP, I0, I1, V)                    \
+       FOP1(N, T, OP, I0, I1, V, f0, f1, f2)
+#else
+#  define  FOP(N, T, OP, I0, I1, V)                    \
+       FOP1(N, T, OP, I0, I1, V, f0, f1, f2)           \
+       FOP1(N, T, OP, I0, I1, V, f0, f2, f3)           \
+       FOP1(N, T, OP, I0, I1, V, f0, f3, f4)           \
+       FOP1(N, T, OP, I0, I1, V, f0, f5, f1)
+#endif
+
+/* unary float */
+
+#define FUNR(N, T, OP, I, V, R0, R1)                   \
+       movi##T %R1 I                                   \
+       OP##r##T %R0 %R1                                \
+       beqi##T OP##N##T##R0##R1 %R0 V                  \
+       calli @abort                                    \
+OP##N##T##R0##R1:
+
+#define FUNRC(N, T, OP, I, V, R0, R1)                  \
+       movi##T %R0 I                                   \
+       OP##r##T %R0 %R0                                \
+       beqi##T OP##N##T##c##R0##R1 %R0 V               \
+       calli @abort                                    \
+OP##N##T##c##R0##R1:
+
+#define FUN2(N, T, OP, I, V, R0, R1)                   \
+       FUNR(N, T, OP, I, V, R0, R1)                    \
+       FUNRC(N, T, OP, I, V, R0, R1)
+
+#define FUN1(N, T, OP, I, V, R0, R1)                   \
+       FUN2(N, T, OP, I, V, R0, R1)                    \
+       FUN2(N, T, OP, I, V, R1, R0)
+
+#if __ia64__
+#  define FUN(N, T, OP, I, V)                          \
+       FUN2(N, T, OP, I, V, f0, f1)
+#else
+#  define FUN(N, T, OP, I, V)                          \
+       FUN1(N, T, OP, I, V, f0, f1)                    \
+       FUN1(N, T, OP, I, V, f0, f2)                    \
+       FUN1(N, T, OP, I, V, f0, f3)                    \
+       FUN1(N, T, OP, I, V, f0, f4)                    \
+       FUN1(N, T, OP, I, V, f0, f5)
+#endif
+
+/* unordered comparison unary float */
+
+#define UFUNR(N, T, OP, I, V, R0, R1)                  \
+       movi##T %R1 I                                   \
+       OP##r##T %R0 %R1                                \
+       buneqi##T OP##N##T##u##R0##R1 %R0 V             \
+       calli @abort                                    \
+OP##N##T##u##R0##R1:
+
+#define UFUNRC(N, T, OP, I, V, R0, R1)                 \
+       movi##T %R0 I                                   \
+       OP##r##T %R0 %R0                                \
+       buneqi##T OP##N##T##uc##R0##R1 %R0 V            \
+       calli @abort                                    \
+OP##N##T##uc##R0##R1:
+
+#define UFUN2(N, T, OP, I, V, R0, R1)                  \
+       UFUNR(N, T, OP, I, V, R0, R1)                   \
+       UFUNRC(N, T, OP, I, V, R0, R1)
+
+#define UFUN1(N, T, OP, I, V, R0, R1)                  \
+       UFUN2(N, T, OP, I, V, R0, R1)                   \
+       UFUN2(N, T, OP, I, V, R1, R0)
+
+#if __ia64__
+#  define UFUN(N, T, OP, I, V)                         \
+       UFUN2(N, T, OP, I, V, f0, f1)
+#else
+#  define UFUN(N, T, OP, I, V)                         \
+       UFUN1(N, T, OP, I, V, f0, f1)                   \
+       UFUN1(N, T, OP, I, V, f0, f2)                   \
+       UFUN1(N, T, OP, I, V, f0, f3)                   \
+       UFUN1(N, T, OP, I, V, f0, f4)                   \
+       UFUN1(N, T, OP, I, V, f0, f5)
+#endif
+
+.      $( $NaN =  0.0/0.0)
+.      $( $Inf =  1.0/0.0)
+.      $($nInf = -1.0/0.0)
diff --git a/deps/lightning/check/alu_add.ok b/deps/lightning/check/alu_add.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_add.tst b/deps/lightning/check/alu_add.tst
new file mode 100644 (file)
index 0000000..16cdf38
--- /dev/null
@@ -0,0 +1,47 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define ADD(N, I0, I1, V)      ALU(N, , add, I0, I1, V)
+
+       ADD(0,  0x7fffffff, 1,          0x80000000)
+       ADD(1,  1,          0x7fffffff, 0x80000000)
+       ADD(2,  0x80000000, 1,          0x80000001)
+       ADD(3,  1,          0x80000000, 0x80000001)
+       ADD(4,  0x7fffffff, 0x80000000, 0xffffffff)
+       ADD(5,  0x80000000, 0x7fffffff, 0xffffffff)
+       ADD(6,  0x7fffffff, 0,          0x7fffffff)
+       ADD(7,  0,          0x7fffffff, 0x7fffffff)
+#if __WORDSIZE == 32
+       ADD(8,  0x7fffffff, 0xffffffff, 0x7ffffffe)
+       ADD(9,  0xffffffff, 0x7fffffff, 0x7ffffffe)
+       ADD(10, 0xffffffff, 0xffffffff, 0xfffffffe)
+#else
+       ADD(8,  0x7fffffff,         0xffffffff,         0x17ffffffe)
+       ADD(9,  0xffffffff,         0x7fffffff,         0x17ffffffe)
+       ADD(10, 0xffffffff,         0xffffffff,         0x1fffffffe)
+       ADD(11, 0x7fffffffffffffff, 1,                  0x8000000000000000)
+       ADD(12, 1,                  0x7fffffffffffffff, 0x8000000000000000)
+       ADD(13, 0x8000000000000000, 1,                  0x8000000000000001)
+       ADD(14, 1,                  0x8000000000000000, 0x8000000000000001)
+       ADD(15, 0x7fffffffffffffff, 0x8000000000000000, 0xffffffffffffffff)
+       ADD(16, 0x8000000000000000, 0x7fffffffffffffff, 0xffffffffffffffff)
+       ADD(17, 0x7fffffffffffffff, 0xffffffffffffffff, 0x7ffffffffffffffe)
+       ADD(18, 0x7fffffffffffffff, 0x7fffffffffffffff, 0xfffffffffffffffe)
+       ADD(19, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffffe)
+#endif
+
+#undef ADD
+#define ADD(N, T, I0, I1, V)   FOP(N, T, add, I0, I1, V)
+       ADD(0, _f,      -0.5,       0.5,        0.0)
+       ADD(1, _f,       0.25,      0.75,       1.0)
+       ADD(0, _d,      -0.5,       0.5,        0.0)
+       ADD(1, _d,       0.25,      0.75,       1.0)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_and.ok b/deps/lightning/check/alu_and.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_and.tst b/deps/lightning/check/alu_and.tst
new file mode 100644 (file)
index 0000000..7474271
--- /dev/null
@@ -0,0 +1,36 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define AND(N, I0, I1, V)      ALU(N, , and, I0, I1, V)
+
+       AND(0,  0x7fffffff, 1,          1)
+       AND(1,  1,          0x7fffffff, 1)
+       AND(2,  0x80000000, 1,          0)
+       AND(3,  1,          0x80000000, 0)
+       AND(4,  0x7fffffff, 0x80000000, 0)
+       AND(5,  0x80000000, 0x7fffffff, 0)
+       AND(6,  0x7fffffff, 0xffffffff, 0x7fffffff)
+       AND(7,  0xffffffff, 0x7fffffff, 0x7fffffff)
+       AND(8,  0xffffffff, 0xffffffff, 0xffffffff)
+       AND(9,  0x7fffffff, 0,          0)
+       AND(10, 0,          0x7fffffff, 0)
+#if __WORDSIZE == 64
+       AND(11, 0x7fffffffffffffff, 1,                  1)
+       AND(12, 1,                  0x7fffffffffffffff, 1)
+       AND(13, 0x8000000000000000, 1,                  0)
+       AND(14, 1,                  0x8000000000000000, 0)
+       AND(15, 0x7fffffffffffffff, 0x8000000000000000, 0)
+       AND(16, 0x8000000000000000, 0x7fffffffffffffff, 0)
+       AND(17, 0x7fffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff)
+       AND(18, 0xffffffffffffffff, 0x7fffffffffffffff, 0x7fffffffffffffff)
+       AND(19, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff)
+#endif
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_com.ok b/deps/lightning/check/alu_com.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_com.tst b/deps/lightning/check/alu_com.tst
new file mode 100644 (file)
index 0000000..581c940
--- /dev/null
@@ -0,0 +1,33 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define COM(N, I0, V)          UN(N, com, I0, V)
+
+#if __WORDSIZE == 32
+       COM(0,  0,                      0xffffffff)
+       COM(1,  1,                      0xfffffffe)
+       COM(2,  0xffffffff,             0)
+       COM(3,  0x80000000,             0x7fffffff)
+       COM(4,  0x7fffffff,             0x80000000)
+       COM(5,  0x80000001,             0x7ffffffe)
+#else
+       COM(0,  0,                      0xffffffffffffffff)
+       COM(1,  1,                      0xfffffffffffffffe)
+       COM(2,  0xffffffff,             0xffffffff00000000)
+       COM(3,  0x80000000,             0xffffffff7fffffff)
+       COM(4,  0x7fffffff,             0xffffffff80000000)
+       COM(5,  0x80000001,             0xffffffff7ffffffe)
+       COM(6,  0xffffffffffffffff,     0)
+       COM(7,  0x8000000000000000,     0x7fffffffffffffff)
+       COM(8,  0x7fffffffffffffff,     0x8000000000000000)
+       COM(9,  0x8000000000000001,     0x7ffffffffffffffe)
+#endif
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_div.ok b/deps/lightning/check/alu_div.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_div.tst b/deps/lightning/check/alu_div.tst
new file mode 100644 (file)
index 0000000..97e024d
--- /dev/null
@@ -0,0 +1,83 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define DIV(N, I0, I1, V)      ALU(N, , div, I0, I1, V)
+#define UDIV(N, I0, I1, V)     ALU(N, _u, div, I0, I1, V)
+
+       DIV(0,  0x7fffffff, 1,          0x7fffffff)
+       DIV(1,  1,          0x7fffffff, 0)
+       DIV(2,  0x80000000, 1,          0x80000000)
+       DIV(3,  1,          0x80000000, 0)
+       DIV(4,  0x7fffffff, 2,          0x3fffffff)
+       DIV(5,  2,          0x7fffffff, 0)
+       DIV(6,  2,          0x80000000, 0)
+       DIV(7,  0x7fffffff, 0x80000000, 0)
+       DIV(8,  0,          0x7fffffff, 0)
+       DIV(9,  0xffffffff, 0xffffffff, 1)
+       UDIV(0, 0x7fffffff, 1,          0x7fffffff)
+       UDIV(1, 1,          0x7fffffff, 0)
+       UDIV(2, 0x80000000, 1,          0x80000000)
+       UDIV(3, 1,          0x80000000, 0)
+       UDIV(4, 0x7fffffff, 2,          0x3fffffff)
+       UDIV(5, 2,          0x7fffffff, 0)
+       UDIV(6, 0x80000000, 2,          0x40000000)
+       UDIV(7, 2,          0x80000000, 0)
+       UDIV(8, 0x7fffffff, 0x80000000, 0)
+       UDIV(9, 0x80000000, 0x7fffffff, 1)
+       UDIV(10,0,          0x7fffffff, 0)
+       UDIV(11,0x7fffffff, 0xffffffff, 0)
+       UDIV(12,0xffffffff, 0x7fffffff, 2)
+       UDIV(13,0xffffffff, 0xffffffff, 1)
+#if __WORDSIZE == 32
+       DIV(10, 0x80000000, 2,          0xc0000000)
+       DIV(11, 0x80000000, 0x7fffffff, 0xffffffff)
+       DIV(12, 0x7fffffff, 0xffffffff, 0x80000001)
+       DIV(13, 0xffffffff, 0x7fffffff, 0)
+#else
+       DIV(10, 0x80000000,         2,                  0x40000000)
+       DIV(11, 0x80000000,         0x7fffffff,         1)
+       DIV(12, 0x7fffffff,         0xffffffff,         0)
+       DIV(13, 0xffffffff,         0x7fffffff,         2)
+       DIV(14, 0x7fffffffffffffff, 1,                  0x7fffffffffffffff)
+       DIV(15, 1,                  0x7fffffffffffffff, 0)
+       DIV(16, 0x8000000000000000, 1,                  0x8000000000000000)
+       DIV(17, 1,                  0x8000000000000000, 0)
+       DIV(18, 0x7fffffffffffffff, 2,                  0x3fffffffffffffff)
+       DIV(19, 2,                  0x7fffffffffffffff, 0)
+       DIV(20, 0x8000000000000000, 2,                  0xc000000000000000)
+       DIV(21, 2,                  0x8000000000000000, 0)
+       DIV(22, 0x7fffffffffffffff, 0x8000000000000000, 0)
+       DIV(23, 0x8000000000000000, 0x7fffffffffffffff, 0xffffffffffffffff)
+       DIV(24, 0x7fffffffffffffff, 0xffffffffffffffff, 0x8000000000000001)
+       DIV(25, 0xffffffffffffffff, 0x7fffffffffffffff, 0)
+       DIV(26, 0xffffffffffffffff, 0xffffffffffffffff, 1)
+       UDIV(14,0x7fffffffffffffff, 1,                  0x7fffffffffffffff)
+       UDIV(15,1,                  0x7fffffffffffffff, 0)
+       UDIV(16,0x8000000000000000, 1,                  0x8000000000000000)
+       UDIV(17,1,                  0x8000000000000000, 0)
+       UDIV(18,0x7fffffffffffffff, 2,                  0x3fffffffffffffff)
+       UDIV(19,2,                  0x7fffffffffffffff, 0)
+       UDIV(20,0x8000000000000000, 2,                  0x4000000000000000)
+       UDIV(21,2,                  0x8000000000000000, 0)
+       UDIV(22,0x7fffffffffffffff, 0x8000000000000000, 0)
+       UDIV(23,0x8000000000000000, 0x7fffffffffffffff, 1)
+       UDIV(24,0x7fffffffffffffff, 0xffffffffffffffff, 0)
+       UDIV(25,0xffffffffffffffff, 0x7fffffffffffffff, 2)
+       UDIV(26,0xffffffffffffffff, 0xffffffffffffffff, 1)
+#endif
+
+#undef DIV
+#define DIV(N, T, I0, I1, V)   FOP(N, T, div, I0, I1, V)
+       DIV(0, _f,      -0.5,       0.5,        -1.0)
+       DIV(1, _f,       1.25,      0.5,         2.5)
+       DIV(0, _d,      -0.5,       0.5,        -1.0)
+       DIV(1, _d,       1.25,      0.5,         2.5)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_lsh.ok b/deps/lightning/check/alu_lsh.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_lsh.tst b/deps/lightning/check/alu_lsh.tst
new file mode 100644 (file)
index 0000000..c05fda0
--- /dev/null
@@ -0,0 +1,57 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define LSH(N, I0, I1, V)      ALU(N, , lsh, I0, I1, V)
+
+       LSH(0,   0x7f,           1,     0xfe)
+       LSH(1,   0x7fff,         2,     0x1fffc)
+       LSH(2,   0x81,          16,     0x810000)
+       LSH(3,   0xff,          15,     0x7f8000)
+       LSH(4,   0x7fffffff,     0,     0x7fffffff)
+#if __WORDSIZE == 32
+       LSH(5,   0xffffffff,    8,      0xffffff00)
+       LSH(6,   0x7fffffff,    3,      0xfffffff8)
+       LSH(7,  -0x7f,          31,     0x80000000)
+       LSH(8,  -0x7fff,        30,     0x40000000)
+       LSH(9,  -0x7fffffff,    29,     0x20000000)
+       LSH(10,  0x80000001,    28,     0x10000000)
+       LSH(11,  0x8001,        17,     0x20000)
+       LSH(12,  0x80000001,    18,     0x40000)
+       LSH(13, -0xffff,        24,     0x1000000)
+#else
+       LSH(5,   0xffffffff,     8,     0xffffffff00)
+       LSH(6,   0x7fffffff,     3,     0x3fffffff8)
+       LSH(7,  -0x7f,          31,     0xffffffc080000000)
+       LSH(8,  -0x7fff,        30,     0xffffe00040000000)
+       LSH(9,  -0x7fffffff,    29,     0xf000000020000000)
+       LSH(10,  0x80000001,    28,     0x800000010000000)
+       LSH(11,  0x8001,        17,     0x100020000)
+       LSH(12,  0x80000001,    18,     0x2000000040000)
+       LSH(13, -0xffff,        24,     0xffffff0001000000)
+       LSH(14,  0x7f,          33,     0xfe00000000)
+       LSH(15,  0x7ffff,       34,     0x1ffffc00000000)
+       LSH(16,  0x7fffffff,    35,     0xfffffff800000000)
+       LSH(17, -0x7f,          63,     0x8000000000000000)
+       LSH(18, -0x7fff,        62,     0x4000000000000000)
+       LSH(19, -0x7fffffff,    61,     0x2000000000000000)
+       LSH(20,  0x80000001,    60,     0x1000000000000000)
+       LSH(21,  0x81,          48,     0x81000000000000)
+       LSH(22,  0x8001,        49,     0x2000000000000)
+       LSH(23,  0x80000001,    40,     0x10000000000)
+       LSH(24,  0xff,          47,     0x7f800000000000)
+       LSH(25,  0xffff0001,    56,     0x100000000000000)
+       LSH(26,  0xffffffff,    40,     0xffffff0000000000)
+       LSH(27,  0x7fffffffff,  33,     0xfffffffe00000000)
+       LSH(28, -0x7fffffffff,  63,     0x8000000000000000)
+       LSH(29,  0x8000000001,  48,     0x1000000000000)
+       LSH(30,  0xffffffffff,  47,     0xffff800000000000)
+#endif
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_mul.ok b/deps/lightning/check/alu_mul.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_mul.tst b/deps/lightning/check/alu_mul.tst
new file mode 100644 (file)
index 0000000..748417c
--- /dev/null
@@ -0,0 +1,59 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define MUL(N, I0, I1, V)      ALU(N, , mul, I0, I1, V)
+
+       MUL(0,  0x7fffffff, 1,          0x7fffffff)
+       MUL(1,  1,          0x7fffffff, 0x7fffffff)
+       MUL(2,  0x80000000, 1,          0x80000000)
+       MUL(3,  1,          0x80000000, 0x80000000)
+       MUL(4,  0x7fffffff, 2,          0xfffffffe)
+       MUL(5,  2,          0x7fffffff, 0xfffffffe)
+       MUL(6,  0x7fffffff, 0,          0)
+       MUL(7,  0,          0x7fffffff, 0)
+#if __WORDSIZE == 32
+       MUL(8,  0x80000000, 2,          0)
+       MUL(9,  2,          0x80000000, 0)
+       MUL(10, 0x7fffffff, 0x80000000, 0x80000000)
+       MUL(11, 0x80000000, 0x7fffffff, 0x80000000)
+       MUL(12, 0x7fffffff, 0xffffffff, 0x80000001)
+       MUL(13, 0xffffffff, 0x7fffffff, 0x80000001)
+       MUL(14, 0xffffffff, 0xffffffff, 1)
+#else
+       MUL(8,  0x80000000,         2,                  0x100000000)
+       MUL(9,  2,                  0x80000000,         0x100000000)
+       MUL(10, 0x7fffffff,         0x80000000,         0x3fffffff80000000)
+       MUL(11, 0x80000000,         0x7fffffff,         0x3fffffff80000000)
+       MUL(12, 0x7fffffff,         0xffffffff,         0x7ffffffe80000001)
+       MUL(13, 0xffffffff,         0x7fffffff,         0x7ffffffe80000001)
+       MUL(14, 0xffffffff,         0xffffffff,         0xfffffffe00000001)
+       MUL(15, 0x7fffffffffffffff, 1,                  0x7fffffffffffffff)
+       MUL(16, 1,                  0x7fffffffffffffff, 0x7fffffffffffffff)
+       MUL(17, 0x8000000000000000, 1,                  0x8000000000000000)
+       MUL(18, 1,                  0x8000000000000000, 0x8000000000000000)
+       MUL(19, 0x7fffffffffffffff, 2,                  0xfffffffffffffffe)
+       MUL(20, 2,                  0x7fffffffffffffff, 0xfffffffffffffffe)
+       MUL(21, 0x8000000000000000, 2,                  0)
+       MUL(22, 2,                  0x8000000000000000, 0)
+       MUL(23, 0x7fffffffffffffff, 0x8000000000000000, 0x8000000000000000)
+       MUL(24, 0x8000000000000000, 0x7fffffffffffffff, 0x8000000000000000)
+       MUL(25, 0x7fffffffffffffff, 0xffffffffffffffff, 0x8000000000000001)
+       MUL(26, 0xffffffffffffffff, 0x7fffffffffffffff, 0x8000000000000001)
+       MUL(27, 0xffffffffffffffff, 0xffffffffffffffff, 1)
+#endif
+
+#undef MUL
+#define MUL(N, T, I0, I1, V)   FOP(N, T, mul, I0, I1, V)
+       MUL(0, _f,      -0.5,       0.5,        -0.25)
+       MUL(1, _f,       0.25,      0.75,        0.1875)
+       MUL(0, _d,      -0.5,       0.5,        -0.25)
+       MUL(1, _d,       0.25,      0.75,        0.1875)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_neg.ok b/deps/lightning/check/alu_neg.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_neg.tst b/deps/lightning/check/alu_neg.tst
new file mode 100644 (file)
index 0000000..3264d13
--- /dev/null
@@ -0,0 +1,42 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define NEG(N, I, V)                   UN(N, neg, I, V)
+
+       NEG(0,  0,                      0)
+#if __WORDSIZE == 32
+       NEG(1,  1,                      0xffffffff)
+       NEG(2,  0xffffffff,             1)
+       NEG(3,  0x80000000,             0x80000000)
+       NEG(4,  0x7fffffff,             0x80000001)
+       NEG(5,  0x80000001,             0x7fffffff)
+#else
+       NEG(1,  1,                      0xffffffffffffffff)
+       NEG(2,  0xffffffff,             0xffffffff00000001)
+       NEG(3,  0x80000000,             0xffffffff80000000)
+       NEG(4,  0x7fffffff,             0xffffffff80000001)
+       NEG(5,  0x80000001,             0xffffffff7fffffff)
+       NEG(6,  0xffffffffffffffff,     1)
+       NEG(7,  0x8000000000000000,     0x8000000000000000)
+       NEG(8,  0x7fffffffffffffff,     0x8000000000000001)
+#endif
+
+#undef NEG
+#define NEG(N, T, I, V)                        FUN(N, T, neg, I, V)
+       NEG(0, _f,      0.0,            -0.0)
+       NEG(1, _f,      0.5,            -0.5)
+       NEG(2, _f,      $(1 / 0.0),     $(-1.0 / 0))
+       NEG(3, _f,      -1.25,           1.25)
+       NEG(0, _d,       0.0,           -0.0)
+       NEG(1, _d,       0.5,           -0.5)
+       NEG(2, _d,       $(1.0 / 0),    $(-1 / 0.0))
+       NEG(3, _d,      -1.25,           1.25)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_or.ok b/deps/lightning/check/alu_or.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_or.tst b/deps/lightning/check/alu_or.tst
new file mode 100644 (file)
index 0000000..1e55a86
--- /dev/null
@@ -0,0 +1,36 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define OR(N, I0, I1, V)       ALU(N, , or, I0, I1, V)
+
+       OR(0,   0x7fffffff, 1,          0x7fffffff)
+       OR(1,   1,          0x7fffffff, 0x7fffffff)
+       OR(2,   0x80000000, 1,          0x80000001)
+       OR(3,   1,          0x80000000, 0x80000001)
+       OR(4,   0x7fffffff, 0x80000000, 0xffffffff)
+       OR(5,   0x80000000, 0x7fffffff, 0xffffffff)
+       OR(6,   0x7fffffff, 0xffffffff, 0xffffffff)
+       OR(7,   0xffffffff, 0x7fffffff, 0xffffffff)
+       OR(8,   0xffffffff, 0xffffffff, 0xffffffff)
+       OR(9,   0x7fffffff, 0,          0x7fffffff)
+       OR(10,  0,          0x7fffffff, 0x7fffffff)
+#if __WORDSIZE == 64
+       OR(11,  0x7fffffffffffffff, 1,                  0x7fffffffffffffff)
+       OR(12,  1,                  0x7fffffffffffffff, 0x7fffffffffffffff)
+       OR(13,  0x8000000000000000, 1,                  0x8000000000000001)
+       OR(14,  1,                  0x8000000000000000, 0x8000000000000001)
+       OR(15,  0x7fffffffffffffff, 0x8000000000000000, 0xffffffffffffffff)
+       OR(16,  0x8000000000000000, 0x7fffffffffffffff, 0xffffffffffffffff)
+       OR(17,  0x7fffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff)
+       OR(18,  0xffffffffffffffff, 0x7fffffffffffffff, 0xffffffffffffffff)
+       OR(19,  0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff)
+#endif
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_rem.ok b/deps/lightning/check/alu_rem.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_rem.tst b/deps/lightning/check/alu_rem.tst
new file mode 100644 (file)
index 0000000..5aea7cf
--- /dev/null
@@ -0,0 +1,76 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define REM(N, I0, I1, V)      ALU(N, , rem, I0, I1, V)
+#define UREM(N, I0, I1, V)     ALU(N, _u, rem, I0, I1, V)
+
+       REM(0,  0x7fffffff, 1,          0)
+       REM(1,  1,          0x7fffffff, 1)
+       REM(2,  0x80000000, 1,          0)
+       REM(3,  1,          0x80000000, 1)
+       REM(4,  0x7fffffff, 2,          1)
+       REM(5,  2,          0x7fffffff, 2)
+       REM(6,  0x80000000, 2,          0)
+       REM(7,  2,          0x80000000, 2)
+       REM(8,  0x7fffffff, 0x80000000, 0x7fffffff)
+       REM(9,  0,          0x7fffffff, 0)
+       REM(10, 0xffffffff, 0xffffffff, 0)
+       UREM(0, 0x7fffffff, 1,          0)
+       UREM(1, 1,          0x7fffffff, 1)
+       UREM(2, 0x80000000, 1,          0)
+       UREM(3, 1,          0x80000000, 1)
+       UREM(4, 0x7fffffff, 2,          1)
+       UREM(5, 2,          0x7fffffff, 2)
+       UREM(6, 0x80000000, 2,          0)
+       UREM(7, 2,          0x80000000, 2)
+       UREM(8, 0x7fffffff, 0x80000000, 0x7fffffff)
+       UREM(9, 0x80000000, 0x7fffffff, 1)
+       UREM(10,0,          0x7fffffff, 0)
+       UREM(11,0x7fffffff, 0xffffffff, 0x7fffffff)
+       UREM(12,0xffffffff, 0x7fffffff, 1)
+       UREM(13,0xffffffff, 0xffffffff, 0)
+
+#if __WORDSIZE == 32
+       REM(11, 0x80000000, 0x7fffffff, 0xffffffff)
+       REM(12, 0x7fffffff, 0xffffffff, 0)
+       REM(13, 0xffffffff, 0x7fffffff, 0xffffffff)
+#else
+       REM(11, 0x80000000,         0x7fffffff,         1)
+       REM(12, 0x7fffffff,         0xffffffff,         0x7fffffff)
+       REM(13, 0xffffffff,         0x7fffffff,         1)
+       REM(14, 0x7fffffffffffffff, 1,                  0)
+       REM(15, 1,                  0x7fffffffffffffff, 1)
+       REM(16, 0x8000000000000000, 1,                  0)
+       REM(17, 1,                  0x8000000000000000, 1)
+       REM(18, 0x7fffffffffffffff, 2,                  1)
+       REM(19, 2,                  0x7fffffffffffffff, 2)
+       REM(20, 0x8000000000000000, 2,                  0)
+       REM(21, 2,                  0x8000000000000000, 2)
+       REM(22, 0x7fffffffffffffff, 0x8000000000000000, 0x7fffffffffffffff)
+       REM(23, 0x8000000000000000, 0x7fffffffffffffff, 0xffffffffffffffff)
+       REM(24, 0x7fffffffffffffff, 0xffffffffffffffff, 0)
+       REM(25, 0xffffffffffffffff, 0x7fffffffffffffff, 0xffffffffffffffff)
+       REM(26, 0xffffffffffffffff, 0xffffffffffffffff, 0)
+       UREM(14,0x7fffffffffffffff, 1,                  0)
+       UREM(15,1,                  0x7fffffffffffffff, 1)
+       UREM(16,0x8000000000000000, 1,                  0)
+       UREM(17,1,                  0x8000000000000000, 1)
+       UREM(18,0x7fffffffffffffff, 2,                  1)
+       UREM(19,2,                  0x7fffffffffffffff, 2)
+       UREM(20,0x8000000000000000, 2,                  0)
+       UREM(21,2,                  0x8000000000000000, 2)
+       UREM(22,0x7fffffffffffffff, 0x8000000000000000, 0x7fffffffffffffff)
+       UREM(23,0x8000000000000000, 0x7fffffffffffffff, 1)
+       UREM(24,0x7fffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff)
+       UREM(25,0xffffffffffffffff, 0x7fffffffffffffff, 1)
+       UREM(26,0xffffffffffffffff, 0xffffffffffffffff, 0)
+#endif
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_rsb.ok b/deps/lightning/check/alu_rsb.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_rsb.tst b/deps/lightning/check/alu_rsb.tst
new file mode 100644 (file)
index 0000000..00e08c2
--- /dev/null
@@ -0,0 +1,49 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define RSB(N, I0, I1, V)      ALU(N, , rsb, I0, I1, V)
+
+       RSB(0,  1,          0x7fffffff, 0x7ffffffe)
+       RSB(2,  1,          0x80000000, 0x7fffffff)
+       RSB(3,  0x7fffffff, 0x80000000, 1)
+       RSB(4,  0xffffffff, 0xffffffff, 0)
+       RSB(5,  0x7fffffff, 0xffffffff, 0x80000000)
+       RSB(6,  0, 0x7fffffff,          0x7fffffff)
+#if __WORDSIZE == 32
+       RSB(7,  0x7fffffff,          1, 0x80000002)
+       RSB(8,  0x80000000,          1, 0x80000001)
+       RSB(9,  0x80000000, 0x7fffffff, 0xffffffff)
+       RSB(10, 0xffffffff, 0x7fffffff, 0x80000000)
+       RSB(11, 0x7fffffff,          0, 0x80000001)
+#else
+       RSB(7,          0x7fffffff,                 1,  0xffffffff80000002)
+       RSB(8,  0xffffffff80000000,                 1,          0x80000001)
+       RSB(9,  0xffffffff80000000,        0x7fffffff,          0xffffffff)
+       RSB(10, 0xffffffffffffffff, 0xffffffff7fffffff, 0xffffffff80000000)
+       RSB(11,         0x7fffffff,                  0, 0xffffffff80000001)
+       RSB(12, 1,                  0x7fffffffffffffff, 0x7ffffffffffffffe)
+       RSB(13, 0x7fffffffffffffff,                  1, 0x8000000000000002)
+       RSB(14,                  1, 0x8000000000000000, 0x7fffffffffffffff)
+       RSB(15, 0x8000000000000000,                  1, 0x8000000000000001)
+       RSB(16, 0x8000000000000000, 0x7fffffffffffffff, 0xffffffffffffffff)
+       RSB(17, 0x7fffffffffffffff, 0x8000000000000000, 1)
+       RSB(18, 0xffffffffffffffff, 0x7fffffffffffffff, 0x8000000000000000)
+       RSB(19, 0x7fffffffffffffff, 0xffffffffffffffff, 0x8000000000000000)
+       RSB(20, 0xffffffffffffffff, 0xffffffffffffffff, 0)
+#endif
+
+#undef RSB
+#define RSB(N, T, I0, I1, V)   FOP(N, T, rsb, I0, I1, V)
+       RSB(0, _f,          0.5,        -0.5,   -1.0)
+       RSB(1, _f,          0.75,        0.25,  -0.5)
+       RSB(0, _d,          0.5,        -0.5,   -1.0)
+       RSB(1, _d,          0.75,        0.25,  -0.5)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_rsh.ok b/deps/lightning/check/alu_rsh.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_rsh.tst b/deps/lightning/check/alu_rsh.tst
new file mode 100644 (file)
index 0000000..93f8c7b
--- /dev/null
@@ -0,0 +1,85 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define RSH(N, I0, I1, V)      ALU(N, , rsh, I0, I1, V)
+#define URSH(N, I0, I1, V)     ALU(N, _u, rsh, I0, I1, V)
+
+       RSH(0,  0xfe,                1,         0x7f)
+       RSH(1,  0x1fffc,             2,         0x7fff)
+       RSH(2,  0x40000000,         30,         1)
+       RSH(3,  0x20000000,         29,         1)
+       RSH(4,  0x10000000,         28,         1)
+       RSH(5,  0x810000,           16,         0x81)
+       RSH(6,  0x20000,            17,         1)
+       RSH(7,  0x40000,            18,         1)
+       RSH(8,  0x7f8000,           15,         0xff)
+       RSH(9,  0x1000000,          24,         1)
+       RSH(10, 0x7fffffff,          0,         0x7fffffff)
+       URSH(0, 0xfe,                1,         0x7f)
+       URSH(1, 0x1fffc,             2,         0x7fff)
+       URSH(2, 0x80000000,         31,         1)
+       URSH(3, 0x40000000,         30,         1)
+       URSH(4, 0x20000000,         29,         1)
+       URSH(5, 0x10000000,         28,         1)
+       URSH(6, 0x810000,           16,         0x81)
+       URSH(7, 0x20000,            17,         1)
+       URSH(8, 0x40000,            18,         1)
+       URSH(9,0x7f8000,            15,         0xff)
+       URSH(10,0x1000000,          24,         1)
+       URSH(11,0xffffff00,          8,         0xffffff)
+       URSH(12,0x7fffffff,          0,         0x7fffffff)
+#if __WORDSIZE == 32
+       RSH(11, 0xfffffff8,          3,         0xffffffff)
+       RSH(12, 0x80000000,         31,         0xffffffff)
+       RSH(13, 0xffffff00,          8,         0xffffffff)
+       URSH(13,0xfffffff8,          3,         0x1fffffff)
+#else
+       RSH(11, 0x3fffffff8,         3,         0x7fffffff)
+       RSH(12, 0xffffffc080000000, 31,         0xffffffffffffff81)
+       RSH(13, 0xffffff00,          8,         0xffffff)
+       RSH(14, 0xfe00000000,       33,         0x7f)
+       RSH(15, 0x1ffffc00000000,   34,         0x7ffff)
+       RSH(16, 0xfffffff800000000, 29,         0xffffffffffffffc0)
+       RSH(17, 0x8000000000000000, 63,         0xffffffffffffffff)
+       RSH(18, 0x4000000000000000, 62,         1)
+       RSH(19, 0x2000000000000000, 61,         1)
+       RSH(20, 0x1000000000000000, 60,         1)
+       RSH(21, 0x81000000000000,   48,         0x81)
+       RSH(22, 0x2000000000000,    49,         1)
+       RSH(23, 0x10000000000,      40,         1)
+       RSH(24, 0x7f800000000000,   47,         0xff)
+       RSH(25, 0x100000000000000,  56,         1)
+       RSH(26, 0xffffff0000000000, 40,         0xffffffffffffffff)
+       RSH(27, 0xfffffffe00000000, 33,         0xffffffffffffffff)
+       RSH(28, 0x8000000000000001, 63,         0xffffffffffffffff)
+       RSH(29, 0x1000000000000,    48,         1)
+       RSH(30, 0xffff800000000000, 47,         0xffffffffffffffff)
+       URSH(13,0x3fffffff8,        3,          0x7fffffff)
+       URSH(14,0xffffffc080000000, 31,         0x1ffffff81)
+       URSH(15,0xfe00000000,       33,         0x7f)
+       URSH(16,0x1ffffc00000000,   34,         0x7ffff)
+       URSH(17,0xfffffff800000000, 29,         0x7ffffffc0)
+       URSH(18,0x8000000000000000, 63,         1)
+       URSH(19,0x4000000000000000, 62,         1)
+       URSH(20,0x2000000000000000, 61,         1)
+       URSH(21,0x1000000000000000, 60,         1)
+       URSH(22,0x81000000000000,   48,         0x81)
+       URSH(23,0x2000000000000,    49,         1)
+       URSH(24,0x10000000000,      40,         1)
+       URSH(25,0x7f800000000000,   47,         0xff)
+       URSH(26,0x100000000000000,  56,         1)
+       URSH(27,0xffffff0000000000, 40,         0xffffff)
+       URSH(28,0xfffffffe00000000, 33,         0x7fffffff)
+       URSH(29,0x8000000000000001, 63,         1)
+       URSH(30,0x1000000000000,    48,         1)
+       URSH(31,0xffff800000000000, 47,         0x1ffff)
+#endif
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_sub.ok b/deps/lightning/check/alu_sub.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_sub.tst b/deps/lightning/check/alu_sub.tst
new file mode 100644 (file)
index 0000000..8f07b62
--- /dev/null
@@ -0,0 +1,49 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define SUB(N, I0, I1, V)      ALU(N, , sub, I0, I1, V)
+
+       SUB(0,  0x7fffffff, 1,          0x7ffffffe)
+       SUB(2,  0x80000000, 1,          0x7fffffff)
+       SUB(3,  0x80000000, 0x7fffffff, 1)
+       SUB(4,  0xffffffff, 0xffffffff, 0)
+       SUB(5,  0xffffffff, 0x7fffffff, 0x80000000)
+       SUB(6,  0x7fffffff, 0,          0x7fffffff)
+#if __WORDSIZE == 32
+       SUB(7,  1,          0x7fffffff, 0x80000002)
+       SUB(8,  1,          0x80000000, 0x80000001)
+       SUB(9,  0x7fffffff, 0x80000000, 0xffffffff)
+       SUB(10, 0x7fffffff, 0xffffffff, 0x80000000)
+       SUB(11, 0,          0x7fffffff, 0x80000001)
+#else
+       SUB(7,  1,                  0x7fffffff,         0xffffffff80000002)
+       SUB(8,  1,                  0xffffffff80000000,         0x80000001)
+       SUB(9,  0x7fffffff,         0xffffffff80000000,         0xffffffff)
+       SUB(10, 0xffffffff7fffffff, 0xffffffffffffffff, 0xffffffff80000000)
+       SUB(11, 0,                  0x7fffffff,         0xffffffff80000001)
+       SUB(12, 0x7fffffffffffffff, 1,                  0x7ffffffffffffffe)
+       SUB(13, 1,                  0x7fffffffffffffff, 0x8000000000000002)
+       SUB(14, 0x8000000000000000, 1,                  0x7fffffffffffffff)
+       SUB(15, 1,                  0x8000000000000000, 0x8000000000000001)
+       SUB(16, 0x7fffffffffffffff, 0x8000000000000000, 0xffffffffffffffff)
+       SUB(17, 0x8000000000000000, 0x7fffffffffffffff, 1)
+       SUB(18, 0x7fffffffffffffff, 0xffffffffffffffff, 0x8000000000000000)
+       SUB(19, 0xffffffffffffffff, 0x7fffffffffffffff, 0x8000000000000000)
+       SUB(20, 0xffffffffffffffff, 0xffffffffffffffff, 0)
+#endif
+
+#undef SUB
+#define SUB(N, T, I0, I1, V)   FOP(N, T, sub, I0, I1, V)
+       SUB(0, _f,      -0.5,       0.5,        -1.0)
+       SUB(1, _f,       0.25,      0.75,       -0.5)
+       SUB(0, _d,      -0.5,       0.5,        -1.0)
+       SUB(1, _d,       0.25,      0.75,       -0.5)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alu_xor.ok b/deps/lightning/check/alu_xor.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alu_xor.tst b/deps/lightning/check/alu_xor.tst
new file mode 100644 (file)
index 0000000..d1976ab
--- /dev/null
@@ -0,0 +1,36 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define XOR(N, I0, I1, V)      ALU(N, , xor, I0, I1, V)
+
+       XOR(0,  0x7fffffff,         1,                  0x7ffffffe)
+       XOR(1,  1,                  0x7fffffff,         0x7ffffffe)
+       XOR(2,  0x80000000,         1,                  0x80000001)
+       XOR(3,  1,                  0x80000000,         0x80000001)
+       XOR(4,  0x7fffffff,         0x80000000,         0xffffffff)
+       XOR(5,  0x80000000,         0x7fffffff,         0xffffffff)
+       XOR(6,  0x7fffffff,         0xffffffff,         0x80000000)
+       XOR(7,  0xffffffff,         0x7fffffff,         0x80000000)
+       XOR(9,  0xffffffff,         0xffffffff,         0)
+       XOR(10, 0x7fffffff,         0,                  0x7fffffff)
+       XOR(11, 0,                  0x7fffffff,         0x7fffffff)
+#if __WORDSIZE == 64
+       XOR(12, 0x7fffffffffffffff, 1,                  0x7ffffffffffffffe)
+       XOR(13, 1,                  0x7fffffffffffffff, 0x7ffffffffffffffe)
+       XOR(14, 0x8000000000000000, 1,                  0x8000000000000001)
+       XOR(15, 1,                  0x8000000000000000, 0x8000000000000001)
+       XOR(16, 0x7fffffffffffffff, 0x8000000000000000, 0xffffffffffffffff)
+       XOR(17, 0x8000000000000000, 0x7fffffffffffffff, 0xffffffffffffffff)
+       XOR(18, 0x7fffffffffffffff, 0xffffffffffffffff, 0x8000000000000000)
+       XOR(19, 0xffffffffffffffff, 0x7fffffffffffffff, 0x8000000000000000)
+       XOR(20, 0xffffffffffffffff, 0xffffffffffffffff, 0)
+#endif
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alux_add.ok b/deps/lightning/check/alux_add.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alux_add.tst b/deps/lightning/check/alux_add.tst
new file mode 100644 (file)
index 0000000..ddc4e57
--- /dev/null
@@ -0,0 +1,49 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define ADDX(N, I0, I1, V)     ALUX(N, add, I0, I1, V)
+
+       /* nothing */
+       ADDX(0, 0,              0,              0)
+#if __WORDSIZE == 32
+       /* carry */
+       ADDX(1, 0xffffffff,     0xffffffff,     1)
+       /* overflow */
+       ADDX(2, 0x7fffffff,     1,              0)
+       /* overflow */
+       ADDX(3, 0x7fffffff,     0x7fffffff,     0)
+       /* carry */
+       ADDX(4, 0x7fffffff,     0x80000000,     0)
+       /* carry+overflow */
+       ADDX(5, 0x80000000,     0x80000000,     1)
+#else
+       /* nothing */
+       ADDX(1, 0xffffffff,             0xffffffff,             0)
+       /* nothing */
+       ADDX(2, 0x7fffffff,             1,                      0)
+       /* nothing */
+       ADDX(3, 0x7fffffff,             0x7fffffff,             0)
+       /* nothing */
+       ADDX(4, 0x7fffffff,             0x80000000,             0)
+       /* nothing */
+       ADDX(5, 0x80000000,             0x80000000,             0)
+       /* carry */
+       ADDX(6, 0xffffffffffffffff,     0xffffffffffffffff,     1)
+       /* overflow */
+       ADDX(7, 0x7fffffffffffffff,     1,                      0)
+       /* overflow */
+       ADDX(8, 0x7fffffffffffffff,     0x7fffffffffffffff,     0)
+       /* overflow */
+       ADDX(9, 0x7fffffffffffffff,     0x8000000000000000,     0)
+       /* carry+overflow */
+       ADDX(10,0x8000000000000000,     0x8000000000000000,     1)
+#endif
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/alux_sub.ok b/deps/lightning/check/alux_sub.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/alux_sub.tst b/deps/lightning/check/alux_sub.tst
new file mode 100644 (file)
index 0000000..8a2838d
--- /dev/null
@@ -0,0 +1,49 @@
+#include "alu.inc"
+
+.code
+       prolog
+
+#define SUBX(N, I0, I1, V)     ALUX(N, sub, I0, I1, V)
+
+       /* nothing */
+       SUBX(0,  0,             0,              0)
+#if __WORDSIZE == 32
+       /* carry */
+       SUBX(1, 0x7fffffff,     0xffffffff,     0xffffffff)
+       /* overflow */
+       SUBX(2, 0x80000000,     1,              0)
+       /* carry */
+       SUBX(3, 0x7fffffff,     0x80000000,     0xffffffff)
+       /* overflow */
+       SUBX(4, 0x80000000,     0x7fffffff,     0)
+       /* carry+overflow */
+       SUBX(5, 1,              0x80000000,     0xffffffff)
+#else
+       /* carry */
+       SUBX(1, 0x7fffffff,             0xffffffff,             -1)
+       /* nothing */
+       SUBX(2, 0x80000000,             1,                      0)
+       /* carry */
+       SUBX(3, 0x7fffffff,             0x80000000,             -1)
+       /* nothing */
+       SUBX(4, 0x80000000,             0x7fffffff,             0)
+       /* carry */
+       SUBX(5, 1,                      0x80000000,             -1)
+       /* carry */
+       SUBX(6, 0x7fffffffffffffff,     0xffffffffffffffff,     -1)
+       /* overflow */
+       SUBX(7, 0x8000000000000000,     1,                      0)
+       /* carry */
+       SUBX(8, 0x7fffffffffffffff,     0x8000000000000000,     -1)
+       /* overflow */
+       SUBX(9, 0x8000000000000000,     0x7fffffffffffffff,     0)
+       /* carry+overflow */
+       SUBX(10,1,                      0x8000000000000000,     -1)
+#endif
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/bp.ok b/deps/lightning/check/bp.ok
new file mode 100644 (file)
index 0000000..7e13ef0
--- /dev/null
@@ -0,0 +1 @@
+nfibs(32) = 2178309
diff --git a/deps/lightning/check/bp.tst b/deps/lightning/check/bp.tst
new file mode 100644 (file)
index 0000000..9e6798d
--- /dev/null
@@ -0,0 +1,46 @@
+.data  32
+fmt:
+.c     "nfibs(%d) = %d\n"
+
+.code
+       jmpi main
+
+       name rfibs
+rfibs:
+       prolog
+       arg $in
+       getarg %r0 $in          /* R0 = N */
+       beqi out %r0 0
+       movr %v0 %r0            /* V0 = R0 */
+       movi %r0 1
+       blei_u out %v0 2
+       subi %v1 %v0 1          /* V1 = N-1 */
+       subi %v2 %v0 2          /* V1 = N-2 */
+       prepare
+               pushargr %v1
+       finishi rfibs
+       retval %v1              /* V1 = rfibs(N-1) */
+       prepare
+               pushargr %v2
+       finishi rfibs
+       retval %r0              /* R0 = rfibs(N-2) */
+       addr %r0 %r0 %v1
+out:
+       retr %r0
+       epilog
+
+       name main
+main:
+       prolog
+       prepare
+               pushargi 32
+       finishi rfibs
+       retval %v0
+       prepare
+               pushargi fmt
+               ellipsis
+               pushargi 32
+               pushargr %v0
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/branch.ok b/deps/lightning/check/branch.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/branch.tst b/deps/lightning/check/branch.tst
new file mode 100644 (file)
index 0000000..2252dff
--- /dev/null
@@ -0,0 +1,563 @@
+#if __WORDSIZE == 64
+#  define I7f          0x7fffffffffffffff
+#  define I80          0x8000000000000000
+#  define I81          0x8000000000000001
+#  define Iff          0xffffffffffffffff
+#else
+#  define I7f          0x7fffffff
+#  define I80          0x80000000
+#  define I81          0x80000001
+#  define Iff          0xffffffff
+#endif
+
+.data  12
+ok:
+.c     "ok\n"
+.      $($NaN  =  0.0 / 0.0)
+
+#define BOP(N, Ls, Rs, Lu, Ru, R0, R1)         \
+       movi %R0 Ls                             \
+       movi %R1 Rs                             \
+       b##N##r N##r_##R0##_##R1 %R0 %R1        \
+       calli @abort                            \
+N##r_##R0##_##R1:                              \
+       b##N##i N##i_##R0##_##R1 %R0 Rs         \
+       calli @abort                            \
+N##i_##R0##_##R1:                              \
+       movi %R0 Lu                             \
+       movi %R1 Ru                             \
+       b##N##r_u N##r_u_##R0##_##R1 %R0 %R1    \
+       calli @abort                            \
+N##r_u_##R0##_##R1:                            \
+       b##N##i_u N##i_u_##R0##_##R1 %R0 Ru     \
+       calli @abort                            \
+N##i_u_##R0##_##R1:                            \
+       movi %R0 Ls                             \
+       movi %R1 Rs                             \
+       N##r %R0 %R0 %R1                        \
+       beqi _##N##r_##R0##_##R1 %R0 1          \
+       calli @abort                            \
+_##N##r_##R0##_##R1:                           \
+       movi %R0 Ls                             \
+       N##i %R1 %R0 Rs                         \
+       beqi _##N##i_##R0##_##R1 %R1 1          \
+       calli @abort                            \
+_##N##i_##R0##_##R1:                           \
+       movi %R0 Lu                             \
+       movi %R1 Ru                             \
+       N##r_u %R0 %R0 %R1                      \
+       beqi _##N##r_u_##R0##_##R1 %R0 1        \
+       calli @abort                            \
+_##N##r_u_##R0##_##R1:                         \
+       movi %R0 Lu                             \
+       N##i_u %R1 %R0 Ru                       \
+       beqi _##N##i_u_##R0##_##R1 %R1 1        \
+       calli @abort                            \
+_##N##i_u_##R0##_##R1:
+
+#define EB(N, L, R, R0, R1)                    \
+       movi %R0 L                              \
+       movi %R1 R                              \
+       b##N##r N##r_##R0##_##R1 %R0 %R1        \
+       calli @abort                            \
+N##r_##R0##_##R1:                              \
+       b##N##i N##i_##R0##_##R1 %R0 R          \
+       calli @abort                            \
+N##i_##R0##_##R1:                              \
+       movi %R0 L                              \
+       movi %R1 R                              \
+       N##r %R0 %R0 %R1                        \
+       beqi _##N##r_##R0##_##R1 %R0 1          \
+       calli @abort                            \
+_##N##r_##R0##_##R1:                           \
+       movi %R0 L                              \
+       N##i %R1 %R0 R                          \
+       beqi _##N##i_##R0##_##R1 %R1 1          \
+       calli @abort                            \
+_##N##i_##R0##_##R1:
+
+#define XEB(N, L, R, R0, R1)                   \
+       movi %R0 L                              \
+       movi %R1 R                              \
+       b##N##r N##r_##R0##_##R1 %R0 %R1        \
+       calli @abort                            \
+N##r_##R0##_##R1:                              \
+       b##N##i N##i_##R0##_##R1 %R0 R          \
+       calli @abort                            \
+N##i_##R0##_##R1:
+
+#define XBOP(N, Ls, Rs, Lu, Ru, R0, R1)                \
+       movi %R0 Ls                             \
+       movi %R1 Rs                             \
+       b##N##r N##r_##R0##_##R1 %R0 %R1        \
+       calli @abort                            \
+N##r_##R0##_##R1:                              \
+       movi %R0 Ls                             \
+       b##N##i N##i_##R0##_##R1 %R0 Rs         \
+       calli @abort                            \
+N##i_##R0##_##R1:                              \
+       movi %R0 Lu                             \
+       movi %R1 Ru                             \
+       b##N##r_u N##r_u_##R0##_##R1 %R0 %R1    \
+       calli @abort                            \
+N##r_u_##R0##_##R1:                            \
+       movi %R0 Lu                             \
+       b##N##i_u N##i_u_##R0##_##R1 %R0 Ru     \
+       calli @abort                            \
+N##i_u_##R0##_##R1:
+
+#define BOPI(N, Ls, Rs, Lu, Ru)                        \
+       BOP(N, Ls, Rs, Lu, Ru, v0, v1)          \
+       BOP(N, Ls, Rs, Lu, Ru, v0, v2)          \
+       BOP(N, Ls, Rs, Lu, Ru, v0, r0)          \
+       BOP(N, Ls, Rs, Lu, Ru, v0, r1)          \
+       BOP(N, Ls, Rs, Lu, Ru, v0, r2)          \
+       BOP(N, Ls, Rs, Lu, Ru, v1, v0)          \
+       BOP(N, Ls, Rs, Lu, Ru, v1, v2)          \
+       BOP(N, Ls, Rs, Lu, Ru, v1, r0)          \
+       BOP(N, Ls, Rs, Lu, Ru, v1, r1)          \
+       BOP(N, Ls, Rs, Lu, Ru, v1, r2)          \
+       BOP(N, Ls, Rs, Lu, Ru, v2, v0)          \
+       BOP(N, Ls, Rs, Lu, Ru, v2, v1)          \
+       BOP(N, Ls, Rs, Lu, Ru, v2, r0)          \
+       BOP(N, Ls, Rs, Lu, Ru, v2, r1)          \
+       BOP(N, Ls, Rs, Lu, Ru, v2, r2)          \
+       BOP(N, Ls, Rs, Lu, Ru, r0, v0)          \
+       BOP(N, Ls, Rs, Lu, Ru, r0, v1)          \
+       BOP(N, Ls, Rs, Lu, Ru, r0, v2)          \
+       BOP(N, Ls, Rs, Lu, Ru, r0, r1)          \
+       BOP(N, Ls, Rs, Lu, Ru, r0, r2)          \
+       BOP(N, Ls, Rs, Lu, Ru, r1, v0)          \
+       BOP(N, Ls, Rs, Lu, Ru, r1, v1)          \
+       BOP(N, Ls, Rs, Lu, Ru, r1, v2)          \
+       BOP(N, Ls, Rs, Lu, Ru, r1, r0)          \
+       BOP(N, Ls, Rs, Lu, Ru, r1, r2)          \
+       BOP(N, Ls, Rs, Lu, Ru, r2, v0)          \
+       BOP(N, Ls, Rs, Lu, Ru, r2, v1)          \
+       BOP(N, Ls, Rs, Lu, Ru, r2, v2)          \
+       BOP(N, Ls, Rs, Lu, Ru, r2, r0)          \
+       BOP(N, Ls, Rs, Lu, Ru, r2, r1)
+
+#define EBI(N, L, R)                           \
+       EB(N, L, R, v0, v1)                     \
+       EB(N, L, R, v0, v2)                     \
+       EB(N, L, R, v0, r0)                     \
+       EB(N, L, R, v0, r1)                     \
+       EB(N, L, R, v0, r2)                     \
+       EB(N, L, R, v1, v0)                     \
+       EB(N, L, R, v1, v2)                     \
+       EB(N, L, R, v1, r0)                     \
+       EB(N, L, R, v1, r1)                     \
+       EB(N, L, R, v1, r2)                     \
+       EB(N, L, R, v2, v0)                     \
+       EB(N, L, R, v2, v1)                     \
+       EB(N, L, R, v2, r0)                     \
+       EB(N, L, R, v2, r1)                     \
+       EB(N, L, R, v2, r2)                     \
+       EB(N, L, R, r0, v0)                     \
+       EB(N, L, R, r0, v1)                     \
+       EB(N, L, R, r0, v2)                     \
+       EB(N, L, R, r0, r1)                     \
+       EB(N, L, R, r0, r2)                     \
+       EB(N, L, R, r1, v0)                     \
+       EB(N, L, R, r1, v1)                     \
+       EB(N, L, R, r1, v2)                     \
+       EB(N, L, R, r1, r0)                     \
+       EB(N, L, R, r1, r2)                     \
+       EB(N, L, R, r2, v0)                     \
+       EB(N, L, R, r2, v1)                     \
+       EB(N, L, R, r2, v2)                     \
+       EB(N, L, R, r2, r0)                     \
+       EB(N, L, R, r2, r1)
+
+
+#define XEBI(N, L, R)                          \
+       XEB(N, L, R, v0, v1)                    \
+       XEB(N, L, R, v0, v2)                    \
+       XEB(N, L, R, v0, r0)                    \
+       XEB(N, L, R, v0, r1)                    \
+       XEB(N, L, R, v0, r2)                    \
+       XEB(N, L, R, v1, v0)                    \
+       XEB(N, L, R, v1, v2)                    \
+       XEB(N, L, R, v1, r0)                    \
+       XEB(N, L, R, v1, r1)                    \
+       XEB(N, L, R, v1, r2)                    \
+       XEB(N, L, R, v2, v0)                    \
+       XEB(N, L, R, v2, v1)                    \
+       XEB(N, L, R, v2, r0)                    \
+       XEB(N, L, R, v2, r1)                    \
+       XEB(N, L, R, v2, r2)                    \
+       XEB(N, L, R, r0, v0)                    \
+       XEB(N, L, R, r0, v1)                    \
+       XEB(N, L, R, r0, v2)                    \
+       XEB(N, L, R, r0, r1)                    \
+       XEB(N, L, R, r0, r2)                    \
+       XEB(N, L, R, r1, v0)                    \
+       XEB(N, L, R, r1, v1)                    \
+       XEB(N, L, R, r1, v2)                    \
+       XEB(N, L, R, r1, r0)                    \
+       XEB(N, L, R, r1, r2)                    \
+       XEB(N, L, R, r2, v0)                    \
+       XEB(N, L, R, r2, v1)                    \
+       XEB(N, L, R, r2, v2)                    \
+       XEB(N, L, R, r2, r0)                    \
+       XEB(N, L, R, r2, r1)
+
+#define XBOPI(N, Ls, Rs, Lu, Ru)               \
+       XBOP(N, Ls, Rs, Lu, Ru, v0, v1)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v0, v2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v0, r0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v0, r1)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v0, r2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v1, v0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v1, v2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v1, r0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v1, r1)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v1, r2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v2, v0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v2, v1)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v2, r0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v2, r1)         \
+       XBOP(N, Ls, Rs, Lu, Ru, v2, r2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r0, v0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r0, v1)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r0, v2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r0, r1)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r0, r2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r1, v0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r1, v1)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r1, v2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r1, r0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r1, r2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r2, v0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r2, v1)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r2, v2)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r2, r0)         \
+       XBOP(N, Ls, Rs, Lu, Ru, r2, r1)
+
+#define TBOPF(N, T, L, R)                      \
+       movi_##T %f0 L                          \
+       movi_##T %f1 R                          \
+       b##N##r##_##T N##r_##T %f0 %f1          \
+       calli @abort                            \
+N##r_##T:                                      \
+       b##N##i##_##T N##i_##T %f0 R            \
+       calli @abort                            \
+N##i_##T:                                      \
+       movi_##T %f1 $NaN                       \
+       b##N##r##_##T N##r_##T##_##u %f0 %f1    \
+       jmpi N##r_##T##_##u0                    \
+N##r_##T##_##u:                                        \
+       calli @abort                            \
+N##r##_##T##_##u0:                             \
+       b##N##i##_##T N##i_##T##_##u %f0 $NaN   \
+       jmpi N##i_##T##_##u0                    \
+N##i##_##T##_##u:                              \
+       calli @abort                            \
+N##i##_##T##_##u0:
+#define BOPF(N, L, R)                          \
+       TBOPF(N, f, L, R)                       \
+       TBOPF(N, d, L, R)
+
+#define TUBOPF(N, T, L, R)                     \
+       movi_##T %f0 L                          \
+       movi_##T %f1 R                          \
+       b##N##r##_##T N##r_##T %f0 %f1          \
+       calli @abort                            \
+N##r_##T:                                      \
+       b##N##i##_##T N##i_##T %f0 R            \
+       calli @abort                            \
+N##i_##T:                                      \
+       movi_##T %f1 $NaN                       \
+       b##N##r##_##T N##r_##T##_##u %f0 %f1    \
+       calli @abort                            \
+N##r_##T##_##u:                                        \
+       b##N##i##_##T N##i_##T##_##u %f0 $NaN   \
+       calli @abort                            \
+N##i##_##T##_##u:
+
+#define UBOPF(N, L, R)                         \
+       TUBOPF(N, f, L, R)                      \
+       TUBOPF(N, d, L, R)
+
+.code
+       prolog
+
+       movi %r0 -1
+       movi %r1 1
+       bltr xltr_r0_r1 %r0 %r1
+       calli @abort
+xltr_r0_r1:
+       blti xlti_r0_r1 %r0 1
+       calli @abort
+xlti_r0_r1:
+       movi %r0 1
+       movi %r1 -1
+       bltr_u xltru_r0_r1 %r0 %r1
+       calli @abort
+xltru_r0_r1:
+       blti_u xltiu_r0_r1 %r0 -1
+       calli @abort
+xltiu_r0_r1:
+       movi %r0 -1
+       movi %r1 -1
+       bler xler_r0_r1 %r0 %r1
+       calli @abort
+xler_r0_r1:
+       blti xlei_r0_r1 %r0 1
+       calli @abort
+xlei_r0_r1:
+       movi %r0 1
+       movi %r1 -1
+       bltr_u xlteu_r0_r1 %r0 %r1
+       calli @abort
+xlteu_r0_r1:
+       blei_u xleiu_r0_r1 %r0 -1
+       calli @abort
+xleiu_r0_r1:
+       movi %r0 32
+       movi %r1 32
+       beqr xeqr_r0_r1 %r0 %r1
+       calli @abort
+xeqr_r0_r1:
+       beqi xeqi_r0_r1 %r0 32
+       calli @abort
+xeqi_r0_r1:
+       movi %r0 -2
+       movi %r1 -2
+       bger xger_r0_r1 %r0 %r1
+       calli @abort
+xger_r0_r1:
+       bgei xgei_r0_r1 %r0 -2
+       calli @abort
+xgei_r0_r1:
+       movi %r0 2
+       movi %r1 2
+       bger_u xgeru_r0_r1 %r0 %r1
+       calli @abort
+xgeru_r0_r1:
+       bgei_u xgeiu_r0_r1 %r0 2
+       calli @abort
+xgeiu_r0_r1:
+       movi %r0 2
+       movi %r1 -2
+       bgtr xgtr_r0_r1 %r0 %r1
+       calli @abort
+xgtr_r0_r1:
+       bgti xgti_r0_r1 %r0 -2
+       calli @abort
+xgti_r0_r1:
+       movi %r0 -2
+       movi %r1 2
+       bgtr_u xgtru_r0_r1 %r0 %r1
+       calli @abort
+xgtru_r0_r1:
+       bgti_u xgtiu_r0_r1 %r0 2
+       calli @abort
+xgtiu_r0_r1:
+       movi %r0 -3
+       movi %r1 3
+       bner xner_r0_r1 %r0 %r1
+       calli @abort
+xner_r0_r1:
+       bnei xnei_r0_r1 %r0 3
+       calli @abort
+xnei_r0_r1:
+       movi %r0 1
+       movi %r1 3
+       bmsr xmsr_r0_r1 %r0 %r1
+       calli @abort
+xmsr_r0_r1:
+       bmsi xmsi_r0_r1 %r0 3
+       calli @abort
+xmsi_r0_r1:
+       movi %r0 1
+       movi %r1 2
+       bmcr xmcr_r0_r1 %r0 %r1
+       calli @abort
+xmcr_r0_r1:
+       bmci xmci_r0_r1 %r0 2
+       calli @abort
+xmci_r0_r1:
+       movi %r0 I7f
+       movi %r1 1
+       boaddr xoaddr_r0_r1 %r0 %r1
+       calli @abort
+xoaddr_r0_r1:
+       movi %r0 Iff
+       movi %r1 1
+       boaddr_u xoaddr_u_r0_r1 %r0 %r1
+       calli @abort
+xoaddr_u_r0_r1:
+       movi %r0 I7f
+       boaddi xoaddi_r0_r1 %r0 1
+       calli @abort
+xoaddi_r0_r1:
+       movi %r0 Iff
+       boaddi_u xoaddi_u_r0_r1 %r0 1
+       calli @abort
+xoaddi_u_r0_r1:
+       movi %r0 I80
+       movi %r1 1
+       bxaddr xxaddr_r0_r1 %r0 %r1
+       calli @abort
+xxaddr_r0_r1:
+       movi %r0 I80
+       bxaddi xxaddi_r0_r1 %r0 1
+       calli @abort
+xxaddi_r0_r1:
+       movi %r0 I7f
+       movi %r1 1
+       bxaddr_u xxaddr_u_r0_r1 %r0 %r1
+       calli @abort
+xxaddr_u_r0_r1:
+       movi %r0 I7f
+       bxaddi_u xxaddi_u_r0_r1 %r0 1
+       calli @abort
+xxaddi_u_r0_r1:
+       movi %r0 I80
+       movi %r1 1
+       bosubr xosubr_r0_r1 %r0 %r1
+       calli @abort
+xosubr_r0_r1:
+       movi %r0 0
+       movi %r1 1
+       bosubr_u xosubr_u_r0_r1 %r0 %r1
+       calli @abort
+xosubr_u_r0_r1:
+       movi %r0 I80
+       bosubi xosubi_r0_r1 %r0 1
+       calli @abort
+xosubi_r0_r1:
+       movi %r0 0
+       bosubi_u xosubi_u_r0_r1 %r0 1
+       calli @abort
+xosubi_u_r0_r1:
+       movi %r0 I81
+       movi %r1 1
+       bxsubr xxsubr_r0_r1 %r0 %r1
+       calli @abort
+xxsubr_r0_r1:
+       movi %r0 I81
+       bxsubi xxsubi_r0_r1 %r0 1
+       calli @abort
+xxsubi_r0_r1:
+       movi %r0 I80
+       movi %r1 1
+       bxsubr_u xxsubr_u_r0_r1 %r0 %r1
+       calli @abort
+xxsubr_u_r0_r1:
+       movi %r0 I80
+       bxsubi_u xxsubi_u_r0_r1 %r0 1
+       calli @abort
+xxsubi_u_r0_r1:
+       movi_f %f0 1
+       movi_f %f1 2
+       bltr_f xltr_f_f0_f1 %f0 %f1
+       calli @abort
+xltr_f_f0_f1:
+       blti_f xlti_f_f0_f1 %f0 2
+       calli @abort
+xlti_f_f0_f1:
+       movi_f %f0 -1
+       movi_f %f1 -1
+       bler_f xler_f_f0_f1 %f0 %f1
+       calli @abort
+xler_f_f0_f1:
+       blei_f xlei_f_f0_f1 %f0 -1
+       calli @abort
+xlei_f_f0_f1:
+       movi_f %f0 -2
+       movi_f %f1 -2
+       beqr_f xeqr_f_f0_f1 %f0 %f1
+       calli @abort
+xeqr_f_f0_f1:
+       beqi_f xeqi_f_f0_f1 %f0 -2
+       calli @abort
+xeqi_f_f0_f1:
+       movi_f %f0 -3
+       movi_f %f1 -3
+       bger_f xger_f_f0_f1 %f0 %f1
+       calli @abort
+xger_f_f0_f1:
+       bgei_f xgei_f_f0_f1 %f0 -3
+       calli @abort
+xgei_f_f0_f1:
+       movi_f %f0 2
+       movi_f %f1 1
+       bgtr_f xgtr_f_f0_f1 %f0 %f1
+       calli @abort
+xgtr_f_f0_f1:
+       bgti_f xgti_f_f0_f1 %f0 1
+       calli @abort
+xgti_f_f0_f1:
+       movi_f %f0 0
+       movi_f %f1 2
+       bner_f xner_f_f0_f1 %f0 %f1
+       calli @abort
+xner_f_f0_f1:
+       bnei_f xnei_f_f0_f1 %f0 2
+       calli @abort
+xnei_f_f0_f1:
+
+       BOPI(lt, -1, 1, 1, -1)
+       BOPI(le, -1, -1, 1, 1)
+       EBI(eq, 32, 32)
+       BOPI(ge, -2, -2, 2, 2)
+       BOPI(gt, 2, -2, -2, 2)
+       EBI(ne, 3, -3)
+       XEBI(ms, 1, 3)
+       XEBI(mc, 1, 2)
+       XBOPI(oadd, I7f, 1, Iff, 1)
+       XBOPI(xadd, I80, 1, I7f, 1)
+       XBOPI(osub, I80, 1, 0, 1)
+       XBOPI(xsub, I81, 1, I80, 1)
+       BOPF(lt, 1, 2)
+       BOPF(le, 2, 2)
+       BOPF(eq, 3, 3)
+       BOPF(ge, 3, 3)
+       BOPF(gt, 4, 3)
+       UBOPF(ne, 4, 3)
+       UBOPF(unlt, 1, 2)
+       UBOPF(unle, 2, 2)
+       UBOPF(uneq, 3, 3)
+       UBOPF(unge, 3, 3)
+       UBOPF(ungt, 4, 3)
+       BOPF(ltgt, 4, 3)
+       movi_f %f0 5
+       movi_f %f1 5
+       bordr_f ordr_f %f0 %f1
+       calli @abort
+ordr_f:
+       bordi_f ordi_f %f0 1
+       calli @abort
+ordi_f:
+       bordi_f ordi_f_u %f0 $NaN
+       jmpi ordi_f_u0
+ordi_f_u:
+       calli @abort
+ordi_f_u0:
+       movi_f %f0 5
+       movi_f %f1 5
+       bunordr_f unordr_f %f0 %f1
+       jmpi unordr_f_0
+unordr_f:
+       calli @abort
+unordr_f_0:
+       bunordi_f unordi_f %f0 1
+       jmpi unordi_f_0
+unordi_f:
+       calli @abort
+unordi_f_0:
+       bunordi_f unordi_f_1 %f0 $NaN
+       calli @abort
+unordi_f_1:
+
+       // just to know did not crash or abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+
+       ret
+       epilog
diff --git a/deps/lightning/check/call.ok b/deps/lightning/check/call.ok
new file mode 100644 (file)
index 0000000..cc119df
--- /dev/null
@@ -0,0 +1,4 @@
+forward
+backward
+forward
+backward
diff --git a/deps/lightning/check/call.tst b/deps/lightning/check/call.tst
new file mode 100644 (file)
index 0000000..21068b6
--- /dev/null
@@ -0,0 +1,272 @@
+#define def_wi(i)                      \
+       name _w##i                      \
+_w##i:                                 \
+       prolog                          \
+       arg $arg##i                     \
+       getarg##i %r0 $arg##i           \
+       retr %r0                        \
+       epilog
+#define def_wf(f)                      \
+       name _w##f                      \
+_w##f:                                 \
+       prolog                          \
+       arg##f $arg##f                  \
+       getarg##f %f0 $arg##f           \
+       truncr##f %r0 %f0               \
+       retr %r0                        \
+       epilog
+#define def_fi(f, i)                   \
+       name f##i                       \
+f##i:                                  \
+       prolog                          \
+       arg $arg##i                     \
+       getarg##i %r0 $arg##i           \
+       extr##f %f0 %r0                 \
+       retr##f %f0                     \
+       epilog
+#define def_f(f)                       \
+       name f##f                       \
+f##f:                                  \
+       prolog                          \
+       arg##f $arg##f                  \
+       getarg##f %f0 $arg##f           \
+       retr##f %f0                     \
+       epilog
+#define def_ff(f, g)                   \
+       name f##g                       \
+       name f##g                       \
+f##g:                                  \
+       prolog                          \
+       arg##g $arg##g                  \
+       getarg##g %f0 $arg##g           \
+       extr##g##f %f0 %f0              \
+       retr##f %f0                     \
+       epilog
+
+.data  32
+fstr:
+.c     "forward"
+bstr:
+.c     "backward"
+
+.code
+       jmpi main
+
+       def_wi(_c)
+       def_wi(_uc)
+       def_wi(_s)
+       def_wi(_us)
+#if __WORDSIZE == 64
+       def_wi(_i)
+       def_wi(_ui)
+#endif
+       def_wf(_f)
+       def_wf(_d)
+       def_fi(_f, _c)
+       def_fi(_f, _uc)
+       def_fi(_f, _s)
+       def_fi(_f, _us)
+       def_fi(_f, _i)
+#if __WORDSIZE == 64
+       def_fi(_f, _ui)
+       def_fi(_f, _l)
+#endif
+       def_fi(_d, _c)
+       def_fi(_d, _uc)
+       def_fi(_d, _s)
+       def_fi(_d, _us)
+       def_fi(_d, _i)
+#if __WORDSIZE == 64
+       def_fi(_d, _ui)
+       def_fi(_d, _l)
+#endif
+       def_f(_f)
+       def_f(_d)
+       def_ff(_f, _d)
+       def_ff(_d, _f)
+
+       name main
+main:
+       prolog
+
+#define _call_w(n, i, a, r)            \
+       prepare                         \
+               pushargi a              \
+       finishi _w##i                   \
+       retval %r0                      \
+       extr##i %r0 %r0                 \
+       beqi _w##i##_##n %r0 r          \
+       calli @abort                    \
+_w##i##_##n:
+#define call_w(n, i, a, r)             _call_w(n, i, a, r)
+#define _call_wf(n, f, a, r)           \
+       prepare                         \
+               pushargi##f a           \
+       finishi _w##f                   \
+       retval %r0                      \
+       extr##f %f0 %r0                 \
+       beqi##f _w##f##_##n %f0 r       \
+       calli @abort                    \
+_w##f##_##n:
+#define call_wf(n, f, a, r)            _call_wf(n, f, a, r)
+#define _call_fi(n, f, i, a, r)                \
+       prepare                         \
+               pushargi a              \
+       finishi f##i                    \
+       retval##f %f0                   \
+       beqi##f f##i##n %f0 r           \
+       calli @abort                    \
+f##i##n:
+#define call_fi(n, f, i, a, r)         _call_fi(n, f, i, a, r)
+#define _call_f(n, f, a, r)            \
+       prepare                         \
+               pushargi##f a           \
+       finishi f##f                    \
+       retval##f %f0                   \
+       beqi##f f##f##n %f0 r           \
+       calli @abort                    \
+f##f##n:
+#define call_f(n, f, a, r)             _call_f(n, f, a, r)
+#define _call_ff(n, f, g, a, r)                \
+       prepare                         \
+               pushargi##g a           \
+       finishi f##g                    \
+       retval##f %f0                   \
+       beqi##f f##g##n %f0 r           \
+       calli @abort                    \
+f##g##n:
+#define call_ff(n, f, g, a, r)         _call_ff(n, f, g, a, r)
+
+#define c7f            0x7f
+#define c80            0x80
+#define c81            0x81
+#define cff            0xff
+#define s7f            0x7fff
+#define s80            0x8000
+#define s81            0x8001
+#define i7f            0x7fffffff
+#define i80            0x80000000
+#define i81            0x80000001
+#define iff            0xffffffff
+#define l7f            0x7fffffffffffffff
+#define l80            0x8000000000000000
+#define l81            0x8000000000000001
+#define f7f             127.0
+#define f80            -128.0
+#define f81            -127.0
+#define uf80            128.0
+#define uf81            127.0
+#if __WORDSIZE == 32
+#  define wc80         0xffffff80
+#  define wc81         0xffffff81
+#  define ws80         0xffff8000
+#  define ws81         0xffff8001
+#else
+#  define wc80         0xffffffffffffff80
+#  define wc81         0xffffffffffffff81
+#  define ws80         0xffffffffffff8000
+#  define ws81         0xffffffffffff8001
+#  define wi80         0xffffffff80000000
+#  define wi81         0xffffffff80000001
+#endif
+
+       call_w(__LINE__, _c,  c7f, c7f)
+       call_w(__LINE__, _c,  c80, wc80)
+       call_w(__LINE__, _c,  c81, wc81)
+       call_w(__LINE__, _uc, c7f, c7f)
+       call_w(__LINE__, _uc, c80, c80)
+       call_w(__LINE__, _uc, c81, c81)
+       call_w(__LINE__, _s,  s7f, s7f)
+       call_w(__LINE__, _s,  s80, ws80)
+       call_w(__LINE__, _s,  s81, ws81)
+       call_w(__LINE__, _us, s7f, s7f)
+       call_w(__LINE__, _us, s80, s80)
+       call_w(__LINE__, _us, s81, s81)
+#if __WORDSIZE == 64
+       call_w(__LINE__, _i,  i7f, i7f)
+       call_w(__LINE__, _i,  i80, wi80)
+       call_w(__LINE__, _i,  i81, wi81)
+       call_w(__LINE__, _ui, i7f, i7f)
+       call_w(__LINE__, _ui, i80, i80)
+       call_w(__LINE__, _ui, i81, i81)
+#endif
+       call_wf(__LINE__, _f, c7f, f7f)
+       call_wf(__LINE__, _f, wc80, f80)
+       call_wf(__LINE__, _f, wc81, f81)
+       call_wf(__LINE__, _d, c7f, f7f)
+       call_wf(__LINE__, _d, wc80, f80)
+       call_wf(__LINE__, _d, wc81, f81)
+       call_fi(__LINE__, _f, _c, c7f, f7f)
+       call_fi(__LINE__, _f, _c, c80, f80)
+       call_fi(__LINE__, _f, _uc, c7f, f7f)
+       call_fi(__LINE__, _f, _uc, c80, uf80)
+       call_fi(__LINE__, _f, _s, c7f, f7f)
+       call_fi(__LINE__, _f, _s, c80, uf80)
+       call_fi(__LINE__, _f, _us, c7f, f7f)
+       call_fi(__LINE__, _f, _us, c80, uf80)
+       call_fi(__LINE__, _f, _i, c7f, f7f)
+       call_fi(__LINE__, _f, _i, c80, uf80)
+#if __WORDSIZE == 64
+       call_fi(__LINE__, _f, _ui, c7f, f7f)
+       call_fi(__LINE__, _f, _ui, c80, uf80)
+       call_fi(__LINE__, _f, _l, c7f, f7f)
+       call_fi(__LINE__, _f, _l, c80, uf80)
+#endif
+       call_fi(__LINE__, _d, _c, c7f, f7f)
+       call_fi(__LINE__, _d, _c, c80, f80)
+       call_fi(__LINE__, _d, _uc, c7f, f7f)
+       call_fi(__LINE__, _d, _uc, c80, uf80)
+       call_fi(__LINE__, _d, _s, c7f, f7f)
+       call_fi(__LINE__, _d, _s, c80, uf80)
+       call_fi(__LINE__, _d, _us, c7f, f7f)
+       call_fi(__LINE__, _d, _us, c80, uf80)
+       call_fi(__LINE__, _d, _i, c7f, f7f)
+       call_fi(__LINE__, _d, _i, c80, uf80)
+#if __WORDSIZE == 64
+       call_fi(__LINE__, _d, _ui, c7f, f7f)
+       call_fi(__LINE__, _d, _ui, c80, uf80)
+       call_fi(__LINE__, _d, _l, c7f, f7f)
+       call_fi(__LINE__, _d, _l, c80, uf80)
+#endif
+       call_f(__LINE__, _f, f7f, f7f)
+       call_f(__LINE__, _d, f7f, f7f)
+       call_ff(__LINE__, _f, _d, f80, f80)
+       call_ff(__LINE__, _d, _f, f81, f81)
+
+       movi %r0 forward
+       callr %r0
+
+       calli iforward
+
+       ret
+       epilog
+
+       name backward
+backward:
+       prolog
+       prepare
+               pushargi bstr
+       finishi @puts
+       ret
+       epilog
+
+       name forward
+forward:
+       prolog
+       prepare
+               pushargi fstr
+       finishi @puts
+       movi %r0 backward
+       callr %r0
+       ret
+       epilog
+
+       name iforward
+iforward:
+       prolog
+       prepare
+               pushargi fstr
+       finishi @puts
+       calli backward
+       ret
+       epilog
diff --git a/deps/lightning/check/carg.c b/deps/lightning/check/carg.c
new file mode 100644 (file)
index 0000000..35b897e
--- /dev/null
@@ -0,0 +1,538 @@
+#include <lightning.h>
+#include <stdio.h>
+
+/*   Simple test for arguments handling, that also shows how to use
+ * arguments to store values.
+ *   Register arguments, if available, are very fast, but are also
+ * very volatile on some ports, because some ports will do C calls
+ * to implement division, remainder, sometimes multiplication, or
+ * some float operations.
+ *   Arguments in registers should be fetched in the prolog of the
+ * function, and if they must be saved, they should be saved in
+ * the prolog.
+ *   The predicate macro "jit_arg_register_p(arg)" allows knowing if
+ * an argument lives in a register, where it is known for being a very
+ * fast to read/write temporary storage.
+ */
+
+#define W              jit_word_t
+#define F              jit_float32_t
+#define D              jit_float64_t
+
+jit_state_t             *_jit;
+
+void
+cw(W a1, W  a2, W  a3, W  a4, W  a5, W  a6, W  a7, W  a8,
+   W a9, W a10, W a11, W a12, W a13, W a14, W a15, W a16)
+{
+    if ( a1 !=  1 ||  a2 !=  2 ||  a3 !=  3 ||  a4 !=  4 ||
+        a5 !=  5 ||  a6 !=  6 ||  a7 !=  7 ||  a8 !=  8 ||
+        a9 !=  9 || a10 != 10 || a11 != 11 || a12 != 12 ||
+       a13 != 13 || a14 != 14 || a15 != 15 || a16 != 16)
+       abort();
+}
+
+void
+cf(F a1, F  a2, F  a3, F  a4, F  a5, F  a6, F  a7, F  a8,
+   F a9, F a10, F a11, F a12, F a13, F a14, F a15, F a16)
+{
+    if ( a1 !=  1 ||  a2 !=  2 ||  a3 !=  3 ||  a4 !=  4 ||
+        a5 !=  5 ||  a6 !=  6 ||  a7 !=  7 ||  a8 !=  8 ||
+        a9 !=  9 || a10 != 10 || a11 != 11 || a12 != 12 ||
+       a13 != 13 || a14 != 14 || a15 != 15 || a16 != 16)
+       abort();
+}
+
+void
+cd(D a1, D  a2, D  a3, D  a4, D  a5, D  a6, D  a7, D  a8,
+   D a9, D a10, D a11, D a12, D a13, D a14, D a15, D a16)
+{
+    if ( a1 !=  1 ||  a2 !=  2 ||  a3 !=  3 ||  a4 !=  4 ||
+        a5 !=  5 ||  a6 !=  6 ||  a7 !=  7 ||  a8 !=  8 ||
+        a9 !=  9 || a10 != 10 || a11 != 11 || a12 != 12 ||
+       a13 != 13 || a14 != 14 || a15 != 15 || a16 != 16)
+       abort();
+}
+
+int
+main(int argc, char *argv[])
+{
+    void               (*code)(void);
+    jit_node_t         *jmp, *pass;
+    jit_node_t          *jw,  *jf,  *jd;
+    jit_int32_t                  s1,   s2,   s3,   s4,   s5,   s6,   s7,   s8,
+                         s9,  s10,  s11,  s12,  s13,  s14,  s15,  s16;
+    jit_node_t          *a1,  *a2,  *a3,  *a4,  *a5,  *a6,  *a7,  *a8,
+                        *a9, *a10, *a11, *a12, *a13, *a14, *a15, *a16;
+
+    init_jit(argv[0]);
+    _jit = jit_new_state();
+
+    /* jump to "main" label */
+    jmp = jit_jmpi();
+
+    /* Create jit function that
+     * o Receives 16 word arguments
+     * o Save in the stack any register argument. Also force register
+     *   arguments to be clobbered to properly make the test
+     * o Calls a C function that receives 16 word arguments, with
+     *   values different from the ones received by this function
+     * o Reload from stack any register argument
+     * o Validated all arguments were not modified in the known
+     *   cases it could have been clobbered
+     */
+    jw = jit_label();
+    jit_name("jw");
+    jit_note(__FILE__, __LINE__);
+    jit_prolog();
+    a1  = jit_arg();
+    a2  = jit_arg();
+    a3  = jit_arg();
+    a4  = jit_arg();
+    a5  = jit_arg();
+    a6  = jit_arg();
+    a7  = jit_arg();
+    a8  = jit_arg();
+    a9  = jit_arg();
+    a10 = jit_arg();
+    a11 = jit_arg();
+    a12 = jit_arg();
+    a13 = jit_arg();
+    a14 = jit_arg();
+    a15 = jit_arg();
+    a16 = jit_arg();
+#define SAVE_ARG(N)                                                    \
+    do {                                                               \
+       if (jit_arg_register_p(a##N)) {                                 \
+           s##N = jit_allocai(sizeof(W));                              \
+           jit_getarg(JIT_R0, a##N);                                   \
+           jit_stxi(s##N, JIT_FP, JIT_R0);                             \
+           jit_putargi(-1, a##N);                                      \
+       }                                                               \
+    } while (0)
+    SAVE_ARG(1);
+    SAVE_ARG(2);
+    SAVE_ARG(3);
+    SAVE_ARG(4);
+    SAVE_ARG(5);
+    SAVE_ARG(6);
+    SAVE_ARG(7);
+    SAVE_ARG(8);
+    SAVE_ARG(9);
+    SAVE_ARG(10);
+    SAVE_ARG(11);
+    SAVE_ARG(12);
+    SAVE_ARG(13);
+    SAVE_ARG(14);
+    SAVE_ARG(15);
+    SAVE_ARG(16);
+#undef SAVE_ARG
+    jit_prepare();
+    {
+       jit_pushargi(1);
+       jit_pushargi(2);
+       jit_pushargi(3);
+       jit_pushargi(4);
+       jit_pushargi(5);
+       jit_pushargi(6);
+       jit_pushargi(7);
+       jit_pushargi(8);
+       jit_pushargi(9);
+       jit_pushargi(10);
+       jit_pushargi(11);
+       jit_pushargi(12);
+       jit_pushargi(13);
+       jit_pushargi(14);
+       jit_pushargi(15);
+       jit_pushargi(16);
+    }
+    jit_finishi(cw);
+#define LOAD_ARG(N)                                                    \
+    do {                                                               \
+       if (jit_arg_register_p(a##N)) {                                 \
+           jit_ldxi(JIT_R0, JIT_FP, s##N);                             \
+           jit_putargr(JIT_R0, a##N);                                  \
+       }                                                               \
+    } while (0)
+    LOAD_ARG(1);
+    LOAD_ARG(2);
+    LOAD_ARG(3);
+    LOAD_ARG(4);
+    LOAD_ARG(5);
+    LOAD_ARG(6);
+    LOAD_ARG(7);
+    LOAD_ARG(8);
+    LOAD_ARG(9);
+    LOAD_ARG(10);
+    LOAD_ARG(11);
+    LOAD_ARG(12);
+    LOAD_ARG(13);
+    LOAD_ARG(14);
+    LOAD_ARG(15);
+    LOAD_ARG(16);
+#undef LOAD_ARG
+    pass = jit_forward();
+#define CHECK_ARG(N)                                                   \
+    do {                                                               \
+       jit_getarg(JIT_R0, a##N);                                       \
+       jit_patch_at(jit_beqi(JIT_R0, 17 - N), pass);                   \
+    } while (0)
+    CHECK_ARG(1);
+    CHECK_ARG(2);
+    CHECK_ARG(3);
+    CHECK_ARG(4);
+    CHECK_ARG(5);
+    CHECK_ARG(6);
+    CHECK_ARG(7);
+    CHECK_ARG(8);
+    CHECK_ARG(9);
+    CHECK_ARG(10);
+    CHECK_ARG(11);
+    CHECK_ARG(12);
+    CHECK_ARG(13);
+    CHECK_ARG(14);
+    CHECK_ARG(15);
+    CHECK_ARG(16);
+#undef CHECK_ARG
+    jit_calli(abort);
+    jit_link(pass);
+    jit_ret();
+    jit_epilog();
+
+    /* Create jit function that
+     * o Receives 16 float arguments
+     * o Save in the stack any register argument. Also force register
+     *   arguments to be clobbered to properly make the test
+     * o Calls a C function that receives 16 float arguments, with
+     *   values different from the ones received by this function
+     * o Reload from stack any register argument
+     * o Validated all arguments were not modified in the known
+     *   cases it could have been clobbered
+     */
+    jf = jit_label();
+    jit_name("jf");
+    jit_note(__FILE__, __LINE__);
+    jit_prolog();
+    a1  = jit_arg_f();
+    a2  = jit_arg_f();
+    a3  = jit_arg_f();
+    a4  = jit_arg_f();
+    a5  = jit_arg_f();
+    a6  = jit_arg_f();
+    a7  = jit_arg_f();
+    a8  = jit_arg_f();
+    a9  = jit_arg_f();
+    a10 = jit_arg_f();
+    a11 = jit_arg_f();
+    a12 = jit_arg_f();
+    a13 = jit_arg_f();
+    a14 = jit_arg_f();
+    a15 = jit_arg_f();
+    a16 = jit_arg_f();
+#define SAVE_ARG(N)                                                    \
+    do {                                                               \
+       if (jit_arg_register_p(a##N)) {                                 \
+           s##N = jit_allocai(sizeof(F));                              \
+           jit_getarg_f(JIT_F0, a##N);                                 \
+           jit_stxi_f(s##N, JIT_FP, JIT_F0);                           \
+           jit_putargi_f(-1, a##N);                                    \
+       }                                                               \
+    } while (0)
+    SAVE_ARG(1);
+    SAVE_ARG(2);
+    SAVE_ARG(3);
+    SAVE_ARG(4);
+    SAVE_ARG(5);
+    SAVE_ARG(6);
+    SAVE_ARG(7);
+    SAVE_ARG(8);
+    SAVE_ARG(9);
+    SAVE_ARG(10);
+    SAVE_ARG(11);
+    SAVE_ARG(12);
+    SAVE_ARG(13);
+    SAVE_ARG(14);
+    SAVE_ARG(15);
+    SAVE_ARG(16);
+#undef SAVE_ARG
+    jit_prepare();
+    {
+       jit_pushargi_f(1);
+       jit_pushargi_f(2);
+       jit_pushargi_f(3);
+       jit_pushargi_f(4);
+       jit_pushargi_f(5);
+       jit_pushargi_f(6);
+       jit_pushargi_f(7);
+       jit_pushargi_f(8);
+       jit_pushargi_f(9);
+       jit_pushargi_f(10);
+       jit_pushargi_f(11);
+       jit_pushargi_f(12);
+       jit_pushargi_f(13);
+       jit_pushargi_f(14);
+       jit_pushargi_f(15);
+       jit_pushargi_f(16);
+    }
+    jit_finishi(cf);
+#define LOAD_ARG(N)                                                    \
+    do {                                                               \
+       if (jit_arg_register_p(a##N)) {                                 \
+           jit_ldxi_f(JIT_F0, JIT_FP, s##N);                           \
+           jit_putargr_f(JIT_F0, a##N);                                \
+       }                                                               \
+    } while (0)
+    LOAD_ARG(1);
+    LOAD_ARG(2);
+    LOAD_ARG(3);
+    LOAD_ARG(4);
+    LOAD_ARG(5);
+    LOAD_ARG(6);
+    LOAD_ARG(7);
+    LOAD_ARG(8);
+    LOAD_ARG(9);
+    LOAD_ARG(10);
+    LOAD_ARG(11);
+    LOAD_ARG(12);
+    LOAD_ARG(13);
+    LOAD_ARG(14);
+    LOAD_ARG(15);
+    LOAD_ARG(16);
+#undef LOAD_ARG
+    pass = jit_forward();
+#define CHECK_ARG(N)                                                   \
+    do {                                                               \
+       jit_getarg_f(JIT_F0, a##N);                                     \
+       jit_patch_at(jit_beqi_f(JIT_F0, 17 - N), pass);                 \
+    } while (0)
+    CHECK_ARG(1);
+    CHECK_ARG(2);
+    CHECK_ARG(3);
+    CHECK_ARG(4);
+    CHECK_ARG(5);
+    CHECK_ARG(6);
+    CHECK_ARG(7);
+    CHECK_ARG(8);
+    CHECK_ARG(9);
+    CHECK_ARG(10);
+    CHECK_ARG(11);
+    CHECK_ARG(12);
+    CHECK_ARG(13);
+    CHECK_ARG(14);
+    CHECK_ARG(15);
+    CHECK_ARG(16);
+#undef CHECK_ARG
+    jit_calli(abort);
+    jit_link(pass);
+    jit_ret();
+    jit_epilog();
+
+    /* Create jit function that
+     * o Receives 16 double arguments
+     * o Save in the stack any register argument. Also force register
+     *   arguments to be clobbered to properly make the test
+     * o Calls a C function that receives 16 double arguments, with
+     *   values different from the ones received by this function
+     * o Reload from stack any register argument
+     * o Validated all arguments were not modified in the known
+     *   cases it could have been clobbered
+     */
+    jd = jit_label();
+    jit_name("jd");
+    jit_note(__FILE__, __LINE__);
+    jit_prolog();
+    a1  = jit_arg_d();
+    a2  = jit_arg_d();
+    a3  = jit_arg_d();
+    a4  = jit_arg_d();
+    a5  = jit_arg_d();
+    a6  = jit_arg_d();
+    a7  = jit_arg_d();
+    a8  = jit_arg_d();
+    a9  = jit_arg_d();
+    a10 = jit_arg_d();
+    a11 = jit_arg_d();
+    a12 = jit_arg_d();
+    a13 = jit_arg_d();
+    a14 = jit_arg_d();
+    a15 = jit_arg_d();
+    a16 = jit_arg_d();
+#define SAVE_ARG(N)                                                    \
+    do {                                                               \
+       if (jit_arg_register_p(a##N)) {                                 \
+           s##N = jit_allocai(sizeof(D));                              \
+           jit_getarg_d(JIT_F0, a##N);                                 \
+           jit_stxi_d(s##N, JIT_FP, JIT_F0);                           \
+           jit_putargi_d(-1, a##N);                                    \
+       }                                                               \
+    } while (0)
+    SAVE_ARG(1);
+    SAVE_ARG(2);
+    SAVE_ARG(3);
+    SAVE_ARG(4);
+    SAVE_ARG(5);
+    SAVE_ARG(6);
+    SAVE_ARG(7);
+    SAVE_ARG(8);
+    SAVE_ARG(9);
+    SAVE_ARG(10);
+    SAVE_ARG(11);
+    SAVE_ARG(12);
+    SAVE_ARG(13);
+    SAVE_ARG(14);
+    SAVE_ARG(15);
+    SAVE_ARG(16);
+#undef SAVE_ARG
+    jit_prepare();
+    {
+       jit_pushargi_d(1);
+       jit_pushargi_d(2);
+       jit_pushargi_d(3);
+       jit_pushargi_d(4);
+       jit_pushargi_d(5);
+       jit_pushargi_d(6);
+       jit_pushargi_d(7);
+       jit_pushargi_d(8);
+       jit_pushargi_d(9);
+       jit_pushargi_d(10);
+       jit_pushargi_d(11);
+       jit_pushargi_d(12);
+       jit_pushargi_d(13);
+       jit_pushargi_d(14);
+       jit_pushargi_d(15);
+       jit_pushargi_d(16);
+    }
+    jit_finishi(cd);
+#define LOAD_ARG(N)                                                    \
+    do {                                                               \
+       if (jit_arg_register_p(a##N)) {                                 \
+           jit_ldxi_d(JIT_F0, JIT_FP, s##N);                           \
+           jit_putargr_d(JIT_F0, a##N);                                \
+       }                                                               \
+    } while (0)
+    LOAD_ARG(1);
+    LOAD_ARG(2);
+    LOAD_ARG(3);
+    LOAD_ARG(4);
+    LOAD_ARG(5);
+    LOAD_ARG(6);
+    LOAD_ARG(7);
+    LOAD_ARG(8);
+    LOAD_ARG(9);
+    LOAD_ARG(10);
+    LOAD_ARG(11);
+    LOAD_ARG(12);
+    LOAD_ARG(13);
+    LOAD_ARG(14);
+    LOAD_ARG(15);
+    LOAD_ARG(16);
+#undef LOAD_ARG
+    pass = jit_forward();
+#define CHECK_ARG(N)                                                   \
+    do {                                                               \
+       jit_getarg_d(JIT_F0, a##N);                                     \
+       jit_patch_at(jit_beqi_d(JIT_F0, 17 - N), pass);                 \
+    } while (0)
+    CHECK_ARG(1);
+    CHECK_ARG(2);
+    CHECK_ARG(3);
+    CHECK_ARG(4);
+    CHECK_ARG(5);
+    CHECK_ARG(6);
+    CHECK_ARG(7);
+    CHECK_ARG(8);
+    CHECK_ARG(9);
+    CHECK_ARG(10);
+    CHECK_ARG(11);
+    CHECK_ARG(12);
+    CHECK_ARG(13);
+    CHECK_ARG(14);
+    CHECK_ARG(15);
+    CHECK_ARG(16);
+#undef CHECK_ARG
+    jit_calli(abort);
+    jit_link(pass);
+    jit_ret();
+    jit_epilog();
+
+    /* Create a jit function that calls the 3 previous ones.
+     * o First call the function that receives 16 word arguments
+     * o Then call the function that receives 16 float arguments
+     * o Finally call the function that receives 16 double arguments
+     */
+    jit_patch(jmp);
+    jit_name("main");
+    jit_note(__FILE__, __LINE__);
+    jit_prolog();
+    jit_prepare();
+    {
+       jit_pushargi(16);
+       jit_pushargi(15);
+       jit_pushargi(14);
+       jit_pushargi(13);
+       jit_pushargi(12);
+       jit_pushargi(11);
+       jit_pushargi(10);
+       jit_pushargi(9);
+       jit_pushargi(8);
+       jit_pushargi(7);
+       jit_pushargi(6);
+       jit_pushargi(5);
+       jit_pushargi(4);
+       jit_pushargi(3);
+       jit_pushargi(2);
+       jit_pushargi(1);
+    }
+    jit_patch_at(jit_finishi(NULL), jw);
+    jit_prepare();
+    {
+       jit_pushargi_f(16);
+       jit_pushargi_f(15);
+       jit_pushargi_f(14);
+       jit_pushargi_f(13);
+       jit_pushargi_f(12);
+       jit_pushargi_f(11);
+       jit_pushargi_f(10);
+       jit_pushargi_f(9);
+       jit_pushargi_f(8);
+       jit_pushargi_f(7);
+       jit_pushargi_f(6);
+       jit_pushargi_f(5);
+       jit_pushargi_f(4);
+       jit_pushargi_f(3);
+       jit_pushargi_f(2);
+       jit_pushargi_f(1);
+    }
+    jit_patch_at(jit_finishi(NULL), jf);
+    jit_prepare();
+    {
+       jit_pushargi_d(16);
+       jit_pushargi_d(15);
+       jit_pushargi_d(14);
+       jit_pushargi_d(13);
+       jit_pushargi_d(12);
+       jit_pushargi_d(11);
+       jit_pushargi_d(10);
+       jit_pushargi_d(9);
+       jit_pushargi_d(8);
+       jit_pushargi_d(7);
+       jit_pushargi_d(6);
+       jit_pushargi_d(5);
+       jit_pushargi_d(4);
+       jit_pushargi_d(3);
+       jit_pushargi_d(2);
+       jit_pushargi_d(1);
+    }
+    jit_patch_at(jit_finishi(NULL), jd);
+    jit_ret();
+    jit_epilog();
+
+    code = jit_emit();
+    jit_clear_state();
+
+    (*code)();
+
+    jit_destroy_state();
+    finish_jit();
+    return (0);
+}
diff --git a/deps/lightning/check/carry.ok b/deps/lightning/check/carry.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/carry.tst b/deps/lightning/check/carry.tst
new file mode 100644 (file)
index 0000000..180d896
--- /dev/null
@@ -0,0 +1,186 @@
+
+#define ix0            0
+#define lx0            0
+#define ix1            1
+#define lx1            1
+#define ix2            2
+#define lx2            2
+#define ix4            4
+#define lx4            4
+#if __WORDSIZE == 32
+#  define ix7fe                0x7ffffffe
+#  define ix7f         0x7fffffff
+#  define ix80         0x80000000
+#  define iff          0xffffffff
+#  define ife          0xfffffffe
+#  define ifd          0xfffffffd
+#  define ifc          0xfffffffc
+#else
+#  define ix7fe                0x7ffffffffffffffe
+#  define ix7f         0x7fffffffffffffff
+#  define ix80         0x8000000000000000
+#  define iff          0xffffffffffffffff
+#  define ife          0xfffffffffffffffe
+#  define ifd          0xfffffffffffffffd
+#  define ifc          0xfffffffffffffffc
+#endif
+
+/* check jumps are taken and result value is correct */
+#define bopr_t(l, u, op, r0, r1, il, ir, iv)                   \
+       movi %r0 il                                             \
+       movi %r1 ir                                             \
+       b##op##r##u op##u##r##l##r0##r1 %r0 %r1                 \
+       /* validate did jump */                                 \
+       movi %r0 0x5a5a5a5a                                     \
+op##u##r##l##r0##r1:                                           \
+       beqi op##u##r##l##ok##r0##r1 %r0 iv                     \
+       calli @abort                                            \
+op##u##r##l##ok##r0##r1:
+#define bopi_t(l, u, op, r0, il, ir, iv)                       \
+       movi %r0 il                                             \
+       b##op##i##u op##u##i##l##r0##r1 %r0 ir                  \
+       /* validate did jump */                                 \
+       movi %r0 0x5a5a5a5a                                     \
+op##u##i##l##r0##r1:                                           \
+       beqi op##u##i##l##ok##r0##r1 %r0 iv                     \
+       calli @abort                                            \
+op##u##i##l##ok##r0##r1:
+#define bopr_f(l, u, op, r0, r1, il, ir, iv)                   \
+       movi %r0 il                                             \
+       movi %r1 ir                                             \
+       b##op##r##u op##u##r##l##r0##r1 %r0 %r1                 \
+       beqi op##u##r##l##ok##r0##r1 %r0 iv                     \
+op##u##r##l##r0##r1:                                           \
+       calli @abort                                            \
+op##u##r##l##ok##r0##r1:
+#define bopi_f(l, u, op, r0, il, ir, iv)                       \
+       movi %r0 il                                             \
+       b##op##i##u op##u##i##l##r0##r1 %r0 ir                  \
+       beqi op##u##i##l##ok##r0##r1 %r0 iv                     \
+op##u##i##l##r0##r1:                                           \
+       calli @abort                                            \
+op##u##i##l##ok##r0##r1:
+#define ccop(cc, l, u, op, r0, r1, il, ir, iv)                 \
+       bopr##cc(l, u, op, r0, r1, i##il, i##ir, i##iv)         \
+       bopi##cc(l, u, op, r0, i##il, i##ir, i##iv)
+#define tadd(l, u, r0, r1, il, ir, iv)                         \
+       ccop(_t, l, u, oadd, r0, r1, il, ir, iv)                \
+       ccop(_f, l, u, xadd, r0, r1, il, ir, iv)
+#define fadd(l, u, r0, r1, il, ir, iv)                         \
+       ccop(_f, l, u, oadd, r0, r1, il, ir, iv)                \
+       ccop(_t, l, u, xadd, r0, r1, il, ir, iv)
+#define tsub(l, u, r0, r1, il, ir, iv)                         \
+       ccop(_t, l, u, osub, r0, r1, il, ir, iv)                \
+       ccop(_f, l, u, xsub, r0, r1, il, ir, iv)
+#define fsub(l, u, r0, r1, il, ir, iv)                         \
+       ccop(_f, l, u, osub, r0, r1, il, ir, iv)                \
+       ccop(_t, l, u, xsub, r0, r1, il, ir, iv)
+
+#define xopr6(l,op,r0,r1,r2,r3,r4,r5,llo,lhi,rlo,rhi,vlo,vhi)  \
+       movi %r1 llo                                            \
+       movi %r2 lhi                                            \
+       movi %r4 rlo                                            \
+       movi %r5 rhi                                            \
+       op##cr %r0 %r1 %r4                                      \
+       op##xr %r3 %r2 %r5                                      \
+       beqi op##l##L##r0##r1##r2##r3##r4##r5 %r0 vlo           \
+       calli @abort                                            \
+op##l##L##r0##r1##r2##r3##r4##r5:                              \
+       beqi op##l##H##r0##r1##r2##r3##r4##r5 %r3 vhi           \
+       calli @abort                                            \
+op##l##H##r0##r1##r2##r3##r4##r5:
+#define xopr4_(l,op,r0,r1,r2,r3,llo,lhi,rlo,rhi,vlo,vhi)       \
+       movi %r0 llo                                            \
+       movi %r1 lhi                                            \
+       movi %r2 rlo                                            \
+       movi %r3 rhi                                            \
+       op##cr %r0 %r0 %r2                                      \
+       op##xr %r1 %r1 %r3                                      \
+       beqi op##l##L_##r0##r1##r2##r3 %r0 vlo                  \
+       calli @abort                                            \
+op##l##L_##r0##r1##r2##r3:                                     \
+       beqi op##l##H_##r0##r1##r2##r3 %r1 vhi                  \
+       calli @abort                                            \
+op##l##H_##r0##r1##r2##r3:
+#define xopr_4(l,op,r0,r1,r2,r3,llo,lhi,rlo,rhi,vlo,vhi)       \
+       movi %r0 rlo                                            \
+       movi %r1 rhi                                            \
+       movi %r2 llo                                            \
+       movi %r3 lhi                                            \
+       op##cr %r0 %r2 %r0                                      \
+       op##xr %r1 %r3 %r1                                      \
+       beqi op##l##_L##r0##r1##r2##r3 %r0 vlo                  \
+       calli @abort                                            \
+op##l##_L##r0##r1##r2##r3:                                     \
+       beqi op##l##_H##r0##r1##r2##r3 %r1 vhi                  \
+       calli @abort                                            \
+op##l##_H##r0##r1##r2##r3:
+
+#define xaddr(l,llo,lhi,rlo,rhi,vlo,vhi)                                               \
+       xopr6(l,add,r0,r1,r2,v0,v1,v2,i##llo,i##lhi,i##rlo,i##rhi,i##vlo,i##vhi)        \
+       xopr4_(l,add,r0,r1,r2,v0,i##llo,i##lhi,i##rlo,i##rhi,i##vlo,i##vhi)             \
+       xopr_4(l,add,r0,r1,r2,v0,i##llo,i##lhi,i##rlo,i##rhi,i##vlo,i##vhi)
+#define xsubr(l,llo,lhi,rlo,rhi,vlo,vhi)                                               \
+       xopr6(l,sub,r0,r1,r2,v0,v1,v2,i##llo,i##lhi,i##rlo,i##rhi,i##vlo,i##vhi)        \
+       xopr4_(l,sub,r0,r1,r2,v0,i##llo,i##lhi,i##rlo,i##rhi,i##vlo,i##vhi)             \
+       xopr_4(l,sub,r0,r1,r2,v0,i##llo,i##lhi,i##rlo,i##rhi,i##vlo,i##vhi)
+
+.data  16
+ok:
+.c     "ok\n"
+
+.code
+       prolog
+
+       tadd(__LINE__,   , r0, r1, x7f,  x1, x80)
+       fadd(__LINE__,   , r0, r1, x7fe, x1, x7f)
+       tsub(__LINE__,   , r0, r1, x80,  x1, x7f)
+       fsub(__LINE__,   , r0, r1, x7f,  x1, x7fe)
+       tadd(__LINE__, _u, r0, r1, ff,   x1, x0)
+       fadd(__LINE__, _u, r0, r1, x7f,  x1, x80)
+       tsub(__LINE__, _u, r0, r1, x0,   x1, ff)
+       fsub(__LINE__, _u, r0, r1, x80,  x1, x7f)
+
+       /* 0xffffffffffffffff + 1 = 0x10000000000000000 */
+       xaddr(__LINE__, ff, ff, x1, x0, x0, x0)
+
+       /* 1 + 0xffffffffffffffff = 0x10000000000000000 */
+       xaddr(__LINE__, x1, x0, ff, ff, x0, x0)
+
+       /* 0xfffffffeffffffff + 1 = 0xffffffff00000000 */
+       xaddr(__LINE__, ff, fe, x1, x0, x0, ff)
+
+       /* 1 + 0xfffffffeffffffff = 0xffffffff00000000 */
+       xaddr(__LINE__, x1, x0, ff, fe, x0, ff)
+
+       /* 0xfffffffefffffffe + 2 = 0xffffffff00000000 */
+       xaddr(__LINE__, fe, fe, x2, x0, x0, ff)
+
+       /* 2 + 0xfffffffefffffffe = 0xffffffff00000000 */
+       xaddr(__LINE__, x2, x0, fe, fe, x0, ff)
+
+       /* 0xffffffffffffffff - 1 = 0xfffffffffffffffe */
+       xsubr(__LINE__, ff, ff, x1, x0, fe, ff)
+
+       /* 1 - 0xffffffffffffffff = -0xfffffffffffffffe */
+       xsubr(__LINE__, x1, x0, ff, ff, x2, x0)
+
+       /* 0xfffffffeffffffff - 1 = 0xfffffffefffffffe */
+       xsubr(__LINE__, ff, fe, x1, x0, fe, fe)
+
+       /* 1 - 0xfffffffeffffffff = -0xfffffffefffffffe */
+       xsubr(__LINE__, x1, x0, ff, fe, x2, x1)
+
+       /* 0xfffffffefffffffe - 2 = 0xfffffffefffffffc */
+       xsubr(__LINE__, fe, fe, x2, x0, fc, fe)
+
+       /* 2 + 0xfffffffefffffffe = -0xfffffffefffffffc */
+       xsubr(__LINE__, x2, x0, fe, fe, x4, x1)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+
+       ret
+       epilog
diff --git a/deps/lightning/check/ccall.c b/deps/lightning/check/ccall.c
new file mode 100644 (file)
index 0000000..9dae256
--- /dev/null
@@ -0,0 +1,903 @@
+#include <lightning.h>
+#include <stdio.h>
+
+#define _w0                    0
+#define _w1                    1
+#define _w2                    (_w1-2)
+#define _w3                    (_w2-3)
+#define _w4                    (_w3-4)
+#define _w5                    (_w4-5)
+#define _w6                    (_w5-6)
+#define _w7                    (_w6-7)
+#define _w8                    (_w7-8)
+#define _w9                    (_w8-9)
+#define _w10                   (_w9-10)
+#define _w11                   (_w10-11)
+#define _w12                   (_w11-12)
+#define _w13                   (_w12-13)
+#define _w14                   (_w13-14)
+#define _w15                   (_w14-15)
+#define _c0                    _w0
+#define _c1                    _w1
+#define _c2                    _w2
+#define _c3                    _w3
+#define _c4                    _w4
+#define _c5                    _w5
+#define _c6                    _w6
+#define _c7                    _w7
+#define _c8                    _w8
+#define _c9                    _w9
+#define _c10                   _w10
+#define _c11                   _w11
+#define _c12                   _w12
+#define _c13                   _w13
+#define _c14                   _w14
+#define _c15                   _w15
+#define _uc0                   (_w0&0xff)
+#define _uc1                   (_w1&0xff)
+#define _uc2                   (_w2&0xff)
+#define _uc3                   (_w3&0xff)
+#define _uc4                   (_w4&0xff)
+#define _uc5                   (_w5&0xff)
+#define _uc6                   (_w6&0xff)
+#define _uc7                   (_w7&0xff)
+#define _uc8                   (_w8&0xff)
+#define _uc9                   (_w9&0xff)
+#define _uc10                  (_w10&0xff)
+#define _uc11                  (_w11&0xff)
+#define _uc12                  (_w12&0xff)
+#define _uc13                  (_w13&0xff)
+#define _uc14                  (_w14&0xff)
+#define _uc15                  (_w15&0xff)
+#define _s0                    _w0
+#define _s1                    _w1
+#define _s2                    _w2
+#define _s3                    _w3
+#define _s4                    _w4
+#define _s5                    _w5
+#define _s6                    _w6
+#define _s7                    _w7
+#define _s8                    _w8
+#define _s9                    _w9
+#define _s10                   _w10
+#define _s11                   _w11
+#define _s12                   _w12
+#define _s13                   _w13
+#define _s14                   _w14
+#define _s15                   _w15
+#define _us0                   (_w0&0xffff)
+#define _us1                   (_w1&0xffff)
+#define _us2                   (_w2&0xffff)
+#define _us3                   (_w3&0xffff)
+#define _us4                   (_w4&0xffff)
+#define _us5                   (_w5&0xffff)
+#define _us6                   (_w6&0xffff)
+#define _us7                   (_w7&0xffff)
+#define _us8                   (_w8&0xffff)
+#define _us9                   (_w9&0xffff)
+#define _us10                  (_w10&0xffff)
+#define _us11                  (_w11&0xffff)
+#define _us12                  (_w12&0xffff)
+#define _us13                  (_w13&0xffff)
+#define _us14                  (_w14&0xffff)
+#define _us15                  (_w15&0xffff)
+#define _i0                    _w0
+#define _i1                    _w1
+#define _i2                    _w2
+#define _i3                    _w3
+#define _i4                    _w4
+#define _i5                    _w5
+#define _i6                    _w6
+#define _i7                    _w7
+#define _i8                    _w8
+#define _i9                    _w9
+#define _i10                   _w10
+#define _i11                   _w11
+#define _i12                   _w12
+#define _i13                   _w13
+#define _i14                   _w14
+#define _i15                   _w15
+#if __WORDSIZE == 64
+#  define _ui0                 (_w0&0xffffffff)
+#  define _ui1                 (_w1&0xffffffff)
+#  define _ui2                 (_w2&0xffffffff)
+#  define _ui3                 (_w3&0xffffffff)
+#  define _ui4                 (_w4&0xffffffff)
+#  define _ui5                 (_w5&0xffffffff)
+#  define _ui6                 (_w6&0xffffffff)
+#  define _ui7                 (_w7&0xffffffff)
+#  define _ui8                 (_w8&0xffffffff)
+#  define _ui9                 (_w9&0xffffffff)
+#  define _ui10                        (_w10&0xffffffff)
+#  define _ui11                        (_w11&0xffffffff)
+#  define _ui12                        (_w12&0xffffffff)
+#  define _ui13                        (_w13&0xffffffff)
+#  define _ui14                        (_w14&0xffffffff)
+#  define _ui15                        (_w15&0xffffffff)
+#  define _l0                  _w0
+#  define _l1                  _w1
+#  define _l2                  _w2
+#  define _l3                  _w3
+#  define _l4                  _w4
+#  define _l5                  _w5
+#  define _l6                  _w6
+#  define _l7                  _w7
+#  define _l8                  _w8
+#  define _l9                  _w9
+#  define _l10                 _w10
+#  define _l11                 _w11
+#  define _l12                 _w12
+#  define _l13                 _w13
+#  define _l14                 _w14
+#  define _l15                 _w15
+#endif
+
+/*
+ * Types
+ */
+typedef signed char            _c;
+typedef unsigned char          _uc;
+typedef signed short           _s;
+typedef unsigned short         _us;
+typedef signed int             _i;
+#if __WORDSIZE == 64
+typedef unsigned int           _ui;
+typedef jit_word_t             _l;
+#endif
+typedef float                  _f;
+typedef double                 _d;
+
+#define prt0(T)                        T C##T##0(void);
+#define prt1(T)                        prt0(T)                                 \
+                               T C##T##1(T);
+#define prt2(T)                        prt1(T)                                 \
+                               T C##T##2(T,T);
+#define prt3(T)                        prt2(T)                                 \
+                               T C##T##3(T,T,T);
+#define prt4(T)                        prt3(T)                                 \
+                               T C##T##4(T,T,T,T);
+#define prt5(T)                        prt4(T)                                 \
+                               T C##T##5(T,T,T,T,T);
+#define prt6(T)                        prt5(T)                                 \
+                               T C##T##6(T,T,T,T,T,T);
+#define prt7(T)                        prt6(T)                                 \
+                               T C##T##7(T,T,T,T,T,T,T);
+#define prt8(T)                        prt7(T)                                 \
+                               T C##T##8(T,T,T,T,T,T,T,T);
+#define prt9(T)                        prt8(T)                                 \
+                               T C##T##9(T,T,T,T,T,T,T,T,T);
+#define prt10(T)               prt9(T)                                 \
+                               T C##T##10(T,T,T,T,T,T,T,T,T,T);
+#define prt11(T)               prt10(T)                                \
+                               T C##T##11(T,T,T,T,T,T,T,T,T,T,T);
+#define prt12(T)               prt11(T)                                \
+                               T C##T##12(T,T,T,T,T,T,T,T,T,T,T,T);
+#define prt13(T)               prt12(T)                                \
+                               T C##T##13(T,T,T,T,T,T,T,T,T,T,T,T,T);
+#define prt14(T)               prt13(T)                                \
+                               T C##T##14(T,T,T,T,T,T,T,T,T,T,T,T,T,T);
+#define prt15(T)               prt14(T)                                \
+                               T C##T##15(T,T,T,T,T,T,T,T,T,T,T,T,T,T,T);
+#define prt(T)                 prt15(T)
+prt(_c)
+prt(_uc)
+prt(_s)
+prt(_us)
+prt(_i)
+#if __WORDSIZE == 64
+prt(_ui)
+prt(_l)
+#endif
+prt(_f)
+prt(_d)
+#undef prt
+#undef prt15
+#undef prt14
+#undef prt13
+#undef prt12
+#undef prt11
+#undef prt10
+#undef prt9
+#undef prt8
+#undef prt7
+#undef prt6
+#undef prt5
+#undef prt4
+#undef prt3
+#undef prt2
+#undef prt1
+#undef prt0
+
+#define prtn(N,T)              T J##T##n(void);
+#define prt0(T)                        prtn(0,T)
+#define prt1(T)                        prt0(T)                 prtn(1,T)
+#define prt2(T)                        prt1(T)                 prtn(2,T)
+#define prt3(T)                        prt2(T)                 prtn(3,T)
+#define prt4(T)                        prt3(T)                 prtn(4,T)
+#define prt5(T)                        prt4(T)                 prtn(5,T)
+#define prt6(T)                        prt5(T)                 prtn(6,T)
+#define prt7(T)                        prt6(T)                 prtn(7,T)
+#define prt8(T)                        prt7(T)                 prtn(8,T)
+#define prt9(T)                        prt8(T)                 prtn(9,T)
+#define prt10(T)               prt9(T)                 prtn(10,T)
+#define prt11(T)               prt10(T)                prtn(11,T)
+#define prt12(T)               prt11(T)                prtn(12,T)
+#define prt13(T)               prt12(T)                prtn(13,T)
+#define prt14(T)               prt13(T)                prtn(14,T)
+#define prt15(T)               prt14(T)                prtn(15,T)
+#define prt(T)                 prt15(T)
+prt(_c)
+prt(_uc)
+prt(_s)
+prt(_us)
+prt(_i)
+#if __WORDSIZE == 64
+prt(_ui)
+prt(_l)
+#endif
+prt(_f)
+prt(_d)
+#undef prt
+#undef prt15
+#undef prt14
+#undef prt13
+#undef prt12
+#undef prt11
+#undef prt10
+#undef prt9
+#undef prt8
+#undef prt7
+#undef prt6
+#undef prt5
+#undef prt4
+#undef prt3
+#undef prt2
+#undef prt1
+#undef prt0
+#undef prtn
+
+/*
+ * Initialization
+ */
+
+#define dat0(T)                        T (*j##T##0)(void);                     \
+                               jit_node_t *n##T##0;
+#define dat1(T)                        dat0(T)                                 \
+                               T (*j##T##1)(T);                        \
+                               jit_node_t *n##T##1;
+#define dat2(T)                        dat1(T)                                 \
+                               T (*j##T##2)(T,T);                      \
+                               jit_node_t *n##T##2;
+#define dat3(T)                        dat2(T)                                 \
+                               T (*j##T##3)(T,T,T);                    \
+                               jit_node_t *n##T##3;
+#define dat4(T)                        dat3(T)                                 \
+                               T (*j##T##4)(T,T,T,T);                  \
+                               jit_node_t *n##T##4;
+#define dat5(T)                        dat4(T)                                 \
+                               T (*j##T##5)(T,T,T,T,T);                \
+                               jit_node_t *n##T##5;
+#define dat6(T)                        dat5(T)                                 \
+                               T (*j##T##6)(T,T,T,T,T,T);              \
+                               jit_node_t *n##T##6;
+#define dat7(T)                        dat6(T)                                 \
+                               T (*j##T##7)(T,T,T,T,T,T,T);            \
+                               jit_node_t *n##T##7;
+#define dat8(T)                        dat7(T)                                 \
+                               T (*j##T##8)(T,T,T,T,T,T,T,T);          \
+                               jit_node_t *n##T##8;
+#define dat9(T)                        dat8(T)                                 \
+                               T (*j##T##9)(T,T,T,T,T,T,T,T,T);        \
+                               jit_node_t *n##T##9;
+#define dat10(T)               dat9(T)                                 \
+                               T (*j##T##10)(T,T,T,T,T,T,T,T,T,T);     \
+                               jit_node_t *n##T##10;
+#define dat11(T)               dat10(T)                                \
+                               T (*j##T##11)(T,T,T,T,T,T,T,T,T,T,T);   \
+                               jit_node_t *n##T##11;
+#define dat12(T)               dat11(T)                                \
+                               T (*j##T##12)(T,T,T,T,T,T,T,T,T,T,T,T); \
+                               jit_node_t *n##T##12;
+#define dat13(T)               dat12(T)                                \
+                               T (*j##T##13)(T,T,T,T,T,T,T,T,T,T,T,T,T);\
+                               jit_node_t *n##T##13;
+#define dat14(T)               dat13(T)                                \
+                               T (*j##T##14)(T,T,T,T,T,T,T,T,T,T,T,T,T,T);\
+                               jit_node_t *n##T##14;
+#define dat15(T)               dat14(T)                                \
+                               T (*j##T##15)(T,T,T,T,T,T,T,T,T,T,T,T,T,T,T);\
+                               jit_node_t *n##T##15;
+#define dat(T)                 dat15(T)
+dat(_c)
+dat(_uc)
+dat(_s)
+dat(_us)
+dat(_i)
+#if __WORDSIZE == 64
+dat(_ui)
+dat(_l)
+#endif
+dat(_f)
+dat(_d)
+#undef dat
+#undef dat15
+#undef dat14
+#undef dat13
+#undef dat12
+#undef dat11
+#undef dat10
+#undef dat9
+#undef dat8
+#undef dat7
+#undef dat6
+#undef dat5
+#undef dat4
+#undef dat3
+#undef dat2
+#undef dat1
+#undef dat0
+
+/*
+ * Implementation
+ */
+#define dcl0(T)                                                                \
+T C##T##0(void)                                                                \
+{                                                                      \
+    return (0);                                                                \
+}
+#define dcl1(T)                                                                \
+dcl0(T)                                                                        \
+T C##T##1(T A)                                                         \
+{                                                                      \
+    return (A);                                                                \
+}
+#define dcl2(T)                                                                \
+dcl1(T)                                                                        \
+T C##T##2(T A,T B)                                                     \
+{                                                                      \
+    return (A-B);                                                      \
+}
+#define dcl3(T)                                                                \
+dcl2(T)                                                                        \
+T C##T##3(T A,T B,T C)                                                 \
+{                                                                      \
+    return (A-B-C);                                                    \
+}
+#define dcl4(T)                                                                \
+dcl3(T)                                                                        \
+T C##T##4(T A,T B,T C,T D)                                             \
+{                                                                      \
+    return (A-B-C-D);                                                  \
+}
+#define dcl5(T)                                                                \
+dcl4(T)                                                                        \
+T C##T##5(T A,T B,T C,T D,T E)                                         \
+{                                                                      \
+    return (A-B-C-D-E);                                                        \
+}
+#define dcl6(T)                                                                \
+dcl5(T)                                                                        \
+T C##T##6(T A,T B,T C,T D,T E,T F)                                     \
+{                                                                      \
+    return (A-B-C-D-E-F);                                              \
+}
+#define dcl7(T)                                                                \
+dcl6(T)                                                                        \
+T C##T##7(T A,T B,T C,T D,T E,T F,T G)                                 \
+{                                                                      \
+    return (A-B-C-D-E-F-G);                                            \
+}
+#define dcl8(T)                                                                \
+dcl7(T)                                                                        \
+T C##T##8(T A,T B,T C,T D,T E,T F,T G,T H)                             \
+{                                                                      \
+    return (A-B-C-D-E-F-G-H);                                          \
+}
+#define dcl9(T)                                                                \
+dcl8(T)                                                                        \
+T C##T##9(T A,T B,T C,T D,T E,T F,T G,T H,T I)                         \
+{                                                                      \
+    return (A-B-C-D-E-F-G-H-I);                                                \
+}
+#define dcl10(T)                                                       \
+dcl9(T)                                                                        \
+T C##T##10(T A,T B,T C,T D,T E,T F,T G,T H,T I,T J)                    \
+{                                                                      \
+    return (A-B-C-D-E-F-G-H-I-J);                                      \
+}
+#define dcl11(T)                                                       \
+dcl10(T)                                                               \
+T C##T##11(T A,T B,T C,T D,T E,T F,T G,T H,T I,T J,T K)                        \
+{                                                                      \
+    return (A-B-C-D-E-F-G-H-I-J-K);                                    \
+}
+#define dcl12(T)                                                       \
+dcl11(T)                                                               \
+T C##T##12(T A,T B,T C,T D,T E,T F,T G,T H,T I,T J,T K,T L)            \
+{                                                                      \
+    return (A-B-C-D-E-F-G-H-I-J-K-L);                                  \
+}
+#define dcl13(T)                                                       \
+dcl12(T)                                                               \
+T C##T##13(T A,T B,T C,T D,T E,T F,T G,T H,T I,T J,T K,T L,T M)                \
+{                                                                      \
+    return (A-B-C-D-E-F-G-H-I-J-K-L-M);                                        \
+}
+#define dcl14(T)                                                       \
+dcl13(T)                                                               \
+T C##T##14(T A,T B,T C,T D,T E,T F,T G,T H,T I,T J,T K,T L,T M,T N)    \
+{                                                                      \
+    return (A-B-C-D-E-F-G-H-I-J-K-L-M-N);                              \
+}
+#define dcl15(T)                                                       \
+dcl14(T)                                                               \
+T C##T##15(T A,T B,T C,T D,T E,T F,T G,T H,T I,T J,T K,T L,T M,T N,T O)        \
+{                                                                      \
+    return (A-B-C-D-E-F-G-H-I-J-K-L-M-N-O);                            \
+}
+#define dcl(T) dcl15(T)
+dcl(_c)
+dcl(_uc)
+dcl(_s)
+dcl(_us)
+dcl(_i)
+#if __WORDSIZE == 64
+dcl(_ui)
+dcl(_l)
+#endif
+dcl(_f)
+dcl(_d)
+#undef dcl
+#undef dcl15
+#undef dcl14
+#undef dcl13
+#undef dcl12
+#undef dcl11
+#undef dcl10
+#undef dcl9
+#undef dcl8
+#undef dcl7
+#undef dcl6
+#undef dcl5
+#undef dcl4
+#undef dcl3
+#undef dcl2
+#undef dcl1
+#undef dcl0
+
+#define dcl0(T)                                                                \
+T CJ##T##0(void)                                                       \
+{                                                                      \
+    return ((*j##T##0)());                                             \
+}
+#define dcl1(T)                                                                \
+dcl0(T)                                                                        \
+T CJ##T##1(void)                                                       \
+{                                                                      \
+    return ((*j##T##1)(1));                                            \
+}
+#define dcl2(T)                                                                \
+dcl1(T)                                                                        \
+T CJ##T##2(void)                                                       \
+{                                                                      \
+    return ((*j##T##2)(1,2));                                          \
+}
+#define dcl3(T)                                                                \
+dcl2(T)                                                                        \
+T CJ##T##3(void)                                                       \
+{                                                                      \
+    return ((*j##T##3)(1,2,3));                                                \
+}
+#define dcl4(T)                                                                \
+dcl3(T)                                                                        \
+T CJ##T##4(void)                                                       \
+{                                                                      \
+    return ((*j##T##4)(1,2,3,4));                                      \
+}
+#define dcl5(T)                                                                \
+dcl4(T)                                                                        \
+T CJ##T##5(void)                                                       \
+{                                                                      \
+    return ((*j##T##5)(1,2,3,4,5));                                    \
+}
+#define dcl6(T)                                                                \
+dcl5(T)                                                                        \
+T CJ##T##6(void)                                                       \
+{                                                                      \
+    return ((*j##T##6)(1,2,3,4,5,6));                                  \
+}
+#define dcl7(T)                                                                \
+dcl6(T)                                                                        \
+T CJ##T##7(void)                                                       \
+{                                                                      \
+    return ((*j##T##7)(1,2,3,4,5,6,7));                                        \
+}
+#define dcl8(T)                                                                \
+dcl7(T)                                                                        \
+T CJ##T##8(void)                                                       \
+{                                                                      \
+    return ((*j##T##8)(1,2,3,4,5,6,7,8));                              \
+}
+#define dcl9(T)                                                                \
+dcl8(T)                                                                        \
+T CJ##T##9(void)                                                       \
+{                                                                      \
+    return ((*j##T##9)(1,2,3,4,5,6,7,8,9));                            \
+}
+#define dcl10(T)                                                       \
+dcl9(T)                                                                        \
+T CJ##T##10(void)                                                      \
+{                                                                      \
+    return ((*j##T##10)(1,2,3,4,5,6,7,8,9,10));                                \
+}
+#define dcl11(T)                                                       \
+dcl10(T)                                                               \
+T CJ##T##11(void)                                                      \
+{                                                                      \
+    return ((*j##T##11)(1,2,3,4,5,6,7,8,9,10,11));                     \
+}
+#define dcl12(T)                                                       \
+dcl11(T)                                                               \
+T CJ##T##12(void)                                                      \
+{                                                                      \
+    return ((*j##T##12)(1,2,3,4,5,6,7,8,9,10,11,12));                  \
+}
+#define dcl13(T)                                                       \
+dcl12(T)                                                               \
+T CJ##T##13(void)                                                      \
+{                                                                      \
+    return ((*j##T##13)(1,2,3,4,5,6,7,8,9,10,11,12,13));               \
+}
+#define dcl14(T)                                                       \
+dcl13(T)                                                               \
+T CJ##T##14(void)                                                      \
+{                                                                      \
+    return ((*j##T##14)(1,2,3,4,5,6,7,8,9,10,11,12,13,14));            \
+}
+#define dcl15(T)                                                       \
+dcl14(T)                                                               \
+T CJ##T##15(void)                                                      \
+{                                                                      \
+    return ((*j##T##15)(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15));         \
+}
+#define dcl(t) dcl15(t)
+dcl(_c)
+dcl(_uc)
+dcl(_s)
+dcl(_us)
+dcl(_i)
+#if __WORDSIZE == 64
+dcl(_ui)
+dcl(_l)
+#endif
+dcl(_f)
+dcl(_d)
+#undef dcl
+#undef dcl15
+#undef dcl14
+#undef dcl13
+#undef dcl12
+#undef dcl11
+#undef dcl10
+#undef dcl9
+#undef dcl8
+#undef dcl7
+#undef dcl6
+#undef dcl5
+#undef dcl4
+#undef dcl3
+#undef dcl2
+#undef dcl1
+#undef dcl0
+
+int
+main(int argc, char *argv[])
+{
+    jit_state_t                 *_jit;
+    jit_node_t          *jmpi_main;
+    void               (*function)(void);
+    jit_node_t          *a1,*a2,*a3,*a4,*a5,*a6,*a7,*a8,*a9;
+    jit_node_t          *a10,*a11,*a12,*a13,*a14,*a15;
+    jit_node_t          *jmp;
+
+    init_jit(argv[0]);
+    _jit = jit_new_state();
+
+    jmpi_main = jit_jmpi();
+
+
+#define arg0(T)                        /**/
+#define arg1(T)                                                a1 = jit_arg##T();
+#define arg2(T)                        arg1(T)                 a2 = jit_arg##T();
+#define arg3(T)                        arg2(T)                 a3 = jit_arg##T();
+#define arg4(T)                        arg3(T)                 a4 = jit_arg##T();
+#define arg5(T)                        arg4(T)                 a5 = jit_arg##T();
+#define arg6(T)                        arg5(T)                 a6 = jit_arg##T();
+#define arg7(T)                        arg6(T)                 a7 = jit_arg##T();
+#define arg8(T)                        arg7(T)                 a8 = jit_arg##T();
+#define arg9(T)                        arg8(T)                 a9 = jit_arg##T();
+#define arg10(T)               arg9(T)                 a10 = jit_arg##T();
+#define arg11(T)               arg10(T)                a11 = jit_arg##T();
+#define arg12(T)               arg11(T)                a12 = jit_arg##T();
+#define arg13(T)               arg12(T)                a13 = jit_arg##T();
+#define arg14(T)               arg13(T)                a14 = jit_arg##T();
+#define arg15(T)               arg14(T)                a15 = jit_arg##T();
+
+#define get0(B,T,R)            jit_movi##B(R##0,0);
+#define get1(B,T,R)            jit_getarg##B(R##0,a##1);
+#define get2(B,T,R)                                                    \
+       get1(B,T,R);                                                    \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##2);                                      \
+       jit_subr##B(R##0, R##1, R##0);
+#define get3(B,T,R)                                                    \
+       get2(B,T,R);                                                    \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##3);                                      \
+       jit_subr##B(R##0, R##1, R##0);
+#define get4(B,T,R)                                                    \
+       get3(B,T,R);                                                    \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##4);                                      \
+       jit_subr##B(R##0, R##1, R##0);
+#define get5(B,T,R)                                                    \
+       get4(B,T,R);                                                    \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##5);                                      \
+       jit_subr##B(R##0, R##1, R##0);
+#define get6(B,T,R)                                                    \
+       get5(B,T,R);                                                    \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##6);                                      \
+       jit_subr##B(R##0, R##1, R##0);
+#define get7(B,T,R)                                                    \
+       get6(B,T,R);                                                    \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##7);                                      \
+       jit_subr##B(R##0, R##1, R##0);
+#define get8(B,T,R)                                                    \
+       get7(B,T,R);                                                    \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##8);                                      \
+       jit_subr##B(R##0, R##1, R##0);
+#define get9(B,T,R)                                                    \
+       get8(B,T,R);                                                    \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##9);                                      \
+       jit_subr##B(R##0, R##1, R##0);
+#define get10(B,T,R)                                                   \
+       get9(B,T,R);                                                    \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##10);                                     \
+       jit_subr##B(R##0, R##1, R##0);
+#define get11(B,T,R)                                                   \
+       get10(B,T,R);                                                   \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##11);                                     \
+       jit_subr##B(R##0, R##1, R##0);
+#define get12(B,T,R)                                                   \
+       get11(B,T,R);                                                   \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##12);                                     \
+       jit_subr##B(R##0, R##1, R##0);
+#define get13(B,T,R)                                                   \
+       get12(B,T,R);                                                   \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##13);                                     \
+       jit_subr##B(R##0, R##1, R##0);
+#define get14(B,T,R)                                                   \
+       get13(B,T,R);                                                   \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##14);                                     \
+       jit_subr##B(R##0, R##1, R##0);
+#define get15(B,T,R)                                                   \
+       get14(B,T,R);                                                   \
+       jit_movr##B(R##1, R##0);                                        \
+       jit_getarg##T(R##0, a##15);                                     \
+       jit_subr##B(R##0, R##1, R##0);
+
+#if __WORDSIZE == 32
+#  define jit_extr_i(u, v)                     /**/
+#else
+#  define jit_extr_l(u, v)                     /**/
+#endif
+
+#define strfy(n)                               #n
+#define defi(T, N)                                                     \
+    n##T##N = jit_name(strfy(n##T##N));                                        \
+    jit_note("ccall.c", __LINE__);                                     \
+    jit_prolog();                                                      \
+    arg##N();                                                          \
+    get##N(,T,JIT_R)                                                   \
+    jit_extr##T(JIT_R0, JIT_R0);                                       \
+    jit_retr(JIT_R0);                                                  \
+    jit_epilog();
+#define deff(T, N)                                                     \
+    n##T##N = jit_name(strfy(n##T##N));                                        \
+    jit_note("ccall.c", __LINE__);                                     \
+    jit_prolog();                                                      \
+    arg##N(T);                                                         \
+    get##N(T,T,JIT_F);                                                 \
+    jit_retr##T(JIT_F0);                                               \
+    jit_epilog();
+
+#define  def0(X, T)                            def##X(T, 0)
+#define  def1(X, T)    def0(X, T)              def##X(T, 1)
+#define  def2(X, T)    def1(X, T)              def##X(T, 2)
+#define  def3(X, T)    def2(X, T)              def##X(T, 3)
+#define  def4(X, T)    def3(X, T)              def##X(T, 4)
+#define  def5(X, T)    def4(X, T)              def##X(T, 5)
+#define  def6(X, T)    def5(X, T)              def##X(T, 6)
+#define  def7(X, T)    def6(X, T)              def##X(T, 7)
+#define  def8(X, T)    def7(X, T)              def##X(T, 8)
+#define  def9(X, T)    def8(X, T)              def##X(T, 9)
+#define def10(X, T)    def9(X, T)              def##X(T, 10)
+#define def11(X, T)    def10(X, T)             def##X(T, 11)
+#define def12(X, T)    def11(X, T)             def##X(T, 12)
+#define def13(X, T)    def12(X, T)             def##X(T, 13)
+#define def14(X, T)    def13(X, T)             def##X(T, 14)
+#define def15(X, T)    def14(X, T)             def##X(T, 15)
+#define def(T)         def15(i, T)
+       def(_c)
+       def(_uc)
+       def(_s)
+       def(_us)
+       def(_i)
+#if __WORDSIZE == 64
+       def(_ui)
+       def(_l)
+#endif
+#undef def
+#define def(T)         def15(f, T)
+       def(_f)
+       def(_d)
+#undef def
+
+    jit_patch(jmpi_main);
+    jit_name("main");
+    jit_note("ccall.c", __LINE__);
+    jit_prolog();
+
+#define  push0(T)      /**/
+#define  push1(T)                              jit_pushargi##T(1);
+#define  push2(T)      push1(T)                jit_pushargi##T(2);
+#define  push3(T)      push2(T)                jit_pushargi##T(3);
+#define  push4(T)      push3(T)                jit_pushargi##T(4);
+#define  push5(T)      push4(T)                jit_pushargi##T(5);
+#define  push6(T)      push5(T)                jit_pushargi##T(6);
+#define  push7(T)      push6(T)                jit_pushargi##T(7);
+#define  push8(T)      push7(T)                jit_pushargi##T(8);
+#define  push9(T)      push8(T)                jit_pushargi##T(9);
+#define  push10(T)     push9(T)                jit_pushargi##T(10);
+#define  push11(T)     push10(T)               jit_pushargi##T(11);
+#define  push12(T)     push11(T)               jit_pushargi##T(12);
+#define  push13(T)     push12(T)               jit_pushargi##T(13);
+#define  push14(T)     push13(T)               jit_pushargi##T(14);
+#define  push15(T)     push14(T)               jit_pushargi##T(15);
+
+#define calin(T,N)                                                     \
+       jit_prepare();                                                  \
+               push##N()                                               \
+       jit_finishi(C##T##N);                                           \
+       jit_retval##T(JIT_R0);                                          \
+       jmp = jit_beqi(JIT_R0, T##N);                                   \
+       jit_calli(abort);                                               \
+       jit_patch(jmp);
+#define calfn(T,N)                                                     \
+       jit_prepare();                                                  \
+               push##N(T)                                              \
+       jit_finishi(C##T##N);                                           \
+       jit_retval##T(JIT_F0);                                          \
+       jmp = jit_beqi##T(JIT_F0, _w##N);                               \
+       jit_calli(abort);                                               \
+       jit_patch(jmp);
+#define  calx0(X,T)                            cal##X##n(T,0)
+#define  calx1(X,T)    calx0(X,T)              cal##X##n(T,1)
+#define  calx2(X,T)    calx1(X,T)              cal##X##n(T,2)
+#define  calx3(X,T)    calx2(X,T)              cal##X##n(T,3)
+#define  calx4(X,T)    calx3(X,T)              cal##X##n(T,4)
+#define  calx5(X,T)    calx4(X,T)              cal##X##n(T,5)
+#define  calx6(X,T)    calx5(X,T)              cal##X##n(T,6)
+#define  calx7(X,T)    calx6(X,T)              cal##X##n(T,7)
+#define  calx8(X,T)    calx7(X,T)              cal##X##n(T,8)
+#define  calx9(X,T)    calx8(X,T)              cal##X##n(T,9)
+#define calx10(X,T)    calx9(X,T)              cal##X##n(T,10)
+#define calx11(X,T)    calx10(X,T)             cal##X##n(T,11)
+#define calx12(X,T)    calx11(X,T)             cal##X##n(T,12)
+#define calx13(X,T)    calx12(X,T)             cal##X##n(T,13)
+#define calx14(X,T)    calx13(X,T)             cal##X##n(T,14)
+#define calx15(X,T)    calx14(X,T)             cal##X##n(T,15)
+#define cali(T)                calx15(i,T)
+#define calf(T)                calx15(f,T)
+
+    cali(_c)
+    cali(_uc)
+    cali(_s)
+    cali(_us)
+    cali(_i)
+#if __WORDSIZE == 64
+    cali(_ui)
+    cali(_l)
+#endif
+    calf(_f)
+    calf(_d)
+
+#undef calin
+#undef calfn
+#define calin(T,N)                                                     \
+       jit_prepare();                                                  \
+               push##N()                                               \
+       jit_finishi(CJ##T##N);                                          \
+       jit_retval##T(JIT_R0);                                          \
+       jmp = jit_beqi(JIT_R0, T##N);                                   \
+       jit_calli(abort);                                               \
+       jit_patch(jmp);
+#define calfn(T,N)                                                     \
+       jit_prepare();                                                  \
+               push##N(T)                                              \
+       jit_finishi(CJ##T##N);                                          \
+       jit_retval##T(JIT_F0);                                          \
+       jmp = jit_beqi##T(JIT_F0, _w##N);                               \
+       jit_calli(abort);                                               \
+       jit_patch(jmp);
+    cali(_c)
+    cali(_uc)
+    cali(_s)
+    cali(_us)
+    cali(_i)
+#if __WORDSIZE == 64
+    cali(_ui)
+    cali(_l)
+#endif
+    calf(_f)
+    calf(_d)
+
+    jit_ret();
+
+    function = jit_emit();
+
+#define initn(T,N)     j##T##N = jit_address(n##T##N);
+#define init0(T)                       initn(T,0)
+#define init1(T)        init0(T)       initn(T,1)
+#define init2(T)        init1(T)       initn(T,2)
+#define init3(T)        init2(T)       initn(T,3)
+#define init4(T)        init3(T)       initn(T,4)
+#define init5(T)        init4(T)       initn(T,5)
+#define init6(T)        init5(T)       initn(T,6)
+#define init7(T)        init6(T)       initn(T,7)
+#define init8(T)        init7(T)       initn(T,8)
+#define init9(T)        init8(T)       initn(T,9)
+#define init10(T)       init9(T)       initn(T,10)
+#define init11(T)      init10(T)       initn(T,11)
+#define init12(T)      init11(T)       initn(T,12)
+#define init13(T)      init12(T)       initn(T,13)
+#define init14(T)      init13(T)       initn(T,14)
+#define init15(T)      init14(T)       initn(T,15)
+#define init(T)                init15(T)
+    init(_c)
+    init(_uc)
+    init(_s)
+    init(_us)
+    init(_i)
+#if __WORDSIZE == 64
+    init(_ui)
+    init(_l)
+#endif
+    init(_f)
+    init(_d)
+
+#if 0
+    jit_print();
+    jit_disassemble();
+#endif
+
+    jit_clear_state();
+    (*function)();
+    jit_destroy_state();
+
+    finish_jit();
+
+    printf("ok\n");
+
+    return (0);
+}
diff --git a/deps/lightning/check/check.arm.sh b/deps/lightning/check/check.arm.sh
new file mode 100755 (executable)
index 0000000..2f576be
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+test=`basename $0 | sed -e 's|\.arm$||'`
+./lightning -mthumb=0 $srcdir/$test.tst | tr -d \\r > $test.out
+if test $? != 0; then
+  exit $?
+fi
+
+cmp -s $srcdir/$test.ok $test.out
+result=$?
+if test $result != 0; then
+    diff $srcdir/$test.ok $test.out
+    rm $test.out
+    exit 1
+fi
+rm $test.out
diff --git a/deps/lightning/check/check.arm.swf.sh b/deps/lightning/check/check.arm.swf.sh
new file mode 100755 (executable)
index 0000000..378b6d7
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+test=`basename $0 | sed -e 's|\.arm\.swf$||'`
+./lightning -mthumb=0 -mvfp=0 $srcdir/$test.tst | tr -d \\r > $test.out
+if test $? != 0; then
+  exit $?
+fi
+
+cmp -s $srcdir/$test.ok $test.out
+result=$?
+if test $result != 0; then
+    diff $srcdir/$test.ok $test.out
+    rm $test.out
+    exit 1
+fi
+rm $test.out
diff --git a/deps/lightning/check/check.arm4.swf.sh b/deps/lightning/check/check.arm4.swf.sh
new file mode 100755 (executable)
index 0000000..21926b6
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+test=`basename $0 | sed -e 's|\.arm4\.swf$||'`
+./lightning -mcpu=4 -mthumb=0 -mvfp=0 $srcdir/$test.tst | tr -d \\r > $test.out
+if test $? != 0; then
+  exit $?
+fi
+
+cmp -s $srcdir/$test.ok $test.out
+result=$?
+if test $result != 0; then
+    diff $srcdir/$test.ok $test.out
+    rm $test.out
+    exit 1
+fi
+rm $test.out
diff --git a/deps/lightning/check/check.nodata.sh b/deps/lightning/check/check.nodata.sh
new file mode 100755 (executable)
index 0000000..0fbc4e9
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+test=`basename $0 | sed -e 's|\.nodata$||'`
+./lightning -d $srcdir/$test.tst | tr -d \\r > $test.out
+if test $? != 0; then
+  exit $?
+fi
+
+cmp -s $srcdir/$test.ok $test.out
+result=$?
+if test $result != 0; then
+    diff $srcdir/$test.ok $test.out
+    rm $test.out
+    exit 1
+fi
+rm $test.out
diff --git a/deps/lightning/check/check.sh b/deps/lightning/check/check.sh
new file mode 100755 (executable)
index 0000000..e0267a2
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+test=`basename $0`
+./lightning $srcdir/$test.tst | tr -d \\r > $test.out
+if test $? != 0; then
+  exit $?
+fi
+
+cmp -s $srcdir/$test.ok $test.out
+result=$?
+if test $result != 0; then
+    diff $srcdir/$test.ok $test.out
+    rm $test.out
+    exit 1
+fi
+rm $test.out
diff --git a/deps/lightning/check/check.swf.sh b/deps/lightning/check/check.swf.sh
new file mode 100755 (executable)
index 0000000..9494eef
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+test=`basename $0 | sed -e 's|\.swf$||'`
+./lightning -mvfp=0 $srcdir/$test.tst | tr -d \\r > $test.out
+if test $? != 0; then
+  exit $?
+fi
+
+cmp -s $srcdir/$test.ok $test.out
+result=$?
+if test $result != 0; then
+    diff $srcdir/$test.ok $test.out
+    rm $test.out
+    exit 1
+fi
+rm $test.out
diff --git a/deps/lightning/check/check.x87.nodata.sh b/deps/lightning/check/check.x87.nodata.sh
new file mode 100755 (executable)
index 0000000..1582e9f
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+test=`basename $0 | sed -e 's|\.x87.nodata$||'`
+./lightning -data=0 -mx87=1 $srcdir/$test.tst | tr -d \\r > $test.out
+if test $? != 0; then
+  exit $?
+fi
+
+cmp -s $srcdir/$test.ok $test.out
+result=$?
+if test $result != 0; then
+    diff $srcdir/$test.ok $test.out
+    rm $test.out
+    exit 1
+fi
+rm $test.out
diff --git a/deps/lightning/check/check.x87.sh b/deps/lightning/check/check.x87.sh
new file mode 100755 (executable)
index 0000000..c0245e1
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+test=`basename $0 | sed -e 's|\.x87$||'`
+./lightning -mx87=1 $srcdir/$test.tst | tr -d \\r > $test.out
+if test $? != 0; then
+  exit $?
+fi
+
+cmp -s $srcdir/$test.ok $test.out
+result=$?
+if test $result != 0; then
+    diff $srcdir/$test.ok $test.out
+    rm $test.out
+    exit 1
+fi
+rm $test.out
diff --git a/deps/lightning/check/clobber.ok b/deps/lightning/check/clobber.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/clobber.tst b/deps/lightning/check/clobber.tst
new file mode 100644 (file)
index 0000000..7530842
--- /dev/null
@@ -0,0 +1,1050 @@
+/* do not bother about result of operations, only ensure valid arguments
+ * and that registers not modified by the operation are not clobbered  */
+
+#define IV0            0x10000
+#define IV1            0x10001
+#define IV2            0x10002
+#define IV3            0x10003
+#define IV4            0x10004
+#define IV5            0x10005
+#define FV0            100.0
+#define FV1            101.0
+#define FV2            102.0
+#define FV3            103.0
+#define FV4            104.0
+#define FV5            105.0
+#define IR0            r0
+#define IR1            r1
+#define IR2            r2
+#define IR3            v0
+#define IR4            v1
+#define IR5            v2
+#define FR0            f0
+#define FR1            f1
+#define FR2            f2
+#define FR3            f3
+#define FR4            f4
+#define FR5            f5
+
+#define setup()                                                        \
+       movi %r0 IV0                                            \
+       movi %r1 IV1                                            \
+       movi %r2 IV2                                            \
+       movi %v0 IV3                                            \
+       movi %v1 IV4                                            \
+       movi %v2 IV5
+#define setup_f()                                              \
+       movi_f %f0 FV0                                          \
+       movi_f %f1 FV1                                          \
+       movi_f %f2 FV2                                          \
+       movi_f %f3 FV3                                          \
+       movi_f %f4 FV4                                          \
+       movi_f %f5 FV5
+#define setup_d()                                              \
+       movi_d %f0 FV0                                          \
+       movi_d %f1 FV1                                          \
+       movi_d %f2 FV2                                          \
+       movi_d %f3 FV3                                          \
+       movi_d %f4 FV4                                          \
+       movi_d %f5 FV5
+
+#define check(label, rn)                                       \
+       beqi label %IR##rn IV##rn                               \
+       calli @abort                                            \
+label:
+#define check1(k, l, i0)                                       \
+       check(k##l##i0##_0, i0)
+#define check2(k, l, i0, i1)                                   \
+       check(k##l##i0##i1##_0, i0)                             \
+       check(k##l##i0##i1##_1, i1)
+#define check3(k, l, i0, i1, i2)                               \
+       check(k##l##i0##i1##i2##_0, i0)                         \
+       check(k##l##i0##i1##i2##_1, i1)                         \
+       check(k##l##i0##i1##i2##_2, i2)
+#define check4(k, l, i0, i1, i2, i3)                           \
+       check(k##l##i0##i1##i2##i3##_0, i0)                     \
+       check(k##l##i0##i1##i2##i3##_1, i1)                     \
+       check(k##l##i0##i1##i2##i3##_2, i2)                     \
+       check(k##l##i0##i1##i2##i3##_3, i3)
+#define check5(k, l, i0, i1, i2, i3, i4)                       \
+       check(k##l##i0##i1##i2##i3##i4##_0, i0)                 \
+       check(k##l##i0##i1##i2##i3##i4##_1, i1)                 \
+       check(k##l##i0##i1##i2##i3##i3##_2, i2)                 \
+       check(k##l##i0##i1##i2##i3##i4##_3, i3)                 \
+       check(k##l##i0##i1##i2##i3##i4##_4, i4)
+#define check6(k, l, i0, i1, i2, i3, i4, i5)                   \
+       check(k##l##i0##i1##i2##i3##i4##i5##_0, i0)             \
+       check(k##l##i0##i1##i2##i3##i4##i5##_1, i1)             \
+       check(k##l##i0##i1##i2##i3##i3##i5##_2, i2)             \
+       check(k##l##i0##i1##i2##i3##i4##i5##_3, i3)             \
+       check(k##l##i0##i1##i2##i3##i4##i5##_4, i4)             \
+       check(k##l##i0##i1##i2##i3##i4##i5##_5, i5)
+
+#define checkf(f, label, rn)                                   \
+       beqi##f label %FR##rn FV##rn                            \
+       calli @abort                                            \
+label:
+#define checkf1(f, k, l, i0)                                   \
+       checkf(f, f##k##l##i0##_0, i0)
+#define checkf2(f, k, l, i0, i1)                               \
+       checkf(f, f##k##l##i0##i1##_0, i0)                      \
+       checkf(f, f##k##l##i0##i1##_1, i1)
+#define checkf3(f, k, l, i0, i1, i2)                           \
+       checkf(f, f##k##l##i0##i1##i2##_0, i0)                  \
+       checkf(f, f##k##l##i0##i1##i2##_1, i1)                  \
+       checkf(f, f##k##l##i0##i1##i2##_2, i2)
+#define checkf4(f, k, l, i0, i1, i2, i3)                       \
+       checkf(f, f##k##l##i0##i1##i2##i3##_0, i0)              \
+       checkf(f, f##k##l##i0##i1##i2##i3##_1, i1)              \
+       checkf(f, f##k##l##i0##i1##i2##i3##_2, i2)              \
+       checkf(f, f##k##l##i0##i1##i2##i3##_3, i3)
+#define checkf5(f, k, l, i0, i1, i2, i3, i4)                   \
+       checkf(f, f##k##l##i0##i1##i2##i3##i4##_0, i0)          \
+       checkf(f, f##k##l##i0##i1##i2##i3##i4##_1, i1)          \
+       checkf(f, f##k##l##i0##i1##i2##i3##i3##_2, i2)          \
+       checkf(f, f##k##l##i0##i1##i2##i3##i4##_3, i3)          \
+       checkf(f, f##k##l##i0##i1##i2##i3##i4##_4, i4)
+#define checkf6(f, k, l, i0, i1, i2, i3, i4, i5)               \
+       checkf(f, f##k##l##i0##i1##i2##i3##i4##i5##_0, i0)      \
+       checkf(f, f##k##l##i0##i1##i2##i3##i4##i5##_1, i1)      \
+       checkf(f, f##k##l##i0##i1##i2##i3##i3##i5##_2, i2)      \
+       checkf(f, f##k##l##i0##i1##i2##i3##i4##i5##_3, i3)      \
+       checkf(f, f##k##l##i0##i1##i2##i3##i4##i5##_4, i4)      \
+       checkf(f, f##k##l##i0##i1##i2##i3##i4##i5##_5, i5)
+
+#define alui(l, op, i0, i1, i2, i3, i4, i5)                    \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op##i %IR##i1 %IR##i0 1                                 \
+       check4(i, l, i2, i3, i4, i5)
+#define aluic(l, op, i0, i1, i2, i3, i4, i5)                   \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op##i %IR##i0 %IR##i0 1                                 \
+       check5(ic, l, i1, i2, i3, i4, i5)
+#define alur(l, op, i0, i1, i2, i3, i4, i5)                    \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       movi %IR##i1 1                                          \
+       op##r %IR##i2 %IR##i0 %IR##i1                           \
+       check3(r, l, i3, i4, i5)
+#define alurc0(l, op, i0, i1, i2, i3, i4, i5)                  \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       movi %IR##i1 1                                          \
+       op##r %IR##i0 %IR##i0 %IR##i1                           \
+       check4(r0, l, i2, i3, i4, i5)
+#define alurc1(l, op, i0, i1, i2, i3, i4, i5)                  \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       movi %IR##i1 1                                          \
+       op##r %IR##i1 %IR##i0 %IR##i1                           \
+       check4(r1, l, i2, i3, i4, i5)
+#define alurc2(l, op, i0, i1, i2, i3, i4, i5)                  \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op##r %IR##i0 %IR##i0 %IR##i0                           \
+       check5(r2, l, i1, i2, i3, i4, i5)
+#define   xalu(l, op, i0, i1, i2, i3, i4, i5)                  \
+         alui(l, op, i0, i1,   i2, i3, i4, i5)                 \
+        aluic(l, op, i0,               i1, i2, i3, i4, i5)     \
+         alur(l, op, i0, i1, i2,       i3, i4, i5)             \
+       alurc0(l, op, i0, i1,   i2, i3, i4, i5)                 \
+       alurc1(l, op, i0, i1,   i2, i3, i4, i5)                 \
+       alurc2(l, op, i0,               i1, i2, i3, i4, i5)
+
+#if __ia64__
+#  define alu(l, op)                                           \
+        xalu(l, op, 0, 1, 2, 3, 4, 5)
+#else
+#  define alu(l, op)                                           \
+        xalu(l, op, 0, 1, 2, 3, 4, 5)                          \
+        xalu(l, op, 1, 2, 3, 4, 5, 0)                          \
+        xalu(l, op, 2, 3, 4, 5, 0, 1)                          \
+        xalu(l, op, 3, 4, 5, 0, 1, 2)                          \
+        xalu(l, op, 4, 5, 0, 1, 2, 3)                          \
+        xalu(l, op, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define fopi(f, l, op, f0, f1, f2, f3, f4, f5)                 \
+       setup##f()                                              \
+       movi##f %FR##f0 1.0                                     \
+       op##i##f %FR##f1 %FR##f0 1.0                            \
+       checkf4(f, i, l, f2, f3, f4, f5)
+#define fopic(f, l, op, f0, f1, f2, f3, f4, f5)                        \
+       setup##f()                                              \
+       movi##f %FR##f0 1.0                                     \
+       op##i##f %FR##f0 %FR##f0 1.0                            \
+       checkf5(f, ic, l, f1, f2, f3, f4, f5)
+#define fopr(f, l, op, f0, f1, f2, f3, f4, f5)                 \
+       setup##f()                                              \
+       movi##f %FR##f0 1.0                                     \
+       movi##f %FR##f1 1.0                                     \
+       op##r##f %FR##f2 %FR##f0 %FR##f1                        \
+       checkf3(f, r, l, f3, f4, f5)
+#define foprc0(f, l, op, f0, f1, f2, f3, f4, f5)               \
+       setup##f()                                              \
+       movi##f %FR##f0 1.0                                     \
+       movi##f %FR##f1 1.0                                     \
+       op##r##f %FR##f0 %FR##f0 %FR##f1                        \
+       checkf4(f, r0, l, f2, f3, f4, f5)
+#define foprc1(f, l, op, f0, f1, f2, f3, f4, f5)               \
+       setup##f()                                              \
+       movi##f %FR##f0 1.0                                     \
+       movi##f %FR##f1 1.0                                     \
+       op##r##f %FR##f1 %FR##f0 %FR##f1                        \
+       checkf4(f, r1, l, f2, f3, f4, f5)
+#define foprc2(f, l, op, f0, f1, f2, f3, f4, f5)               \
+       setup##f()                                              \
+       movi##f %FR##f0 1.0                                     \
+       op##r##f %FR##f0 %FR##f0 %FR##f0                        \
+       checkf5(f, r2, l, f1, f2, f3, f4, f5)
+#define   xfop(f, l, op, f0, f1, f2, f3, f4, f5)               \
+         fopi(f, l, op, f0, f1, f2,            f3, f4, f5)     \
+        fopic(f, l, op, f0, f1, f2,            f3, f4, f5)     \
+         fopr(f, l, op, f0, f1, f2,            f3, f4, f5)     \
+       foprc0(f, l, op, f0, f1,                f2, f3, f4, f5) \
+       foprc1(f, l, op, f0, f1,                f2, f3, f4, f5) \
+       foprc2(f, l, op, f0, f1,                f2, f3, f4, f5)
+#if __ia64__
+#  define xxfop(l, op, f, f0, f1, f2, f3, f4, f5)              \
+          xfop(_f, l, op, f0, f1, f2, f3, f4, f5)
+#else
+#  define xxfop(l, op, f, f0, f1, f2, f3, f4, f5)              \
+          xfop(_f, l, op, f0, f1, f2, f3, f4, f5)              \
+          xfop(_d, l, op, f0, f1, f2, f3, f4, f5)
+#endif
+#if __ia64__
+#  define fop(l, op)                                           \
+       xxfop(l, op, f, 0, 1, 2, 3, 4, 5)
+#else
+#  define fop(l, op)                                           \
+       xxfop(l, op, f, 0, 1, 2, 3, 4, 5)                       \
+       xxfop(l, op, f, 1, 2, 3, 4, 5, 0)                       \
+       xxfop(l, op, f, 2, 3, 4, 5, 0, 1)                       \
+       xxfop(l, op, f, 3, 4, 5, 0, 1, 2)                       \
+       xxfop(l, op, f, 4, 5, 0, 1, 2, 3)                       \
+       xxfop(l, op, f, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define aluxii(l, op, i0, i1, i2, i3, i4, i5)                  \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op##ci %IR##i1 %IR##i0 1                                \
+       op##xi %IR##i2 %IR##i0 1                                \
+       check3(ii, l, i3, i4, i5)
+#define aluxir(l, op, i0, i1, i2, i3, i4, i5)                  \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op##ci %IR##i1 %IR##i0 1                                \
+       op##xr %IR##i2 %IR##i0 %IR##i1                          \
+       check3(ir, l, i3, i4, i5)
+#define aluxri(l, op, i0, i1, i2, i3, i4, i5)                  \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       movi %IR##i1 1                                          \
+       op##cr %IR##i2 %IR##i0 %IR##i1                          \
+       op##xi %IR##i0 %IR##i1 1                                \
+       check3(ri, l, i3, i4, i5)
+#define aluxrr(l, op, i0, i1, i2, i3, i4, i5)                  \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       movi %IR##i1 1                                          \
+       op##cr %IR##i2 %IR##i0 %IR##i1                          \
+       op##xr %IR##i2 %IR##i0 %IR##i1                          \
+       check3(rr, l, i3, i4, i5)
+#define  xalux(l, op, i0, i1, i2, i3, i4, i5)                  \
+       aluxii(l, op, i0, i1, i2,       i3, i4, i5)             \
+       aluxir(l, op, i0, i1, i2,       i3, i4, i5)             \
+       aluxri(l, op, i0, i1, i2,       i3, i4, i5)             \
+       aluxrr(l, op, i0, i1, i2,       i3, i4, i5)
+#if __ia64__
+#  define alux(l, op)                                          \
+        xalux(l, op, 0, 1, 2, 3, 4, 5)
+#else
+#  define alux(l, op)                                          \
+        xalux(l, op, 0, 1, 2, 3, 4, 5)                         \
+        xalux(l, op, 1, 2, 3, 4, 5, 0)                         \
+        xalux(l, op, 2, 3, 4, 5, 0, 1)                         \
+        xalux(l, op, 3, 4, 5, 0, 1, 2)                         \
+        xalux(l, op, 4, 5, 0, 1, 2, 3)                         \
+        xalux(l, op, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define alui_u(l, op, i0, i1, i2, i3, i4, i5)                  \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op##i_u %IR##i1 %IR##i0 1                               \
+       check4(i_u, l, i2, i3, i4, i5)
+#define aluic_u(l, op, i0, i1, i2, i3, i4, i5)                 \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op##i_u %IR##i0 %IR##i0 1                               \
+       check5(ic_u, l, i1, i2, i3, i4, i5)
+#define alur_u(l, op, i0, i1, i2, i3, i4, i5)                  \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       movi %IR##i1 1                                          \
+       op##r_u %IR##i2 %IR##i0 %IR##i1                         \
+       check3(r_u, l, i3, i4, i5)
+#define alurc0_u(l, op, i0, i1, i2, i3, i4, i5)                        \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       movi %IR##i1 1                                          \
+       op##r_u %IR##i0 %IR##i0 %IR##i1                         \
+       check4(r0_u, l, i2, i3, i4, i5)
+#define alurc1_u(l, op, i0, i1, i2, i3, i4, i5)                        \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       movi %IR##i1 1                                          \
+       op##r_u %IR##i1 %IR##i0 %IR##i1                         \
+       check4(r1_u, l, i2, i3, i4, i5)
+#define alurc2_u(l, op, i0, i1, i2, i3, i4, i5)                        \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op##r_u %IR##i0 %IR##i0 %IR##i0                         \
+       check5(r2_u, l, i1, i2, i3, i4, i5)
+#define   xalu_u(l, op, i0, i1, i2, i3, i4, i5)                        \
+         alui_u(l, op, i0, i1, i2, i3, i4, i5)                 \
+        aluic_u(l, op, i0,             i1, i2, i3, i4, i5)     \
+         alur_u(l, op, i0, i1, i2,     i3, i4, i5)             \
+       alurc0_u(l, op, i0, i1, i2, i3, i4, i5)                 \
+       alurc1_u(l, op, i0, i1, i2, i3, i4, i5)                 \
+       alurc2_u(l, op, i0,             i1, i2, i3, i4, i5)
+#if __ia64__
+#  define alu_u(l, op)                                         \
+        xalu_u(l, op, 0, 1, 2, 3, 4, 5)
+#else
+#  define alu_u(l, op)                                         \
+        xalu_u(l, op, 0, 1, 2, 3, 4, 5)                        \
+        xalu_u(l, op, 1, 2, 3, 4, 5, 0)                        \
+        xalu_u(l, op, 2, 3, 4, 5, 0, 1)                        \
+        xalu_u(l, op, 3, 4, 5, 0, 1, 2)                        \
+        xalu_u(l, op, 4, 5, 0, 1, 2, 3)                        \
+        xalu_u(l, op, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define unir(l, op, i0, i1, i2, i3, i4, i5)                    \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op %IR##i1 %IR##i0                                      \
+       check4(rr, l, i2, i3, i4, i5)
+#define unirc(l, op, i0, i1, i2, i3, i4, i5)                   \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       op %IR##i0 %IR##i0                                      \
+       check5(rc, l, i1, i2, i3, i4, i5)
+#define   xuni(l, op, i0, i1, i2, i3, i4, i5)                  \
+         unir(l, op, i0, i1,   i2, i3, i4, i5)                 \
+        unirc(l, op, i0,               i1, i2, i3, i4, i5)
+#if __ia64__
+#  define uni(l, op)                                           \
+        xuni(l, op, 0, 1, 2, 3, 4, 5)
+#else
+#  define uni(l, op)                                           \
+        xuni(l, op, 0, 1, 2, 3, 4, 5)                          \
+        xuni(l, op, 1, 2, 3, 4, 5, 0)                          \
+        xuni(l, op, 2, 3, 4, 5, 0, 1)                          \
+        xuni(l, op, 3, 4, 5, 0, 1, 2)                          \
+        xuni(l, op, 4, 5, 0, 1, 2, 3)                          \
+        xuni(l, op, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define unfr(f, l, op, f0, f1, f2, f3, f4, f5)                 \
+       setup##f()                                              \
+       movi##f %FR##f0 1                                       \
+       op##f %FR##f1 %FR##f0                                   \
+       checkf4(f, rr, l, f2, f3, f4, f5)
+#define unfrc(f, l, op, f0, f1, f2, f3, f4, f5)                        \
+       setup##f()                                              \
+       movi##f %FR##f0 1                                       \
+       op##f %FR##f0 %FR##f0                                   \
+       checkf5(f, rc, l, f1, f2, f3, f4, f5)
+#define   xunf(f, l, op, f0, f1, f2, f3, f4, f5)               \
+         unfr(f, l, op, f0, f1,        f2, f3, f4, f5)         \
+        unfrc(f, l, op, f0,            f1, f2, f3, f4, f5)
+#define xxunf(l, op, f0, f1, f2, f3, f4, f5)                   \
+        xunf(_f, l, op, f0, f1, f2, f3, f4, f5)                \
+        xunf(_d, l, op, f0, f1, f2, f3, f4, f5)
+#if __ia64__
+#  define unf(l, op)                                           \
+       xxunf(l, op, 0, 1, 2, 3, 4, 5)
+#else
+#  define unf(l, op)                                           \
+       xxunf(l, op, 0, 1, 2, 3, 4, 5)                          \
+       xxunf(l, op, 1, 2, 3, 4, 5, 0)                          \
+       xxunf(l, op, 2, 3, 4, 5, 0, 1)                          \
+       xxunf(l, op, 3, 4, 5, 0, 1, 2)                          \
+       xxunf(l, op, 4, 5, 0, 1, 2, 3)                          \
+       xxunf(l, op, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define fcpi(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)   \
+       setup()                                                 \
+       setup##f()                                              \
+       movi##f %FR##f0 1.0                                     \
+       op##i##f %IR##r0 %FR##f0 1.0                            \
+       check5(i##f##f0, l, r1, r2, r3, r4, r5)                 \
+       checkf5(f, i##r0, l, f1, f2, f3, f4, f5)
+#define fcpr(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)   \
+       setup()                                                 \
+       setup##f()                                              \
+       movi##f %FR##f0 1.0                                     \
+       movi##f %FR##f1 1.0                                     \
+       op##r##f %IR##r0 %FR##f0 %FR##f1                        \
+       check5(r##f##f0, l, r1, r2, r3, r4, r5)                 \
+       checkf4(f, r##r0, l, f2, f3, f4, f5)
+#define fcprc(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)  \
+       setup()                                                 \
+       setup##f()                                              \
+       movi##f %FR##f0 1.0                                     \
+       op##r##f %IR##r0 %FR##f0 %FR##f0                        \
+       check5(rc##f##f0, l, r1, r2, r3, r4, r5)                \
+       checkf5(f, rc##r0, l, f1, f2, f3, f4, f5)
+#if __ia64__
+#  define ifcp(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         fcpi(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#else
+#  define ifcp(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         fcpi(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)  \
+         fcpr(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)  \
+        fcprc(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)  \
+         fcpi(f, l, op, r1,r2,r3,r4,r5,r0, f0,f1,f2,f3,f4,f5)  \
+         fcpr(f, l, op, r1,r2,r3,r4,r5,r0, f0,f1,f2,f3,f4,f5)  \
+        fcprc(f, l, op, r1,r2,r3,r4,r5,r0, f0,f1,f2,f3,f4,f5)  \
+         fcpi(f, l, op, r2,r3,r4,r5,r0,r1, f0,f1,f2,f3,f4,f5)  \
+         fcpr(f, l, op, r2,r3,r4,r5,r0,r1, f0,f1,f2,f3,f4,f5)  \
+        fcprc(f, l, op, r2,r3,r4,r5,r0,r1, f0,f1,f2,f3,f4,f5)  \
+         fcpi(f, l, op, r3,r4,r5,r0,r1,r2, f0,f1,f2,f3,f4,f5)  \
+         fcpr(f, l, op, r3,r4,r5,r0,r1,r2, f0,f1,f2,f3,f4,f5)  \
+        fcprc(f, l, op, r3,r4,r5,r0,r1,r2, f0,f1,f2,f3,f4,f5)  \
+         fcpi(f, l, op, r4,r5,r0,r1,r2,r3, f0,f1,f2,f3,f4,f5)  \
+         fcpr(f, l, op, r4,r5,r0,r1,r2,r3, f0,f1,f2,f3,f4,f5)  \
+        fcprc(f, l, op, r4,r5,r0,r1,r2,r3, f0,f1,f2,f3,f4,f5)  \
+         fcpi(f, l, op, r5,r0,r1,r2,r3,r4, f0,f1,f2,f3,f4,f5)  \
+         fcpr(f, l, op, r5,r0,r1,r2,r3,r4, f0,f1,f2,f3,f4,f5)  \
+        fcprc(f, l, op, r5,r0,r1,r2,r3,r4, f0,f1,f2,f3,f4,f5)
+#endif
+#if __ia64__
+#  define xfcp(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         ifcp(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#else
+#  define xfcp(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         ifcp(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)  \
+         ifcp(f, l, op, r0,r1,r2,r3,r4,r5, f1,f2,f3,f4,f5,f0)  \
+         ifcp(f, l, op, r0,r1,r2,r3,r4,r5, f2,f3,f4,f5,f0,f1)  \
+         ifcp(f, l, op, r0,r1,r2,r3,r4,r5, f3,f4,f5,f0,f1,f2)  \
+         ifcp(f, l, op, r0,r1,r2,r3,r4,r5, f4,f5,f0,f1,f2,f3)  \
+         ifcp(f, l, op, r0,r1,r2,r3,r4,r5, f5,f0,f1,f2,f3,f4)
+#endif
+#if __ia64__
+#  define fcmp(l, op)                                          \
+         xfcp(_f, l, op, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5)
+#else
+#  define fcmp(l, op)                                          \
+         xfcp(_f, l, op, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5)   \
+         xfcp(_d, l, op, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5)
+#endif
+
+#define imvi(l, i0, i1, i2, i3, i4, i5)                                \
+       setup()                                                 \
+       movi %IR##i0 1                                          \
+       check5(i, l, i1, i2, i3, i4, i5)
+#define imvr(l, i0, i1, i2, i3, i4, i5)                                \
+       setup()                                                 \
+       movi %IR##i1 1                                          \
+       movr %IR##i0 %IR##i1                                    \
+       check4(r, l, i2, i3, i4, i5)
+#define xmvi(l, i0, i1, i2, i3, i4, i5)                                \
+       imvi(l, i0,     i1, i2, i3, i4, i5)                     \
+       imvr(l, i0, i1, i2, i3, i4, i5)
+#if __ia64__
+#  define mvi(l)                                               \
+        xmvi(l, 0, 1, 2, 3, 4, 5)
+#else
+#  define mvi(l)                                               \
+        xmvi(l, 0, 1, 2, 3, 4, 5)                              \
+        xmvi(l, 1, 2, 3, 4, 5, 0)                              \
+        xmvi(l, 2, 3, 4, 5, 0, 1)                              \
+        xmvi(l, 3, 4, 5, 0, 1, 2)                              \
+        xmvi(l, 4, 5, 0, 1, 2, 3)                              \
+        xmvi(l, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define fmvi(f, l, f0, f1, f2, f3, f4, f5)                     \
+       setup##f()                                              \
+       movi##f %FR##f0 1                                       \
+       checkf5(f, i, l, f1, f2, f3, f4, f5)
+#define fmvr(f, l, f0, f1, f2, f3, f4, f5)                     \
+       setup##f()                                              \
+       movi##f %FR##f1 1                                       \
+       movr##f %FR##f0 %FR##f1                                 \
+       checkf4(f, r, l, f2, f3, f4, f5)
+#define xmvf(f, l, f0, f1, f2, f3, f4, f5)                     \
+       fmvi(f, l, f0, f1, f2, f3, f4, f5)                      \
+       fmvr(f, l, f0, f1,      f2, f3, f4, f5)
+#if __ia64__
+#  define xxmvf(f, l)                                          \
+         xmvf(f, l, 0, 1, 2, 3, 4, 5)
+#else
+#  define xxmvf(f, l)                                          \
+          xmvf(f, l, 0, 1, 2, 3, 4, 5)                         \
+          xmvf(f, l, 1, 2, 3, 4, 5, 0)                         \
+          xmvf(f, l, 2, 3, 4, 5, 0, 1)                         \
+          xmvf(f, l, 3, 4, 5, 0, 1, 2)                         \
+          xmvf(f, l, 4, 5, 0, 1, 2, 3)                         \
+          xmvf(f, l, 5, 0, 1, 2, 3, 4)
+#endif
+#define   mvf(l)                                               \
+       xxmvf(_f, l)                                            \
+       xxmvf(_d, l)
+
+#define f2fr(f, l, op, f0, f1, f2, f3, f4, f5)                 \
+       setup##f()                                              \
+       movi##f %FR##f0 1                                       \
+       op %FR##f1 %FR##f0                                      \
+       checkf4(f, rr, l, f2, f3, f4, f5)
+#define f2frc(f, l, op, f0, f1, f2, f3, f4, f5)                        \
+       setup##f()                                              \
+       movi##f %FR##f0 1                                       \
+       op %FR##f0 %FR##f0                                      \
+       checkf5(f, rc, l, f1, f2, f3, f4, f5)
+#define  xf2f(f, l, op, f0, f1, f2, f3, f4, f5)                        \
+        f2fr(f, l, op, f0, f1, f2, f3, f4, f5)                 \
+       f2frc(f, l, op, f0,             f1, f2, f3, f4, f5)
+#if __ia64__
+#  define f2f(l, f, op)                                                \
+        xf2f(f, l, op, 0, 1, 2, 3, 4, 5)
+#else
+#  define f2f(l, f, op)                                                \
+        xf2f(f, l, op, 0, 1, 2, 3, 4, 5)                       \
+        xf2f(f, l, op, 1, 2, 3, 4, 5, 0)                       \
+        xf2f(f, l, op, 2, 3, 4, 5, 0, 1)                       \
+        xf2f(f, l, op, 3, 4, 5, 0, 1, 2)                       \
+        xf2f(f, l, op, 4, 5, 0, 1, 2, 3)                       \
+        xf2f(f, l, op, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define f2ir(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)   \
+       setup()                                                 \
+       setup##f()                                              \
+       movi##f %FR##f0 1                                       \
+       op##f %IR##r0 %FR##f0                                   \
+       check5(r##f##f0, l, r1, r2, r3, r4, r5)                 \
+       checkf5(f, i##r0, l, f1, f2, f3, f4, f5)
+#if __ia64__
+#  define if2i(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         f2ir(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#  define xf2i(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         if2i(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#else
+#  define if2i(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         f2ir(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)  \
+         f2ir(f, l, op, r1,r2,r3,r4,r5,r0, f0,f1,f2,f3,f4,f5)  \
+         f2ir(f, l, op, r2,r3,r4,r5,r0,r1, f0,f1,f2,f3,f4,f5)  \
+         f2ir(f, l, op, r3,r4,r5,r0,r1,r2, f0,f1,f2,f3,f4,f5)  \
+         f2ir(f, l, op, r4,r5,r0,r1,r2,r3, f0,f1,f2,f3,f4,f5)  \
+         f2ir(f, l, op, r5,r0,r1,r2,r3,r4, f0,f1,f2,f3,f4,f5)
+#  define xf2i(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         if2i(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)  \
+         if2i(f, l, op, r0,r1,r2,r3,r4,r5, f1,f2,f3,f4,f5,f0)  \
+         if2i(f, l, op, r0,r1,r2,r3,r4,r5, f2,f3,f4,f5,f0,f1)  \
+         if2i(f, l, op, r0,r1,r2,r3,r4,r5, f3,f4,f5,f0,f1,f2)  \
+         if2i(f, l, op, r0,r1,r2,r3,r4,r5, f4,f5,f0,f1,f2,f3)  \
+         if2i(f, l, op, r0,r1,r2,r3,r4,r5, f5,f0,f1,f2,f3,f4)
+#endif
+#define f2i(l, op)                                             \
+       xf2i(_f, l, op, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5)     \
+       xf2i(_d, l, op, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5)
+
+#define i2fr(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)   \
+       setup()                                                 \
+       setup##f()                                              \
+       movi %IR##r0 1                                          \
+       op##f %FR##f0 %IR##r0                                   \
+       check5(r##f##f0, l, r1, r2, r3, r4, r5)                 \
+       checkf5(f, i##r0, l, f1, f2, f3, f4, f5)
+#if __ia64__
+#  define ii2f(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         i2fr(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#  define xi2f(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         ii2f(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#else
+#  define ii2f(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         i2fr(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)  \
+         i2fr(f, l, op, r1,r2,r3,r4,r5,r0, f0,f1,f2,f3,f4,f5)  \
+         i2fr(f, l, op, r2,r3,r4,r5,r0,r1, f0,f1,f2,f3,f4,f5)  \
+         i2fr(f, l, op, r3,r4,r5,r0,r1,r2, f0,f1,f2,f3,f4,f5)  \
+         i2fr(f, l, op, r4,r5,r0,r1,r2,r3, f0,f1,f2,f3,f4,f5)  \
+         i2fr(f, l, op, r5,r0,r1,r2,r3,r4, f0,f1,f2,f3,f4,f5)
+#  define xi2f(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5) \
+         ii2f(f, l, op, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)  \
+         ii2f(f, l, op, r0,r1,r2,r3,r4,r5, f1,f2,f3,f4,f5,f0)  \
+         ii2f(f, l, op, r0,r1,r2,r3,r4,r5, f2,f3,f4,f5,f0,f1)  \
+         ii2f(f, l, op, r0,r1,r2,r3,r4,r5, f3,f4,f5,f0,f1,f2)  \
+         ii2f(f, l, op, r0,r1,r2,r3,r4,r5, f4,f5,f0,f1,f2,f3)  \
+         ii2f(f, l, op, r0,r1,r2,r3,r4,r5, f5,f0,f1,f2,f3,f4)
+#endif
+#define i2f(l, op)                                             \
+       xi2f(_f, l, op, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5)     \
+       xi2f(_d, l, op, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5)
+
+#define off_c          1
+#define off_uc         off_c
+#define off_s          2
+#define off_us         off_s
+#define off_i          4
+#define off_ui         off_i
+#define off_l          8
+#define off_f          4
+#define off_d          8
+
+#define ildi(i, l, r0, r1, r2, r3, r4, r5)                     \
+       setup()                                                 \
+       ldi##i %IR##r0 buff                                     \
+       check5(ldi##i, l, r1, r2, r3, r4, r5)
+#define ildr(i, l, r0, r1, r2, r3, r4, r5)                     \
+       setup()                                                 \
+       movi %IR##r1 buff                                       \
+       ldr##i %IR##r0 %IR##r1                                  \
+       check4(ldr##i, l, r2, r3, r4, r5)
+#define ildr0(i, l, r0, r1, r2, r3, r4, r5)                    \
+       setup()                                                 \
+       movi %IR##r0 buff                                       \
+       ldr##i %IR##r0 %IR##r0                                  \
+       check5(ldr##i, l, r1, r2, r3, r4, r5)
+#define ildxi(i, l, r0, r1, r2, r3, r4, r5)                    \
+       setup()                                                 \
+       movi %IR##r1 buff                                       \
+       ldxi##i %IR##r0 %IR##r1 off##i                          \
+       check4(ldxi##i, l, r2, r3, r4, r5)
+#define ildxr(i, l, r0, r1, r2, r3, r4, r5)                    \
+       setup()                                                 \
+       movi %IR##r1 buff                                       \
+       movi %IR##r2 off##i                                     \
+       ldxr##i %IR##r0 %IR##r1 %IR##r2                         \
+       check3(ldxr##i, l, r3, r4, r5)
+#define ildxr0(i, l, r0, r1, r2, r3, r4, r5)                   \
+       setup()                                                 \
+       movi %IR##r1 buff                                       \
+       movi %IR##r0 off##i                                     \
+       ldxr##i %IR##r0 %IR##r1 %IR##r0                         \
+       check4(ldxr0##i, l, r2, r3, r4, r5)
+#define ildxr1(i, l, r0, r1, r2, r3, r4, r5)                   \
+       setup()                                                 \
+       movi %IR##r0 buff                                       \
+       movi %IR##r1 off##i                                     \
+       ldxr##i %IR##r0 %IR##r0 %IR##r1                         \
+       check4(ldxr1##i, l, r2, r3, r4, r5)
+#define  xxldi(i, l, r0, r1, r2, r3, r4, r5)                   \
+         ildi(i, l, r0, r1, r2, r3, r4, r5)                    \
+         ildr(i, l, r0, r1, r2, r3, r4, r5)                    \
+        ildr0(i, l, r0, r1, r2, r3, r4, r5)                    \
+        ildxi(i, l, r0, r1, r2, r3, r4, r5)                    \
+        ildxr(i, l, r0, r1, r2, r3, r4, r5)                    \
+       ildxr0(i, l, r0, r1, r2, r3, r4, r5)                    \
+       ildxr1(i, l, r0, r1, r2, r3, r4, r5)
+#if __WORDSIZE == 32
+#define xxxldi(l, r0, r1, r2, r3, r4, r5)
+#else
+#define xxxldi(l, r0, r1, r2, r3, r4, r5)                      \
+        xxldi(_ui, l, r0, r1, r2, r3, r4, r5)                  \
+        xxldi( _l, l, r0, r1, r2, r3, r4, r5)
+#endif
+#define   xldi(l, r0, r1, r2, r3, r4, r5)                      \
+        xxldi( _c, l, r0, r1, r2, r3, r4, r5)                  \
+        xxldi(_uc, l, r0, r1, r2, r3, r4, r5)                  \
+        xxldi( _s, l, r0, r1, r2, r3, r4, r5)                  \
+        xxldi(_us, l, r0, r1, r2, r3, r4, r5)                  \
+        xxldi( _i, l, r0, r1, r2, r3, r4, r5)                  \
+       xxxldi(l, r0, r1, r2, r3, r4, r5)
+#if __ia64__
+#  define ldi(l)                                               \
+        xldi(l, 0, 1, 2, 3, 4, 5)
+#else
+#  define ldi(l)                                               \
+        xldi(l, 0, 1, 2, 3, 4, 5)                              \
+        xldi(l, 1, 2, 3, 4, 5, 0)                              \
+        xldi(l, 2, 3, 4, 5, 0, 1)                              \
+        xldi(l, 3, 4, 5, 0, 1, 2)                              \
+        xldi(l, 4, 5, 0, 1, 2, 3)                              \
+        xldi(l, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define fldi(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+       setup()                                                 \
+       setup##f()                                              \
+       ldi##f %FR##f0 buff                                     \
+       check6(ldi##f##r0##f0, l, r0, r1, r2, r3, r4, r5)       \
+       checkf5(f, ldi##r0##f0, l, f1, f2, f3, f4, f5)
+#define fldr(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+       setup()                                                 \
+       setup##f()                                              \
+       movi %IR##r0 buff                                       \
+       ldr##f %FR##f0 %IR##r0                                  \
+       check5(ldr##f##r0##f0, l, r1, r2, r3, r4, r5)           \
+       checkf5(f, ldr##r0##f0, l, f1, f2, f3, f4, f5)
+#define fldxi(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)      \
+       setup()                                                 \
+       setup##f()                                              \
+       movi %IR##r0 buff                                       \
+       ldxi##f %FR##f0 %IR##r0 off##f                          \
+       check5(ldxi##f##r0##f0, l, r1, r2, r3, r4, r5)          \
+       checkf5(f, ldxi##r0##f0, l, f1, f2, f3, f4, f5)
+#define fldxr(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)      \
+       setup()                                                 \
+       setup##f()                                              \
+       movi %IR##r0 buff                                       \
+       movi %IR##r1 off##f                                     \
+       ldxr##f %FR##f0 %IR##r0 %IR##r1                         \
+       check4(ldxr##f##r0##f0, l, r2, r3, r4, r5)              \
+       checkf5(f, ldxr##r0##f0, l, f1, f2, f3, f4, f5)
+#define          xldf(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)      \
+       fldi(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)        \
+       fldr(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)        \
+       fldxi(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+       fldxr(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#define         xxldf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)         \
+         xldf(_f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)     \
+         xldf(_d, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#if __ia64__
+#  define ixldf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+         xxldf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#else
+#  define fxldf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+         xxldf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)        \
+         xxldf(l, r0,r1,r2,r3,r4,r5, f1,f2,f3,f4,f5,f0)        \
+         xxldf(l, r0,r1,r2,r3,r4,r5, f2,f3,f4,f5,f0,f1)        \
+         xxldf(l, r0,r1,r2,r3,r4,r5, f3,f4,f5,f0,f1,f2)        \
+         xxldf(l, r0,r1,r2,r3,r4,r5, f4,f5,f0,f1,f2,f3)        \
+         xxldf(l, r0,r1,r2,r3,r4,r5, f5,f0,f1,f2,f3,f4)
+#  define ixldf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+         fxldf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)        \
+         fxldf(l, r1,r2,r3,r4,r5,r0, f0,f1,f2,f3,f4,f5)        \
+         fxldf(l, r2,r3,r4,r5,r0,r1, f0,f1,f2,f3,f4,f5)        \
+         fxldf(l, r3,r4,r5,r0,r1,r2, f0,f1,f2,f3,f4,f5)        \
+         fxldf(l, r4,r5,r0,r1,r2,r3, f0,f1,f2,f3,f4,f5)        \
+         fxldf(l, r5,r0,r1,r2,r3,r4, f0,f1,f2,f3,f4,f5)
+#endif
+#define   ldf(l)                                               \
+       ixldf(l, 0,1,2,3,4,5, 0,1,2,3,4,5)
+
+#define isti(i, l, r0, r1, r2, r3, r4, r5)                     \
+       setup()                                                 \
+       sti##i buff %IR##r0                                     \
+       check5(sti##i, l, r1, r2, r3, r4, r5)
+#define istr(i, l, r0, r1, r2, r3, r4, r5)                     \
+       setup()                                                 \
+       movi %IR##r1 buff                                       \
+       str##i %IR##r1 %IR##r0                                  \
+       check4(str##i, l, r2, r3, r4, r5)
+#define istr0(i, l, r0, r1, r2, r3, r4, r5)                    \
+       setup()                                                 \
+       movi %IR##r1 buff                                       \
+       str##i %IR##r1 %IR##r0                                  \
+       check4(str0##i, l, r2, r3, r4, r5)
+#define istxi(i, l, r0, r1, r2, r3, r4, r5)                    \
+       setup()                                                 \
+       movi %IR##r1 buff                                       \
+       stxi##i off##i %IR##r1 %IR##r0                          \
+       check4(stxi##i, l, r2, r3, r4, r5)
+#define istxr(i, l, r0, r1, r2, r3, r4, r5)                    \
+       setup()                                                 \
+       movi %IR##r1 buff                                       \
+       movi %IR##r2 off##i                                     \
+       stxr##i %IR##r2 %IR##r1 %IR##r0                         \
+       check3(stxr##i, l, r3, r4, r5)
+#define istxr0(i, l, r0, r1, r2, r3, r4, r5)                   \
+       setup()                                                 \
+       movi %IR##r1 buff                                       \
+       movi %IR##r0 off##i                                     \
+       stxr##i %IR##r0 %IR##r1 %IR##r0                         \
+       check4(stxr0##i, l, r2, r3, r4, r5)
+#define istxr1(i, l, r0, r1, r2, r3, r4, r5)                   \
+       setup()                                                 \
+       movi %IR##r0 buff                                       \
+       movi %IR##r1 off##i                                     \
+       stxr##i %IR##r1 %IR##r0 %IR##r0                         \
+       check4(stxr1##i, l, r2, r3, r4, r5)
+#define  xxsti(i, l, r0, r1, r2, r3, r4, r5)                   \
+         isti(i, l, r0, r1, r2, r3, r4, r5)                    \
+         istr(i, l, r0, r1, r2, r3, r4, r5)                    \
+        istr0(i, l, r0, r1, r2, r3, r4, r5)                    \
+        istxi(i, l, r0, r1, r2, r3, r4, r5)                    \
+        istxr(i, l, r0, r1, r2, r3, r4, r5)                    \
+       istxr0(i, l, r0, r1, r2, r3, r4, r5)                    \
+       istxr1(i, l, r0, r1, r2, r3, r4, r5)
+#if __WORDSIZE == 32
+#define xxxsti(l, r0, r1, r2, r3, r4, r5)
+#else
+#define xxxsti(l, r0, r1, r2, r3, r4, r5)                      \
+        xxsti( _l, l, r0, r1, r2, r3, r4, r5)
+#endif
+#define   xsti(l, r0, r1, r2, r3, r4, r5)                      \
+        xxsti( _c, l, r0, r1, r2, r3, r4, r5)                  \
+        xxsti( _s, l, r0, r1, r2, r3, r4, r5)                  \
+        xxsti( _i, l, r0, r1, r2, r3, r4, r5)                  \
+       xxxsti(l, r0, r1, r2, r3, r4, r5)
+#if __ia64__
+#  define sti(l)                                               \
+        xsti(l, 0, 1, 2, 3, 4, 5)
+#else
+#  define sti(l)                                               \
+        xsti(l, 0, 1, 2, 3, 4, 5)                              \
+        xsti(l, 1, 2, 3, 4, 5, 0)                              \
+        xsti(l, 2, 3, 4, 5, 0, 1)                              \
+        xsti(l, 3, 4, 5, 0, 1, 2)                              \
+        xsti(l, 4, 5, 0, 1, 2, 3)                              \
+        xsti(l, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define fsti(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+       setup()                                                 \
+       setup##f()                                              \
+       sti##f buff %FR##f0                                     \
+       check6(sti##f##r0##f0, l, r0, r1, r2, r3, r4, r5)       \
+       checkf5(f, sti##r0##f0, l, f1, f2, f3, f4, f5)
+#define fstr(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+       setup()                                                 \
+       setup##f()                                              \
+       movi %IR##r0 buff                                       \
+       str##f %IR##r0 %FR##f0                                  \
+       check5(str##f##r0##f0, l, r1, r2, r3, r4, r5)           \
+       checkf5(f, str##r0##f0, l, f1, f2, f3, f4, f5)
+#define fstxi(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)      \
+       setup()                                                 \
+       setup##f()                                              \
+       movi %IR##r0 buff                                       \
+       stxi##f off##f %IR##r0 %FR##f0                          \
+       check5(stxi##f##r0##f0, l, r1, r2, r3, r4, r5)          \
+       checkf5(f, stxi##r0##f0, l, f1, f2, f3, f4, f5)
+#define fstxr(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)      \
+       setup()                                                 \
+       setup##f()                                              \
+       movi %IR##r0 buff                                       \
+       movi %IR##r1 off##f                                     \
+       stxr##f %IR##r1 %IR##r0 %FR##f0                         \
+       check4(stxr##f##r0##f0, l, r2, r3, r4, r5)              \
+       checkf5(f, stxr##r0##f0, l, f1, f2, f3, f4, f5)
+#define          xstf(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)      \
+       fsti(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)        \
+       fstr(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)        \
+       fstxi(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+       fstxr(f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#define         xxstf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)         \
+         xstf(_f, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)     \
+         xstf(_d, l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#if __ia64__
+#  define ixstf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+         xxstf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)
+#else
+#  define fxstf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)       \
+         xxstf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)        \
+         xxstf(l, r0,r1,r2,r3,r4,r5, f1,f2,f3,f4,f5,f0)        \
+         xxstf(l, r0,r1,r2,r3,r4,r5, f2,f3,f4,f5,f0,f1)        \
+         xxstf(l, r0,r1,r2,r3,r4,r5, f3,f4,f5,f0,f1,f2)        \
+         xxstf(l, r0,r1,r2,r3,r4,r5, f4,f5,f0,f1,f2,f3)        \
+         xxstf(l, r0,r1,r2,r3,r4,r5, f5,f0,f1,f2,f3,f4)
+# define ixstf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)                \
+         fxstf(l, r0,r1,r2,r3,r4,r5, f0,f1,f2,f3,f4,f5)        \
+         fxstf(l, r1,r2,r3,r4,r5,r0, f0,f1,f2,f3,f4,f5)        \
+         fxstf(l, r2,r3,r4,r5,r0,r1, f0,f1,f2,f3,f4,f5)        \
+         fxstf(l, r3,r4,r5,r0,r1,r2, f0,f1,f2,f3,f4,f5)        \
+         fxstf(l, r4,r5,r0,r1,r2,r3, f0,f1,f2,f3,f4,f5)        \
+         fxstf(l, r5,r0,r1,r2,r3,r4, f0,f1,f2,f3,f4,f5)
+#endif
+#define   stf(l)                                               \
+       ixstf(l, 0,1,2,3,4,5, 0,1,2,3,4,5)
+
+/* Need a valid jump or simple optimization will remove it */
+#define bri(l, op, u, il, ir, r0, r1, r2, r3, r4, r5)          \
+       setup()                                                 \
+       movi %IR##r0 il                                         \
+       b##op##i##u i##l##op##r0 %IR##r0 ir                     \
+       calli @abort                                            \
+i##l##op##r0:                                                  \
+       check5(i, l, r1, r2, r3, r4, r5)
+#define brr(l, op, u, il, ir, r0, r1, r2, r3, r4, r5)          \
+       setup()                                                 \
+       movi %IR##r0 il                                         \
+       movi %IR##r1 ir                                         \
+       b##op##r##u r##l##op##r0 %IR##r0 %IR##r1                \
+       calli @abort                                            \
+r##l##op##r0:                                                  \
+       check4(r, l, r2, r3, r4, r5)
+#define  xjmpi(l, op, u, il, ir, r0, r1, r2, r3, r4, r5)       \
+          bri(l, op, u, il, ir, r0, r1, r2, r3, r4, r5)        \
+          brr(l, op, u, il, ir, r0, r1, r2, r3, r4, r5)
+#if __ia64__
+#  define jmpi(l, op, u, il, ir)                               \
+        xjmpi(l, op, u, il, ir, 0, 1, 2, 3, 4, 5)
+#else
+#  define jmpi(l, op, u, il, ir)                               \
+        xjmpi(l, op, u, il, ir, 0, 1, 2, 3, 4, 5)              \
+        xjmpi(l, op, u, il, ir, 1, 2, 3, 4, 5, 0)              \
+        xjmpi(l, op, u, il, ir, 2, 3, 4, 5, 0, 1)              \
+        xjmpi(l, op, u, il, ir, 3, 4, 5, 0, 1, 2)              \
+        xjmpi(l, op, u, il, ir, 4, 5, 0, 1, 2, 3)              \
+        xjmpi(l, op, u, il, ir, 5, 0, 1, 2, 3, 4)
+#endif
+
+#define bfi(f, l, op, il, ir, f0, f1, f2, f3, f4, f5)          \
+       setup##f()                                              \
+       movi##f %FR##f0 il                                      \
+       b##op##i##f i##l##op##f##f0 %FR##f0 ir                  \
+       calli @abort                                            \
+i##l##op##f##f0:                                               \
+       checkf5(f, i, l, f1, f2, f3, f4, f5)
+#define bff(f, l, op, il, ir, f0, f1, f2, f3, f4, f5)          \
+       setup##f()                                              \
+       movi##f %FR##f0 il                                      \
+       movi##f %FR##f1 ir                                      \
+       b##op##r##f r##l##op##f##f0 %FR##f0 %FR##f1             \
+       calli @abort                                            \
+r##l##op##f##f0:                                               \
+       checkf4(f, r, l, f2, f3, f4, f5)
+#define  xjmpf(f, l, op, il, ir, f0, f1, f2, f3, f4, f5)       \
+          bfi(f, l, op, il, ir, f0, f1, f2, f3, f4, f5)        \
+          bff(f, l, op, il, ir, f0, f1, f2, f3, f4, f5)
+#define xxjmpf(l, op, il, ir, f0, f1, f2, f3, f4, f5)          \
+        xjmpf(_f, l, op, il, ir, f0, f1, f2, f3, f4, f5)       \
+        xjmpf(_d, l, op, il, ir, f0, f1, f2, f3, f4, f5)
+#if __ia64__
+#  define jmpf(l, op, il, ir)                                  \
+       xxjmpf(l, op, il, ir, 0, 1, 2, 3, 4, 5)
+#else
+#  define jmpf(l, op, il, ir)                                  \
+       xxjmpf(l, op, il, ir, 0, 1, 2, 3, 4, 5)                 \
+       xxjmpf(l, op, il, ir, 1, 2, 3, 4, 5, 0)                 \
+       xxjmpf(l, op, il, ir, 2, 3, 4, 5, 0, 1)                 \
+       xxjmpf(l, op, il, ir, 3, 4, 5, 0, 1, 2)                 \
+       xxjmpf(l, op, il, ir, 4, 5, 0, 1, 2, 3)                 \
+       xxjmpf(l, op, il, ir, 5, 0, 1, 2, 3, 4)
+#endif
+
+.data  32
+buff:
+.size  16
+ok:
+.c     "ok\n"
+
+.code
+       prolog
+
+         alu(__LINE__, add)
+        alux(__LINE__, add)
+         fop(__LINE__, add)
+         alu(__LINE__, sub)
+        alux(__LINE__, sub)
+         fop(__LINE__, sub)
+         alu(__LINE__, mul)
+         fop(__LINE__, mul)
+         alu(__LINE__, div)
+       alu_u(__LINE__, div)
+         fop(__LINE__, div)
+         alu(__LINE__, rem)
+       alu_u(__LINE__, rem)
+         alu(__LINE__, and)
+         alu(__LINE__, or)
+         alu(__LINE__, xor)
+         alu(__LINE__, lsh)
+         alu(__LINE__, rsh)
+       alu_u(__LINE__, rsh)
+         uni(__LINE__, negr)
+         unf(__LINE__, negr)
+         uni(__LINE__, comr)
+         unf(__LINE__, absr)
+         unf(__LINE__, sqrtr)
+         alu(__LINE__, lt)
+       alu_u(__LINE__, lt)
+        fcmp(__LINE__, lt)
+         alu(__LINE__, le)
+       alu_u(__LINE__, le)
+        fcmp(__LINE__, le)
+         alu(__LINE__, eq)
+        fcmp(__LINE__, eq)
+         alu(__LINE__, ge)
+       alu_u(__LINE__, ge)
+        fcmp(__LINE__, ge)
+         alu(__LINE__, gt)
+       alu_u(__LINE__, gt)
+        fcmp(__LINE__, gt)
+         alu(__LINE__, ne)
+        fcmp(__LINE__, ne)
+        fcmp(__LINE__, unlt)
+        fcmp(__LINE__, unle)
+        fcmp(__LINE__, uneq)
+        fcmp(__LINE__, unge)
+        fcmp(__LINE__, ungt)
+        fcmp(__LINE__, ltgt)
+        fcmp(__LINE__, ord)
+        fcmp(__LINE__, unord)
+         mvi(__LINE__)
+         mvf(__LINE__)
+         uni(__LINE__, extr_c)
+         uni(__LINE__, extr_uc)
+         uni(__LINE__, extr_s)
+         uni(__LINE__, extr_us)
+#if __WORDSIZE == 64
+         uni(__LINE__, extr_ui)
+#endif
+         uni(__LINE__, htonr)
+         f2f(__LINE__, _f, extr_d_f)
+         f2f(__LINE__, _d, extr_f_d)
+         f2i(__LINE__, truncr)
+         i2f(__LINE__, extr)
+         ldi(__LINE__)
+         ldf(__LINE__)
+         sti(__LINE__)
+         stf(__LINE__)
+        jmpi(__LINE__, lt,   ,  0,  1)
+        jmpi(__LINE__, lt, _u,  0,  1)
+        jmpf(__LINE__, lt,      0,  1)
+        jmpi(__LINE__, le,   ,  1,  1)
+        jmpi(__LINE__, le, _u,  1,  1)
+        jmpf(__LINE__, le,      1,  1)
+        jmpi(__LINE__, eq,   , -1, -1)
+        jmpf(__LINE__, eq,     -1, -1)
+        jmpi(__LINE__, ge,   ,  2,  2)
+        jmpi(__LINE__, ge, _u,  2,  2)
+        jmpf(__LINE__, ge,      2,  2)
+        jmpi(__LINE__, gt,   ,  2,  1)
+        jmpi(__LINE__, gt, _u,  2,  1)
+        jmpf(__LINE__, gt,      2,  1)
+        jmpi(__LINE__, ne,   ,  3,  2)
+        jmpf(__LINE__, ne,      3,  2)
+        jmpi(__LINE__, ms, , 1, 1)
+        jmpi(__LINE__, mc, , 1, 2)
+#if __WORDSIZE == 32
+#  define ix7f         0x7fffffff
+#  define ix80         0x80000000
+#  define ixff         0xffffffff
+#else
+#  define ix7f         0x7fffffffffffffff
+#  define ix80         0x8000000000000000
+#  define ixff         0xffffffffffffffff
+#endif
+        jmpi(__LINE__, oadd,   , ix7f, 1)
+        jmpi(__LINE__, oadd, _u, ixff, 1)
+        jmpi(__LINE__, xadd,   , ix80, 1)
+        jmpi(__LINE__, xadd, _u, ix7f, 1)
+        jmpi(__LINE__, osub,   , ix80, 1)
+        jmpi(__LINE__, osub, _u,    0, 1)
+        jmpi(__LINE__, xsub,   , ix7f, 1)
+        jmpi(__LINE__, xsub, _u, ix80, 1)
+        jmpf(__LINE__, unlt,        0, 1)
+        jmpf(__LINE__, unle,        1, 1)
+        jmpf(__LINE__, uneq,        2, 2)
+        jmpf(__LINE__, unge,        3, 3)
+        jmpf(__LINE__, ungt,        4, 3)
+        jmpf(__LINE__, ltgt,        5, 4)
+        jmpf(__LINE__, ord,         0, 0)
+        jmpf(__LINE__, unord,       0, $(0.0 / 0.0))
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+
+       ret
+       epilog
diff --git a/deps/lightning/check/ctramp.c b/deps/lightning/check/ctramp.c
new file mode 100644 (file)
index 0000000..941c7c1
--- /dev/null
@@ -0,0 +1,123 @@
+#include <lightning.h>
+#include <stdio.h>
+
+jit_state_t            *_jit;
+long                    top;
+long                    stk[1024];
+
+int
+main(int argc, char *argv[])
+{
+    void                *address;
+    void               (*call)(void*);
+    jit_state_t                 *frame_jit, *tramp_jit;
+    jit_node_t          *arg, *done, *xfibs, *out, *ret1, *ret2;
+
+    init_jit(argv[0]);
+    _jit = frame_jit = jit_new_state();
+    jit_name("main");
+    jit_prolog();
+    jit_frame(64);
+
+    arg = jit_arg();
+    jit_getarg(JIT_R1, arg);
+
+    /* Initialize language stack */
+    jit_movi(JIT_R0, (jit_word_t)stk);
+    jit_sti(&top, JIT_R0);
+
+    /* return address */
+    done = jit_movi(JIT_R0, 0);
+    /* argument */
+    jit_movi(JIT_V0, 32);
+    /* jump to code */
+    jit_jmpr(JIT_R1);
+    jit_patch(done);
+
+    jit_prepare();
+    jit_pushargi((jit_word_t)"xfibs(%d) = %d\n");
+    jit_ellipsis();
+    jit_pushargi(32);
+    jit_pushargr(JIT_V0);
+    jit_finishi(printf);
+    jit_ret();
+    jit_epilog();
+    call = jit_emit();
+    jit_clear_state();
+
+#define SIZE                           sizeof(jit_word_t)
+    _jit = tramp_jit = jit_new_state();
+    jit_name("xfibs");
+    xfibs = jit_label();
+    jit_prolog();
+    jit_tramp(64);
+    out = jit_blti(JIT_V0, 2);
+    jit_subi(JIT_V1, JIT_V0, 1);       /* V1 = N-1 */
+    jit_subi(JIT_V2, JIT_V0, 2);       /* V1 = N-2 */
+
+    /* save return address */
+    jit_ldi(JIT_R1, &top);
+    jit_stxi(SIZE * 0, JIT_R1, JIT_R0);
+    /* save operands */
+    jit_stxi(SIZE * 1, JIT_R1, JIT_V0);
+    jit_stxi(SIZE * 2, JIT_R1, JIT_V1);
+    jit_stxi(SIZE * 3, JIT_R1, JIT_V2);
+    /* adjust "language" stack */
+    jit_addi(JIT_R1, JIT_R1, SIZE * 4);
+    jit_sti(&top, JIT_R1);
+
+    /* return address */
+    ret1 = jit_movi(JIT_R0, 0);
+    /* argument */
+    jit_movr(JIT_V0, JIT_V1);
+    /* indirect goto */
+    jit_patch_at(jit_jmpi(), xfibs);
+    jit_patch(ret1);
+    jit_movr(JIT_V1, JIT_V0);          /* V1 = rfibs(N-1) */
+    /* save V1 */
+    jit_ldi(JIT_R1, &top);
+    jit_stxi(-SIZE * 2, JIT_R1, JIT_V1);
+
+    /* reload V2 */
+    jit_ldxi(JIT_V2, JIT_R1, -SIZE * 1);
+
+    /* return address */
+    ret2 = jit_movi(JIT_R0, 0);
+    /* argument */
+    jit_movr(JIT_V0, JIT_V2);
+    /* indirect goto */
+    jit_patch_at(jit_jmpi(), xfibs);
+    jit_patch(ret2);
+    jit_movr(JIT_V2, JIT_V0);          /* V2 = rfibs(N-2) */
+
+    /* reload return address */
+    jit_ldi(JIT_R1, &top);
+    jit_subi(JIT_R1, JIT_R1, SIZE * 4);
+    jit_ldxi(JIT_R0, JIT_R1, SIZE * 0);
+    /* reload operands */
+    jit_ldxi(JIT_V0, JIT_R1, SIZE * 1);
+    jit_ldxi(JIT_V1, JIT_R1, SIZE * 2);
+    /* V2 already loaded */
+    /* update "language" stack */
+    jit_sti(&top, JIT_R1);
+
+    jit_addi(JIT_V1, JIT_V1, 1);
+    jit_addr(JIT_V0, JIT_V1, JIT_V2);
+    jit_jmpr(JIT_R0);
+
+    jit_patch(out);
+    jit_movi(JIT_V0, 1);
+    jit_jmpr(JIT_R0);
+    jit_epilog();
+
+    address = jit_emit();
+    jit_clear_state();
+
+    (*call)(address);
+
+    jit_destroy_state();
+
+    _jit = frame_jit;
+    jit_destroy_state();
+    return 0;
+}
diff --git a/deps/lightning/check/cva_list.c b/deps/lightning/check/cva_list.c
new file mode 100644 (file)
index 0000000..b0e668c
--- /dev/null
@@ -0,0 +1,1187 @@
+#include <lightning.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#define W              jit_word_t
+#define D              jit_float64_t
+#define VASTART(A)                                                     \
+    va_list            ap;                                             \
+    va_start(ap, A)
+#define VARG2()                a2 = va_arg(ap, jit_word_t);    VARG3()
+#define VARG3()                a3 = va_arg(ap, jit_word_t);    VARG4()
+#define VARG4()                a4 = va_arg(ap, jit_word_t);    VARG5()
+#define VARG5()                a5 = va_arg(ap, jit_word_t);    VARG6()
+#define VARG6()                a6 = va_arg(ap, jit_word_t);    VARG7()
+#define VARG7()                a7 = va_arg(ap, jit_word_t);    VARG8()
+#define VARG8()                a8 = va_arg(ap, jit_word_t);    VARG9()
+#define VARG9()                a9 = va_arg(ap, jit_word_t);    VARG10()
+#define VARG10()       a10 = va_arg(ap, jit_word_t);   va_end(ap)
+
+#define VARGD2()       a2 = va_arg(ap, jit_float64_t); VARGD3()
+#define VARGD3()       a3 = va_arg(ap, jit_float64_t); VARGD4()
+#define VARGD4()       a4 = va_arg(ap, jit_float64_t); VARGD5()
+#define VARGD5()       a5 = va_arg(ap, jit_float64_t); VARGD6()
+#define VARGD6()       a6 = va_arg(ap, jit_float64_t); VARGD7()
+#define VARGD7()       a7 = va_arg(ap, jit_float64_t); VARGD8()
+#define VARGD8()       a8 = va_arg(ap, jit_float64_t); VARGD9()
+#define VARGD9()       a9 = va_arg(ap, jit_float64_t); VARGD10()
+#define VARGD10()      a10 = va_arg(ap, jit_float64_t);va_end(ap)
+
+#define IDVARG2()      a2 = va_arg(ap, jit_float64_t); IDVARG3()
+#define IDVARG3()      a3 = va_arg(ap, jit_word_t);    IDVARG4()
+#define IDVARG4()      a4 = va_arg(ap, jit_float64_t); IDVARG5()
+#define IDVARG5()      a5 = va_arg(ap, jit_word_t);    IDVARG6()
+#define IDVARG6()      a6 = va_arg(ap, jit_float64_t); IDVARG7()
+#define IDVARG7()      a7 = va_arg(ap, jit_word_t);    IDVARG8()
+#define IDVARG8()      a8 = va_arg(ap, jit_float64_t); IDVARG9()
+#define IDVARG9()      a9 = va_arg(ap, jit_word_t);    IDVARG10()
+#define IDVARG10()     a10 = va_arg(ap, jit_float64_t);va_end(ap)
+
+#define DIVARG2()      a2 = va_arg(ap, jit_word_t);    DIVARG3()
+#define DIVARG3()      a3 = va_arg(ap, jit_float64_t); DIVARG4()
+#define DIVARG4()      a4 = va_arg(ap, jit_word_t);    DIVARG5()
+#define DIVARG5()      a5 = va_arg(ap, jit_float64_t); DIVARG6()
+#define DIVARG6()      a6 = va_arg(ap, jit_word_t);    DIVARG7()
+#define DIVARG7()      a7 = va_arg(ap, jit_float64_t); DIVARG8()
+#define DIVARG8()      a8 = va_arg(ap, jit_word_t);    DIVARG9()
+#define DIVARG9()      a9 = va_arg(ap, jit_float64_t); DIVARG10()
+#define DIVARG10()     a10 = va_arg(ap, jit_word_t);   va_end(ap)
+
+#define CHECK()                                                                \
+    do {                                                               \
+       if (a1 != 1 || a2 != 2 || a3 != 3 || a4 != 4 || a5 != 5 ||      \
+           a6 != 6 || a7 != 7 || a8 != 8 || a9 != 9 || a10 != 10)      \
+           abort();                                                    \
+    } while (0)
+
+
+void i_iiiiiiiii(W a1, ...)
+{
+    W          a2, a3, a4, a5, a6, a7, a8, a9, a10;
+    VASTART(a1);
+    VARG2();
+    CHECK();
+}
+
+void ii_iiiiiiii(W a1, W a2, ...)
+{
+    W          a3, a4, a5, a6, a7, a8, a9, a10;
+    VASTART(a2);
+    VARG3();
+    CHECK();
+}
+
+void iii_iiiiiii(W a1, W a2, W a3, ...)
+{
+    W          a4, a5, a6, a7, a8, a9, a10;
+    VASTART(a3);
+    VARG4();
+    CHECK();
+}
+
+void iiii_iiiiii(W a1, W a2, W a3, W a4, ...)
+{
+    W          a5, a6, a7, a8, a9, a10;
+    VASTART(a4);
+    VARG5();
+    CHECK();
+}
+
+void iiiii_iiiii(W a1, W a2, W a3, W a4, W a5, ...)
+{
+    W          a6, a7, a8, a9, a10;
+    VASTART(a5);
+    VARG6();
+    CHECK();
+}
+
+void iiiiii_iiii(W a1, W a2, W a3, W a4, W a5, W a6, ...)
+{
+    W          a7, a8, a9, a10;
+    VASTART(a6);
+    VARG7();
+    CHECK();
+}
+
+void iiiiiii_iii(W a1, W a2, W a3, W a4, W a5, W a6, W a7, ...)
+{
+    W          a8, a9, a10;
+    VASTART(a7);
+    VARG8();
+    CHECK();
+}
+
+void iiiiiiii_ii(W a1, W a2, W a3, W a4, W a5, W a6, W a7, W a8, ...)
+{
+    W          a9, a10;
+    VASTART(a8);
+    VARG9();
+    CHECK();
+}
+
+void iiiiiiiii_i(W a1, W a2, W a3, W a4, W a5, W a6, W a7, W a8, W a9, ...)
+{
+    W          a10;
+    VASTART(a9);
+    VARG10();
+    CHECK();
+}
+
+void d_ddddddddd(D a1, ...)
+{
+    D          a2, a3, a4, a5, a6, a7, a8, a9, a10;
+    VASTART(a1);
+    VARGD2();
+    CHECK();
+}
+
+void dd_dddddddd(D a1, D a2, ...)
+{
+    D          a3, a4, a5, a6, a7, a8, a9, a10;
+    VASTART(a2);
+    VARGD3();
+    CHECK();
+}
+
+void ddd_ddddddd(D a1, D a2, D a3, ...)
+{
+    D          a4, a5, a6, a7, a8, a9, a10;
+    VASTART(a3);
+    VARGD4();
+    CHECK();
+}
+
+void dddd_dddddd(D a1, D a2, D a3, D a4, ...)
+{
+    D          a5, a6, a7, a8, a9, a10;
+    VASTART(a4);
+    VARGD5();
+    CHECK();
+}
+
+void ddddd_ddddd(D a1, D a2, D a3, D a4, D a5, ...)
+{
+    D          a6, a7, a8, a9, a10;
+    VASTART(a5);
+    VARGD6();
+    CHECK();
+}
+
+void dddddd_dddd(D a1, D a2, D a3, D a4, D a5, D a6, ...)
+{
+    D          a7, a8, a9, a10;
+    VASTART(a6);
+    VARGD7();
+    CHECK();
+}
+
+void ddddddd_ddd(D a1, D a2, D a3, D a4, D a5, D a6, D a7, ...)
+{
+    D          a8, a9, a10;
+    VASTART(a7);
+    VARGD8();
+    CHECK();
+}
+
+void dddddddd_dd(D a1, D a2, D a3, D a4, D a5, D a6, D a7, D a8, ...)
+{
+    D          a9, a10;
+    VASTART(a8);
+    VARGD9();
+    CHECK();
+}
+
+void ddddddddd_d(D a1, D a2, D a3, D a4, D a5, D a6, D a7, D a8, D a9, ...)
+{
+    D          a10;
+    VASTART(a9);
+    VARGD10();
+    CHECK();
+}
+
+void i_didididid(W a1, ...)
+{
+    W          a3, a5, a7, a9;
+    D          a2, a4, a6, a8, a10;
+    VASTART(a1);
+    IDVARG2();
+    CHECK();
+}
+
+void id_idididid(W a1, D a2, ...)
+{
+    W          a3, a5, a7, a9;
+    D          a4, a6, a8, a10;
+    VASTART(a2);
+    IDVARG3();
+    CHECK();
+}
+
+void idi_dididid(W a1, D a2, W a3, ...)
+{
+    W          a5, a7, a9;
+    D          a4, a6, a8, a10;
+    VASTART(a3);
+    IDVARG4();
+    CHECK();
+}
+
+void idid_ididid(W a1, D a2, W a3, D a4, ...)
+{
+    W          a5, a7, a9;
+    D          a6, a8, a10;
+    VASTART(a4);
+    IDVARG5();
+    CHECK();
+}
+
+void ididi_didid(W a1, D a2, W a3, D a4, W a5, ...)
+{
+    W          a7, a9;
+    D          a6, a8, a10;
+    VASTART(a5);
+    IDVARG6();
+    CHECK();
+}
+
+void ididid_idid(W a1, D a2, W a3, D a4, W a5, D a6, ...)
+{
+    W          a7, a9;
+    D          a8, a10;
+    VASTART(a6);
+    IDVARG7();
+    CHECK();
+}
+
+void idididi_did(W a1, D a2, W a3, D a4, W a5, D a6, W a7, ...)
+{
+    W          a9;
+    D          a8, a10;
+    VASTART(a7);
+    IDVARG8();
+    CHECK();
+}
+
+void idididid_id(W a1, D a2, W a3, D a4, W a5, D a6, W a7, D a8, ...)
+{
+    W          a9;
+    D          a10;
+    VASTART(a8);
+    IDVARG9();
+    CHECK();
+}
+
+void ididididi_d(W a1, D a2, W a3, D a4, W a5, D a6, W a7, D a8, W a9, ...)
+{
+    D          a10;
+    VASTART(a9);
+    IDVARG10();
+    CHECK();
+}
+
+void d_ididididi(D a1, ...)
+{
+    W          a2, a4, a6, a8, a10;
+    D          a3, a5, a7, a9;
+    VASTART(a1);
+    DIVARG2();
+    CHECK();
+}
+
+void di_didididi(D a1, W a2, ...)
+{
+    W          a4, a6, a8, a10;
+    D          a3, a5, a7, a9;
+    VASTART(a2);
+    DIVARG3();
+    CHECK();
+}
+
+void did_idididi(D a1, W a2, D a3, ...)
+{
+    W          a4, a6, a8, a10;
+    D          a5, a7, a9;
+    VASTART(a3);
+    DIVARG4();
+    CHECK();
+}
+
+void didi_dididi(D a1, W a2, D a3, W a4, ...)
+{
+    W          a6, a8, a10;
+    D          a5, a7, a9;
+    VASTART(a4);
+    DIVARG5();
+    CHECK();
+}
+
+void didid_ididi(D a1, W a2, D a3, W a4, D a5, ...)
+{
+    W          a6, a8, a10;
+    D          a7, a9;
+    VASTART(a5);
+    DIVARG6();
+    CHECK();
+}
+
+void dididi_didi(D a1, W a2, D a3, W a4, D a5, W a6, ...)
+{
+    W          a8, a10;
+    D          a7, a9;
+    VASTART(a6);
+    DIVARG7();
+    CHECK();
+}
+
+void dididid_idi(D a1, W a2, D a3, W a4, D a5, W a6, D a7, ...)
+{
+    W          a8, a10;
+    D          a9;
+    VASTART(a7);
+    DIVARG8();
+    CHECK();
+}
+
+void didididi_di(D a1, W a2, D a3, W a4, D a5, W a6, D a7, W a8, ...)
+{
+    W          a10;
+    D          a9;
+    VASTART(a8);
+    DIVARG9();
+    CHECK();
+}
+
+void didididid_i(D a1, W a2, D a3, W a4, D a5, W a6, D a7, W a8, D a9, ...)
+{
+    W          a10;
+    VASTART(a9);
+    DIVARG10();
+    CHECK();
+}
+
+void va_i_iiiiiiiii(W a1, va_list ap)
+{
+    W          a2, a3, a4, a5, a6, a7, a8, a9, a10;
+    VARG2();
+    CHECK();
+}
+
+void va_ii_iiiiiiii(W a1, W a2, va_list ap)
+{
+    W          a3, a4, a5, a6, a7, a8, a9, a10;
+    VARG3();
+    CHECK();
+}
+
+void va_iii_iiiiiii(W a1, W a2, W a3, va_list ap)
+{
+    W          a4, a5, a6, a7, a8, a9, a10;
+    VARG4();
+    CHECK();
+}
+
+void va_iiii_iiiiii(W a1, W a2, W a3, W a4, va_list ap)
+{
+    W          a5, a6, a7, a8, a9, a10;
+    VARG5();
+    CHECK();
+}
+
+
+void va_d_ddddddddd(D a1, va_list ap)
+{
+    D          a2, a3, a4, a5, a6, a7, a8, a9, a10;
+    VARGD2();
+    CHECK();
+}
+
+void va_dd_dddddddd(D a1, D a2, va_list ap)
+{
+    D          a3, a4, a5, a6, a7, a8, a9, a10;
+    VARGD3();
+    CHECK();
+}
+
+void va_ddd_ddddddd(D a1, D a2, D a3, va_list ap)
+{
+    D          a4, a5, a6, a7, a8, a9, a10;
+    VARGD4();
+    CHECK();
+}
+
+void va_dddd_dddddd(D a1, D a2, D a3, D a4, va_list ap)
+{
+    D          a5, a6, a7, a8, a9, a10;
+    VARGD5();
+    CHECK();
+}
+
+void va_i_didididid(W a1, va_list ap)
+{
+    W          a3, a5, a7, a9;
+    D          a2, a4, a6, a8, a10;
+    IDVARG2();
+    CHECK();
+}
+
+void va_id_idididid(W a1, D a2, va_list ap)
+{
+    W          a3, a5, a7, a9;
+    D          a4, a6, a8, a10;
+    IDVARG3();
+    CHECK();
+}
+
+void va_idi_dididid(W a1, D a2, W a3, va_list ap)
+{
+    W          a5, a7, a9;
+    D          a4, a6, a8, a10;
+    IDVARG4();
+    CHECK();
+}
+
+void va_idid_ididid(W a1, D a2, W a3, D a4, va_list ap)
+{
+    W          a5, a7, a9;
+    D          a6, a8, a10;
+    IDVARG5();
+    CHECK();
+}
+
+void va_d_ididididi(D a1, va_list ap)
+{
+    W          a2, a4, a6, a8, a10;
+    D          a3, a5, a7, a9;
+    DIVARG2();
+    CHECK();
+}
+
+void va_di_didididi(D a1, W a2, va_list ap)
+{
+    W          a4, a6, a8, a10;
+    D          a3, a5, a7, a9;
+    DIVARG3();
+    CHECK();
+}
+
+void va_did_idididi(D a1, W a2, D a3, va_list ap)
+{
+    W          a4, a6, a8, a10;
+    D          a5, a7, a9;
+    DIVARG4();
+    CHECK();
+}
+
+void va_didi_dididi(D a1, W a2, D a3, W a4, va_list ap)
+{
+    W          a6, a8, a10;
+    D          a5, a7, a9;
+    DIVARG5();
+    CHECK();
+}
+
+#define PUSH1()                                        jit_pushargi(1)
+#define PUSH2()                PUSH1();                jit_pushargi(2)
+#define PUSH3()                PUSH2();                jit_pushargi(3)
+#define PUSH4()                PUSH3();                jit_pushargi(4)
+#define PUSH5()                PUSH4();                jit_pushargi(5)
+#define PUSH6()                PUSH5();                jit_pushargi(6)
+#define PUSH7()                PUSH6();                jit_pushargi(7)
+#define PUSH8()                PUSH7();                jit_pushargi(8)
+#define PUSH9()                PUSH8();                jit_pushargi(9)
+#define VPUSH2()       jit_pushargi(2);        VPUSH3()
+#define VPUSH3()       jit_pushargi(3);        VPUSH4()
+#define VPUSH4()       jit_pushargi(4);        VPUSH5()
+#define VPUSH5()       jit_pushargi(5);        VPUSH6()
+#define VPUSH6()       jit_pushargi(6);        VPUSH7()
+#define VPUSH7()       jit_pushargi(7);        VPUSH8()
+#define VPUSH8()       jit_pushargi(8);        VPUSH9()
+#define VPUSH9()       jit_pushargi(9);        VPUSH10()
+#define VPUSH10()      jit_pushargi(10);
+#define PUSHD1()                               jit_pushargi_d(1)
+#define PUSHD2()       PUSHD1();               jit_pushargi_d(2)
+#define PUSHD3()       PUSHD2();               jit_pushargi_d(3)
+#define PUSHD4()       PUSHD3();               jit_pushargi_d(4)
+#define PUSHD5()       PUSHD4();               jit_pushargi_d(5)
+#define PUSHD6()       PUSHD5();               jit_pushargi_d(6)
+#define PUSHD7()       PUSHD6();               jit_pushargi_d(7)
+#define PUSHD8()       PUSHD7();               jit_pushargi_d(8)
+#define PUSHD9()       PUSHD8();               jit_pushargi_d(9)
+#define VPUSHD2()      jit_pushargi_d(2);      VPUSHD3()
+#define VPUSHD3()      jit_pushargi_d(3);      VPUSHD4()
+#define VPUSHD4()      jit_pushargi_d(4);      VPUSHD5()
+#define VPUSHD5()      jit_pushargi_d(5);      VPUSHD6()
+#define VPUSHD6()      jit_pushargi_d(6);      VPUSHD7()
+#define VPUSHD7()      jit_pushargi_d(7);      VPUSHD8()
+#define VPUSHD8()      jit_pushargi_d(8);      VPUSHD9()
+#define VPUSHD9()      jit_pushargi_d(9);      VPUSHD10()
+#define VPUSHD10()     jit_pushargi_d(10);
+#define IDPUSH1()                              jit_pushargi(1)
+#define IDPUSH2()      IDPUSH1();              jit_pushargi_d(2)
+#define IDPUSH3()      IDPUSH2();              jit_pushargi(3)
+#define IDPUSH4()      IDPUSH3();              jit_pushargi_d(4)
+#define IDPUSH5()      IDPUSH4();              jit_pushargi(5)
+#define IDPUSH6()      IDPUSH5();              jit_pushargi_d(6)
+#define IDPUSH7()      IDPUSH6();              jit_pushargi(7)
+#define IDPUSH8()      IDPUSH7();              jit_pushargi_d(8)
+#define IDPUSH9()      IDPUSH8();              jit_pushargi(9)
+#define IDVPUSH2()     jit_pushargi_d(2);      IDVPUSH3()
+#define IDVPUSH3()     jit_pushargi(3);        IDVPUSH4()
+#define IDVPUSH4()     jit_pushargi_d(4);      IDVPUSH5()
+#define IDVPUSH5()     jit_pushargi(5);        IDVPUSH6()
+#define IDVPUSH6()     jit_pushargi_d(6);      IDVPUSH7()
+#define IDVPUSH7()     jit_pushargi(7);        IDVPUSH8()
+#define IDVPUSH8()     jit_pushargi_d(8);      IDVPUSH9()
+#define IDVPUSH9()     jit_pushargi(9);        IDVPUSH10()
+#define IDVPUSH10()    jit_pushargi_d(10);
+#define DIPUSH1()                              jit_pushargi_d(1)
+#define DIPUSH2()      DIPUSH1();              jit_pushargi(2)
+#define DIPUSH3()      DIPUSH2();              jit_pushargi_d(3)
+#define DIPUSH4()      DIPUSH3();              jit_pushargi(4)
+#define DIPUSH5()      DIPUSH4();              jit_pushargi_d(5)
+#define DIPUSH6()      DIPUSH5();              jit_pushargi(6)
+#define DIPUSH7()      DIPUSH6();              jit_pushargi_d(7)
+#define DIPUSH8()      DIPUSH7();              jit_pushargi(8)
+#define DIPUSH9()      DIPUSH8();              jit_pushargi_d(9)
+#define DIVPUSH2()     jit_pushargi(2);        DIVPUSH3()
+#define DIVPUSH3()     jit_pushargi_d(3);      DIVPUSH4()
+#define DIVPUSH4()     jit_pushargi(4);        DIVPUSH5()
+#define DIVPUSH5()     jit_pushargi_d(5);      DIVPUSH6()
+#define DIVPUSH6()     jit_pushargi(6);        DIVPUSH7()
+#define DIVPUSH7()     jit_pushargi_d(7);      DIVPUSH8()
+#define DIVPUSH8()     jit_pushargi(8);        DIVPUSH9()
+#define DIVPUSH9()     jit_pushargi_d(9);      DIVPUSH10()
+#define DIVPUSH10()    jit_pushargi(10);
+
+jit_state_t     *_jit;
+
+int main(int argc, char *argv[])
+{
+    void               (*function)(void);
+    jit_node_t         *jmpi_main;
+    jit_node_t         *a1, *a2, *node;
+    jit_node_t         *jva_i_iiiiiiiii, *jva_ii_iiiiiiii;
+    jit_node_t         *jva_d_ddddddddd, *jva_dd_dddddddd;
+    jit_node_t         *jva_i_didididid, *jva_id_idididid;
+    jit_node_t         *jva_d_ididididi, *jva_di_didididi;
+    jit_node_t         *jva_iii_iiiiiii, *jva_iiii_iiiiii;
+    jit_node_t         *jva_ddd_ddddddd, *jva_dddd_dddddd;
+    jit_node_t         *jva_idi_dididid, *jva_idid_ididid;
+    jit_node_t         *jva_did_idididi, *jva_didi_dididi;
+
+    init_jit(argv[0]);
+    _jit = jit_new_state();
+
+    jmpi_main = jit_jmpi();
+
+    /* Define simple functions to validate a jit_va_list_t
+     * is a valid va_list; these do not fetch arguments from
+     * the va_list. */
+    jva_i_iiiiiiiii = jit_label();
+    jit_name("va_i_iiiiiiiii");
+    jit_prolog();
+    a1 = jit_arg();
+    jit_getarg(JIT_V1, a1);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_prepare();
+    jit_pushargr(JIT_V1);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_i_iiiiiiiii);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_ii_iiiiiiii = jit_label();
+    jit_name("va_ii_iiiiiiii");
+    jit_prolog();
+    a1 = jit_arg();
+    a2 = jit_arg();
+    jit_getarg(JIT_V1, a1);
+    jit_getarg(JIT_V2, a2);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_prepare();
+    jit_pushargr(JIT_V1);
+    jit_pushargr(JIT_V2);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_ii_iiiiiiii);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_d_ddddddddd = jit_label();
+    jit_name("va_d_ddddddddd");
+    jit_prolog();
+    a1 = jit_arg_d();
+    jit_getarg_d(JIT_F3, a1);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_prepare();
+    jit_pushargr_d(JIT_F3);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_d_ddddddddd);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_dd_dddddddd = jit_label();
+    jit_name("va_dd_dddddddd");
+    jit_prolog();
+    a1 = jit_arg_d();
+    a2 = jit_arg_d();
+    jit_getarg_d(JIT_F3, a1);
+    jit_getarg_d(JIT_F4, a2);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_prepare();
+    jit_pushargr_d(JIT_F3);
+    jit_pushargr_d(JIT_F4);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_dd_dddddddd);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_i_didididid = jit_label();
+    jit_name("va_i_didididid");
+    jit_prolog();
+    a1 = jit_arg();
+    jit_getarg(JIT_V1, a1);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_prepare();
+    jit_pushargr(JIT_V1);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_i_didididid);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_id_idididid = jit_label();
+    jit_name("va_id_idididid");
+    jit_prolog();
+    a1 = jit_arg();
+    a2 = jit_arg_d();
+    jit_getarg(JIT_V1, a1);
+    jit_getarg_d(JIT_F3, a2);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_prepare();
+    jit_pushargr(JIT_V1);
+    jit_pushargr_d(JIT_F3);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_id_idididid);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_d_ididididi = jit_label();
+    jit_name("va_d_ididididi");
+    jit_prolog();
+    a1 = jit_arg_d();
+    jit_getarg_d(JIT_F3, a1);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_prepare();
+    jit_pushargr_d(JIT_F3);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_d_ididididi);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_di_didididi = jit_label();
+    jit_name("va_di_didididi");
+    jit_prolog();
+    a1 = jit_arg_d();
+    a2 = jit_arg();
+    jit_getarg_d(JIT_F3, a1);
+    jit_getarg(JIT_V1, a2);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_prepare();
+    jit_pushargr_d(JIT_F3);
+    jit_pushargr(JIT_V1);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_di_didididi);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+
+    /* Define complex functions to validate a jit_va_list_t
+     * is a valid va_list; these do fetch arguments from
+     * the va_list, to ensure it does the correct operations
+     * fetching arguments, and pass a valid va_list to the
+     * C function. */
+    jva_iii_iiiiiii = jit_label();
+    jit_name("va_iii_iiiiiii");
+    jit_prolog();
+    a1 = jit_arg();
+    jit_getarg(JIT_V1, a1);
+    node = jit_beqi(JIT_V1, 1);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_va_arg(JIT_V1, JIT_V0);
+    jit_va_arg(JIT_V2, JIT_V0);
+    jit_prepare();
+    jit_pushargi(1);
+    jit_pushargr(JIT_V1);
+    jit_pushargr(JIT_V2);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_iii_iiiiiii);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_iiii_iiiiii = jit_label();
+    jit_name("va_iiii_iiiiii");
+    jit_prolog();
+    a1 = jit_arg();
+    a2 = jit_arg();
+    jit_getarg(JIT_V1, a1);
+    node = jit_beqi(JIT_V1, 1);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_getarg(JIT_V1, a2);
+    node = jit_beqi(JIT_V1, 2);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_va_arg(JIT_V1, JIT_V0);
+    jit_va_arg(JIT_V2, JIT_V0);
+    jit_prepare();
+    jit_pushargi(1);
+    jit_pushargi(2);
+    jit_pushargr(JIT_V1);
+    jit_pushargr(JIT_V2);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_iiii_iiiiii);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_ddd_ddddddd = jit_label();
+    jit_name("va_ddd_ddddddd");
+    jit_prolog();
+    a1 = jit_arg_d();
+    jit_getarg_d(JIT_F3, a1);
+    node = jit_beqi_d(JIT_F3, 1);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_va_arg_d(JIT_F3, JIT_V0);
+    jit_va_arg_d(JIT_F4, JIT_V0);
+    jit_prepare();
+    jit_pushargi_d(1);
+    jit_pushargr_d(JIT_F3);
+    jit_pushargr_d(JIT_F4);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_ddd_ddddddd);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_dddd_dddddd = jit_label();
+    jit_name("va_dddd_dddddd");
+    jit_prolog();
+    a1 = jit_arg_d();
+    a2 = jit_arg_d();
+    jit_getarg_d(JIT_F3, a1);
+    node = jit_beqi_d(JIT_F3, 1);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_getarg_d(JIT_F3, a2);
+    node = jit_beqi_d(JIT_F3, 2);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_va_arg_d(JIT_F3, JIT_V0);
+    jit_va_arg_d(JIT_F4, JIT_V0);
+    jit_prepare();
+    jit_pushargi_d(1);
+    jit_pushargi_d(2);
+    jit_pushargr_d(JIT_F3);
+    jit_pushargr_d(JIT_F4);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_dddd_dddddd);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_idi_dididid = jit_label();
+    jit_name("va_idi_dididid");
+    jit_prolog();
+    a1 = jit_arg();
+    jit_getarg(JIT_V1, a1);
+    node = jit_beqi(JIT_V1, 1);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_va_arg_d(JIT_F3, JIT_V0);
+    jit_va_arg(JIT_V1, JIT_V0);
+    jit_prepare();
+    jit_pushargi(1);
+    jit_pushargr_d(JIT_F3);
+    jit_pushargr(JIT_V1);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_idi_dididid);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_idid_ididid = jit_label();
+    jit_name("va_idid_ididid");
+    jit_prolog();
+    a1 = jit_arg();
+    a2 = jit_arg_d();
+    jit_getarg(JIT_V1, a1);
+    node = jit_beqi(JIT_V1, 1);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_getarg_d(JIT_F3, a2);
+    node = jit_beqi_d(JIT_F3, 2);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_va_arg(JIT_V1, JIT_V0);
+    jit_va_arg_d(JIT_F3, JIT_V0);
+    jit_prepare();
+    jit_pushargi(1);
+    jit_pushargi_d(2);
+    jit_pushargr(JIT_V1);
+    jit_pushargr_d(JIT_F3);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_idid_ididid);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_did_idididi = jit_label();
+    jit_name("va_did_idididi");
+    jit_prolog();
+    a1 = jit_arg_d();
+    jit_getarg_d(JIT_F3, a1);
+    node = jit_beqi_d(JIT_F3, 1);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_va_arg(JIT_V1, JIT_V0);
+    jit_va_arg_d(JIT_F3, JIT_V0);
+    jit_prepare();
+    jit_pushargi_d(1);
+    jit_pushargr(JIT_V1);
+    jit_pushargr_d(JIT_F3);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_did_idididi);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+    jva_didi_dididi = jit_label();
+    jit_name("va_didi_dididi");
+    jit_prolog();
+    a1 = jit_arg_d();
+    a2 = jit_arg();
+    jit_getarg_d(JIT_F3, a1);
+    node = jit_beqi_d(JIT_F3, 1);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_getarg(JIT_V1, a2);
+    node = jit_beqi(JIT_V1, 2);
+    jit_calli(abort);
+    jit_patch(node);
+    jit_ellipsis();
+    jit_va_start(JIT_V0);
+    jit_va_arg_d(JIT_F3, JIT_V0);
+    jit_va_arg(JIT_V1, JIT_V0);
+    jit_prepare();
+    jit_pushargi_d(1);
+    jit_pushargi(2);
+    jit_pushargr_d(JIT_F3);
+    jit_pushargr(JIT_V1);
+    jit_va_push(JIT_V0);
+    jit_finishi(va_didi_dididi);
+    jit_va_end(JIT_V0);
+    jit_ret();
+    jit_epilog();
+
+    jit_patch(jmpi_main);
+    jit_name("main");
+    jit_prolog();
+
+    /* Check that lightning properly calls vararg functions */
+    jit_prepare();
+    PUSH1();
+    jit_ellipsis();
+    VPUSH2();
+    jit_finishi(i_iiiiiiiii);
+    jit_prepare();
+    PUSH2();
+    jit_ellipsis();
+    VPUSH3();
+    jit_finishi(ii_iiiiiiii);
+    jit_prepare();
+    PUSH3();
+    jit_ellipsis();
+    VPUSH4();
+    jit_finishi(iii_iiiiiii);
+    jit_prepare();
+    PUSH4();
+    jit_ellipsis();
+    VPUSH5();
+    jit_finishi(iiii_iiiiii);
+    jit_prepare();
+    PUSH5();
+    jit_ellipsis();
+    VPUSH6();
+    jit_finishi(iiiii_iiiii);
+    jit_prepare();
+    PUSH6();
+    jit_ellipsis();
+    VPUSH7();
+    jit_finishi(iiiiii_iiii);
+    jit_prepare();
+    PUSH7();
+    jit_ellipsis();
+    VPUSH8();
+    jit_finishi(iiiiiii_iii);
+    jit_prepare();
+    PUSH8();
+    jit_ellipsis();
+    VPUSH9();
+    jit_finishi(iiiiiiii_ii);
+    jit_prepare();
+    PUSH9();
+    jit_ellipsis();
+    VPUSH10();
+    jit_finishi(iiiiiiiii_i);
+    jit_prepare();
+    PUSHD1();
+    jit_ellipsis();
+    VPUSHD2();
+    jit_finishi(d_ddddddddd);
+    jit_prepare();
+    PUSHD2();
+    jit_ellipsis();
+    VPUSHD3();
+    jit_finishi(dd_dddddddd);
+    jit_prepare();
+    PUSHD3();
+    jit_ellipsis();
+    VPUSHD4();
+    jit_finishi(ddd_ddddddd);
+    jit_prepare();
+    PUSHD4();
+    jit_ellipsis();
+    VPUSHD5();
+    jit_finishi(dddd_dddddd);
+    jit_prepare();
+    PUSHD5();
+    jit_ellipsis();
+    VPUSHD6();
+    jit_finishi(ddddd_ddddd);
+    jit_prepare();
+    PUSHD6();
+    jit_ellipsis();
+    VPUSHD7();
+    jit_finishi(dddddd_dddd);
+    jit_prepare();
+    PUSHD7();
+    jit_ellipsis();
+    VPUSHD8();
+    jit_finishi(ddddddd_ddd);
+    jit_prepare();
+    PUSHD8();
+    jit_ellipsis();
+    VPUSHD9();
+    jit_finishi(dddddddd_dd);
+    jit_prepare();
+    PUSHD9();
+    jit_ellipsis();
+    VPUSHD10();
+    jit_finishi(ddddddddd_d);
+    jit_prepare();
+    IDPUSH1();
+    jit_ellipsis();
+    IDVPUSH2();
+    jit_finishi(i_didididid);
+    jit_prepare();
+    IDPUSH2();
+    jit_ellipsis();
+    IDVPUSH3();
+    jit_finishi(id_idididid);
+    jit_prepare();
+    IDPUSH3();
+    jit_ellipsis();
+    IDVPUSH4();
+    jit_finishi(idi_dididid);
+    jit_prepare();
+    IDPUSH4();
+    jit_ellipsis();
+    IDVPUSH5();
+    jit_finishi(idid_ididid);
+    jit_prepare();
+    IDPUSH5();
+    jit_ellipsis();
+    IDVPUSH6();
+    jit_finishi(ididi_didid);
+    jit_prepare();
+    IDPUSH6();
+    jit_ellipsis();
+    IDVPUSH7();
+    jit_finishi(ididid_idid);
+    jit_prepare();
+    IDPUSH7();
+    jit_ellipsis();
+    IDVPUSH8();
+    jit_finishi(idididi_did);
+    jit_prepare();
+    IDPUSH8();
+    jit_ellipsis();
+    IDVPUSH9();
+    jit_finishi(idididid_id);
+    jit_prepare();
+    IDPUSH9();
+    jit_ellipsis();
+    IDVPUSH10();
+    jit_finishi(ididididi_d);
+    jit_prepare();
+    DIPUSH1();
+    jit_ellipsis();
+    DIVPUSH2();
+    jit_finishi(d_ididididi);
+    jit_prepare();
+    DIPUSH2();
+    jit_ellipsis();
+    DIVPUSH3();
+    jit_finishi(di_didididi);
+    jit_prepare();
+    DIPUSH3();
+    jit_ellipsis();
+    DIVPUSH4();
+    jit_finishi(did_idididi);
+    jit_prepare();
+    DIPUSH4();
+    jit_ellipsis();
+    DIVPUSH5();
+    jit_finishi(didi_dididi);
+    jit_prepare();
+    DIPUSH5();
+    jit_ellipsis();
+    DIVPUSH6();
+    jit_finishi(didid_ididi);
+    jit_prepare();
+    DIPUSH6();
+    jit_ellipsis();
+    DIVPUSH7();
+    jit_finishi(dididi_didi);
+    jit_prepare();
+    DIPUSH7();
+    jit_ellipsis();
+    DIVPUSH8();
+    jit_finishi(dididid_idi);
+    jit_prepare();
+    DIPUSH8();
+    jit_ellipsis();
+    DIVPUSH9();
+    jit_finishi(didididi_di);
+    jit_prepare();
+    DIPUSH9();
+    jit_ellipsis();
+    DIVPUSH10();
+    jit_finishi(didididid_i);
+
+    /* Check that unmodified jit_va_list_t is a valid va_list */
+    jit_prepare();
+    PUSH1();
+    jit_ellipsis();
+    VPUSH2();
+    jit_patch_at(jit_finishi(NULL), jva_i_iiiiiiiii);
+    jit_prepare();
+    PUSH2();
+    jit_ellipsis();
+    VPUSH3();
+    jit_patch_at(jit_finishi(NULL), jva_ii_iiiiiiii);
+    jit_prepare();
+    PUSHD1();
+    jit_ellipsis();
+    VPUSHD2();
+    jit_patch_at(jit_finishi(NULL), jva_d_ddddddddd);
+    jit_prepare();
+    PUSHD2();
+    jit_ellipsis();
+    VPUSHD3();
+    jit_patch_at(jit_finishi(NULL), jva_dd_dddddddd);
+    jit_prepare();
+    IDPUSH1();
+    jit_ellipsis();
+    IDVPUSH2();
+    jit_patch_at(jit_finishi(NULL), jva_i_didididid);
+    jit_prepare();
+    IDPUSH2();
+    jit_ellipsis();
+    IDVPUSH3();
+    jit_patch_at(jit_finishi(NULL), jva_id_idididid);
+    jit_prepare();
+    DIPUSH1();
+    jit_ellipsis();
+    DIVPUSH2();
+    jit_patch_at(jit_finishi(NULL), jva_d_ididididi);
+    jit_prepare();
+    DIPUSH2();
+    jit_ellipsis();
+    DIVPUSH3();
+    jit_patch_at(jit_finishi(NULL), jva_di_didididi);
+
+    /* Check that modified jit_va_list_t is a valid va_list */
+    jit_prepare();
+    PUSH1();
+    jit_ellipsis();
+    VPUSH2();
+    jit_patch_at(jit_finishi(NULL), jva_iii_iiiiiii);
+    jit_prepare();
+    PUSH2();
+    jit_ellipsis();
+    VPUSH3();
+    jit_patch_at(jit_finishi(NULL), jva_iiii_iiiiii);
+    jit_prepare();
+    PUSHD1();
+    jit_ellipsis();
+    VPUSHD2();
+    jit_patch_at(jit_finishi(NULL), jva_ddd_ddddddd);
+    jit_prepare();
+    PUSHD2();
+    jit_ellipsis();
+    VPUSHD3();
+    jit_patch_at(jit_finishi(NULL), jva_dddd_dddddd);
+    jit_prepare();
+    IDPUSH1();
+    jit_ellipsis();
+    IDVPUSH2();
+    jit_patch_at(jit_finishi(NULL), jva_idi_dididid);
+    jit_prepare();
+    IDPUSH2();
+    jit_ellipsis();
+    IDVPUSH3();
+    jit_patch_at(jit_finishi(NULL), jva_idid_ididid);
+    jit_prepare();
+    DIPUSH1();
+    jit_ellipsis();
+    DIVPUSH2();
+    jit_patch_at(jit_finishi(NULL), jva_did_idididi);
+    jit_prepare();
+    DIPUSH2();
+    jit_ellipsis();
+    DIVPUSH3();
+    jit_patch_at(jit_finishi(NULL), jva_didi_dididi);
+
+    jit_ret();
+    jit_epilog();
+
+
+    function = jit_emit();
+    jit_clear_state();
+    //jit_disassemble();
+    (*function)();
+    jit_destroy_state();
+
+    finish_jit();
+
+    printf("ok\n");
+    return 0;
+}
diff --git a/deps/lightning/check/cvt.ok b/deps/lightning/check/cvt.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/cvt.tst b/deps/lightning/check/cvt.tst
new file mode 100644 (file)
index 0000000..1828259
--- /dev/null
@@ -0,0 +1,380 @@
+.data  12
+ok:
+.c     "ok\n"
+
+#if __WORDSIZE == 32
+#  define w7f          0x7fffffff
+#  define w80          0x80000000
+#  define w81          0x80000001
+#  define wff          0xffffffff
+#  define LEXTII2(N, R0, R1)
+#  define LEXTIC2(N, R0)
+#else
+#  define w7f          0x7fffffffffffffff
+#  define w80          0x8000000000000000
+#  define w81          0x8000000000000001
+#  define wff          0xffffffffffffffff
+#  define i7f          wff
+#  define ui7f         0xffffffff
+#  define i80          0
+#  define ui80         0
+#  define i81          1
+#  define ui81         1
+#  define iff          wff
+#  define uiff         0xffffffff
+#  define LEXTII2(N, R0, R1)                                   \
+       EXTII2(N, i, R0, R1)                                    \
+       EXTII2(N, ui, R0, R1)
+#  define LEXTIC2(N, R0)                                       \
+       EXTIC2(N, i, R0)                                        \
+       EXTIC2(N, ui, R0)
+#endif
+#define c7f            wff
+#define uc7f           0xff
+#define s7f            wff
+#define us7f           0xffff
+#define c80            0
+#define uc80           0
+#define s80            0
+#define us80           0
+#define c81            1
+#define uc81           1
+#define s81            1
+#define us81           1
+#define cff            wff
+#define ucff           0xff
+#define sff            wff
+#define usff           0xffff
+
+#define EXTII2(N, T, R0, R1)                                   \
+       movi %R0 w##N                                           \
+       extr_##T %R1 %R0                                        \
+       beqi T##_##R0##_##R1##_##N %R1 T##N                     \
+       calli @abort                                            \
+T##_##R0##_##R1##_##N:
+#define EXTII1(N, R0, R1)                                      \
+       EXTII2(N, c, R0, R1)                                    \
+       EXTII2(N, uc, R0, R1)                                   \
+       EXTII2(N, s, R0, R1)                                    \
+       EXTII2(N, us, R0, R1)                                   \
+       LEXTII2(N, R0, R1)
+#define EXTII0(R0, R1)                                         \
+       EXTII1(7f, R0, R1)                                      \
+       EXTII1(80, R0, R1)                                      \
+       EXTII1(81, R0, R1)                                      \
+       EXTII1(ff, R0, R1)
+
+#define EXTIC2(N, T, R0)                                       \
+       movi %R0 w##N                                           \
+       extr_##T %R0 %R0                                        \
+       beqi T##_##R0##_##N %R0 T##N                            \
+       calli @abort                                            \
+T##_##R0##_##N:
+#define EXTIC1(N, R0)                                          \
+       EXTIC2(N, c, R0)                                        \
+       EXTIC2(N, uc, R0)                                       \
+       EXTIC2(N, s, R0)                                        \
+       EXTIC2(N, us, R0)                                       \
+       LEXTIC2(N, R0)
+#define EXTIC0(R0)                                             \
+       EXTIC1(7f, R0)                                          \
+       EXTIC1(80, R0)                                          \
+       EXTIC1(81, R0)                                          \
+       EXTIC1(ff, R0)
+
+#define EXTII(V0, V1, V2, R0, R1, R2)                          \
+       EXTII0(V0, V1)                                          \
+       EXTII0(V0, V2)                                          \
+       EXTII0(V0, R0)                                          \
+       EXTII0(V0, R1)                                          \
+       EXTII0(V0, R2)                                          \
+       EXTII0(V1, V0)                                          \
+       EXTII0(V1, V2)                                          \
+       EXTII0(V1, R0)                                          \
+       EXTII0(V1, R1)                                          \
+       EXTII0(V1, R2)                                          \
+       EXTII0(V2, V0)                                          \
+       EXTII0(V2, V1)                                          \
+       EXTII0(V2, R0)                                          \
+       EXTII0(V2, R1)                                          \
+       EXTII0(V2, R2)                                          \
+       EXTII0(R0, V0)                                          \
+       EXTII0(R0, V1)                                          \
+       EXTII0(R0, V2)                                          \
+       EXTII0(R0, R1)                                          \
+       EXTII0(R0, R2)                                          \
+       EXTII0(R1, V0)                                          \
+       EXTII0(R1, V1)                                          \
+       EXTII0(R1, V2)                                          \
+       EXTII0(R1, R0)                                          \
+       EXTII0(R1, R2)                                          \
+       EXTII0(R2, V0)                                          \
+       EXTII0(R2, V1)                                          \
+       EXTII0(R2, V2)                                          \
+       EXTII0(R2, R0)                                          \
+       EXTII0(R2, R1)                                          \
+       EXTIC0(V0)                                              \
+       EXTIC0(V1)                                              \
+       EXTIC0(V2)                                              \
+       EXTIC0(R0)                                              \
+       EXTIC0(R1)                                              \
+       EXTIC0(R2)
+
+#define EXIF1(N, V, R0, R1)                                    \
+       movi %R0 V                                              \
+       extr_f %R1 %R0                                          \
+       beqi_f wf##_##R0##_##R1##_##N %R1 V                     \
+wf##_##R0##_##R1##_##N:
+#define EXIF0(R0, R1)                                          \
+       EXIF1(0, -1, R0, R1)                                    \
+       EXIF1(1, 64, R0, R1)
+#define EXIF(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)   \
+       EXIF0(V0, F0)                                           \
+       EXIF0(V1, F1)                                           \
+       EXIF0(V2, F2)                                           \
+       EXIF0(R0, F3)                                           \
+       EXIF0(R1, F4)                                           \
+       EXIF0(R2, F5)
+#define EXID1(N, V, R0, R1)                                    \
+       movi %R0 V                                              \
+       extr_d %R1 %R0                                          \
+       beqi_d wd##_##R0##_##R1##_##N %R1 V                     \
+wd##_##R0##_##R1##_##N:
+#define EXID0(R0, R1)                                          \
+       EXID1(0, -1, R0, R1)                                    \
+       EXID1(1, 64, R0, R1)
+#define EXID(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)   \
+       EXID0(V0, F0)                                           \
+       EXID0(V1, F1)                                           \
+       EXID0(V2, F2)                                           \
+       EXID0(R0, F3)                                           \
+       EXID0(R1, F4)                                           \
+       EXID0(R2, F5)
+
+#define EXFI1(N, V, R0, R1)                                    \
+       movi_f %R1 V                                            \
+       truncr_f %R0 %R1                                        \
+       beqi fi##_##R0##_##R1##_##N %R0 V                       \
+       calli @abort                                            \
+fi##_##R0##_##R1##_##N:
+#define EXFI0(R0, R1)                                          \
+       EXFI1(0,   42, R0, R1)                                  \
+       EXFI1(1, -128, R0, R1)
+#define EXFI(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)   \
+       EXFI0(V0, F5)                                           \
+       EXFI0(V1, F4)                                           \
+       EXFI0(V2, F3)                                           \
+       EXFI0(R0, F2)                                           \
+       EXFI0(R1, F1)                                           \
+       EXFI0(R2, F0)
+#define EXDI1(N, V, R0, R1)                                    \
+       movi_d %R1 V                                            \
+       truncr_d %R0 %R1                                        \
+       beqi di##_##R0##_##R1##_##N %R0 V                       \
+       calli @abort                                            \
+di##_##R0##_##R1##_##N:
+#define EXDI0(R0, R1)                                          \
+       EXDI1(0,   42, R0, R1)                                  \
+       EXDI1(1, -128, R0, R1)
+#define EXDI(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)   \
+       EXDI0(V0, F5)                                           \
+       EXDI0(V1, F4)                                           \
+       EXDI0(V2, F3)                                           \
+       EXDI0(R0, F2)                                           \
+       EXDI0(R1, F1)                                           \
+       EXDI0(R2, F0)
+
+#define LEXFI1(N, V, R0, R1)                                   \
+       movi_f %R1 V                                            \
+       truncr_f_i %R0 %R1                                      \
+       andi %R0 %R0 0xffffffff                                 \
+       beqi lfi##_##R0##_##R1##_##N %R0 $(V & 0xffffffff)      \
+       calli @abort                                            \
+lfi##_##R0##_##R1##_##N:
+#define LEXFI0(R0, R1)                                         \
+       LEXFI1(0,   42, R0, R1)                                 \
+       LEXFI1(1, -128, R0, R1)
+#define LEXFI(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)  \
+       LEXFI0(V0, F5)                                          \
+       LEXFI0(V1, F4)                                          \
+       LEXFI0(V2, F3)                                          \
+       LEXFI0(R0, F2)                                          \
+       LEXFI0(R1, F1)                                          \
+       LEXFI0(R2, F0)
+#define LEXDI1(N, V, R0, R1)                                   \
+       movi_d %R1 V                                            \
+       truncr_d_i %R0 %R1                                      \
+       andi %R0 %R0 0xffffffff                                 \
+       beqi ldi##_##R0##_##R1##_##N %R0 $(V & 0xffffffff)      \
+       calli @abort                                            \
+ldi##_##R0##_##R1##_##N:
+#define LEXDI0(R0, R1)                                         \
+       LEXDI1(0,   42, R0, R1)                                 \
+       LEXDI1(1, -128, R0, R1)
+#define LEXDI(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)  \
+       LEXDI0(V0, F5)                                          \
+       LEXDI0(V1, F4)                                          \
+       LEXDI0(V2, F3)                                          \
+       LEXDI0(R0, F2)                                          \
+       LEXDI0(R1, F1)                                          \
+       LEXDI0(R2, F0)
+
+#define EXTFD2(V, R0, R1)                                      \
+       movi_f %R0 V                                            \
+       extr_f_d %R1 %R0                                        \
+       beqi_d fd##_##R0##_##R1 %R1 V                           \
+       calli @abort                                            \
+fd##_##R0##_##R1:
+#define EXTFD1(R0, R1)                                         \
+       EXTFD2(1.25, R0, R1)
+#define EXTFDC2(V, R0)                                         \
+       movi_f %R0 V                                            \
+       extr_f_d %R0 %R0                                        \
+       beqi_d fdc##_##R0 %R0 V                                 \
+       calli @abort                                            \
+fdc##_##R0:
+#define EXTFDC1(R0)                                            \
+       EXTFDC2(-0.75, R0)
+#define EXTFD(R0, R1, R2, R3, R4, R5)                          \
+       EXTFD1(R0, R1)                                          \
+       EXTFD1(R0, R2)                                          \
+       EXTFD1(R0, R3)                                          \
+       EXTFD1(R0, R4)                                          \
+       EXTFD1(R0, R5)                                          \
+       EXTFDC1(R0)                                             \
+       EXTFDC1(R1)                                             \
+       EXTFDC1(R2)                                             \
+       EXTFDC1(R3)                                             \
+       EXTFDC1(R4)                                             \
+       EXTFDC1(R5)
+
+#define EXTDF2(V, R0, R1)                                      \
+       movi_d %R0 V                                            \
+       extr_d_f %R1 %R0                                        \
+       beqi_f df##_##R0##_##R1 %R1 V                           \
+       calli @abort                                            \
+df##_##R0##_##R1:
+#define EXTDF1(R0, R1)                                         \
+       EXTDF2(1.25, R0, R1)
+#define EXTDFC2(V, R0)                                         \
+       movi_d %R0 V                                            \
+       extr_d_f %R0 %R0                                        \
+       beqi_f dfc##_##R0 %R0 V                                 \
+       calli @abort                                            \
+dfc##_##R0:
+#define EXTDFC1(R0)                                            \
+       EXTDFC2(-0.75, R0)
+#define EXTDF(R0, R1, R2, R3, R4, R5)                          \
+       EXTDF1(R0, R1)                                          \
+       EXTDF1(R0, R2)                                          \
+       EXTDF1(R0, R3)                                          \
+       EXTDF1(R0, R4)                                          \
+       EXTDF1(R0, R5)                                          \
+       EXTDFC1(R0)                                             \
+       EXTDFC1(R1)                                             \
+       EXTDFC1(R2)                                             \
+       EXTDFC1(R3)                                             \
+       EXTDFC1(R4)                                             \
+       EXTDFC1(R5)
+
+.code
+       prolog
+
+       /* simple sequence for easier disassembly reading and encoding check */
+       movi %r0 w7f
+       extr_c %r1 %r0
+       beqi xc %r1 c7f
+       calli @abort
+xc:
+       movi %r0 w7f
+       extr_uc %r1 %r0
+       beqi xuc %r1 uc7f
+       calli @abort
+xuc:
+       movi %r0 w7f
+       extr_s %r1 %r0
+       beqi xs %r1 s7f
+       calli @abort
+xs:
+       movi %r0 w7f
+       extr_us %r1 %r0
+       beqi xus %r1 us7f
+       calli @abort
+xus:
+#if __WORDSIZE == 64
+       movi %r0 w7f
+       extr_i %r1 %r0
+       beqi xi %r1 i7f
+       calli @abort
+xi:
+       movi %r0 w7f
+       extr_ui %r1 %r0
+       beqi xui %r1 ui7f
+       calli @abort
+xui:
+#endif
+       movi %r0 -2
+       extr_f %f0 %r0
+       beqi_f xif %f0 -2
+       calli @abort
+xif:
+       movi %r0 32
+       extr_d %f0 %r0
+       beqi_d xid %f0 32
+       calli @abort
+xid:
+       movi_f %f0 -128
+       truncr_f %r0 %f0
+       beqi xfi %r0 -128
+       calli @abort
+xfi:
+       movi_d %f0 -128
+       truncr_d %r0 %f0
+       beqi xdi %r0 -128
+       calli @abort
+xdi:
+#if __WORDSIZE == 64
+       movi_f %f0 -128
+       truncr_f_i %r0 %f0
+       andi %r0 %r0 0xffffffff
+       beqi yfi %r0 $(-128 & 0xffffffff)
+       calli @abort
+yfi:
+       movi_d %f0 -128
+       truncr_d_i %r0 %f0
+       andi %r0 %r0 0xffffffff
+       beqi ydi %r0 $(-128 & 0xffffffff)
+       calli @abort
+ydi:
+#endif
+       movi_f %f0 0.5
+       extr_f_d %f1 %f0
+       beqi_d xfd %f1 0.5
+       calli @abort
+xfd:
+       movi_d %f0 0.5
+       extr_d_f %f1 %f0
+       beqi_f xdf %f1 0.5
+       calli @abort
+xdf:
+
+       EXTII(v0, v1, v2, r0, r1, r2)
+       EXIF(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+       EXID(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+       EXFI(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+#if __WORDSIZE == 64
+       LEXFI(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+       LEXDI(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+#endif
+       EXDI(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+       EXTFD(f0, f1, f2, f3, f4, f5)
+       EXTDF(f0, f1, f2, f3, f4, f5)
+
+       // just to know did not abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+
+       ret
+       epilog
diff --git a/deps/lightning/check/divi.ok b/deps/lightning/check/divi.ok
new file mode 100644 (file)
index 0000000..c23cbd2
--- /dev/null
@@ -0,0 +1,6 @@
+40/8 = 5 (expected 5)
+64/8 = 8 (expected 8)
+80/8 = 10 (expected 10)
+98304/32768 = 3 (expected 3)
+65536/32768 = 2 (expected 2)
+163840/32768 = 5 (expected 5)
diff --git a/deps/lightning/check/divi.tst b/deps/lightning/check/divi.tst
new file mode 100644 (file)
index 0000000..9c03ed8
--- /dev/null
@@ -0,0 +1,85 @@
+.data  128
+small_ops:
+.i     40 64 80
+large_ops:
+.i     98304 65536 163840
+fmt:
+.c     "%i/%i = %i (expected %i)\n"
+x:
+.c     "%d\n"
+.code
+       jmpi main
+
+#define generate_divider(operand)      \
+       name divider_##operand          \
+divider_##operand:                     \
+       prolog                          \
+       arg $i                          \
+       getarg %r1 $i                   \
+       divi %r2 %r1 operand            \
+       retr %r2                        \
+       epilog
+generate_divider(8)
+generate_divider(32768)
+
+#define generate_test_divider(divisor) \
+       name test_divider_##divisor     \
+test_divider_##divisor:                        \
+       prolog                          \
+       allocai 4 $loc                  \
+       arg $p                          \
+       arg $c                          \
+       getarg %v0 $p                   \
+       getarg %v1 $c                   \
+       muli %v1 %v1 4                  \
+       addr %v1 %v0 %v1                \
+loop_##divisor:                                \
+       bger done_##divisor %v0 %v1     \
+       ldr_i %v2 %v0                   \
+       prepare                         \
+               pushargr %v2            \
+       finishi divider_##divisor       \
+       retval %v2                      \
+       ldr_i %r2 %v0                   \
+       divi %r0 %r2 divisor            \
+       /* save div result */           \
+       stxi_i $loc %fp %r0             \
+       prepare                         \
+               pushargi fmt            \
+               ellipsis                \
+               pushargr %r2            \
+               pushargi divisor        \
+               pushargr %v2            \
+               pushargr %r0            \
+       finishi @printf                 \
+       addi %v0 %v0 4                  \
+       /* reload div result */         \
+       ldxi_i %r0 %fp $loc             \
+       beqr loop_##divisor %r0 %v2     \
+       /* return if failed */          \
+       reti 1                          \
+done_##divisor:                                \
+       reti 0                          \
+       epilog
+generate_test_divider(8)
+generate_test_divider(32768)
+
+       name main
+main:
+       prolog
+       prepare
+               pushargi small_ops
+               pushargi 3
+       finishi test_divider_8
+       retval %r0
+       bnei fail %r0 0 
+       prepare
+               pushargi large_ops
+               pushargi 3
+       finishi test_divider_32768
+       retval %r0
+       bnei fail %r0 0 
+       reti 0
+fail:
+       reti 1
+       epilog
diff --git a/deps/lightning/check/fib.ok b/deps/lightning/check/fib.ok
new file mode 100644 (file)
index 0000000..7e13ef0
--- /dev/null
@@ -0,0 +1 @@
+nfibs(32) = 2178309
diff --git a/deps/lightning/check/fib.tst b/deps/lightning/check/fib.tst
new file mode 100644 (file)
index 0000000..0835323
--- /dev/null
@@ -0,0 +1,62 @@
+.data  32
+format:
+.c     "nfibs(%d) = %d\n"
+
+.code
+       jmpi main
+
+       name nfibs
+nfibs:
+       prolog
+       arg $in
+       getarg %r0 $in          // R0 = n
+       beqi ref %r0 0
+       movr %r1 %r0
+       movi %r0 1
+       blei_u ref %r1 2
+       subi %r2 %r1 2
+       movr %r1 %r0
+loop:
+       subi %r2 %r2 1          // decr. counter
+       movr %v0 %r0            // V0 = R0
+       addr %r0 %r0 %r1        // R0 = R0 + R1
+       movr %r1 %v0            // R1 = V0
+       bnei loop %r2 0         // if (R2) goto loop
+ref:
+       retr %r0                // RET = R0
+       epilog
+
+       name main
+main:
+       prolog
+       arg $argc
+       arg $argv
+
+       getarg_i %r0 $argc
+       blei default %r0 1
+       getarg %r0 $argv
+       addi %r0 %r0 $(__WORDSIZE >> 3)
+       ldr %r0 %r0
+       prepare
+               pushargr %r0
+       finishi @atoi
+       retval %r0
+       jmpi call
+
+default:
+       movi %r0 32
+
+call:
+       movr %v0 %r0
+       prepare
+               pushargr %r0
+       finishi nfibs
+       retval %r0
+       prepare
+               pushargi format
+               ellipsis
+               pushargr %v0
+               pushargr %r0
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/float.ok b/deps/lightning/check/float.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/float.tst b/deps/lightning/check/float.tst
new file mode 100644 (file)
index 0000000..ff5606a
--- /dev/null
@@ -0,0 +1,367 @@
+
+.data  4
+ok:
+.c     "ok"
+
+.      $($NaN  =                0.0 / 0.0)
+.      $($pInf =                1.0 / 0.0)
+.      $($nInf =               -1.0 / 0.0)
+#if __WORDSIZE == 32
+#  define x7f                  0x7fffffff
+#  define x80                  0x80000000
+#else
+#  define x7f                  0x7fffffffffffffff
+#  define x80                  0x8000000000000000
+#endif
+
+#if __mips__ || __sparc__ || __hppa__ || __riscv
+#  define wnan                 x7f
+#elif __arm__ || __aarch64__ || __alpha__
+#  define wnan                 0
+#else
+#  define wnan                 x80
+#endif
+#if __mips__ || __arm__ || __ppc__ || __sparc__ || __hppa__ || __aarch64__ || __s390__ || __riscv
+#  define wpinf                        x7f
+#elif __alpha__
+/* (at least) bug compatible with gcc 4.2.3 -ieee */
+#  define wpinf                        0
+#else
+#  define wpinf                        x80
+#endif
+#if __alpha__
+/* (at least) bug compatible with gcc 4.2.3 -ieee */
+#  define wninf                        0
+#else
+#  define wninf                        x80
+#endif
+
+/* ensure result is correct and 0 or 1 in the result register */
+#define xtcmp(l, t, op, r0, f0, f1, li, ri)            \
+       movi##t %f0 li                                  \
+       movi##t %f1 ri                                  \
+       op##r##t %r0 %f0 %f1                            \
+       bnei T##op##r##t##r0##f0##f1##l %r0 0           \
+       calli @abort                                    \
+T##op##r##t##r0##f0##f1##l:                            \
+       movi##t %f0 li                                  \
+       movi##t %f1 ri                                  \
+       b##op##r##t bT##op##r##t##r0##f0##f1##l %f0 %f1 \
+       calli @abort                                    \
+bT##op##r##t##r0##f0##f1##l:                           \
+       movi##t %f1 li                                  \
+       op##i##t %r0 %f0 ri                             \
+       bnei T##op##i##t##r0##f0##f1##l %r0 0           \
+       calli @abort                                    \
+T##op##i##t##r0##f0##f1##l:                            \
+       movi##t %f1 li                                  \
+       b##op##i##t bT##op##i##t##r0##f0##f1##l %f0 ri  \
+       calli @abort                                    \
+bT##op##i##t##r0##f0##f1##l:                           \
+       movi##t %f0 li                                  \
+       movi##t %f1 ri                                  \
+       op##r##t %r0 %f0 %f1                            \
+       beqi F##op##r##t##r0##f0##f1##l %r0 1           \
+       calli @abort                                    \
+F##op##r##t##r0##f0##f1##l:                            \
+       movi##t %f1 li                                  \
+       op##i##t %r0 %f0 ri                             \
+       beqi F##op##i##t##r0##f0##f1##l %r0 1           \
+       calli @abort                                    \
+F##op##i##t##r0##f0##f1##l:
+#define tcmp1(l, t, op, r0, li, ri)                    \
+       xtcmp(l, t, op, r0, f0, f1, li, ri)             \
+       xtcmp(l, t, op, r0, f1, f2, li, ri)             \
+       xtcmp(l, t, op, r0, f2, f3, li, ri)             \
+       xtcmp(l, t, op, r0, f3, f4, li, ri)             \
+       xtcmp(l, t, op, r0, f4, f5, li, ri)
+#define tcmp0(l, t, op, li, ri)                                \
+       tcmp1(l, t, op, v0, li, ri)                     \
+       tcmp1(l, t, op, v1, li, ri)                     \
+       tcmp1(l, t, op, v2, li, ri)                     \
+       tcmp1(l, t, op, r0, li, ri)                     \
+       tcmp1(l, t, op, r1, li, ri)                     \
+       tcmp1(l, t, op, r2, li, ri)
+#if __ia64__
+#  define tcmp(l, op, li, ri)                          \
+        xtcmp(l, _f, op, r0, f0, f1, li, ri)           \
+        xtcmp(l, _d, op, r0, f0, f1, li, ri)
+#else
+#  define tcmp(l, op, li, ri)                          \
+        tcmp0(l, _f, op, li, ri)                       \
+        tcmp0(l, _d, op, li, ri)
+#endif
+
+#define xfcmp(l, t, op, r0, f0, f1, li, ri)            \
+       movi##t %f0 li                                  \
+       movi##t %f1 ri                                  \
+       op##r##t %r0 %f0 %f1                            \
+       beqi T##op##r##t##r0##f0##f1##l %r0 0           \
+       calli @abort                                    \
+T##op##r##t##r0##f0##f1##l:                            \
+       movi##t %f1 li                                  \
+       op##i##t %r0 %f0 ri                             \
+       beqi T##op##i##t##r0##f0##f1##l %r0 0           \
+       calli @abort                                    \
+T##op##i##t##r0##f0##f1##l:                            \
+       movi##t %f0 li                                  \
+       movi##t %f1 ri                                  \
+       op##r##t %r0 %f0 %f1                            \
+       bnei F##op##r##t##r0##f0##f1##l %r0 1           \
+       calli @abort                                    \
+F##op##r##t##r0##f0##f1##l:                            \
+       movi##t %f1 li                                  \
+       op##i##t %r0 %f0 ri                             \
+       bnei F##op##i##t##r0##f0##f1##l %r0 1           \
+       calli @abort                                    \
+F##op##i##t##r0##f0##f1##l:
+#define fcmp1(l, t, op, r0, li, ri)                    \
+       xfcmp(l, t, op, r0, f0, f1, li, ri)             \
+       xfcmp(l, t, op, r0, f1, f2, li, ri)             \
+       xfcmp(l, t, op, r0, f2, f3, li, ri)             \
+       xfcmp(l, t, op, r0, f3, f4, li, ri)             \
+       xfcmp(l, t, op, r0, f4, f5, li, ri)
+#define fcmp0(l, t, op, li, ri)                                \
+       fcmp1(l, t, op, v0, li, ri)                     \
+       fcmp1(l, t, op, v1, li, ri)                     \
+       fcmp1(l, t, op, v2, li, ri)                     \
+       fcmp1(l, t, op, r0, li, ri)                     \
+       fcmp1(l, t, op, r1, li, ri)                     \
+       fcmp1(l, t, op, r2, li, ri)
+#if __ia64__
+#  define fcmp(l, op, li, ri)                          \
+       xfcmp(l, _f, op, r0, f0, f1, li, ri)            \
+       xfcmp(l, _d, op, r0, f0, f1, li, ri)
+#else
+#  define fcmp(l, op, li, ri)                          \
+        fcmp0(l, _f, op, li, ri)                       \
+        fcmp0(l, _d, op, li, ri)
+#endif
+
+#define xf2w(l, f, r0, f0, iv, fv)                     \
+       movi##f %f0 fv                                  \
+       truncr##f %r0 %f0                               \
+       beqi W##f##r0##f0##l %r0 iv                     \
+       calli @abort                                    \
+W##f##r0##f0##l:
+#define f2w1(l, t, r0, iv, fv)                         \
+       xf2w(l, t, r0, f0, iv, fv)                      \
+       xf2w(l, t, r0, f1, iv, fv)                      \
+       xf2w(l, t, r0, f2, iv, fv)                      \
+       xf2w(l, t, r0, f3, iv, fv)                      \
+       xf2w(l, t, r0, f4, iv, fv)                      \
+       xf2w(l, t, r0, f5, iv, fv)
+#define f2w0(l, t, iv, fv)                             \
+       f2w1(l, t, v0, iv, fv)                          \
+       f2w1(l, t, v1, iv, fv)                          \
+       f2w1(l, t, v2, iv, fv)                          \
+       f2w1(l, t, r0, iv, fv)                          \
+       f2w1(l, t, r1, iv, fv)                          \
+       f2w1(l, t, r2, iv, fv)
+#if __ia64__
+#  define f2w(l, iv, fv)                               \
+       xf2w(l, _f, r0, f0, iv, fv)                     \
+       xf2w(l, _d, r0, f0, iv, fv)
+#else
+#  define f2w(l, iv, fv)                               \
+       f2w0(l, _f, iv, fv)                             \
+       f2w0(l, _d, iv, fv)
+#endif
+
+.code
+       prolog
+
+       tcmp(__LINE__, lt, 0, 1)
+       tcmp(__LINE__, lt, $nInf, $pInf)
+       tcmp(__LINE__, lt, $nInf, 0)
+       tcmp(__LINE__, lt, 0, $pInf)
+       fcmp(__LINE__, lt, $NaN, 0)
+       fcmp(__LINE__, lt, $NaN, $NaN)
+       fcmp(__LINE__, lt, $nInf, $NaN)
+       fcmp(__LINE__, lt, 1, 0)
+       fcmp(__LINE__, lt, 0, 0)
+       fcmp(__LINE__, lt, $pInf, $nInf)
+       fcmp(__LINE__, lt, 0, $nInf)
+       fcmp(__LINE__, lt, 0, $NaN)
+
+       tcmp(__LINE__, le, 0, 1)
+       tcmp(__LINE__, le, 0, 0)
+       tcmp(__LINE__, le, 1, 1)
+       tcmp(__LINE__, le, $nInf, $pInf)
+       tcmp(__LINE__, le, $nInf, 0)
+       tcmp(__LINE__, le, 0, $pInf)
+       fcmp(__LINE__, le, $NaN, 0)
+       fcmp(__LINE__, le, $NaN, $NaN)
+       fcmp(__LINE__, le, $nInf, $NaN)
+       fcmp(__LINE__, le, 1, 0)
+       fcmp(__LINE__, le, $pInf, $nInf)
+       fcmp(__LINE__, le, 0, $nInf)
+       fcmp(__LINE__, le, 0, $NaN)
+
+       tcmp(__LINE__, eq, 0, 0)
+       tcmp(__LINE__, eq, 1, 1)
+       fcmp(__LINE__, eq, $NaN, 0)
+       fcmp(__LINE__, eq, $NaN, $NaN)
+       fcmp(__LINE__, eq, $nInf, $NaN)
+       fcmp(__LINE__, eq, 0, 1)
+       fcmp(__LINE__, eq, 1, 0)
+       fcmp(__LINE__, eq, $pInf, $nInf)
+       fcmp(__LINE__, eq, 0, $nInf)
+       fcmp(__LINE__, eq, 0, $NaN)
+
+       tcmp(__LINE__, ge, 1, 0)
+       tcmp(__LINE__, ge, 0, 0)
+       tcmp(__LINE__, ge, 1, 1)
+       tcmp(__LINE__, ge, $pInf, $nInf)
+       tcmp(__LINE__, ge, 0, $nInf)
+       tcmp(__LINE__, ge, $pInf, 0)
+       fcmp(__LINE__, ge, $NaN, 0)
+       fcmp(__LINE__, ge, $NaN, $NaN)
+       fcmp(__LINE__, ge, $nInf, $NaN)
+       fcmp(__LINE__, ge, 0, 1)
+       fcmp(__LINE__, ge, $nInf, $pInf)
+       fcmp(__LINE__, ge, $nInf, 0)
+       fcmp(__LINE__, ge, 0, $NaN)
+
+       tcmp(__LINE__, gt, 1, 0)
+       tcmp(__LINE__, gt, $pInf, $nInf)
+       tcmp(__LINE__, gt, 0, $nInf)
+       tcmp(__LINE__, gt, $pInf, 0)
+       fcmp(__LINE__, gt, $NaN, 0)
+       fcmp(__LINE__, gt, $NaN, $NaN)
+       fcmp(__LINE__, gt, $nInf, $NaN)
+       fcmp(__LINE__, gt, 0, 1)
+       fcmp(__LINE__, gt, 0, 0)
+       fcmp(__LINE__, gt, $nInf, $pInf)
+       fcmp(__LINE__, gt, $nInf, 0)
+       fcmp(__LINE__, gt, 0, $NaN)
+
+       tcmp(__LINE__, ne, 0, 1)
+       tcmp(__LINE__, ne, 1, 0)
+       tcmp(__LINE__, ne, $NaN, $NaN)
+       tcmp(__LINE__, ne, $nInf, $pInf)
+       tcmp(__LINE__, ne, $NaN, 0)
+       tcmp(__LINE__, ne, $nInf, $NaN)
+       tcmp(__LINE__, ne, $pInf, $nInf)
+       tcmp(__LINE__, ne, 0, $nInf)
+       tcmp(__LINE__, ne, 0, $NaN)
+       fcmp(__LINE__, ne, 0, 0)
+       fcmp(__LINE__, ne, 1, 1)
+
+       tcmp(__LINE__, unlt, 0, 1)
+       tcmp(__LINE__, unlt, $nInf, $pInf)
+       tcmp(__LINE__, unlt, $nInf, 0)
+       tcmp(__LINE__, unlt, 0, $pInf)
+       tcmp(__LINE__, unlt, $NaN, 0)
+       tcmp(__LINE__, unlt, $NaN, $NaN)
+       tcmp(__LINE__, unlt, $nInf, $NaN)
+       tcmp(__LINE__, unlt, 0, $NaN)
+       fcmp(__LINE__, unlt, 1, 0)
+       fcmp(__LINE__, unlt, 0, 0)
+       fcmp(__LINE__, unlt, $pInf, $nInf)
+       fcmp(__LINE__, unlt, 0, $nInf)
+
+       tcmp(__LINE__, unle, 0, 1)
+       tcmp(__LINE__, unle, 0, 0)
+       tcmp(__LINE__, unle, 1, 1)
+       tcmp(__LINE__, unle, $nInf, $pInf)
+       tcmp(__LINE__, unle, $nInf, 0)
+       tcmp(__LINE__, unle, 0, $pInf)
+       tcmp(__LINE__, unle, $NaN, 0)
+       tcmp(__LINE__, unle, $NaN, $NaN)
+       tcmp(__LINE__, unle, $nInf, $NaN)
+       tcmp(__LINE__, unle, 0, $NaN)
+       fcmp(__LINE__, unle, 1, 0)
+       fcmp(__LINE__, unle, $pInf, $nInf)
+       fcmp(__LINE__, unle, 0, $nInf)
+
+       tcmp(__LINE__, uneq, 0, 0)
+       tcmp(__LINE__, uneq, 1, 1)
+       tcmp(__LINE__, uneq, $NaN, 0)
+       tcmp(__LINE__, uneq, $NaN, $NaN)
+       tcmp(__LINE__, uneq, $nInf, $NaN)
+       tcmp(__LINE__, uneq, 0, $NaN)
+       fcmp(__LINE__, uneq, 0, 1)
+       fcmp(__LINE__, uneq, 1, 0)
+       fcmp(__LINE__, uneq, $pInf, $nInf)
+       fcmp(__LINE__, uneq, 0, $nInf)
+
+       tcmp(__LINE__, unge, 1, 0)
+       tcmp(__LINE__, unge, 0, 0)
+       tcmp(__LINE__, unge, 1, 1)
+       tcmp(__LINE__, unge, $pInf, $nInf)
+       tcmp(__LINE__, unge, 0, $nInf)
+       tcmp(__LINE__, unge, $pInf, 0)
+       tcmp(__LINE__, unge, $NaN, 0)
+       tcmp(__LINE__, unge, $NaN, $NaN)
+       tcmp(__LINE__, unge, $nInf, $NaN)
+       tcmp(__LINE__, unge, 0, $NaN)
+       fcmp(__LINE__, unge, 0, 1)
+       fcmp(__LINE__, unge, $nInf, $pInf)
+       fcmp(__LINE__, unge, $nInf, 0)
+
+       tcmp(__LINE__, ungt, 1, 0)
+       tcmp(__LINE__, ungt, $pInf, $nInf)
+       tcmp(__LINE__, ungt, 0, $nInf)
+       tcmp(__LINE__, ungt, $pInf, 0)
+       tcmp(__LINE__, ungt, $NaN, 0)
+       tcmp(__LINE__, ungt, $NaN, $NaN)
+       tcmp(__LINE__, ungt, $nInf, $NaN)
+       tcmp(__LINE__, ungt, 0, $NaN)
+       fcmp(__LINE__, ungt, 0, 1)
+       fcmp(__LINE__, ungt, 0, 0)
+       fcmp(__LINE__, ungt, $nInf, $pInf)
+       fcmp(__LINE__, ungt, $nInf, 0)
+
+       tcmp(__LINE__, ltgt, 0, 1)
+       tcmp(__LINE__, ltgt, 1, 0)
+       tcmp(__LINE__, ltgt, $nInf, $pInf)
+       tcmp(__LINE__, ltgt, $pInf, $nInf)
+       tcmp(__LINE__, ltgt, 0, $nInf)
+       fcmp(__LINE__, ltgt, $NaN, $NaN)
+       fcmp(__LINE__, ltgt, $NaN, 0)
+       fcmp(__LINE__, ltgt, $nInf, $NaN)
+       fcmp(__LINE__, ltgt, 0, $NaN)
+       fcmp(__LINE__, ltgt, 0, 0)
+       fcmp(__LINE__, ltgt, 1, 1)
+
+       tcmp(__LINE__, ord, 0, 1)
+       tcmp(__LINE__, ord, 1, 0)
+       tcmp(__LINE__, ord, $nInf, $pInf)
+       tcmp(__LINE__, ord, $pInf, $nInf)
+       tcmp(__LINE__, ord, 0, $nInf)
+       tcmp(__LINE__, ord, 0, 0)
+       tcmp(__LINE__, ord, 1, 1)
+       fcmp(__LINE__, ord, $NaN, $NaN)
+       fcmp(__LINE__, ord, $NaN, 0)
+       fcmp(__LINE__, ord, $nInf, $NaN)
+       fcmp(__LINE__, ord, 0, $NaN)
+
+       tcmp(__LINE__, unord, $NaN, $NaN)
+       tcmp(__LINE__, unord, $NaN, 0)
+       tcmp(__LINE__, unord, $nInf, $NaN)
+       tcmp(__LINE__, unord, 0, $NaN)
+       fcmp(__LINE__, unord, 0, 1)
+       fcmp(__LINE__, unord, 1, 0)
+       fcmp(__LINE__, unord, $nInf, $pInf)
+       fcmp(__LINE__, unord, $pInf, $nInf)
+       fcmp(__LINE__, unord, 0, $nInf)
+       fcmp(__LINE__, unord, 0, 0)
+       fcmp(__LINE__, unord, 1, 1)
+
+       f2w(__LINE__, 0, 0)
+       f2w(__LINE__, 1, 1)
+        /* not all loongson agree on it */
+#if !__mips__
+       f2w(__LINE__, wninf, $nInf)
+#endif
+       f2w(__LINE__, wpinf, $pInf)
+       f2w(__LINE__, wnan, $NaN)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @puts
+
+       ret
+       epilog
diff --git a/deps/lightning/check/fop_abs.ok b/deps/lightning/check/fop_abs.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/fop_abs.tst b/deps/lightning/check/fop_abs.tst
new file mode 100644 (file)
index 0000000..cb7be14
--- /dev/null
@@ -0,0 +1,31 @@
+#include "alu.inc"
+
+.code
+       prolog
+#define ABS(N, T, I, V)                FUN(N, T, abs, I, V)
+#define UABS(N, T, I, V)       UFUN(N, T, abs, I, V)
+       ABS(0, _f,      -0.0,            0.0)
+       ABS(1, _f,       0.5,            0.5)
+       ABS(2, _f,      -0.5,            0.5)
+       ABS(3, _f,      $Inf,           $Inf)
+       ABS(4, _f,      $nInf,          $Inf)
+       ABS(5, _f,       1.25,          1.25)
+       ABS(6, _f,      -1.25,          1.25)
+       ABS(7, _f,      $nInf,          $Inf)
+       UABS(0, _f,     $NaN,           $NaN)
+       ABS(0, _d,      -0.0,            0.0)
+       ABS(1, _d,       0.5,            0.5)
+       ABS(2, _d,      -0.5,            0.5)
+       ABS(3, _d,      $Inf,           $Inf)
+       ABS(4, _d,      $nInf,          $Inf)
+       ABS(5, _d,       1.25,           1.25)
+       ABS(6, _d,      -1.25,           1.25)
+       ABS(7, _d,      $nInf,          $Inf)
+       UABS(0, _d,     $NaN,           $NaN)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/fop_sqrt.ok b/deps/lightning/check/fop_sqrt.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/fop_sqrt.tst b/deps/lightning/check/fop_sqrt.tst
new file mode 100644 (file)
index 0000000..fa93dbc
--- /dev/null
@@ -0,0 +1,23 @@
+#include "alu.inc"
+
+.code
+       prolog
+#define SQRT(N, T, I, V)       FUN(N, T, sqrt, I, V)
+#define USQRT(N, T, I, V)      UFUN(N, T, sqrt, I, V)
+        SQRT(0, _f,    -0.0,            0.0)
+        SQRT(1, _f,     4.0,            2.0)
+        SQRT(2, _f,     2.25,           1.5)
+        SQRT(3, _f,    $Inf,           $Inf)
+       USQRT(0, _f,    $NaN,           $NaN)
+        SQRT(0, _d,    -0.0,            0.0)
+        SQRT(1, _d,     4.0,            2.0)
+        SQRT(2, _d,     2.25,           1.5)
+        SQRT(3, _d,    $Inf,           $Inf)
+       USQRT(0, _d,    $NaN,           $NaN)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/hton.ok b/deps/lightning/check/hton.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/hton.tst b/deps/lightning/check/hton.tst
new file mode 100644 (file)
index 0000000..fcaf147
--- /dev/null
@@ -0,0 +1,169 @@
+.data  16
+ok:
+.c     "ok\n"
+
+#define us12_i         0x1234
+#define us7f_i         0x7ff7
+#define us80_i         0x8008
+#define usff_i         0xffff
+#define ui12_i         0x01234567
+#define ui7f_i         0x7f7ff7f7
+#define ui80_i         0x80800808
+#define uiff_i         0xffffffff
+#define ul12_i         0x0123456789abcdef
+#define ul7f_i         0x7f7f7f7ff7f7f7f7
+#define ul80_i         0x8080808008080808
+#define ulff_i         0xffffffffffffffff
+
+#if __WORDSIZE == 32
+#  define xus12_i      0xffff1234
+#  define xus7f_i      0x10107ff7
+#  define xus80_i      0x81188008
+#  define xusff_i      0xeaaeffff
+#else
+#  define xus12_i      0xffffffffffff1234
+#  define xus7f_i      0x1010100101017ff7
+#  define xus80_i      0x8181811818818008
+#  define xusff_i      0xeaeaeaaeaeaeffff
+#  define xui12_i      0xffffffff01234567
+#  define xui7f_i      0x101001017f7ff7f7
+#  define xui80_i      0x8181181880800808
+#  define xuiff_i      0xeaeaaeaeffffffff
+#endif
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define us12_o       0x3412
+#  define us7f_o       0xf77f
+#  define us80_o       0x0880
+#  define usff_o       0xffff
+#  define ui12_o       0x67452301
+#  define ui7f_o       0xf7f77f7f
+#  define ui80_o       0x08088080
+#  define uiff_o       0xffffffff
+#  define ul12_o       0xefcdab8967452301
+#  define ul7f_o       0xf7f7f7f77f7f7f7f
+#  define ul80_o       0x0808080880808080
+#  define ulff_o       0xffffffffffffffff
+#else
+#  define us12_o       us12_i
+#  define us7f_o       us7f_i
+#  define us80_o       us80_i
+#  define usff_o       usff_i
+#  define ui12_o       ui12_i
+#  define ui7f_o       ui7f_i
+#  define ui80_o       ui80_i
+#  define uiff_o       uiff_i
+#  define ul12_o       ul12_i
+#  define ul7f_o       ul7f_i
+#  define ul80_o       ul80_i
+#  define ulff_o       ulff_i
+#endif
+
+#define HTON4(I, O, T, R0, R1)                         \
+       movi %R0 I                                      \
+       htonr_##T %R1 %R0                               \
+       beqi T##R0##R1##I %R1 O                         \
+       calli @abort                                    \
+T##R0##R1##I:
+
+#define HTON3(T, R0, R1)                               \
+       HTON4(T##12_i, T##12_o, T, R0, R1)              \
+       HTON4(x##T##12_i, T##12_o, T, R0, R1)           \
+       HTON4(T##7f_i, T##7f_o, T, R0, R1)              \
+       HTON4(x##T##7f_i, T##7f_o, T, R0, R1)           \
+       HTON4(T##80_i, T##80_o, T, R0, R1)              \
+       HTON4(x##T##80_i, T##80_o, T, R0, R1)           \
+       HTON4(T##ff_i, T##ff_o, T, R0, R1)              \
+       HTON4(x##T##ff_i, T##ff_o, T, R0, R1)
+
+#define HTON3x(T, R0, R1)                              \
+       HTON4(T##12_i, T##12_o, T, R0, R1)              \
+       HTON4(T##7f_i, T##7f_o, T, R0, R1)              \
+       HTON4(T##80_i, T##80_o, T, R0, R1)              \
+       HTON4(T##ff_i, T##ff_o, T, R0, R1)
+
+#define HTON2(T, V0, V1, V2, R0, R1, R2)               \
+       HTON3(T, V0, V0)                                \
+       HTON3(T, V0, V1)                                \
+       HTON3(T, V0, V2)                                \
+       HTON3(T, V0, R0)                                \
+       HTON3(T, V0, R1)                                \
+       HTON3(T, V0, R2)                                \
+
+#define HTON2x(T, V0, V1, V2, R0, R1, R2)              \
+       HTON3x(T, V0, V0)                               \
+       HTON3x(T, V0, V1)                               \
+       HTON3x(T, V0, V2)                               \
+       HTON3x(T, V0, R0)                               \
+       HTON3x(T, V0, R1)                               \
+       HTON3x(T, V0, R2)                               \
+
+#define HTON1(T, V0, V1, V2, R0, R1, R2)               \
+       HTON2(T, V0, V1, V2, R0, R1, R2)                \
+       HTON2(T, V1, V2, R0, R1, R2, V0)                \
+       HTON2(T, V2, R0, R1, R2, V0, V1)                \
+       HTON2(T, R0, R1, R2, V0, V1, V2)                \
+       HTON2(T, R1, R2, V0, V1, V2, R0)                \
+       HTON2(T, R2, V0, V1, V2, R0, R1)
+
+#define HTON1x(T, V0, V1, V2, R0, R1, R2)              \
+       HTON2x(T, V0, V1, V2, R0, R1, R2)               \
+       HTON2x(T, V1, V2, R0, R1, R2, V0)               \
+       HTON2x(T, V2, R0, R1, R2, V0, V1)               \
+       HTON2x(T, R0, R1, R2, V0, V1, V2)               \
+       HTON2x(T, R1, R2, V0, V1, V2, R0)               \
+       HTON2x(T, R2, V0, V1, V2, R0, R1)
+
+#if __WORDSIZE == 32
+#  define HTON(V0, V1, V2, R0, R1, R2)                 \
+       HTON1(us, V0, V1, V2, R0, R1, R2)               \
+       HTON1x(ui, V0, V1, V2, R0, R1, R2)
+#else
+#  define HTON(V0, V1, V2, R0, R1, R2)                 \
+       HTON1(us, V0, V1, V2, R0, R1, R2)               \
+       HTON1(ui, V0, V1, V2, R0, R1, R2)               \
+       HTON1x(ul, V0, V1, V2, R0, R1, R2)
+#endif
+
+.code
+       prolog
+       /* simple sequence for easier disassembly reading and encoding check */
+       movi %r0 us12_i
+       htonr_us %r1 %r0
+       beqi us %r1 us12_o
+       calli @abort
+us:
+
+       movi %r0 xus12_i
+       htonr_us %r1 %r0
+       beqi xus %r1 us12_o
+       calli @abort
+xus:
+       movi %r0 ui12_i
+       htonr_ui %r1 %r0
+       beqi ui %r1 ui12_o
+       calli @abort
+ui:
+#if __WORDSIZE == 64
+       movi %r0 xui12_i
+       htonr_ui %r1 %r0
+       beqi xui %r1 ui12_o
+       calli @abort
+xui:
+       movi %r0 ul12_i
+       htonr_ul %r1 %r0
+       beqi ul %r1 ul12_o
+       calli @abort
+ul:
+#endif
+
+       HTON(v0, v1, v2, r0, r1, r2)
+
+       // just to know did not abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+
+       ret
+       epilog
diff --git a/deps/lightning/check/jmpr.ok b/deps/lightning/check/jmpr.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/jmpr.tst b/deps/lightning/check/jmpr.tst
new file mode 100644 (file)
index 0000000..669f54e
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+This is a very simple check to a condition that on lightning 2.0.5
+could cause an assertion on some backends, due to correcting a problem
+with temporaries that could not be saved/reloaded due to being used only
+in the hardware instruction, or being considered live for too long on the
+lightning instruction, and that could not be reloaded after the jump target
+(or after false/true target on conditional branches).
+
+If this code in lib/lightning.c:_jit_update():
+
+                   for (regno = 0; regno < _jitc->reglen; regno++) {
+                       spec = jit_class(_rvs[regno].spec);
+                       if (jit_regset_tstbit(mask, regno) &&
+                           (spec & (jit_class_gpr|jit_class_fpr)) &&
+                           !(spec & jit_class_sav))
+                           jit_regset_clrbit(mask, regno);
+                   }
+
+were removed, this test case, on x86_64 would fail like this:
+
+lt-lightning: lightning.c:305: _jit_get_reg: Assertion `regspec & 0x02000000' failed.
+Aborted (core dumped)
+ */
+
+.data  32
+ret:
+#if __WORDSIZE == 32
+.i     0
+#else
+.l     0
+#endif
+ok:
+.c     "ok"
+
+.code
+       prolog
+       jmpi start
+
+add_v1_v2:
+       addr %v1 %v1 %v2
+       ldi %r0 ret
+       jmpr %r0
+
+start:
+       movi %v1 1
+       movi %v2 2
+       movi %r0 ret_add_v1_v2
+       sti ret %r0
+       movi %v0 add_v1_v2
+       jmpr %v0
+       movi_d %f0 3
+       beqi_d pass_movi_f0 %f0 3
+       calli @abort
+pass_movi_f0:
+       beqi pass_check_v2 %v2 2
+       calli @abort
+pass_check_v2:
+ret_add_v1_v2:
+       beqi pass_add_v1_v2 %v1 3
+       calli @abort
+pass_add_v1_v2:
+       prepare
+               pushargi ok
+       finishi @puts
+       ret
+       epilog
diff --git a/deps/lightning/check/ldst.inc b/deps/lightning/check/ldst.inc
new file mode 100644 (file)
index 0000000..c2bc59a
--- /dev/null
@@ -0,0 +1,102 @@
+#if __WORDSIZE == 64
+#  define L0           0x8000000000000001
+#  define LL0          L0
+#  define LC0          0xffffffffffffff81
+#  define LS0          0xffffffffffff8001
+#  define LI0          0xffffffff80000001
+#  define L1           0x8000000000000000
+#  define LL1          L1
+#  define LC1          0xffffffffffffff80
+#  define LS1          0xffffffffffff8000
+#  define LI1          0xffffffff80000000
+#  define L2           0x7fffffffffffffff
+#  define LL2          L2
+#  define LC2          0x000000000000007f
+#  define LS2          0x0000000000007fff
+#  define LI2          0x000000007fffffff
+#  define L3           0xffffffffffffffff
+#  define LL3          L3
+#  define LC3          0xffffffffffffffff
+#  define LS3          0xffffffffffffffff
+#  define LI3          0xffffffffffffffff
+#  define XC           LC0
+#  define XS           LS0
+#  define XI           LI0
+#else
+#  define XC           IC0
+#  define XS           IS0
+#  define XI           II0
+#endif
+#define I0             0x80000001
+#define II0            I0
+#define IC0            0xffffff81
+#define IS0            0xffff8001
+#define I1             0x80000000
+#define II1            I1
+#define IC1            0xffffff80
+#define IS1            0xffff8000
+#define I2             0x7fffffff
+#define II2            I2
+#define IC2            0x0000007f
+#define IS2            0x00007fff
+#define I3             0xffffffff
+#define II3            I3
+#define IC3            0xffffffff
+#define IS3            0xffffffff
+#define S0             0x8001
+#define S1             0x8000
+#define S2             0x7fff
+#define S3             0xffff
+#define C0             0x81
+#define C1             0x80
+#define C2             0x7f
+#define C3             0xff
+#define F0              0.25
+#define F1              0.75
+#define F2             -0.25
+#define F3             -0.75
+#define D0              0.25
+#define D1              0.75
+#define D2             -0.25
+#define D3             -0.75
+
+.data  512
+ok:
+.c     "ok\n"
+.align 8
+t0:
+c0:
+.c     0
+uc0:
+.c     0
+s0:
+.s     0
+us0:
+.s     0
+.align 4
+i0:
+.i     0
+#if __WORDSIZE == 64
+ui0:
+.i     0
+.align 8
+l0:
+.l     0
+#endif
+f0:
+.f     0
+.align 8
+d0:
+.d     0
+
+.      $($offc  = c0  - t0)
+.      $($offuc = uc0 - t0)
+.      $($offs  = s0  - t0)
+.      $($offus = us0 - t0)
+.      $($offi  = i0  - t0)
+#if __WORDSIZE == 64
+.      $($offui = ui0 - t0)
+.      $($offl  = l0  - t0)
+#endif
+.      $($offf  = f0  - t0)
+.      $($offd  = d0  - t0)
diff --git a/deps/lightning/check/ldsti.ok b/deps/lightning/check/ldsti.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/ldsti.tst b/deps/lightning/check/ldsti.tst
new file mode 100644 (file)
index 0000000..362cb84
--- /dev/null
@@ -0,0 +1,146 @@
+#include "ldst.inc"
+
+#if __WORDSIZE == 64
+#  define LDSTL(N, R0)                                         \
+       sti_i ui0 %R0                                           \
+       movi %R0 L##N                                           \
+       sti_l l0 %R0
+
+#  define SI(C, N, x, X, R0)                                   \
+       ldi_##x %R0 x##0                                        \
+       beqi L##x##C %R0 L##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0)                                       \
+       UI(C, N, i, I, R0)                                      \
+       SI(C, N, l, L, R0)
+#else
+#  define LDSTL(C, R0)
+#  define SI(C, N, x, X, R0)                                   \
+       ldi_##x %R0 x##0                                        \
+       beqi L##x##C %R0 I##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0)
+
+#endif
+
+#define UI(C, N, x, X, R0)                                     \
+       ldi_u##x %R0 u##x##0                                    \
+       beqi Lu##x##C %R0 X##N                                  \
+       calli @abort                                            \
+Lu##x##C:
+
+#define FF(C, N, x, X, F0)                                     \
+       ldi_##x %F0 x##0                                        \
+       beqi_##x L##x##C %F0 X##N                               \
+L##x##C:
+
+#define LDST1(X, N, R0, F0)                                    \
+       movi %R0 C##N                                           \
+       sti_c c0 %R0                                            \
+       sti_c uc0 %R0                                           \
+       movi %R0 S##N                                           \
+       sti_s s0 %R0                                            \
+       sti_s us0 %R0                                           \
+       movi %R0 I##N                                           \
+       sti_i i0 %R0                                            \
+       LDSTL(N, R0)                                            \
+       movi_f %F0 F##N                                         \
+       sti_f f0 %F0                                            \
+       movi_d %F0 D##N                                         \
+       sti_d d0 %F0                                            \
+       SI(X, N, c, C, R0)                                      \
+       UI(X, N, c, C, R0)                                      \
+       SI(X, N, s, S, R0)                                      \
+       UI(X, N, s, S, R0)                                      \
+       SI(X, N, i, I, R0)                                      \
+       LDRL(X, N, R0)                                          \
+       FF(X, N, f, F, F0)                                      \
+       FF(X, N, d, D, F0)
+
+#define LDST0(R0, F0)                                          \
+       LDST1(0_##R0##_##F0, 0, R0, F0)                         \
+       LDST1(1_##R0##_##F0, 1, R0, F0)                         \
+       LDST1(2_##R0##_##F0, 2, R0, F0)                         \
+       LDST1(3_##R0##_##F0, 3, R0, F0)
+
+#define LDST(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)   \
+       LDST0(V0, F0)                                           \
+       LDST0(V1, F1)                                           \
+       LDST0(V2, F3)                                           \
+       LDST0(R0, F4)                                           \
+       LDST0(R1, F5)                                           \
+       LDST0(R2, F0)
+
+.code
+       prolog
+
+       /* Simple test to simplify validating encodings before
+        * brute force tests */
+       movi %r1 0x81
+       sti_c c0 %r1
+       sti_c uc0 %r1
+       movi %r1 0x8001
+       sti_s s0 %r1
+       sti_s us0 %r1
+       movi %r1 0x80000001
+       sti_i i0 %r1
+#if __WORDSIZE == 64
+       sti_i ui0 %r1
+       movi %r1 0x8000000000000001
+       sti_l l0 %r1
+#endif
+       movi_f %f0 0.5
+       sti_f f0 %f0
+       movi_d %f0 0.25
+       sti_d d0 %f0
+       ldi_c %r1 c0
+       beqi Lc %r1 XC
+       calli @abort
+Lc:
+       ldi_uc %r1 uc0
+       beqi Luc %r1 0x81
+       calli @abort
+Luc:
+       ldi_s %r1 s0
+       beqi Ls %r1 XS
+       calli @abort
+Ls:
+       ldi_us %r1 us0
+       beqi Lus %r1 0x8001
+       calli @abort
+Lus:
+       ldi_i %r1 i0
+       beqi Li %r1 XI
+       calli @abort
+Li:
+#if __WORDSIZE == 64
+       ldi_ui %r1 ui0
+       beqi Lui %r1 0x80000001
+       calli @abort
+Lui:
+       ldi_l %r1 l0
+       beqi Ll %r1 0x8000000000000001
+       calli @abort
+Ll:
+#endif
+       ldi_f %f0 f0
+       beqi_f Lf %f0 0.5
+       calli @abort
+Lf:
+       ldi_d %f0 d0
+       beqi_d Ld %f0 0.25
+       calli @abort
+Ld:
+
+       LDST(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+       // just to know did not abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/ldstr-c.ok b/deps/lightning/check/ldstr-c.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/ldstr-c.tst b/deps/lightning/check/ldstr-c.tst
new file mode 100644 (file)
index 0000000..6ddc86e
--- /dev/null
@@ -0,0 +1,155 @@
+#include "ldst.inc"
+
+#if __WORDSIZE == 64
+#  define LDSTL(N, R0, R1)                                     \
+       movi %R0 $(t0 + $offui)                                 \
+       str_i %R0 %R1                                           \
+       movi %R0 $(t0 + $offl)                                  \
+       movi %R1 L##N                                           \
+       str_l %R0 %R1
+
+#  define SI(C, N, x, X, R0)                                   \
+       movi %R0 $(t0 + $off##x)                                \
+       ldr_##x %R0 %R0                                         \
+       beqi L##x##C %R0 L##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1)                                   \
+       UI(C, N, i, I, R0)                                      \
+       SI(C, N, l, L, R0)
+#else
+#  define LDSTL(C, R0, R1)
+#  define SI(C, N, x, X, R0)                                   \
+       movi %R0 $(t0 + $off##x)                                \
+       ldr_##x %R0 %R0                                         \
+       beqi L##x##C %R0 I##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1)
+
+#endif
+
+#define UI(C, N, x, X, R0)                                     \
+       movi %R0 $(t0 + $offu##x)                               \
+       ldr_u##x %R0 %R0                                        \
+       beqi Lu##x##C %R0 X##N                                  \
+       calli @abort                                            \
+Lu##x##C:
+
+#define LDST1(X, N, R0, R1)                                    \
+       movi %R0 $(t0 + $offc)                                  \
+       movi %R1 C##N                                           \
+       str_c %R0 %R1                                           \
+       movi %R0 $(t0 + $offuc)                                 \
+       str_c %R0 %R1                                           \
+       movi %R0 $(t0 + $offs)                                  \
+       movi %R1 S##N                                           \
+       str_s %R0 %R1                                           \
+       movi %R0 $(t0 + $offus)                                 \
+       str_s %R0 %R1                                           \
+       movi %R0 $(t0 + $offi)                                  \
+       movi %R1 I##N                                           \
+       str_i %R0 %R1                                           \
+       LDSTL(N, R0, R1)                                        \
+       movi %R0 $(t0 + $offf)                                  \
+       SI(X, N, c, C, R0)                                      \
+       UI(X, N, c, C, R0)                                      \
+       SI(X, N, s, S, R0)                                      \
+       UI(X, N, s, S, R0)                                      \
+       SI(X, N, i, I, R0)                                      \
+       LDRL(X, N, R0, R1)                                      \
+
+#define LDST0(R0, R1)                                          \
+       LDST1(0_##R0##_##R1, 0, R0, R1)                         \
+       LDST1(1_##R0##_##R1, 1, R0, R1)                         \
+       LDST1(2_##R0##_##R1, 2, R0, R1)                         \
+       LDST1(3_##R0##_##R1, 3, R0, R1)
+
+#define LDST(V0, V1, V2, R0, R1, R2)                           \
+       LDST0(V0, V1)                                           \
+       LDST0(V0, V2)                                           \
+       LDST0(V0, R0)                                           \
+       LDST0(V0, R1)                                           \
+       LDST0(V0, R2)                                           \
+       LDST0(V1, V0)                                           \
+       LDST0(V1, V2)                                           \
+       LDST0(V1, R0)                                           \
+       LDST0(V1, R1)                                           \
+       LDST0(V1, R2)                                           \
+       LDST0(V2, R0)                                           \
+       LDST0(V2, R1)                                           \
+       LDST0(V2, R2)
+
+.code
+       prolog
+
+       /* Simple test to simplify validating encodings before
+        * brute force tests */
+       movi %r0 $(t0 + $offc)
+       movi %r1 0x81
+       str_c %r0 %r1
+       movi %r0 $(t0 + $offuc)
+       str_c %r0 %r1
+       movi %r0 $(t0 + $offs)
+       movi %r1 0x8001
+       str_s %r0 %r1
+       movi %r0 $(t0 + $offus)
+       str_s %r0 %r1
+       movi %r0 $(t0 + $offi)
+       movi %r1 0x80000001
+       str_i %r0 %r1
+#if __WORDSIZE == 64
+       movi %r0 $(t0 + $offui)
+       str_i %r0 %r1
+       movi %r0 $(t0 + $offl)
+       movi %r1 0x8000000000000001
+       str_l %r0 %r1
+#endif
+       movi %r0 $(t0 + $offc)
+       ldr_c %r0 %r0
+       beqi Lc %r0 XC
+       calli @abort
+Lc:
+       movi %r0 $(t0 + $offuc)
+       ldr_uc %r0 %r0
+       beqi Luc %r0 0x81
+       calli @abort
+Luc:
+       movi %r0 $(t0 + $offs)
+       ldr_s %r0 %r0
+       beqi Ls %r0 XS
+       calli @abort
+Ls:
+       movi %r0 $(t0 + $offus)
+       ldr_us %r0 %r0
+       beqi Lus %r0 0x8001
+       calli @abort
+Lus:
+       movi %r0 $(t0 + $offi)
+       ldr_i %r0 %r0
+       beqi Li %r0 XI
+       calli @abort
+Li:
+#if __WORDSIZE == 64
+       movi %r0 $(t0 + $offui)
+       ldr_ui %r0 %r0
+       beqi Lui %r0 0x80000001
+       calli @abort
+Lui:
+       movi %r0 $(t0 + $offl)
+       ldr_l %r0 %r0
+       beqi Ll %r0 0x8000000000000001
+       calli @abort
+Ll:
+#endif
+
+       LDST(v0, v1, v2, r0, r1, r2)
+       // just to know did not abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/ldstr.ok b/deps/lightning/check/ldstr.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/ldstr.tst b/deps/lightning/check/ldstr.tst
new file mode 100644 (file)
index 0000000..1ed26b1
--- /dev/null
@@ -0,0 +1,183 @@
+#include "ldst.inc"
+
+#if __WORDSIZE == 64
+#  define LDSTL(N, R0, R1)                                     \
+       movi %R0 $(t0 + $offui)                                 \
+       str_i %R0 %R1                                           \
+       movi %R0 $(t0 + $offl)                                  \
+       movi %R1 L##N                                           \
+       str_l %R0 %R1
+
+#  define SI(C, N, x, X, R0, R1)                               \
+       movi %R0 $(t0 + $off##x)                                \
+       ldr_##x %R1 %R0                                         \
+       beqi L##x##C %R1 L##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1)                                   \
+       UI(C, N, i, I, R0, R1)                                  \
+       SI(C, N, l, L, R0, R1)
+#else
+#  define LDSTL(C, R0, R1)
+#  define SI(C, N, x, X, R0, R1)                               \
+       movi %R0 $(t0 + $off##x)                                \
+       ldr_##x %R1 %R0                                         \
+       beqi L##x##C %R1 I##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1)
+
+#endif
+
+#define UI(C, N, x, X, R0, R1)                                 \
+       movi %R0 $(t0 + $offu##x)                               \
+       ldr_u##x %R1 %R0                                        \
+       beqi Lu##x##C %R1 X##N                                  \
+       calli @abort                                            \
+Lu##x##C:
+
+#define FF(C, N, x, X, R0, F0)                                 \
+       movi %R0 $(t0 + $off##x)                                \
+       ldr_##x %F0 %R0                                         \
+       beqi_##x L##x##C %F0 X##N                               \
+L##x##C:
+
+#define LDST1(X, N, R0, R1, F0)                                        \
+       movi %R0 $(t0 + $offc)                                  \
+       movi %R1 C##N                                           \
+       str_c %R0 %R1                                           \
+       movi %R0 $(t0 + $offuc)                                 \
+       str_c %R0 %R1                                           \
+       movi %R0 $(t0 + $offs)                                  \
+       movi %R1 S##N                                           \
+       str_s %R0 %R1                                           \
+       movi %R0 $(t0 + $offus)                                 \
+       str_s %R0 %R1                                           \
+       movi %R0 $(t0 + $offi)                                  \
+       movi %R1 I##N                                           \
+       str_i %R0 %R1                                           \
+       LDSTL(N, R0, R1)                                        \
+       movi %R0 $(t0 + $offf)                                  \
+       movi_f %F0 F##N                                         \
+       str_f %R0 %F0                                           \
+       movi %R0 $(t0 + $offd)                                  \
+       movi_d %F0 D##N                                         \
+       str_d %R0 %F0                                           \
+       SI(X, N, c, C, R0, R1)                                  \
+       UI(X, N, c, C, R0, R1)                                  \
+       SI(X, N, s, S, R0, R1)                                  \
+       UI(X, N, s, S, R0, R1)                                  \
+       SI(X, N, i, I, R0, R1)                                  \
+       LDRL(X, N, R0, R1)                                      \
+       FF(X, N, f, F, R0, F0)                                  \
+       FF(X, N, d, D, R0, F0)
+
+#define LDST0(R0, R1, F0)                                      \
+       LDST1(0_##R0##_##R1##_##F0, 0, R0, R1, F0)              \
+       LDST1(1_##R0##_##R1##_##F0, 1, R0, R1, F0)              \
+       LDST1(2_##R0##_##R1##_##F0, 2, R0, R1, F0)              \
+       LDST1(3_##R0##_##R1##_##F0, 3, R0, R1, F0)
+
+#define LDST(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)   \
+       LDST0(V0, V1, F0)                                       \
+       LDST0(V0, V2, F1)                                       \
+       LDST0(V0, R0, F3)                                       \
+       LDST0(V0, R1, F4)                                       \
+       LDST0(V0, R2, F5)                                       \
+       LDST0(V1, V2, F0)                                       \
+       LDST0(V1, R0, F1)                                       \
+       LDST0(V1, R1, F2)                                       \
+       LDST0(V1, R2, F3)                                       \
+       LDST0(V2, R0, F4)                                       \
+       LDST0(V2, R1, F5)                                       \
+       LDST0(V2, R2, F0)
+
+.code
+       prolog
+
+       /* Simple test to simplify validating encodings before
+        * brute force tests */
+       movi %r0 $(t0 + $offc)
+       movi %r1 0x81
+       str_c %r0 %r1
+       movi %r0 $(t0 + $offuc)
+       str_c %r0 %r1
+       movi %r0 $(t0 + $offs)
+       movi %r1 0x8001
+       str_s %r0 %r1
+       movi %r0 $(t0 + $offus)
+       str_s %r0 %r1
+       movi %r0 $(t0 + $offi)
+       movi %r1 0x80000001
+       str_i %r0 %r1
+#if __WORDSIZE == 64
+       movi %r0 $(t0 + $offui)
+       str_i %r0 %r1
+       movi %r0 $(t0 + $offl)
+       movi %r1 0x8000000000000001
+       str_l %r0 %r1
+#endif
+       movi %r0 $(t0 + $offf)
+       movi_f %f0 0.5
+       str_f %r0 %f0
+       movi %r0 $(t0 + $offd)
+       movi_d %f0 0.25
+       str_d %r0 %f0
+       movi %r0 $(t0 + $offc)
+       ldr_c %r1 %r0
+       beqi Lc %r1 XC
+       calli @abort
+Lc:
+       movi %r0 $(t0 + $offuc)
+       ldr_uc %r1 %r0
+       beqi Luc %r1 0x81
+       calli @abort
+Luc:
+       movi %r0 $(t0 + $offs)
+       ldr_s %r1 %r0
+       beqi Ls %r1 XS
+       calli @abort
+Ls:
+       movi %r0 $(t0 + $offus)
+       ldr_us %r1 %r0
+       beqi Lus %r1 0x8001
+       calli @abort
+Lus:
+       movi %r0 $(t0 + $offi)
+       ldr_i %r1 %r0
+       beqi Li %r1 XI
+       calli @abort
+Li:
+#if __WORDSIZE == 64
+       movi %r0 $(t0 + $offui)
+       ldr_ui %r1 %r0
+       beqi Lui %r1 0x80000001
+       calli @abort
+Lui:
+       movi %r0 $(t0 + $offl)
+       ldr_l %r1 %r0
+       beqi Ll %r1 0x8000000000000001
+       calli @abort
+Ll:
+#endif
+       movi %r0 $(t0 + $offf)
+       ldr_f %f0 %r0
+       beqi_f Lf %f0 0.5
+       calli @abort
+Lf:
+       movi %r0 $(t0 + $offd)
+       ldr_d %f0 %r0
+       beqi_d Ld %f0 0.25
+       calli @abort
+Ld:
+
+       LDST(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+       // just to know did not abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/ldstxi-c.ok b/deps/lightning/check/ldstxi-c.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/ldstxi-c.tst b/deps/lightning/check/ldstxi-c.tst
new file mode 100644 (file)
index 0000000..1ad0168
--- /dev/null
@@ -0,0 +1,158 @@
+#include "ldst.inc"
+
+#if __WORDSIZE == 64
+#  define LDSTL(N, R0, R1)                                     \
+       stxi_i $offui %R0 %R1                                   \
+       movi %R1 L##N                                           \
+       stxi_l $offl %R0 %R1
+
+#  define SI(C, N, x, X, R0)                                   \
+       ldxi_##x %R0 %R0 $off##x                                \
+       beqi L##x##C %R0 L##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1)                                   \
+       UI(C, N, i, I, R0)                                      \
+       movi %R0 t0                                             \
+       SI(C, N, l, L, R0)
+#else
+#  define LDSTL(C, R0, R1)
+#  define SI(C, N, x, X, R0)                                   \
+       ldxi_##x %R0 %R0 $off##x                                \
+       beqi L##x##C %R0 I##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1)
+
+#endif
+
+#define UI(C, N, x, X, R0)                                     \
+       ldxi_u##x %R0 %R0 $offu##x                              \
+       beqi Lu##x##C %R0 X##N                                  \
+       calli @abort                                            \
+Lu##x##C:
+
+#define LDST1(X, N, R0, R1)                                    \
+       movi %R0 t0                                             \
+       movi %R1 C##N                                           \
+       stxi_c $offc %R0 %R1                                    \
+       stxi_c $offuc %R0 %R1                                   \
+       movi %R1 S##N                                           \
+       stxi_s $offs %R0 %R1                                    \
+       stxi_s $offus %R0 %R1                                   \
+       movi %R1 I##N                                           \
+       stxi_i $offi %R0 %R1                                    \
+       LDSTL(N, R0, R1)                                        \
+       SI(X, N, c, C, R0)                                      \
+       movi %R0 t0                                             \
+       UI(X, N, c, C, R0)                                      \
+       movi %R0 t0                                             \
+       SI(X, N, s, S, R0)                                      \
+       movi %R0 t0                                             \
+       UI(X, N, s, S, R0)                                      \
+       movi %R0 t0                                             \
+       SI(X, N, i, I, R0)                                      \
+       movi %R0 t0                                             \
+       LDRL(X, N, R0, R1)                                      \
+
+#define LDST0(R0, R1)                                          \
+       LDST1(0_##R0##_##R1, 0, R0, R1)                         \
+       LDST1(1_##R0##_##R1, 1, R0, R1)                         \
+       LDST1(2_##R0##_##R1, 2, R0, R1)                         \
+       LDST1(3_##R0##_##R1, 3, R0, R1)
+
+#define LDST(V0, V1, V2, R0, R1, R2)                           \
+       LDST0(V0, V1)                                           \
+       LDST0(V0, V2)                                           \
+       LDST0(V0, R0)                                           \
+       LDST0(V0, R1)                                           \
+       LDST0(V0, R2)                                           \
+       LDST0(V1, V2)                                           \
+       LDST0(V1, R0)                                           \
+       LDST0(V1, R1)                                           \
+       LDST0(V1, R2)                                           \
+       LDST0(V2, R0)                                           \
+       LDST0(V2, R1)                                           \
+       LDST0(V2, R2)                                           \
+       LDST0(R0, V0)                                           \
+       LDST0(R0, V1)                                           \
+       LDST0(R0, V2)                                           \
+       LDST0(R0, R1)                                           \
+       LDST0(R0, R2)                                           \
+       LDST0(R1, V0)                                           \
+       LDST0(R1, V1)                                           \
+       LDST0(R1, V2)                                           \
+       LDST0(R1, R0)                                           \
+       LDST0(R1, R2)                                           \
+       LDST0(R2, V0)                                           \
+       LDST0(R2, V1)                                           \
+       LDST0(R2, V2)                                           \
+       LDST0(R2, R0)                                           \
+       LDST0(R2, R1)
+
+.code
+       prolog
+
+       /* Simple test to simplify validating encodings before
+        * brute force tests */
+       movi %r0 t0
+       movi %r1 0x81
+       stxi_c $offc %r0 %r1
+       stxi_c $offuc %r0 %r1
+       movi %r1 0x8001
+       stxi_s $offs %r0 %r1
+       stxi_s $offus %r0 %r1
+       movi %r1 0x80000001
+       stxi_i $offi %r0 %r1
+#if __WORDSIZE == 64
+       stxi_i $offui %r0 %r1
+       movi %r1 0x8000000000000001
+       stxi_l $offl %r0 %r1
+#endif
+       ldxi_c %r0 %r0 $offc
+       beqi Lc %r0 XC
+       calli @abort
+Lc:
+       movi %r0 t0
+       ldxi_uc %r0 %r0 $offuc
+       beqi Luc %r0 0x81
+       calli @abort
+Luc:
+       movi %r0 t0
+       ldxi_s %r0 %r0 $offs
+       beqi Ls %r0 XS
+       calli @abort
+Ls:
+       movi %r0 t0
+       ldxi_us %r0 %r0 $offus
+       beqi Lus %r0 0x8001
+       calli @abort
+Lus:
+       movi %r0 t0
+       ldxi_i %r0 %r0 $offi
+       beqi Li %r0 XI
+       calli @abort
+Li:
+#if __WORDSIZE == 64
+       movi %r0 t0
+       ldxi_ui %r0 %r0 $offui
+       beqi Lui %r0 0x80000001
+       calli @abort
+Lui:
+       movi %r0 t0
+       ldxi_l %r0 %r0 $offl
+       beqi Ll %r0 0x8000000000000001
+       calli @abort
+Ll:
+#endif
+
+       LDST(v0, v1, v2, r0, r1, r2)
+       // just to know did not abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/ldstxi.ok b/deps/lightning/check/ldstxi.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/ldstxi.tst b/deps/lightning/check/ldstxi.tst
new file mode 100644 (file)
index 0000000..574521a
--- /dev/null
@@ -0,0 +1,154 @@
+#include "ldst.inc"
+
+#if __WORDSIZE == 64
+#  define LDSTL(N, R0, R1)                                     \
+       stxi_i $offui %R0 %R1                                   \
+       movi %R1 L##N                                           \
+       stxi_l $offl %R0 %R1
+
+#  define SI(C, N, x, X, R0, R1)                               \
+       ldxi_##x %R1 %R0 $off##x                                \
+       beqi L##x##C %R1 L##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1)                                   \
+       UI(C, N, i, I, R0, R1)                                  \
+       SI(C, N, l, L, R0, R1)
+#else
+#  define LDSTL(C, R0, R1)
+#  define SI(C, N, x, X, R0, R1)                               \
+       ldxi_##x %R1 %R0 $off##x                                \
+       beqi L##x##C %R1 I##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1)
+
+#endif
+
+#define UI(C, N, x, X, R0, R1)                                 \
+       ldxi_u##x %R1 %R0 $offu##x                              \
+       beqi Lu##x##C %R1 X##N                                  \
+       calli @abort                                            \
+Lu##x##C:
+
+#define FF(C, N, x, X, R0, F0)                                 \
+       ldxi_##x %F0 %R0 $off##x                                \
+       beqi_##x L##x##C %F0 X##N                               \
+L##x##C:
+
+#define LDST1(X, N, R0, R1, F0)                                        \
+       movi %R0 t0                                             \
+       movi %R1 C##N                                           \
+       stxi_c $offc %R0 %R1                                    \
+       stxi_c $offuc %R0 %R1                                   \
+       movi %R1 S##N                                           \
+       stxi_s $offs %R0 %R1                                    \
+       stxi_s $offus %R0 %R1                                   \
+       movi %R1 I##N                                           \
+       stxi_i $offi %R0 %R1                                    \
+       LDSTL(N, R0, R1)                                        \
+       movi_f %F0 F##N                                         \
+       stxi_f $offf %R0 %F0                                    \
+       movi_d %F0 D##N                                         \
+       stxi_d $offd %R0 %F0                                    \
+       SI(X, N, c, C, R0, R1)                                  \
+       UI(X, N, c, C, R0, R1)                                  \
+       SI(X, N, s, S, R0, R1)                                  \
+       UI(X, N, s, S, R0, R1)                                  \
+       SI(X, N, i, I, R0, R1)                                  \
+       LDRL(X, N, R0, R1)                                      \
+       FF(X, N, f, F, R0, F0)                                  \
+       FF(X, N, d, D, R0, F0)
+
+#define LDST0(R0, R1, F0)                                      \
+       LDST1(0_##R0##_##R1##_##F0, 0, R0, R1, F0)              \
+       LDST1(1_##R0##_##R1##_##F0, 1, R0, R1, F0)              \
+       LDST1(2_##R0##_##R1##_##F0, 2, R0, R1, F0)              \
+       LDST1(3_##R0##_##R1##_##F0, 3, R0, R1, F0)
+
+#define LDST(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)   \
+       LDST0(V0, V1, F0)                                       \
+       LDST0(V0, V2, F1)                                       \
+       LDST0(V0, R0, F3)                                       \
+       LDST0(V0, R1, F4)                                       \
+       LDST0(V0, R2, F5)                                       \
+       LDST0(V1, V2, F0)                                       \
+       LDST0(V1, R0, F1)                                       \
+       LDST0(V1, R1, F2)                                       \
+       LDST0(V1, R2, F3)                                       \
+       LDST0(V2, R0, F4)                                       \
+       LDST0(V2, R1, F5)                                       \
+       LDST0(V2, R2, F0)
+
+.code
+       prolog
+
+       /* Simple test to simplify validating encodings before
+        * brute force tests */
+       movi %r0 t0
+       movi %r1 0x81
+       stxi_c $offc %r0 %r1
+       stxi_c $offuc %r0 %r1
+       movi %r1 0x8001
+       stxi_s $offs %r0 %r1
+       stxi_s $offus %r0 %r1
+       movi %r1 0x80000001
+       stxi_i $offi %r0 %r1
+#if __WORDSIZE == 64
+       stxi_i $offui %r0 %r1
+       movi %r1 0x8000000000000001
+       stxi_l $offl %r0 %r1
+#endif
+       movi_f %f0 0.5
+       stxi_f $offf %r0 %f0
+       movi_d %f0 0.25
+       stxi_d $offd %r0 %f0
+       ldxi_c %r1 %r0 $offc
+       beqi Lc %r1 XC
+       calli @abort
+Lc:
+       ldxi_uc %r1 %r0 $offuc
+       beqi Luc %r1 0x81
+       calli @abort
+Luc:
+       ldxi_s %r1 %r0 $offs
+       beqi Ls %r1 XS
+       calli @abort
+Ls:
+       ldxi_us %r1 %r0 $offus
+       beqi Lus %r1 0x8001
+       calli @abort
+Lus:
+       ldxi_i %r1 %r0 $offi
+       beqi Li %r1 XI
+       calli @abort
+Li:
+#if __WORDSIZE == 64
+       ldxi_ui %r1 %r0 $offui
+       beqi Lui %r1 0x80000001
+       calli @abort
+Lui:
+       ldxi_l %r1 %r0 $offl
+       beqi Ll %r1 0x8000000000000001
+       calli @abort
+Ll:
+#endif
+       ldxi_f %f0 %r0 $offf
+       beqi_f Lf %f0 0.5
+       calli @abort
+Lf:
+       ldxi_d %f0 %r0 $offd
+       beqi_d Ld %f0 0.25
+       calli @abort
+Ld:
+
+       LDST(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+       // just to know did not abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/ldstxr-c.ok b/deps/lightning/check/ldstxr-c.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/ldstxr-c.tst b/deps/lightning/check/ldstxr-c.tst
new file mode 100644 (file)
index 0000000..cd770a6
--- /dev/null
@@ -0,0 +1,219 @@
+#include "ldst.inc"
+
+#if __WORDSIZE == 64
+#  define LDSTL(N, R0, R1, R2)                                 \
+       movi %R2 $offui                                         \
+       stxr_i %R2 %R0 %R1                                      \
+       movi %R1 L##N                                           \
+       movi %R2 $offl                                          \
+       stxr_l %R2 %R0 %R1
+
+#  define SI(C, N, x, X, R0, R1)                               \
+       movi %R1 $off##x                                        \
+       ldxr_##x %R1 %R0 %R1                                    \
+       beqi L##x##C##0 %R1 L##X##N                             \
+       calli @abort                                            \
+L##x##C##0:                                                    \
+       movi %R1 $off##x                                        \
+       ldxr_##x %R0 %R0 %R1                                    \
+       beqi L##x##C##1 %R0 L##X##N                             \
+       calli @abort                                            \
+L##x##C##1:
+
+#  define LDRL(C, N, R0, R1, R2)                               \
+       UI(C, N, i, I, R0, R1)                                  \
+       movi %R0 t0                                             \
+       SI(C, N, l, L, R0, R1)
+#else
+#  define LDSTL(C, R0, R1, R2)
+#  define SI(C, N, x, X, R0, R1)                               \
+       movi %R1 $off##x                                        \
+       ldxr_##x %R1 %R0 %R1                                    \
+       beqi L##x##C##0 %R1 I##X##N                             \
+       calli @abort                                            \
+L##x##C##0:                                                    \
+       movi %R1 $off##x                                        \
+       ldxr_##x %R0 %R0 %R1                                    \
+       beqi L##x##C##1 %R0 I##X##N                             \
+       calli @abort                                            \
+L##x##C##1:
+
+#  define LDRL(C, N, R0, R1, R2)
+
+#endif
+
+#define UI(C, N, x, X, R0, R1)                                 \
+       movi %R1 $offu##x                                       \
+       ldxr_u##x %R1 %R0 %R1                                   \
+       beqi Lu##x##C##0 %R1 X##N                               \
+       calli @abort                                            \
+Lu##x##C##0:                                                   \
+       movi %R1 $offu##x                                       \
+       ldxr_u##x %R0 %R0 %R1                                   \
+       beqi Lu##x##C##1 %R0 X##N                               \
+       calli @abort                                            \
+Lu##x##C##1:
+
+#define LDST1(X, N, R0, R1, R2)                                        \
+       movi %R0 t0                                             \
+       movi %R1 C##N                                           \
+       movi %R2 $offc                                          \
+       stxr_c %R2 %R0 %R1                                      \
+       movi %R2 $offuc                                         \
+       stxr_c %R2 %R0 %R1                                      \
+       movi %R1 S##N                                           \
+       movi %R2 $offs                                          \
+       stxr_s %R2 %R0 %R1                                      \
+       movi %R2 $offus                                         \
+       stxr_s %R2 %R0 %R1                                      \
+       movi %R1 I##N                                           \
+       movi %R2 $offi                                          \
+       stxr_i %R2 %R0 %R1                                      \
+       LDSTL(N, R0, R1, R2)                                    \
+       SI(X, N, c, C, R0, R1)                                  \
+       movi %R0 t0                                             \
+       UI(X, N, c, C, R0, R1)                                  \
+       movi %R0 t0                                             \
+       SI(X, N, s, S, R0, R1)                                  \
+       movi %R0 t0                                             \
+       UI(X, N, s, S, R0, R1)                                  \
+       movi %R0 t0                                             \
+       SI(X, N, i, I, R0, R1)                                  \
+       movi %R0 t0                                             \
+       LDRL(X, N, R0, R1, R2)                                  \
+
+#define LDST0(R0, R1, R2)                                      \
+       LDST1(0_##R0##_##R1##_##R2, 0, R0, R1, R2)              \
+       LDST1(1_##R0##_##R1##_##R2, 1, R0, R1, R2)              \
+       LDST1(2_##R0##_##R1##_##R2, 2, R0, R1, R2)              \
+       LDST1(3_##R0##_##R1##_##R2, 3, R0, R1, R2)
+
+#define LDST(V0, V1, V2, R0, R1, R2)                           \
+       LDST0(V1, V2, V0)                                       \
+       LDST0(V1, R0, V0)                                       \
+       LDST0(V1, R1, V0)                                       \
+       LDST0(V1, R2, V0)                                       \
+       LDST0(V0, R0, V1)                                       \
+       LDST0(V0, R1, V1)                                       \
+       LDST0(V0, R2, V1)                                       \
+       LDST0(V0, V2, V1)                                       \
+       LDST0(V2, V0, V1)                                       \
+       LDST0(V2, R0, V1)                                       \
+       LDST0(V2, R1, V1)                                       \
+       LDST0(V2, R2, V1)                                       \
+       LDST0(R0, R1, V2)                                       \
+       LDST0(R0, R2, V2)
+
+.code
+       prolog
+
+       /* Simple test to simplify validating encodings before
+        * brute force tests */
+       movi %r0 t0
+       movi %r1 0x81
+       movi %r2 $offc
+       stxr_c %r2 %r0 %r1
+       movi %r2 $offuc
+       stxr_c %r2 %r0 %r1
+       movi %r1 0x8001
+       movi %r2 $offs
+       stxr_s %r2 %r0 %r1
+       movi %r2 $offus
+       stxr_s %r2 %r0 %r1
+       movi %r1 0x80000001
+       movi %r2 $offi
+       stxr_i %r2 %r0 %r1
+#if __WORDSIZE == 64
+       movi %r2 $offui
+       stxr_i %r2 %r0 %r1
+       movi %r1 0x8000000000000001
+       movi %r2 $offl
+       stxr_l %r2 %r0 %r1
+#endif
+       movi %r1 $offc
+       ldxr_c %r1 %r0 %r1
+       beqi Lc0 %r1 XC
+       calli @abort
+Lc0:
+       movi %r1 $offc
+       ldxr_c %r0 %r0 %r1
+       beqi Lc1 %r0 XC
+       calli @abort
+Lc1:
+       movi %r0 t0
+       movi %r1 $offuc
+       ldxr_uc %r1 %r0 %r1
+       beqi Luc0 %r1 0x81
+       calli @abort
+Luc0:
+       movi %r1 $offuc
+       ldxr_uc %r0 %r0 %r1
+       beqi Luc1 %r0 0x81
+       calli @abort
+Luc1:
+       movi %r0 t0
+       movi %r1 $offs
+       ldxr_s %r1 %r0 %r1
+       beqi Ls0 %r1 XS
+       calli @abort
+Ls0:
+       movi %r1 $offs
+       ldxr_s %r0 %r0 %r1
+       beqi Ls1 %r0 XS
+       calli @abort
+Ls1:
+       movi %r0 t0
+       movi %r1 $offus
+       ldxr_us %r1 %r0 %r1
+       beqi Lus0 %r1 0x8001
+       calli @abort
+Lus0:
+       movi %r1 $offus
+       ldxr_us %r0 %r0 %r1
+       beqi Lus1 %r0 0x8001
+       calli @abort
+Lus1:
+       movi %r0 t0
+       movi %r1 $offi
+       ldxr_i %r1 %r0 %r1
+       beqi Li0 %r1 XI
+       calli @abort
+Li0:
+       movi %r1 $offi
+       ldxr_i %r0 %r0 %r1
+       beqi Li1 %r0 XI
+       calli @abort
+Li1:
+#if __WORDSIZE == 64
+       movi %r0 t0
+       movi %r1 $offui
+       ldxr_ui %r1 %r0 %r1
+       beqi Lui0 %r1 0x80000001
+       calli @abort
+Lui0:
+       movi %r1 $offui
+       ldxr_ui %r0 %r0 %r1
+       beqi Lui1 %r0 0x80000001
+       calli @abort
+Lui1:
+       movi %r0 t0
+       movi %r1 $offl
+       ldxr_l %r1 %r0 %r1
+       beqi Ll0 %r1 0x8000000000000001
+       calli @abort
+Ll0:
+       movi %r1 $offl
+       ldxr_l %r0 %r0 %r1
+       beqi Ll1 %r0 0x8000000000000001
+       calli @abort
+Ll1:
+#endif
+
+       LDST(v0, v1, v2, r0, r1, r2)
+       // just to know did not abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/ldstxr.ok b/deps/lightning/check/ldstxr.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/ldstxr.tst b/deps/lightning/check/ldstxr.tst
new file mode 100644 (file)
index 0000000..14620dc
--- /dev/null
@@ -0,0 +1,209 @@
+#include "ldst.inc"
+
+#if __WORDSIZE == 64
+#  define LDSTL(N, R0, R1, R2)                                 \
+       movi %R2 $offui                                         \
+       stxr_i %R2 %R0 %R1                                      \
+       movi %R1 L##N                                           \
+       movi %R2 $offl                                          \
+       stxr_l %R2 %R0 %R1
+
+#  define SI(C, N, x, X, R0, R1, R2)                           \
+       movi %R2 $off##x                                        \
+       ldxr_##x %R1 %R0 %R2                                    \
+       beqi L##x##C %R1 L##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1, R2)                               \
+       UI(C, N, i, I, R0, R1, R2)                              \
+       SI(C, N, l, L, R0, R1, R2)
+#else
+#  define LDSTL(C, R0, R1, R2)
+#  define SI(C, N, x, X, R0, R1, R2)                           \
+       movi %R2 $off##x                                        \
+       ldxr_##x %R1 %R0 %R2                                    \
+       beqi L##x##C %R1 I##X##N                                \
+       calli @abort                                            \
+L##x##C:
+
+#  define LDRL(C, N, R0, R1, R2)
+
+#endif
+
+#define UI(C, N, x, X, R0, R1, R2)                             \
+       movi %R2 $offu##x                                       \
+       ldxr_u##x %R1 %R0 %R2                                   \
+       beqi Lu##x##C %R1 X##N                                  \
+       calli @abort                                            \
+Lu##x##C:
+
+#define FF(C, N, x, X, R0, R1, F0)                             \
+       movi %R1 $off##x                                        \
+       ldxr_##x %F0 %R0 %R1                                    \
+       beqi_##x L##x##C %F0 X##N                               \
+L##x##C:
+
+#define LDST1(X, N, R0, R1, R2, F0)                            \
+       movi %R0 t0                                             \
+       movi %R1 C##N                                           \
+       movi %R2 $offc                                          \
+       stxr_c %R2 %R0 %R1                                      \
+       movi %R2 $offuc                                         \
+       stxr_c %R2 %R0 %R1                                      \
+       movi %R1 S##N                                           \
+       movi %R2 $offs                                          \
+       stxr_s %R2 %R0 %R1                                      \
+       movi %R2 $offus                                         \
+       stxr_s %R2 %R0 %R1                                      \
+       movi %R1 I##N                                           \
+       movi %R2 $offi                                          \
+       stxr_i %R2 %R0 %R1                                      \
+       LDSTL(N, R0, R1, R2)                                    \
+       movi_f %F0 F##N                                         \
+       movi %R2 $offf                                          \
+       stxr_f %R2 %R0 %F0                                      \
+       movi_d %F0 D##N                                         \
+       movi %R2 $offd                                          \
+       stxr_d %R2 %R0 %F0                                      \
+       SI(X, N, c, C, R0, R1, R2)                              \
+       UI(X, N, c, C, R0, R1, R2)                              \
+       SI(X, N, s, S, R0, R1, R2)                              \
+       UI(X, N, s, S, R0, R1, R2)                              \
+       SI(X, N, i, I, R0, R1, R2)                              \
+       LDRL(X, N, R0, R1, R2)                                  \
+       FF(X, N, f, F, R0, R1, F0)                              \
+       FF(X, N, d, D, R0, R1, F0)
+
+#define LDST0(R0, R1, R2, F0)                                  \
+       LDST1(0_##R0##_##R1##_##R2##_##F0, 0, R0, R1, R2, F0)   \
+       LDST1(1_##R0##_##R1##_##R2##_##F0, 1, R0, R1, R2, F0)   \
+       LDST1(2_##R0##_##R1##_##R2##_##F0, 2, R0, R1, R2, F0)   \
+       LDST1(3_##R0##_##R1##_##R2##_##F0, 3, R0, R1, R2, F0)
+
+#define LDST(V0, V1, V2, R0, R1, R2, F0, F1, F2, F3, F4, F5)   \
+       LDST0(V0, V1, R0, F0)                                   \
+       LDST0(V0, V1, R1, F1)                                   \
+       LDST0(V0, V1, R2, F2)                                   \
+       LDST0(V0, V2, R0, F3)                                   \
+       LDST0(V0, V2, R1, F4)                                   \
+       LDST0(V0, V2, R2, F5)                                   \
+       LDST0(V0, R0, V1, F0)                                   \
+       LDST0(V0, R0, V2, F1)                                   \
+       LDST0(V0, R0, R1, F2)                                   \
+       LDST0(V0, R0, R2, F3)                                   \
+       LDST0(V0, R0, V1, F4)                                   \
+       LDST0(V0, R1, V1, F5)                                   \
+       LDST0(V0, R1, V2, F0)                                   \
+       LDST0(V0, R1, R0, F1)                                   \
+       LDST0(V0, R1, R2, F2)                                   \
+       LDST0(V0, V1, V2, F3)                                   \
+       LDST0(V0, R1, R0, F4)                                   \
+       LDST0(V0, R1, R2, F5)                                   \
+       LDST0(R0, V1, V0, F0)                                   \
+       LDST0(R0, V1, R1, F1)                                   \
+       LDST0(R0, V1, R2, F2)                                   \
+       LDST0(R0, V2, V0, F3)                                   \
+       LDST0(R0, V2, R1, F4)                                   \
+       LDST0(R0, V2, R2, F5)                                   \
+       LDST0(R0, V0, V1, F0)                                   \
+       LDST0(R0, V0, V2, F1)                                   \
+       LDST0(R0, V0, R1, F2)                                   \
+       LDST0(R0, V0, R2, F3)                                   \
+       LDST0(R0, V0, V1, F4)                                   \
+       LDST0(R0, R1, V1, F5)                                   \
+       LDST0(R0, R1, V2, F0)                                   \
+       LDST0(R0, R1, V0, F1)                                   \
+       LDST0(R0, R1, R2, F2)                                   \
+       LDST0(R0, V1, V2, F3)                                   \
+       LDST0(R0, R1, V0, F4)                                   \
+       LDST0(R0, R1, R2, F5)
+
+.code
+       prolog
+
+       /* Simple test to simplify validating encodings before
+        * brute force tests */
+       movi %r0 t0
+       movi %r1 0x81
+       movi %r2 $offc
+       stxr_c %r2 %r0 %r1
+       movi %r2 $offuc
+       stxr_c %r2 %r0 %r1
+       movi %r1 0x8001
+       movi %r2 $offs
+       stxr_s %r2 %r0 %r1
+       movi %r2 $offus
+       stxr_s %r2 %r0 %r1
+       movi %r1 0x80000001
+       movi %r2 $offi
+       stxr_i %r2 %r0 %r1
+#if __WORDSIZE == 64
+       movi %r2 $offui
+       stxr_i %r2 %r0 %r1
+       movi %r1 0x8000000000000001
+       movi %r2 $offl
+       stxr_l %r2 %r0 %r1
+#endif
+       movi_f %f0 0.5
+       movi %r2 $offf
+       stxr_f %r2 %r0 %f0
+       movi_d %f0 0.25
+       movi %r2 $offd
+       stxr_d %r2 %r0 %f0
+       movi %r2 $offc
+       ldxr_c %r1 %r0 %r2
+       beqi Lc %r1 XC
+       calli @abort
+Lc:
+       movi %r2 $offuc
+       ldxr_uc %r1 %r0 %r2
+       beqi Luc %r1 0x81
+       calli @abort
+Luc:
+       movi %r2 $offs
+       ldxr_s %r1 %r0 %r2
+       beqi Ls %r1 XS
+       calli @abort
+Ls:
+       movi %r2 $offus
+       ldxr_us %r1 %r0 %r2
+       beqi Lus %r1 0x8001
+       calli @abort
+Lus:
+       movi %r2 $offi
+       ldxr_i %r1 %r0 %r2
+       beqi Li %r1 XI
+       calli @abort
+Li:
+#if __WORDSIZE == 64
+       movi %r2 $offui
+       ldxr_ui %r1 %r0 %r2
+       beqi Lui %r1 0x80000001
+       calli @abort
+Lui:
+       movi %r2 $offl
+       ldxr_l %r1 %r0 %r2
+       beqi Ll %r1 0x8000000000000001
+       calli @abort
+Ll:
+#endif
+       movi %r2 $offf
+       ldxr_f %f0 %r0 %r2
+       beqi_f Lf %f0 0.5
+       calli @abort
+Lf:
+       movi %r2 $offd
+       ldxr_d %f0 %r0 %r2
+       beqi_d Ld %f0 0.25
+       calli @abort
+Ld:
+
+       LDST(v0, v1, v2, r0, r1, r2, f0, f1, f2, f3, f4, f5)
+       // just to know did not abort
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/lightning.c b/deps/lightning/check/lightning.c
new file mode 100644 (file)
index 0000000..e60ef05
--- /dev/null
@@ -0,0 +1,4329 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if HAVE_GETOPT_H
+#  include <getopt.h>
+#else
+#  include <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdarg.h>
+#include <lightning.h>
+#include <dlfcn.h>
+
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
+#  include <fpu_control.h>
+#endif
+
+/* The label_t identifier clashes with a system definitions */
+#if defined(_AIX) || defined(__sun__) || defined(__osf__)
+#  define label_t              l_label_t
+#endif
+
+#if defined(__hpux)
+#  define DL_HANDLE            RTLD_NEXT
+#elif defined(__sgi)
+static void                    *DL_HANDLE;
+#elif defined(__osf__)
+#  define DL_HANDLE            NULL
+#else
+#  define DL_HANDLE            RTLD_DEFAULT
+#endif
+
+#if defined(__GNUC__)
+#  define noreturn             __attribute__ ((noreturn))
+#  define printf_format(f, v)  __attribute__ ((format (printf, f, v)))
+#  define maybe_unused         __attribute__ ((unused))
+#else
+#  define noreturn             /**/
+#  define printf_format(f, v)  /**/
+#  define maybe_unused         /**/
+#endif
+
+#define check_data(length)                                             \
+    do {                                                               \
+       if (data_offset + length > data_length)                         \
+           error(".data too small (%ld < %ld)",                        \
+                 data_length, data_offset + length);                   \
+    } while (0)
+
+#define get_label_by_name(name)        ((label_t *)get_hash(labels, name))
+
+#define PARSING_NONE           0
+#define PARSING_DATA           1
+#define PARSING_CODE           2
+#define MAX_IDENTIFIER         256
+
+/*
+ * Types
+ */
+typedef struct instr             instr_t;
+typedef union value              value_t;
+typedef struct parser            parser_t;
+typedef struct label             label_t;
+typedef struct patch             patch_t;
+typedef struct symbol            symbol_t;
+typedef struct hash              hash_t;
+typedef struct entry             entry_t;
+typedef int                    (*function_t)(int argc, char *argv[]);
+
+typedef enum {
+    tok_eof = -1,
+    tok_symbol,
+    tok_char,
+    tok_int,
+    tok_float,
+    tok_pointer,
+    tok_string,
+    tok_register,
+    tok_dot,
+    tok_newline,
+    tok_semicollon,
+} token_t;
+
+typedef enum {
+    skip_none,
+    skip_ws,
+    skip_nl,
+} skip_t;
+
+typedef enum {
+    type_none,
+    type_c,
+    type_s,
+    type_i,
+    type_l,
+    type_f,
+    type_d,
+    type_p,
+} type_t;
+
+#define compose(a, b)          (((a) << 8) | b)
+typedef enum {
+    expr_inc    = compose('+', '+'),
+    expr_dec    = compose('-', '-'),
+    expr_not    = '!',
+    expr_com    = '~',
+    expr_mul    = '*',
+    expr_div    = '/',
+    expr_rem    = '%',
+    expr_add    = '+',
+    expr_sub    = '-',
+    expr_lsh    = compose('<', '<'),
+    expr_rsh    = compose('>', '>'),
+    expr_and    = '&',
+    expr_or     = '|',
+    expr_xor    = '^',
+    expr_set    = '=',
+    expr_mulset         = compose('*', '='),
+    expr_divset         = compose('/', '='),
+    expr_remset         = compose('%', '='),
+    expr_addset         = compose('+', '='),
+    expr_subset         = compose('-', '='),
+    expr_lshset         = compose(expr_lsh, '='),
+    expr_rshset         = compose(expr_rsh, '='),
+    expr_andset         = compose('&', '='),
+    expr_orset  = compose('|', '='),
+    expr_xorset         = compose('^', '='),
+    expr_lt     = '<',
+    expr_le     = compose('<', '='),
+    expr_eq     = compose('=', '='),
+    expr_ne     = compose('!', '='),
+    expr_gt     = '>',
+    expr_ge     = compose('>', '='),
+    expr_andand         = compose('&', '&'),
+    expr_oror   = compose('|', '|'),
+    expr_lparen         = '(',
+    expr_rparen         = ')',
+    expr_int    = '0',
+    expr_float  = '.',
+    expr_pointer = '@',
+    expr_symbol  = '$',
+} expr_t;
+#undef compose
+
+struct instr {
+    instr_t             *next;
+    const char          *name;
+    void               (*function)(void);
+    int                          flag;
+};
+
+union value {
+    jit_word_t          i;
+    jit_uword_t                 ui;
+    float               f;
+    double              d;
+    void               *p;
+    char               *cp;
+    label_t            *label;
+    patch_t            *patch;
+};
+
+struct parser {
+    FILE               *fp;
+    char                name[256];
+    int                         line;
+    int                         regval;
+    type_t              regtype;
+    expr_t              expr;
+    type_t              type;
+    value_t             value;
+
+    /* variable length string buffer */
+    char               *string;
+    int                         length;
+    int                         offset;
+
+    int                         newline;
+    expr_t              putback;
+    int                         short_circuit;
+    int                         parsing;
+
+    struct {
+       unsigned char    buffer[4096];
+       int              offset;
+       int              length;
+    } data;
+};
+
+typedef enum {
+    label_kind_data,
+    label_kind_code,
+    label_kind_code_forward,
+    label_kind_dynamic,
+} label_kind_t;
+
+struct hash {
+    entry_t            **entries;
+    int                          size;
+    int                          count;
+};
+
+struct entry {
+    entry_t             *next;
+    char                *name;
+    void                *value;
+    int                          flag;
+};
+
+struct label {
+    label_t            *next;
+    char               *name;
+    void               *value;
+    label_kind_t        kind;
+};
+
+typedef enum {
+    patch_kind_jmp,
+    patch_kind_mov,
+    patch_kind_call,
+} patch_kind_t;
+
+struct patch {
+    patch_t            *next;
+    label_t            *label;
+    void               *value;
+    patch_kind_t        kind;
+};
+
+/* minor support for expressions */
+struct symbol {
+    symbol_t           *next;
+    char               *name;
+    value_t             value;
+    type_t              type;
+};
+
+/*
+ * Prototypes
+ */
+static jit_gpr_t get_ireg(void);
+static jit_fpr_t get_freg(void);
+static symbol_t *get_symbol(void);
+static void jmp_forward(void *value, label_t *label);
+static void mov_forward(void *value, label_t *label);
+static void call_forward(void *value, label_t *label);
+static void make_arg(void *value);
+static jit_pointer_t get_arg(void);
+static jit_word_t get_imm(void);
+static void live(void);
+static void align(void);       static void name(void);
+static void prolog(void);
+static void frame(void);       static void tramp(void);
+static void ellipsis(void);
+static void allocai(void);     static void allocar(void);
+static void arg(void);
+static void getarg_c(void);    static void getarg_uc(void);
+static void getarg_s(void);    static void getarg_us(void);
+static void getarg_i(void);
+#if __WORDSIZE == 64
+static void getarg_ui(void);   static void getarg_l(void);
+#endif
+static void getarg(void);
+static void putargr(void);     static void putargi(void);
+static void addr(void);                static void addi(void);
+static void addxr(void);       static void addxi(void);
+static void addcr(void);       static void addci(void);
+static void subr(void);                static void subi(void);
+static void subxr(void);       static void subxi(void);
+static void subcr(void);       static void subci(void);
+static void rsbr(void);                static void rsbi(void);
+static void mulr(void);                static void muli(void);
+static void qmulr(void);       static void qmuli(void);
+static void qmulr_u(void);     static void qmuli_u(void);
+static void divr(void);                static void divi(void);
+static void divr_u(void);      static void divi_u(void);
+static void qdivr(void);       static void qdivi(void);
+static void qdivr_u(void);     static void qdivi_u(void);
+static void remr(void);                static void remi(void);
+static void remr_u(void);      static void remi_u(void);
+static void andr(void);                static void andi(void);
+static void orr(void);         static void ori(void);
+static void xorr(void);                static void xori(void);
+static void lshr(void);                static void lshi(void);
+static void rshr(void);                static void rshi(void);
+static void rshr_u(void);      static void rshi_u(void);
+static void negr(void);                static void comr(void);
+static void ltr(void);         static void lti(void);
+static void ltr_u(void);       static void lti_u(void);
+static void ler(void);         static void lei(void);
+static void ler_u(void);       static void lei_u(void);
+static void eqr(void);         static void eqi(void);
+static void ger(void);         static void gei(void);
+static void ger_u(void);       static void gei_u(void);
+static void gtr(void);         static void gti(void);
+static void gtr_u(void);       static void gti_u(void);
+static void ner(void);         static void nei(void);
+static void movr(void);                static void movi(void);
+static void extr_c(void);      static void extr_uc(void);
+static void extr_s(void);      static void extr_us(void);
+#if __WORDSIZE == 64
+static void extr_i(void);      static void extr_ui(void);
+#endif
+static void htonr_us(void);    static void ntohr_us(void);
+static void htonr_ui(void);    static void ntohr_ui(void);
+#if __WORDSIZE == 64
+static void htonr_ul(void);    static void ntohr_ul(void);
+#endif
+static void htonr(void);       static void ntohr(void);
+static void ldr_c(void);       static void ldi_c(void);
+static void ldr_uc(void);      static void ldi_uc(void);
+static void ldr_s(void);       static void ldi_s(void);
+static void ldr_us(void);      static void ldi_us(void);
+static void ldr_i(void);       static void ldi_i(void);
+#if __WORDSIZE == 64
+static void ldr_ui(void);      static void ldi_ui(void);
+static void ldr_l(void);       static void ldi_l(void);
+#endif
+static void ldr(void);         static void ldi(void);
+static void ldxr_c(void);      static void ldxi_c(void);
+static void ldxr_uc(void);     static void ldxi_uc(void);
+static void ldxr_s(void);      static void ldxi_s(void);
+static void ldxr_us(void);     static void ldxi_us(void);
+static void ldxr_i(void);      static void ldxi_i(void);
+#if __WORDSIZE == 64
+static void ldxr_ui(void);     static void ldxi_ui(void);
+static void ldxr_l(void);      static void ldxi_l(void);
+#endif
+static void ldxr(void);                static void ldxi(void);
+static void str_c(void);       static void sti_c(void);
+static void str_s(void);       static void sti_s(void);
+static void str_i(void);       static void sti_i(void);
+#if __WORDSIZE == 64
+static void str_l(void);       static void sti_l(void);
+#endif
+static void str(void);         static void sti(void);
+static void stxr_c(void);      static void stxi_c(void);
+static void stxr_s(void);      static void stxi_s(void);
+static void stxr_i(void);      static void stxi_i(void);
+#if __WORDSIZE == 64
+static void stxr_l(void);      static void stxi_l(void);
+#endif
+static void stxr(void);                static void stxi(void);
+static void bltr(void);                static void blti(void);
+static void bltr_u(void);      static void blti_u(void);
+static void bler(void);                static void blei(void);
+static void bler_u(void);      static void blei_u(void);
+static void beqr(void);                static void beqi(void);
+static void bger(void);                static void bgei(void);
+static void bger_u(void);      static void bgei_u(void);
+static void bgtr(void);                static void bgti(void);
+static void bgtr_u(void);      static void bgti_u(void);
+static void bner(void);                static void bnei(void);
+static void bmsr(void);                static void bmsi(void);
+static void bmcr(void);                static void bmci(void);
+static void boaddr(void);      static void boaddi(void);
+static void boaddr_u(void);    static void boaddi_u(void);
+static void bxaddr(void);      static void bxaddi(void);
+static void bxaddr_u(void);    static void bxaddi_u(void);
+static void bosubr(void);      static void bosubi(void);
+static void bosubr_u(void);    static void bosubi_u(void);
+static void bxsubr(void);      static void bxsubi(void);
+static void bxsubr_u(void);    static void bxsubi_u(void);
+static void jmpr(void);                static void jmpi(void);
+static void callr(void);       static void calli(void);
+static void prepare(void);
+static void pushargr(void);    static void pushargi(void);
+static void finishr(void);     static void finishi(void);
+static void ret(void);
+static void retr(void);                static void reti(void);
+static void retval_c(void);    static void retval_uc(void);
+static void retval_s(void);    static void retval_us(void);
+static void retval_i(void);
+#if __WORDSIZE == 64
+static void retval_ui(void);   static void retval_l(void);
+#endif
+static void retval(void);
+static void epilog(void);
+static void arg_f(void);       static void getarg_f(void);
+static void putargr_f(void);   static void putargi_f(void);
+static void addr_f(void);      static void addi_f(void);
+static void subr_f(void);      static void subi_f(void);
+static void rsbr_f(void);      static void rsbi_f(void);
+static void mulr_f(void);      static void muli_f(void);
+static void divr_f(void);      static void divi_f(void);
+static void negr_f(void);      static void absr_f(void);
+static void sqrtr_f(void);
+static void ltr_f(void);       static void lti_f(void);
+static void ler_f(void);       static void lei_f(void);
+static void eqr_f(void);       static void eqi_f(void);
+static void ger_f(void);       static void gei_f(void);
+static void gtr_f(void);       static void gti_f(void);
+static void ner_f(void);       static void nei_f(void);
+static void unltr_f(void);     static void unlti_f(void);
+static void unler_f(void);     static void unlei_f(void);
+static void uneqr_f(void);     static void uneqi_f(void);
+static void unger_f(void);     static void ungei_f(void);
+static void ungtr_f(void);     static void ungti_f(void);
+static void ltgtr_f(void);     static void ltgti_f(void);
+static void ordr_f(void);      static void ordi_f(void);
+static void unordr_f(void);    static void unordi_f(void);
+static void truncr_f_i(void);
+#if __WORDSIZE == 64
+static void truncr_f_l(void);
+#endif
+static void truncr_f(void);
+static void extr_f(void);      static void extr_d_f(void);
+static void movr_f(void);      static void movi_f(void);
+static void ldr_f(void);       static void ldi_f(void);
+static void ldxr_f(void);      static void ldxi_f(void);
+static void str_f(void);       static void sti_f(void);
+static void stxr_f(void);      static void stxi_f(void);
+static void bltr_f(void);      static void blti_f(void);
+static void bler_f(void);      static void blei_f(void);
+static void beqr_f(void);      static void beqi_f(void);
+static void bger_f(void);      static void bgei_f(void);
+static void bgtr_f(void);      static void bgti_f(void);
+static void bner_f(void);      static void bnei_f(void);
+static void bunltr_f(void);    static void bunlti_f(void);
+static void bunler_f(void);    static void bunlei_f(void);
+static void buneqr_f(void);    static void buneqi_f(void);
+static void bunger_f(void);    static void bungei_f(void);
+static void bungtr_f(void);    static void bungti_f(void);
+static void bltgtr_f(void);    static void bltgti_f(void);
+static void bordr_f(void);     static void bordi_f(void);
+static void bunordr_f(void);   static void bunordi_f(void);
+static void pushargr_f(void);  static void pushargi_f(void);
+static void retr_f(void);      static void reti_f(void);
+static void retval_f(void);
+static void arg_d(void);       static void getarg_d(void);
+static void putargr_d(void);   static void putargi_d(void);
+static void addr_d(void);      static void addi_d(void);
+static void subr_d(void);      static void subi_d(void);
+static void rsbr_d(void);      static void rsbi_d(void);
+static void mulr_d(void);      static void muli_d(void);
+static void divr_d(void);      static void divi_d(void);
+static void negr_d(void);      static void absr_d(void);
+static void sqrtr_d(void);
+static void ltr_d(void);       static void lti_d(void);
+static void ler_d(void);       static void lei_d(void);
+static void eqr_d(void);       static void eqi_d(void);
+static void ger_d(void);       static void gei_d(void);
+static void gtr_d(void);       static void gti_d(void);
+static void ner_d(void);       static void nei_d(void);
+static void unltr_d(void);     static void unlti_d(void);
+static void unler_d(void);     static void unlei_d(void);
+static void uneqr_d(void);     static void uneqi_d(void);
+static void unger_d(void);     static void ungei_d(void);
+static void ungtr_d(void);     static void ungti_d(void);
+static void ltgtr_d(void);     static void ltgti_d(void);
+static void ordr_d(void);      static void ordi_d(void);
+static void unordr_d(void);    static void unordi_d(void);
+static void truncr_d_i(void);
+#if __WORDSIZE == 64
+static void truncr_d_l(void);
+#endif
+static void truncr_d(void);
+static void extr_d(void);      static void extr_f_d(void);
+static void movr_d(void);      static void movi_d(void);
+static void ldr_d(void);       static void ldi_d(void);
+static void ldxr_d(void);      static void ldxi_d(void);
+static void str_d(void);       static void sti_d(void);
+static void stxr_d(void);      static void stxi_d(void);
+static void bltr_d(void);      static void blti_d(void);
+static void bler_d(void);      static void blei_d(void);
+static void beqr_d(void);      static void beqi_d(void);
+static void bger_d(void);      static void bgei_d(void);
+static void bgtr_d(void);      static void bgti_d(void);
+static void bner_d(void);      static void bnei_d(void);
+static void bunltr_d(void);    static void bunlti_d(void);
+static void bunler_d(void);    static void bunlei_d(void);
+static void buneqr_d(void);    static void buneqi_d(void);
+static void bunger_d(void);    static void bungei_d(void);
+static void bungtr_d(void);    static void bungti_d(void);
+static void bltgtr_d(void);    static void bltgti_d(void);
+static void bordr_d(void);     static void bordi_d(void);
+static void bunordr_d(void);   static void bunordi_d(void);
+static void pushargr_d(void);  static void pushargi_d(void);
+static void retr_d(void);      static void reti_d(void);
+static void retval_d(void);
+static void vastart(void);     static void vapush(void);
+static void vaarg(void);       static void vaarg_d(void);
+static void vaend(void);
+
+static void error(const char *format, ...) noreturn printf_format(1, 2);
+static void warn(const char *format, ...) printf_format(1, 2) maybe_unused;
+static void message(const char *kind, const char *format, va_list ap);
+
+static int getch(void);
+static int getch_noeof(void);
+static int ungetch(int ch);
+static int skipws(void);
+static int skipnl(void);
+static int skipct(void);
+static int skipcp(void);
+static jit_word_t get_int(skip_t skip);
+static jit_uword_t get_uint(skip_t skip);
+static double get_float(skip_t skip);
+static float make_float(double d);
+static void *get_pointer(skip_t skip);
+static label_t *get_label(skip_t skip);
+static token_t regname(void);
+static token_t identifier(int ch);
+static void get_data(type_t type);
+static void dot(void);
+static token_t number(int ch);
+static int escape(int ch);
+static token_t string(void);
+static token_t dynamic(void);
+static token_t character(void);
+static void expression_prim(void);
+static void expression_inc(int pre);
+static void expression_dec(int pre);
+static void expression_unary(void);
+static void expression_mul(void);
+static void expression_add(void);
+static void expression_shift(void);
+static void expression_bit(void);
+static void expression_rel(void);
+static void expression_cond(void);
+static token_t expression(void);
+static token_t primary(skip_t skip);
+static void parse(void);
+static int execute(int argc, char *argv[]);
+
+static void *xmalloc(size_t size);
+static void *xrealloc(void *pointer, size_t size);
+static void *xcalloc(size_t nmemb, size_t size);
+
+static label_t *new_label(label_kind_t kind, char *name, void *value);
+static patch_t *new_patch(patch_kind_t kind, label_t *label, void *value);
+static int bcmp_symbols(const void *left, const void *right);
+static int qcmp_symbols(const void *left, const void *right);
+static symbol_t *new_symbol(char *name);
+static symbol_t *get_symbol_by_name(char *name);
+
+static hash_t *new_hash(void);
+static int hash_string(char *name);
+static void put_hash(hash_t *hash, entry_t *entry);
+static entry_t *get_hash(hash_t *hash, char *name);
+static void rehash(hash_t *hash);
+
+/*
+ * Initialization
+ */
+static jit_state_t      *_jit;
+static int               flag_verbose;
+static int               flag_data;
+static int               flag_disasm;
+static char             *progname;
+static parser_t                  parser;
+static hash_t           *labels;
+static int               label_offset;
+static patch_t          *patches;
+static symbol_t                **symbols;
+static int               symbol_length;
+static int               symbol_offset;
+static hash_t           *instrs;
+static char             *data;
+static size_t            data_offset, data_length;
+static instr_t           instr_vector[] = {
+#define entry(value)   { NULL, #value, value }
+#define entry2(name, function) { NULL, name, function }
+    entry(live),
+    entry(align),      entry(name),
+    entry(prolog),
+    entry(frame),      entry(tramp),
+    entry(ellipsis),
+    entry(allocai),    entry(allocar),
+    entry(arg),
+    entry(getarg_c),   entry(getarg_uc),
+    entry(getarg_s),   entry(getarg_us),
+    entry(getarg_i),
+#if __WORDSIZE == 64
+    entry(getarg_ui),  entry(getarg_l),
+#endif
+    entry(getarg),
+    entry(putargr),    entry(putargi),
+    entry(addr),       entry(addi),
+    entry(addxr),      entry(addxi),
+    entry(addcr),      entry(addci),
+    entry(subr),       entry(subi),
+    entry(subxr),      entry(subxi),
+    entry(subcr),      entry(subci),
+    entry(rsbr),       entry(rsbi),
+    entry(mulr),       entry(muli),
+    entry(qmulr),      entry(qmuli),
+    entry(qmulr_u),    entry(qmuli_u),
+    entry(divr),       entry(divi),
+    entry(divr_u),     entry(divi_u),
+    entry(qdivr),      entry(qdivi),
+    entry(qdivr_u),    entry(qdivi_u),
+    entry(remr),       entry(remi),
+    entry(remr_u),     entry(remi_u),
+    entry(andr),       entry(andi),
+    entry(orr),                entry(ori),
+    entry(xorr),       entry(xori),
+    entry(lshr),       entry(lshi),
+    entry(rshr),       entry(rshi),
+    entry(rshr_u),     entry(rshi_u),
+    entry(negr),       entry(comr),
+    entry(ltr),                entry(lti),
+    entry(ltr_u),      entry(lti_u),
+    entry(ler),                entry(lei),
+    entry(ler_u),      entry(lei_u),
+    entry(eqr),                entry(eqi),
+    entry(ger),                entry(gei),
+    entry(ger_u),      entry(gei_u),
+    entry(gtr),                entry(gti),
+    entry(gtr_u),      entry(gti_u),
+    entry(ner),                entry(nei),
+    entry(movr),       entry(movi),
+    entry(extr_c),     entry(extr_uc),
+    entry(extr_s),     entry(extr_us),
+#if __WORDSIZE == 64
+    entry(extr_i),     entry(extr_ui),
+#endif
+    entry(htonr_us),   entry(ntohr_us),
+    entry(htonr_ui),   entry(ntohr_ui),
+#if __WORDSIZE == 64
+    entry(htonr_ul),   entry(ntohr_ul),
+#endif
+    entry(htonr),      entry(ntohr),
+    entry(ldr_c),      entry(ldi_c),
+    entry(ldr_uc),     entry(ldi_uc),
+    entry(ldr_s),      entry(ldi_s),
+    entry(ldr_us),     entry(ldi_us),
+    entry(ldr_i),      entry(ldi_i),
+#if __WORDSIZE == 64
+    entry(ldr_ui),     entry(ldi_ui),
+    entry(ldr_l),      entry(ldi_l),
+#endif
+    entry(ldr),                entry(ldi),
+    entry(ldxr_c),     entry(ldxi_c),
+    entry(ldxr_uc),    entry(ldxi_uc),
+    entry(ldxr_s),     entry(ldxi_s),
+    entry(ldxr_us),    entry(ldxi_us),
+    entry(ldxr_i),     entry(ldxi_i),
+#if __WORDSIZE == 64
+    entry(ldxr_ui),    entry(ldxi_ui),
+    entry(ldxr_l),     entry(ldxi_l),
+#endif
+    entry(ldxr),       entry(ldxi),
+    entry(str_c),      entry(sti_c),
+    entry(str_s),      entry(sti_s),
+    entry(str_i),      entry(sti_i),
+#if __WORDSIZE == 64
+    entry(str_l),      entry(sti_l),
+#endif
+    entry(str),                entry(sti),
+    entry(stxr_c),     entry(stxi_c),
+    entry(stxr_s),     entry(stxi_s),
+    entry(stxr_i),     entry(stxi_i),
+#if __WORDSIZE == 64
+    entry(stxr_l),     entry(stxi_l),
+#endif
+    entry(stxr),       entry(stxi),
+    entry(bltr),       entry(blti),
+    entry(bltr_u),     entry(blti_u),
+    entry(bler),       entry(blei),
+    entry(bler_u),     entry(blei_u),
+    entry(beqr),       entry(beqi),
+    entry(bger),       entry(bgei),
+    entry(bger_u),     entry(bgei_u),
+    entry(bgtr),       entry(bgti),
+    entry(bgtr_u),     entry(bgti_u),
+    entry(bner),       entry(bnei),
+    entry(bmsr),       entry(bmsi),
+    entry(bmcr),       entry(bmci),
+    entry(boaddr),     entry(boaddi),
+    entry(boaddr_u),   entry(boaddi_u),
+    entry(bxaddr),     entry(bxaddi),
+    entry(bxaddr_u),   entry(bxaddi_u),
+    entry(bosubr),     entry(bosubi),
+    entry(bosubr_u),   entry(bosubi_u),
+    entry(bxsubr),     entry(bxsubi),
+    entry(bxsubr_u),   entry(bxsubi_u),
+    entry(jmpr),       entry(jmpi),
+    entry(callr),      entry(calli),
+    entry(prepare),
+    entry(pushargr),   entry(pushargi),
+    entry(finishr),    entry(finishi),
+    entry(ret),
+    entry(retr),       entry(reti),
+    entry(retval_c),   entry(retval_uc),
+    entry(retval_s),   entry(retval_us),
+    entry(retval_i),
+#if __WORDSIZE == 64
+    entry(retval_ui),  entry(retval_l),
+#endif
+    entry(retval),
+    entry(epilog),
+    entry(arg_f),      entry(getarg_f),
+    entry(putargr_f),  entry(putargi_f),
+    entry(addr_f),     entry(addi_f),
+    entry(subr_f),     entry(subi_f),
+    entry(rsbr_f),     entry(rsbi_f),
+    entry(mulr_f),     entry(muli_f),
+    entry(divr_f),     entry(divi_f),
+    entry(negr_f),     entry(absr_f),
+    entry(sqrtr_f),
+    entry(ltr_f),      entry(lti_f),
+    entry(ler_f),      entry(lei_f),
+    entry(eqr_f),      entry(eqi_f),
+    entry(ger_f),      entry(gei_f),
+    entry(gtr_f),      entry(gti_f),
+    entry(ner_f),      entry(nei_f),
+    entry(unltr_f),    entry(unlti_f),
+    entry(unler_f),    entry(unlei_f),
+    entry(uneqr_f),    entry(uneqi_f),
+    entry(unger_f),    entry(ungei_f),
+    entry(ungtr_f),    entry(ungti_f),
+    entry(ltgtr_f),    entry(ltgti_f),
+    entry(ordr_f),     entry(ordi_f),
+    entry(unordr_f),   entry(unordi_f),
+    entry(truncr_f_i),
+#if __WORDSIZE == 64
+    entry(truncr_f_l),
+#endif
+    entry(truncr_f),
+    entry(extr_f),     entry(extr_d_f),
+    entry(movr_f),     entry(movi_f),
+    entry(ldr_f),      entry(ldi_f),
+    entry(ldxr_f),     entry(ldxi_f),
+    entry(str_f),      entry(sti_f),
+    entry(stxr_f),     entry(stxi_f),
+    entry(bltr_f),     entry(blti_f),
+    entry(bler_f),     entry(blei_f),
+    entry(beqr_f),     entry(beqi_f),
+    entry(bger_f),     entry(bgei_f),
+    entry(bgtr_f),     entry(bgti_f),
+    entry(bner_f),     entry(bnei_f),
+    entry(bunltr_f),   entry(bunlti_f),
+    entry(bunler_f),   entry(bunlei_f),
+    entry(buneqr_f),   entry(buneqi_f),
+    entry(bunger_f),   entry(bungei_f),
+    entry(bungtr_f),   entry(bungti_f),
+    entry(bltgtr_f),   entry(bltgti_f),
+    entry(bordr_f),    entry(bordi_f),
+    entry(bunordr_f),  entry(bunordi_f),
+    entry(pushargr_f), entry(pushargi_f),
+    entry(retr_f),     entry(reti_f),
+    entry(retval_f),
+    entry(arg_d),      entry(getarg_d),
+    entry(putargr_d),  entry(putargi_d),
+    entry(addr_d),     entry(addi_d),
+    entry(subr_d),     entry(subi_d),
+    entry(rsbr_d),     entry(rsbi_d),
+    entry(mulr_d),     entry(muli_d),
+    entry(divr_d),     entry(divi_d),
+    entry(negr_d),     entry(absr_d),
+    entry(sqrtr_d),
+    entry(ltr_d),      entry(lti_d),
+    entry(ler_d),      entry(lei_d),
+    entry(eqr_d),      entry(eqi_d),
+    entry(ger_d),      entry(gei_d),
+    entry(gtr_d),      entry(gti_d),
+    entry(ner_d),      entry(nei_d),
+    entry(unltr_d),    entry(unlti_d),
+    entry(unler_d),    entry(unlei_d),
+    entry(uneqr_d),    entry(uneqi_d),
+    entry(unger_d),    entry(ungei_d),
+    entry(ungtr_d),    entry(ungti_d),
+    entry(ltgtr_d),    entry(ltgti_d),
+    entry(ordr_d),     entry(ordi_d),
+    entry(unordr_d),   entry(unordi_d),
+    entry(truncr_d_i),
+#if __WORDSIZE == 64
+    entry(truncr_d_l),
+#endif
+    entry(truncr_d),
+    entry(extr_d),     entry(extr_f_d),
+    entry(movr_d),     entry(movi_d),
+    entry(ldr_d),      entry(ldi_d),
+    entry(ldxr_d),     entry(ldxi_d),
+    entry(str_d),      entry(sti_d),
+    entry(stxr_d),     entry(stxi_d),
+    entry(bltr_d),     entry(blti_d),
+    entry(bler_d),     entry(blei_d),
+    entry(beqr_d),     entry(beqi_d),
+    entry(bger_d),     entry(bgei_d),
+    entry(bgtr_d),     entry(bgti_d),
+    entry(bner_d),     entry(bnei_d),
+    entry(bunltr_d),   entry(bunlti_d),
+    entry(bunler_d),   entry(bunlei_d),
+    entry(buneqr_d),   entry(buneqi_d),
+    entry(bunger_d),   entry(bungei_d),
+    entry(bungtr_d),   entry(bungti_d),
+    entry(bltgtr_d),   entry(bltgti_d),
+    entry(bordr_d),    entry(bordi_d),
+    entry(bunordr_d),  entry(bunordi_d),
+    entry(pushargr_d), entry(pushargi_d),
+    entry(retr_d),     entry(reti_d),
+    entry(retval_d),
+    entry2("va_start", vastart),
+    entry2("va_push", vapush),
+    entry2("va_arg", vaarg),
+    entry2("va_arg_d", vaarg_d),
+    entry2("va_end", vaend),
+#undef entry
+};
+
+/*
+ * Implementation
+ */
+static jit_gpr_t
+get_ireg(void)
+{
+    if (primary(skip_ws) != tok_register)
+       error("bad register");
+    if (parser.regtype != type_l)
+       error("bad int register");
+
+    return ((jit_gpr_t)parser.regval);
+}
+
+static jit_fpr_t
+get_freg(void)
+{
+    if (primary(skip_ws) != tok_register)
+       error("bad register");
+    if (parser.regtype != type_d)
+       error("bad float register");
+
+    return ((jit_fpr_t)parser.regval);
+}
+
+static symbol_t *
+get_symbol(void)
+{
+    symbol_t   *symbol;
+    int                 ch = skipws();
+
+    if (ch != '$')
+       error("expecting variable");
+    (void)identifier('$');
+    if (parser.string[1] == '\0')
+       error("expecting variable");
+    if ((symbol = get_symbol_by_name(parser.string)) == NULL)
+       symbol = new_symbol(parser.string);
+
+    return (symbol);
+}
+
+static void
+jmp_forward(void *value, label_t *label)
+{
+    (void)new_patch(patch_kind_jmp, label, value);
+}
+
+static void
+mov_forward(void *value, label_t *label)
+{
+    (void)new_patch(patch_kind_mov, label, value);
+}
+
+static void
+call_forward(void *value, label_t *label)
+{
+    (void)new_patch(patch_kind_call, label, value);
+}
+
+static void
+make_arg(void *value)
+{
+    symbol_t   *symbol = get_symbol();
+
+    symbol->type = type_p;
+    symbol->value.p = value;
+}
+
+static jit_pointer_t
+get_arg(void)
+{
+    symbol_t   *symbol = get_symbol();
+
+    if (symbol->type != type_p)
+       error("bad argument %s type", symbol->name);
+
+    return symbol->value.p;
+}
+
+static jit_word_t
+get_imm(void)
+{
+    int                 ch;
+    label_t    *label;
+    jit_word_t  value;
+    ch = skipws();
+    switch (ch) {
+       case '+': case '-': case '0' ... '9':
+           ungetch(ch);
+           value = get_int(skip_none);
+           break;
+       case '\'':
+           character();
+           value = parser.value.i;
+           break;
+       case '$':
+           switch (expression()) {
+               case tok_int:
+               case tok_pointer:
+                   value = parser.value.i;
+                   break;
+               default:
+                   error("expecting immediate");
+           }
+           break;
+       case '@':
+           dynamic();
+           value = (jit_word_t)parser.value.p;
+           break;
+       default:
+           ungetch(ch);
+           label = get_label(skip_none);
+           if (label->kind == label_kind_data)
+               value = (jit_word_t)label->value;
+           else
+               error("expecting immediate");
+           break;
+    }
+    return (value);
+}
+
+#define entry(name)                                                    \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_##name();                                                      \
+}
+#define entry_ca(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    make_arg(jit_##name());                                            \
+}
+#define entry_ia(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t          r0 = get_ireg();                                \
+    jit_pointer_t      ac = get_arg();                                 \
+    jit_##name(r0, ac);                                                        \
+}
+#define entry_im(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_word_t  im = get_imm();                                        \
+    jit_##name(im);                                                    \
+}
+#define entry_ir(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t   r0 = get_ireg();                                       \
+    jit_##name(r0);                                                    \
+}
+#define entry_ima(name)                                                        \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_word_t         im = get_imm();                                 \
+    jit_pointer_t      ac = get_arg();                                 \
+    jit_##name(im, ac);                                                        \
+}
+#define entry_ir_ir_ir(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t  r0 = get_ireg(), r1 = get_ireg(), r2 = get_ireg();      \
+    jit_##name(r0, r1, r2);                                            \
+}
+#define entry_ir_ir_im(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t  r0 = get_ireg(), r1 = get_ireg();                       \
+    jit_word_t im = get_imm();                                         \
+    jit_##name(r0, r1, im);                                            \
+}
+#define entry_ir_ir_ir_ir(name)                                                \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t  r0 = get_ireg(), r1 = get_ireg(),                       \
+               r2 = get_ireg(), r3 = get_ireg();                       \
+    jit_##name(r0, r1, r2, r3);                                                \
+}
+#define entry_ir_ir_ir_im(name)                                                \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t  r0 = get_ireg(), r1 = get_ireg(), r2 = get_ireg();      \
+    jit_word_t im = get_imm();                                         \
+    jit_##name(r0, r1, r2, im);                                                \
+}
+#define entry_ir_ir(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t  r0 = get_ireg(), r1 = get_ireg();                       \
+    jit_##name(r0, r1);                                                        \
+}
+#define entry_ir_im(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t  r0 = get_ireg();                                        \
+    jit_word_t im = get_imm();                                         \
+    jit_##name(r0, im);                                                        \
+}
+#define entry_ir_pm(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t   r0 = get_ireg();                                       \
+    void       *pm = get_pointer(skip_ws);                             \
+    jit_##name(r0, pm);                                                        \
+}
+#define entry_pm_ir(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    void       *pm = get_pointer(skip_ws);                             \
+    jit_gpr_t   r0 = get_ireg();                                       \
+    jit_##name(pm, r0);                                                        \
+}
+#define entry_im_ir_ir(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_word_t im = get_imm();                                         \
+    jit_gpr_t  r0 = get_ireg(), r1 = get_ireg();                       \
+    (void)jit_##name(im, r0, r1);                                      \
+}
+#define entry_lb_ir_ir(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_node_t *jmp;                                                   \
+    label_t    *label = get_label(skip_ws);                            \
+    jit_gpr_t   r0 = get_ireg(), r1 = get_ireg();                      \
+    if (label->kind == label_kind_code_forward)                                \
+       jmp_forward((void *)jit_##name(r0, r1), label);                 \
+    else {                                                             \
+       jmp = jit_##name(r0, r1);                                       \
+       jit_patch_at(jmp, (jit_node_t *)label->value);                  \
+    }                                                                  \
+}
+#define entry_lb_ir_im(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_node_t *jmp;                                                   \
+    label_t    *label = get_label(skip_ws);                            \
+    jit_gpr_t   r0 = get_ireg();                                       \
+    jit_word_t  im = get_imm();                                        \
+    if (label->kind == label_kind_code_forward)                                \
+       jmp_forward((void *)jit_##name(r0, im), label);                 \
+    else {                                                             \
+       jmp = jit_##name(r0, im);                                       \
+       jit_patch_at(jmp, (jit_node_t *)label->value);                  \
+    }                                                                  \
+}
+#define entry_lb(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_node_t *jmp;                                                   \
+    label_t    *label = get_label(skip_ws);                            \
+    if (label->kind == label_kind_code_forward)                                \
+       jmp_forward((void *)jit_##name(), label);                       \
+    else {                                                             \
+       jmp = jit_##name();                                             \
+       jit_patch_at(jmp, (jit_node_t *)label->value);                  \
+    }                                                                  \
+}
+#define entry_pm(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    void       *pm = get_pointer(skip_ws);                             \
+    jit_##name(pm);                                                    \
+}
+#define entry_fa(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t          r0 = get_freg();                                \
+    jit_pointer_t      ac = get_arg();                                 \
+    jit_##name(r0, ac);                                                        \
+}
+#define entry_fma(name)                                                        \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_float64_t      im = get_float(skip_ws);                        \
+    jit_pointer_t      ac = get_arg();                                 \
+    jit_##name(im, ac);                                                        \
+}
+#define entry_fr_fr_fr(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t  r0 = get_freg(), r1 = get_freg(), r2 = get_freg();      \
+    jit_##name(r0, r1, r2);                                            \
+}
+#define entry_fr_fr_fm(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t          r0 = get_freg(), r1 = get_freg();               \
+    jit_float64_t      im = get_float(skip_ws);                        \
+    jit_##name(r0, r1, make_float(im));                                        \
+}
+#define entry_fr_fr_dm(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t          r0 = get_freg(), r1 = get_freg();               \
+    jit_float64_t      im = get_float(skip_ws);                        \
+    jit_##name(r0, r1, im);                                            \
+}
+#define entry_fr_fr(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t  r0 = get_freg(), r1 = get_freg();                       \
+    jit_##name(r0, r1);                                                        \
+}
+#define entry_ir_fr_fr(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t  r0 = get_ireg();                                        \
+    jit_fpr_t  r1 = get_freg(), r2 = get_freg();                       \
+    jit_##name(r0, r1, r2);                                            \
+}
+#define entry_ir_fr_fm(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t          r0 = get_ireg();                                \
+    jit_fpr_t          r1 = get_freg();                                \
+    jit_float64_t      im = get_float(skip_ws);                        \
+    jit_##name(r0, r1, make_float(im));                                        \
+}
+#define entry_ir_fr_dm(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t          r0 = get_ireg();                                \
+    jit_fpr_t          r1 = get_freg();                                \
+    jit_float64_t      im = get_float(skip_ws);                        \
+    jit_##name(r0, r1, im);                                            \
+}
+#define entry_ir_fr(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t  r0 = get_ireg();                                        \
+    jit_fpr_t  r1 = get_freg();                                        \
+    jit_##name(r0, r1);                                                        \
+}
+#define entry_fr_ir(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t  r0 = get_freg();                                        \
+    jit_gpr_t  r1 = get_ireg();                                        \
+    jit_##name(r0, r1);                                                        \
+}
+#define entry_fr_fm(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t          r0 = get_freg();                                \
+    jit_float64_t      im = get_float(skip_ws);                        \
+    jit_##name(r0, make_float(im));                                    \
+}
+#define entry_fr_dm(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t          r0 = get_freg();                                \
+    jit_float64_t      im = get_float(skip_ws);                        \
+    jit_##name(r0, im);                                                        \
+}
+#define entry_fr_pm(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t   r0 = get_freg();                                       \
+    void       *pm = get_pointer(skip_ws);                             \
+    jit_##name(r0, pm);                                                        \
+}
+#define entry_fr_ir_ir(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t  r0 = get_freg();                                        \
+    jit_gpr_t  r1 = get_ireg(), r2 = get_ireg();                       \
+    jit_##name(r0, r1, r2);                                            \
+}
+#define entry_fr_ir_im(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t  r0 = get_freg();                                        \
+    jit_gpr_t  r1 = get_ireg();                                        \
+    jit_word_t im = get_imm();                                         \
+    jit_##name(r0, r1, im);                                            \
+}
+#define entry_pm_fr(name)                                              \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    void       *pm = get_pointer(skip_ws);                             \
+    jit_fpr_t   r0 = get_freg();                                       \
+    jit_##name(pm, r0);                                                        \
+}
+#define entry_ir_ir_fr(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_gpr_t  r0 = get_ireg(), r1 = get_ireg();                       \
+    jit_fpr_t  r2 = get_freg();                                        \
+    jit_##name(r0, r1, r2);                                            \
+}
+#define entry_im_ir_fr(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_word_t im = get_imm();                                         \
+    jit_gpr_t  r0 = get_ireg();                                        \
+    jit_fpr_t  r1 = get_freg();                                        \
+    jit_##name(im, r0, r1);                                            \
+}
+#define entry_lb_fr_fr(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_node_t *jmp;                                                   \
+    label_t    *label = get_label(skip_ws);                            \
+    jit_fpr_t   r0 = get_freg(), r1 = get_freg();                      \
+    if (label->kind == label_kind_code_forward)                                \
+       jmp_forward((void *)jit_##name(r0, r1), label);                 \
+    else {                                                             \
+       jmp = jit_##name(r0, r1);                                       \
+       jit_patch_at(jmp, (jit_node_t *)label->value);                  \
+    }                                                                  \
+}
+#define entry_lb_fr_fm(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_node_t         *jmp;                                           \
+    label_t            *label = get_label(skip_ws);                    \
+    jit_fpr_t           r0 = get_freg();                               \
+    jit_float64_t       im = get_float(skip_ws);                       \
+    if (label->kind == label_kind_code_forward)                                \
+       jmp_forward((void *)jit_##name(r0, make_float(im)), label);     \
+    else {                                                             \
+       jmp = jit_##name(r0, make_float(im));                           \
+       jit_patch_at(jmp, (jit_node_t *)label->value);                  \
+    }                                                                  \
+}
+#define entry_lb_fr_dm(name)                                           \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_node_t         *jmp;                                           \
+    label_t            *label = get_label(skip_ws);                    \
+    jit_fpr_t           r0 = get_freg();                               \
+    jit_float64_t       im = get_float(skip_ws);                       \
+    if (label->kind == label_kind_code_forward)                                \
+       jmp_forward((void *)jit_##name(r0, im), label);                 \
+    else {                                                             \
+       jmp = jit_##name(r0, im);                                       \
+       jit_patch_at(jmp, (jit_node_t *)label->value);                  \
+    }                                                                  \
+}
+#define entry_fr(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_fpr_t  r0 = get_freg();                                        \
+    jit_##name(r0);                                                    \
+}
+#define entry_fm(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_float64_t      im = get_float(skip_ws);                        \
+    jit_##name(make_float(im));                                                \
+}
+#define entry_dm(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    jit_float64_t      im = get_float(skip_ws);                        \
+    jit_##name(im);                                                    \
+}
+#define entry_fn(name)                                                 \
+static void                                                            \
+name(void)                                                             \
+{                                                                      \
+    int                 ch;                                                    \
+    label_t    *label;                                                 \
+    void       *value;                                                 \
+    ch = skipws();                                                     \
+    switch (ch) {                                                      \
+       case '0' ... '9':                                               \
+           ungetch(ch);                                                \
+           value = (void *)(jit_word_t)get_uint(skip_none);            \
+           break;                                                      \
+       case '$':                                                       \
+           switch (expression()) {                                     \
+               case tok_int:                                           \
+                   value = (void *)parser.value.i;                     \
+                   break;                                              \
+               case tok_pointer:                                       \
+                   value = parser.value.p;                             \
+                   break;                                              \
+               default:                                                \
+                   error("expecting pointer");                         \
+           }                                                           \
+           break;                                                      \
+       case '@':                                                       \
+           dynamic();                                                  \
+           value = parser.value.p;                                     \
+           break;                                                      \
+       default:                                                        \
+           ungetch(ch);                                                \
+           label = get_label(skip_none);                               \
+           if (label->kind == label_kind_code_forward)                 \
+               call_forward((void *)jit_##name(NULL), label);          \
+           else                                                        \
+               jit_patch_at(jit_##name(NULL), label->value);           \
+           return;                                                     \
+    }                                                                  \
+    jit_##name(value);                                                 \
+}
+static void
+name(void) {
+    int                 ch = skipws();
+    (void)identifier(ch);
+    jit_name(parser.string);
+}
+static void
+live(void) {
+    if (primary(skip_ws) != tok_register)
+       error("bad register");
+    jit_live(parser.regval);
+}
+entry_im(align)
+entry(prolog)
+entry_im(frame)                        entry_im(tramp)
+entry(ellipsis)
+void
+allocai(void) {
+    symbol_t   *symbol;
+    jit_word_t  i, im = get_imm();
+    i = jit_allocai(im);
+    symbol = get_symbol();
+    symbol->type = type_l;
+    symbol->value.i = i;
+}
+entry_ir_ir(allocar)
+entry_ca(arg)
+entry_ia(getarg_c)             entry_ia(getarg_uc)
+entry_ia(getarg_s)             entry_ia(getarg_us)
+entry_ia(getarg_i)
+#if __WORDSIZE == 64
+entry_ia(getarg_ui)            entry_ia(getarg_l)
+#endif
+entry_ia(getarg)
+entry_ia(putargr)              entry_ima(putargi)
+entry_ir_ir_ir(addr)           entry_ir_ir_im(addi)
+entry_ir_ir_ir(addxr)          entry_ir_ir_im(addxi)
+entry_ir_ir_ir(addcr)          entry_ir_ir_im(addci)
+entry_ir_ir_ir(subr)           entry_ir_ir_im(subi)
+entry_ir_ir_ir(subxr)          entry_ir_ir_im(subxi)
+entry_ir_ir_ir(subcr)          entry_ir_ir_im(subci)
+entry_ir_ir_ir(rsbr)           entry_ir_ir_im(rsbi)
+entry_ir_ir_ir(mulr)           entry_ir_ir_im(muli)
+entry_ir_ir_ir_ir(qmulr)       entry_ir_ir_ir_im(qmuli)
+entry_ir_ir_ir_ir(qmulr_u)     entry_ir_ir_ir_im(qmuli_u)
+entry_ir_ir_ir(divr)           entry_ir_ir_im(divi)
+entry_ir_ir_ir(divr_u)         entry_ir_ir_im(divi_u)
+entry_ir_ir_ir_ir(qdivr)       entry_ir_ir_ir_im(qdivi)
+entry_ir_ir_ir_ir(qdivr_u)     entry_ir_ir_ir_im(qdivi_u)
+entry_ir_ir_ir(remr)           entry_ir_ir_im(remi)
+entry_ir_ir_ir(remr_u)         entry_ir_ir_im(remi_u)
+entry_ir_ir_ir(andr)           entry_ir_ir_im(andi)
+entry_ir_ir_ir(orr)            entry_ir_ir_im(ori)
+entry_ir_ir_ir(xorr)           entry_ir_ir_im(xori)
+entry_ir_ir_ir(lshr)           entry_ir_ir_im(lshi)
+entry_ir_ir_ir(rshr)           entry_ir_ir_im(rshi)
+entry_ir_ir_ir(rshr_u)         entry_ir_ir_im(rshi_u)
+entry_ir_ir(negr)              entry_ir_ir(comr)
+entry_ir_ir_ir(ltr)            entry_ir_ir_im(lti)
+entry_ir_ir_ir(ltr_u)          entry_ir_ir_im(lti_u)
+entry_ir_ir_ir(ler)            entry_ir_ir_im(lei)
+entry_ir_ir_ir(ler_u)          entry_ir_ir_im(lei_u)
+entry_ir_ir_ir(eqr)            entry_ir_ir_im(eqi)
+entry_ir_ir_ir(ger)            entry_ir_ir_im(gei)
+entry_ir_ir_ir(ger_u)          entry_ir_ir_im(gei_u)
+entry_ir_ir_ir(gtr)            entry_ir_ir_im(gti)
+entry_ir_ir_ir(gtr_u)          entry_ir_ir_im(gti_u)
+entry_ir_ir_ir(ner)            entry_ir_ir_im(nei)
+entry_ir_ir(movr)
+static void
+movi(void)
+{
+    int                 ch;
+    label_t    *label;
+    void       *value;
+    jit_gpr_t   r0 = get_ireg();
+    ch = skipws();
+    switch (ch) {
+       case '+': case '-':
+       case '0' ... '9':
+           ungetch(ch);
+           value = (void *)(jit_word_t)get_uint(skip_none);
+           break;
+       case '\'':
+           character();
+           value = (void *)parser.value.i;
+           break;
+       case '$':
+           switch (expression()) {
+               case tok_int:
+                   value = (void *)parser.value.i;
+                   break;
+               case tok_pointer:
+                   value = parser.value.p;
+                   break;
+               default:
+                   error("expecting pointer");
+           }
+           break;
+       case '@':
+           dynamic();
+           value = parser.value.p;
+           break;
+       default:
+           ungetch(ch);
+           label = get_label(skip_none);
+           if (label->kind == label_kind_code ||
+               label->kind == label_kind_code_forward) {
+               mov_forward((void *)jit_movi(r0, 0), label);
+               return;
+           }
+           value = label->value;
+           break;
+    }
+    jit_movi(r0, (jit_word_t)value);
+}
+entry_ir_ir(extr_c)            entry_ir_ir(extr_uc)
+entry_ir_ir(extr_s)            entry_ir_ir(extr_us)
+#if __WORDSIZE == 64
+entry_ir_ir(extr_i)            entry_ir_ir(extr_ui)
+#endif
+entry_ir_ir(htonr_us)          entry_ir_ir(ntohr_us)
+entry_ir_ir(htonr_ui)          entry_ir_ir(ntohr_ui)
+#if __WORDSIZE == 64
+entry_ir_ir(htonr_ul)          entry_ir_ir(ntohr_ul)
+#endif
+entry_ir_ir(htonr)             entry_ir_ir(ntohr)
+entry_ir_ir(ldr_c)             entry_ir_pm(ldi_c)
+entry_ir_ir(ldr_uc)            entry_ir_pm(ldi_uc)
+entry_ir_ir(ldr_s)             entry_ir_pm(ldi_s)
+entry_ir_ir(ldr_us)            entry_ir_pm(ldi_us)
+entry_ir_ir(ldr_i)             entry_ir_pm(ldi_i)
+#if __WORDSIZE == 64
+entry_ir_ir(ldr_ui)            entry_ir_pm(ldi_ui)
+entry_ir_ir(ldr_l)             entry_ir_pm(ldi_l)
+#endif
+entry_ir_ir(ldr)               entry_ir_pm(ldi)
+entry_ir_ir_ir(ldxr_c)         entry_ir_ir_im(ldxi_c)
+entry_ir_ir_ir(ldxr_uc)                entry_ir_ir_im(ldxi_uc)
+entry_ir_ir_ir(ldxr_s)         entry_ir_ir_im(ldxi_s)
+entry_ir_ir_ir(ldxr_us)                entry_ir_ir_im(ldxi_us)
+entry_ir_ir_ir(ldxr_i)         entry_ir_ir_im(ldxi_i)
+#if __WORDSIZE == 64
+entry_ir_ir_ir(ldxr_ui)                entry_ir_ir_im(ldxi_ui)
+entry_ir_ir_ir(ldxr_l)         entry_ir_ir_im(ldxi_l)
+#endif
+entry_ir_ir_ir(ldxr)           entry_ir_ir_im(ldxi)
+entry_ir_ir(str_c)             entry_pm_ir(sti_c)
+entry_ir_ir(str_s)             entry_pm_ir(sti_s)
+entry_ir_ir(str_i)             entry_pm_ir(sti_i)
+#if __WORDSIZE == 64
+entry_ir_ir(str_l)             entry_pm_ir(sti_l)
+#endif
+entry_ir_ir(str)               entry_pm_ir(sti)
+entry_ir_ir_ir(stxr_c)         entry_im_ir_ir(stxi_c)
+entry_ir_ir_ir(stxr_s)         entry_im_ir_ir(stxi_s)
+entry_ir_ir_ir(stxr_i)         entry_im_ir_ir(stxi_i)
+#if __WORDSIZE == 64
+entry_ir_ir_ir(stxr_l)         entry_im_ir_ir(stxi_l)
+#endif
+entry_ir_ir_ir(stxr)           entry_im_ir_ir(stxi)
+entry_lb_ir_ir(bltr)           entry_lb_ir_im(blti)
+entry_lb_ir_ir(bltr_u)         entry_lb_ir_im(blti_u)
+entry_lb_ir_ir(bler)           entry_lb_ir_im(blei)
+entry_lb_ir_ir(bler_u)         entry_lb_ir_im(blei_u)
+entry_lb_ir_ir(beqr)           entry_lb_ir_im(beqi)
+entry_lb_ir_ir(bger)           entry_lb_ir_im(bgei)
+entry_lb_ir_ir(bger_u)         entry_lb_ir_im(bgei_u)
+entry_lb_ir_ir(bgtr)           entry_lb_ir_im(bgti)
+entry_lb_ir_ir(bgtr_u)         entry_lb_ir_im(bgti_u)
+entry_lb_ir_ir(bner)           entry_lb_ir_im(bnei)
+entry_lb_ir_ir(bmsr)           entry_lb_ir_im(bmsi)
+entry_lb_ir_ir(bmcr)           entry_lb_ir_im(bmci)
+entry_lb_ir_ir(boaddr)         entry_lb_ir_im(boaddi)
+entry_lb_ir_ir(boaddr_u)       entry_lb_ir_im(boaddi_u)
+entry_lb_ir_ir(bxaddr)         entry_lb_ir_im(bxaddi)
+entry_lb_ir_ir(bxaddr_u)       entry_lb_ir_im(bxaddi_u)
+entry_lb_ir_ir(bosubr)         entry_lb_ir_im(bosubi)
+entry_lb_ir_ir(bosubr_u)       entry_lb_ir_im(bosubi_u)
+entry_lb_ir_ir(bxsubr)         entry_lb_ir_im(bxsubi)
+entry_lb_ir_ir(bxsubr_u)       entry_lb_ir_im(bxsubi_u)
+entry_ir(jmpr)                 entry_lb(jmpi)
+entry_ir(callr)                        entry_fn(calli)
+entry(prepare)
+entry_ir(pushargr)             entry_im(pushargi)
+entry_ir(finishr)              entry_fn(finishi)
+entry(ret)
+entry_ir(retr)                 entry_im(reti)
+entry_ir(retval_c)             entry_ir(retval_uc)
+entry_ir(retval_s)             entry_ir(retval_us)
+entry_ir(retval_i)
+#if __WORDSIZE == 64
+entry_ir(retval_ui)            entry_ir(retval_l)
+#endif
+entry_ir(retval)
+entry(epilog)
+entry_ca(arg_f)                        entry_fa(getarg_f)
+entry_fa(putargr_f)            entry_fma(putargi_f)
+entry_fr_fr_fr(addr_f)         entry_fr_fr_fm(addi_f)
+entry_fr_fr_fr(subr_f)         entry_fr_fr_fm(subi_f)
+entry_fr_fr_fr(rsbr_f)         entry_fr_fr_fm(rsbi_f)
+entry_fr_fr_fr(mulr_f)         entry_fr_fr_fm(muli_f)
+entry_fr_fr_fr(divr_f)         entry_fr_fr_fm(divi_f)
+entry_fr_fr(negr_f)            entry_fr_fr(absr_f)
+entry_fr_fr(sqrtr_f)
+entry_ir_fr_fr(ltr_f)          entry_ir_fr_fm(lti_f)
+entry_ir_fr_fr(ler_f)          entry_ir_fr_fm(lei_f)
+entry_ir_fr_fr(eqr_f)          entry_ir_fr_fm(eqi_f)
+entry_ir_fr_fr(ger_f)          entry_ir_fr_fm(gei_f)
+entry_ir_fr_fr(gtr_f)          entry_ir_fr_fm(gti_f)
+entry_ir_fr_fr(ner_f)          entry_ir_fr_fm(nei_f)
+entry_ir_fr_fr(unltr_f)                entry_ir_fr_fm(unlti_f)
+entry_ir_fr_fr(unler_f)                entry_ir_fr_fm(unlei_f)
+entry_ir_fr_fr(uneqr_f)                entry_ir_fr_fm(uneqi_f)
+entry_ir_fr_fr(unger_f)                entry_ir_fr_fm(ungei_f)
+entry_ir_fr_fr(ungtr_f)                entry_ir_fr_fm(ungti_f)
+entry_ir_fr_fr(ltgtr_f)                entry_ir_fr_fm(ltgti_f)
+entry_ir_fr_fr(ordr_f)         entry_ir_fr_fm(ordi_f)
+entry_ir_fr_fr(unordr_f)       entry_ir_fr_fm(unordi_f)
+entry_ir_fr(truncr_f_i)
+#if __WORDSIZE == 64
+entry_ir_fr(truncr_f_l)
+#endif
+entry_ir_fr(truncr_f)
+entry_fr_ir(extr_f)            entry_fr_fr(extr_d_f)
+entry_fr_fr(movr_f)            entry_fr_fm(movi_f)
+entry_fr_ir(ldr_f)             entry_fr_pm(ldi_f)
+entry_fr_ir_ir(ldxr_f)         entry_fr_ir_im(ldxi_f)
+entry_ir_fr(str_f)             entry_pm_fr(sti_f)
+entry_ir_ir_fr(stxr_f)         entry_im_ir_fr(stxi_f)
+entry_lb_fr_fr(bltr_f)         entry_lb_fr_fm(blti_f)
+entry_lb_fr_fr(bler_f)         entry_lb_fr_fm(blei_f)
+entry_lb_fr_fr(beqr_f)         entry_lb_fr_fm(beqi_f)
+entry_lb_fr_fr(bger_f)         entry_lb_fr_fm(bgei_f)
+entry_lb_fr_fr(bgtr_f)         entry_lb_fr_fm(bgti_f)
+entry_lb_fr_fr(bner_f)         entry_lb_fr_fm(bnei_f)
+entry_lb_fr_fr(bunltr_f)       entry_lb_fr_fm(bunlti_f)
+entry_lb_fr_fr(bunler_f)       entry_lb_fr_fm(bunlei_f)
+entry_lb_fr_fr(buneqr_f)       entry_lb_fr_fm(buneqi_f)
+entry_lb_fr_fr(bunger_f)       entry_lb_fr_fm(bungei_f)
+entry_lb_fr_fr(bungtr_f)       entry_lb_fr_fm(bungti_f)
+entry_lb_fr_fr(bltgtr_f)       entry_lb_fr_fm(bltgti_f)
+entry_lb_fr_fr(bordr_f)                entry_lb_fr_fm(bordi_f)
+entry_lb_fr_fr(bunordr_f)      entry_lb_fr_fm(bunordi_f)
+entry_fr(pushargr_f)           entry_fm(pushargi_f)
+entry_fr(retr_f)               entry_fm(reti_f)
+entry_fr(retval_f)
+entry_ca(arg_d)                        entry_fa(getarg_d)
+entry_fa(putargr_d)            entry_fma(putargi_d)
+entry_fr_fr_fr(addr_d)         entry_fr_fr_dm(addi_d)
+entry_fr_fr_fr(subr_d)         entry_fr_fr_dm(subi_d)
+entry_fr_fr_fr(rsbr_d)         entry_fr_fr_dm(rsbi_d)
+entry_fr_fr_fr(mulr_d)         entry_fr_fr_dm(muli_d)
+entry_fr_fr_fr(divr_d)         entry_fr_fr_dm(divi_d)
+entry_fr_fr(negr_d)            entry_fr_fr(absr_d)
+entry_fr_fr(sqrtr_d)
+entry_ir_fr_fr(ltr_d)          entry_ir_fr_dm(lti_d)
+entry_ir_fr_fr(ler_d)          entry_ir_fr_dm(lei_d)
+entry_ir_fr_fr(eqr_d)          entry_ir_fr_dm(eqi_d)
+entry_ir_fr_fr(ger_d)          entry_ir_fr_dm(gei_d)
+entry_ir_fr_fr(gtr_d)          entry_ir_fr_dm(gti_d)
+entry_ir_fr_fr(ner_d)          entry_ir_fr_dm(nei_d)
+entry_ir_fr_fr(unltr_d)                entry_ir_fr_dm(unlti_d)
+entry_ir_fr_fr(unler_d)                entry_ir_fr_dm(unlei_d)
+entry_ir_fr_fr(uneqr_d)                entry_ir_fr_dm(uneqi_d)
+entry_ir_fr_fr(unger_d)                entry_ir_fr_dm(ungei_d)
+entry_ir_fr_fr(ungtr_d)                entry_ir_fr_dm(ungti_d)
+entry_ir_fr_fr(ltgtr_d)                entry_ir_fr_dm(ltgti_d)
+entry_ir_fr_fr(ordr_d)         entry_ir_fr_dm(ordi_d)
+entry_ir_fr_fr(unordr_d)       entry_ir_fr_dm(unordi_d)
+entry_ir_fr(truncr_d_i)
+#if __WORDSIZE == 64
+entry_ir_fr(truncr_d_l)
+#endif
+entry_ir_fr(truncr_d)
+entry_fr_ir(extr_d)            entry_fr_fr(extr_f_d)
+entry_fr_fr(movr_d)            entry_fr_dm(movi_d)
+entry_fr_ir(ldr_d)             entry_fr_pm(ldi_d)
+entry_fr_ir_ir(ldxr_d)         entry_fr_ir_im(ldxi_d)
+entry_ir_fr(str_d)             entry_pm_fr(sti_d)
+entry_ir_ir_fr(stxr_d)         entry_im_ir_fr(stxi_d)
+entry_lb_fr_fr(bltr_d)         entry_lb_fr_dm(blti_d)
+entry_lb_fr_fr(bler_d)         entry_lb_fr_dm(blei_d)
+entry_lb_fr_fr(beqr_d)         entry_lb_fr_dm(beqi_d)
+entry_lb_fr_fr(bger_d)         entry_lb_fr_dm(bgei_d)
+entry_lb_fr_fr(bgtr_d)         entry_lb_fr_dm(bgti_d)
+entry_lb_fr_fr(bner_d)         entry_lb_fr_dm(bnei_d)
+entry_lb_fr_fr(bunltr_d)       entry_lb_fr_dm(bunlti_d)
+entry_lb_fr_fr(bunler_d)       entry_lb_fr_dm(bunlei_d)
+entry_lb_fr_fr(buneqr_d)       entry_lb_fr_dm(buneqi_d)
+entry_lb_fr_fr(bunger_d)       entry_lb_fr_dm(bungei_d)
+entry_lb_fr_fr(bungtr_d)       entry_lb_fr_dm(bungti_d)
+entry_lb_fr_fr(bltgtr_d)       entry_lb_fr_dm(bltgti_d)
+entry_lb_fr_fr(bordr_d)                entry_lb_fr_dm(bordi_d)
+entry_lb_fr_fr(bunordr_d)      entry_lb_fr_dm(bunordi_d)
+entry_fr(pushargr_d)           entry_dm(pushargi_d)
+entry_fr(retr_d)               entry_dm(reti_d)
+entry_fr(retval_d)
+static void
+vastart(void)
+{
+    jit_gpr_t  r0 = get_ireg();
+    jit_va_start(r0);
+}
+static void
+vapush(void)
+{
+    jit_gpr_t  r0 = get_ireg();
+    jit_va_push(r0);
+}
+static void
+vaarg(void)
+{
+    jit_gpr_t  r0 = get_ireg(), r1 = get_ireg();
+    jit_va_arg(r0, r1);
+}
+static void
+vaarg_d(void)
+{
+    jit_fpr_t  r0 = get_freg();
+    jit_gpr_t  r1 = get_ireg();
+    jit_va_arg_d(r0, r1);
+}
+static void
+vaend(void)
+{
+    jit_gpr_t  r0 = get_ireg();
+    jit_va_end(r0);
+}
+#undef entry_fn
+#undef entry_fm
+#undef entry_dm
+#undef entry_lb_fr_fm
+#undef entry_lb_fr_dm
+#undef entry_lb_fr_fr
+#undef entry_im_ir_fr
+#undef entry_ir_ir_fr
+#undef entry_pm_fr
+#undef entry_fr_ir_ir
+#undef entry_fr_ir_im
+#undef entry_fr_pm
+#undef entry_fr_fm
+#undef entry_fr_dm
+#undef entry_fr_ir
+#undef entry_ir_fr
+#undef entry_ir_fr_fm
+#undef entry_ir_fr_dm
+#undef entry_ir_fr_fr
+#undef entry_fr_fr
+#undef entry_fr_fr_fm
+#undef entry_fr_fr_dm
+#undef entry_fr_fr_fr
+#undef entry_fma
+#undef entry_fa
+#undef entry_pm
+#undef entry_lb
+#undef entry_lb_ir_im
+#undef entry_lb_ir_ir
+#undef entry_im_ir_ir
+#undef entry_pm_ir
+#undef entry_ir_pm
+#undef entry_ir_im
+#undef entry_ir_ir
+#undef entry_ir_ir_im
+#undef entry_ir_ir_ir
+#undef entry_ima
+#undef entry_ir
+#undef entry_im
+#undef entry_ia
+#undef entry_ca
+#undef entry
+
+static void
+error(const char *format, ...)
+{
+    va_list     ap;
+    int                 length;
+    char       *string;
+
+    va_start(ap, format);
+    message("error", format, ap);
+    va_end(ap);
+    length = parser.data.length - parser.data.offset;
+    string = (char *)(parser.data.buffer + parser.data.offset - 1);
+    if (length > 77)
+       strcpy(string + 74, "...");
+    else
+       parser.data.buffer[parser.data.length - 1] = '\0';
+    fprintf(stderr, "(%s)\n", string);
+    exit(-1);
+}
+
+static void
+warn(const char *format, ...)
+{
+    va_list    ap;
+    va_start(ap, format);
+    message("warning", format, ap);
+    va_end(ap);
+}
+
+static void
+message(const char *kind, const char *format, va_list ap)
+{
+    fprintf(stderr, "%s:%d: %s: ", parser.name,
+           parser.line - parser.newline, kind);
+    vfprintf(stderr, format, ap);
+    fputc('\n', stderr);
+}
+
+static int
+getch(void)
+{
+    int                ch;
+
+    if (parser.data.offset < parser.data.length)
+       ch = parser.data.buffer[parser.data.offset++];
+    else {
+       /* keep first offset for ungetch */
+       if ((parser.data.length = fread(parser.data.buffer + 1, 1,
+                                       sizeof(parser.data.buffer) - 1,
+                                       parser.fp) + 1) <= 1) {
+           ch = EOF;
+           parser.data.offset = 1;
+       }
+       else {
+           ch = parser.data.buffer[1];
+           parser.data.offset = 2;
+       }
+    }
+    if ((parser.newline = ch == '\n'))
+       ++parser.line;
+
+    return (ch);
+}
+
+static int
+getch_noeof(void)
+{
+    int                ch = getch();
+
+    if (ch == EOF)
+       error("unexpected end of file");
+
+    return (ch);
+}
+
+static int
+ungetch(int ch)
+{
+    if ((parser.newline = ch == '\n'))
+       --parser.line;
+
+    if (parser.data.offset)
+       parser.data.buffer[--parser.data.offset] = ch;
+    else
+       /* overwrite */
+       parser.data.buffer[0] = ch;
+
+    return (ch);
+}
+
+static int
+skipws(void)
+{
+    int                ch;
+
+    for (ch = getch();; ch = getch()) {
+       switch (ch) {
+           case '/':
+               ch = skipct();
+               break;
+           case '#':
+               ch = skipcp();
+               break;
+       }
+       switch (ch) {
+           case ' ': case '\f': case '\r': case '\t':
+               break;
+           default:
+               return (ch);
+       }
+    }
+}
+
+static int
+skipnl(void)
+{
+    int                ch;
+
+    for (ch = getch();; ch = getch()) {
+       switch (ch) {
+           case '/':
+               ch = skipct();
+               break;
+           case '#':
+               ch = skipcp();
+               break;
+       }
+       switch (ch) {
+           case ' ': case '\f': case '\n': case '\r': case '\t':
+               break;
+               /* handle as newline */
+           case ';':
+               break;
+           default:
+               return (ch);
+       }
+    }
+}
+
+static int
+skipct(void)
+{
+    int                ch;
+
+    ch = getch();
+    switch (ch) {
+       case '/':
+           for (ch = getch(); ch != '\n' && ch != EOF; ch = getch())
+               ;
+           return (ch);
+       case '*':
+           for (; ch != '/';) {
+               while (getch_noeof() != '*')
+                   ;
+               while ((ch = getch_noeof()) == '*')
+                   ;
+           }
+           return (getch());
+       default:
+           ungetch(ch);
+           return ('/');
+    }
+}
+
+static int
+skipcp(void)
+{
+    int                ch;
+
+    for (ch = getch(); ch != '\n' && ch != EOF; ch = getch()) {
+       switch (ch) {
+           case '0' ... '9':
+               if ((number(ch)) == tok_int)
+                   parser.line = parser.value.i - 1;
+               break;
+           case '"':
+               string();
+               if (parser.offset >= (int)sizeof(parser.name)) {
+                   strncpy(parser.name, parser.string, sizeof(parser.name));
+                   parser.name[sizeof(parser.name) - 1] = '\0';
+               }
+               else
+                   strcpy(parser.name, parser.string);
+               break;
+           default:
+               break;
+       }
+    }
+
+    return (ch);
+}
+
+static jit_word_t
+get_int(skip_t skip)
+{
+    switch (primary(skip)) {
+       case tok_int:
+           break;
+       case tok_pointer:
+           parser.type = type_l;
+           parser.value.i = (jit_word_t)parser.value.p;
+           break;
+       default:
+           error("expecting integer");
+    }
+
+    return (parser.value.i);
+}
+
+static jit_uword_t
+get_uint(skip_t skip)
+{
+    switch (primary(skip)) {
+       case tok_char:          case tok_int:
+           break;
+       case tok_pointer:
+           parser.type = type_l;
+           parser.value.ui = (jit_uword_t)parser.value.p;
+           break;
+       default:
+           error("expecting integer");
+    }
+
+    return (parser.value.ui);
+}
+
+static double
+get_float(skip_t skip)
+{
+    switch (primary(skip)) {
+       case tok_char:
+       case tok_int:
+           parser.type = type_d;
+           parser.value.d = parser.value.i;
+           break;
+       case tok_float:
+           break;
+       default:
+           error("expecting float");
+    }
+
+    return (parser.value.d);
+}
+
+/* Workaround gcc not converting unordered values from double to
+ * float (as done in other architectures) on s390 */
+static float
+make_float(double d)
+{
+    /* This is an workaround to a bug in Hercules s390 emulator,
+     * and at least HP-UX ia64 not have these */
+#if defined(HAVE_ISNAN) && defined(HAVE_ISINF)
+    if (isnan(d))      return ( 0.0f/0.0f);
+    if (isinf(d)) {
+       if (d > 0.0)    return ( 1.0f/0.0f);
+       else            return (-1.0f/0.0f);
+    }
+#endif
+    return ((float)d);
+}
+
+static void *
+get_pointer(skip_t skip)
+{
+    label_t    *label;
+    token_t     token = primary(skip);
+
+    switch (token) {
+       case tok_symbol:
+           label = get_label_by_name(parser.string);
+           if (label == NULL)
+               error("bad identifier %s", parser.string);
+           switch (label->kind) {
+               case label_kind_data:
+               case label_kind_code:
+                   break;
+               case label_kind_code_forward:
+                   /* as expression arguments */
+                   error("forward references not implemented");
+                   break;
+               case label_kind_dynamic:
+                   break;
+           }
+           parser.type = type_p;
+           return (parser.value.p = label->value);
+       case tok_int:
+           parser.type = type_p;
+           return (parser.value.p = (void *)parser.value.ui);
+       case tok_pointer:
+           return (parser.value.p);
+       default:                error("bad pointer");
+    }
+}
+
+static label_t *
+get_label(skip_t skip)
+{
+    label_t    *label;
+    int                 ch = skipws();
+
+    switch (ch) {
+       case '@':
+           (void)dynamic();
+           break;
+       case 'a' ... 'z': case 'A' ... 'Z': case '_':
+           (void)identifier(ch);
+           break;
+       default:
+           error("expecting label/immediate");
+    }
+    if ((label = get_label_by_name(parser.string)) == NULL)
+       label = new_label(label_kind_code_forward,
+                         parser.string, jit_forward());
+
+    return (label);
+}
+
+static token_t
+regname(void)
+{
+    jit_word_t num;
+    int                check = 1, ch = getch();
+
+    switch (ch) {
+       case 'r':
+           parser.regtype = type_l;
+           switch (ch = getch()) {
+               case '0':       parser.regval = JIT_R0;         break;
+               case '1':       parser.regval = JIT_R1;         break;
+               case '2':       parser.regval = JIT_R2;         break;
+               case '(':
+                   num = get_int(skip_none);
+                   if (num < 0 || num >= JIT_R_NUM)            goto fail;
+                   parser.regval = JIT_R(num);
+                   if (getch() != ')')                         goto fail;
+                   check = 0;
+                   break;
+               default:                                        goto fail;
+           }
+           break;
+       case 'v':
+           parser.regtype = type_l;
+           switch (ch = getch()) {
+               case '0':       parser.regval = JIT_V0;         break;
+               case '1':       parser.regval = JIT_V1;         break;
+               case '2':       parser.regval = JIT_V2;         break;
+               default:                                        goto fail;
+               case '(':
+                   num = get_int(skip_none);
+                   if (num < 0 || num >= JIT_V_NUM)            goto fail;
+                   parser.regval = JIT_V(num);
+                   if (getch() != ')')                         goto fail;
+                   check = 0;
+                   break;
+           }
+           break;
+       case 'f':
+           parser.regtype = type_d;
+           switch (ch = getch()) {
+               case '0':       parser.regval = JIT_F0;         break;
+               case '1':       parser.regval = JIT_F1;         break;
+               case '2':       parser.regval = JIT_F2;         break;
+               case '3':       parser.regval = JIT_F3;         break;
+               case '4':       parser.regval = JIT_F4;         break;
+               case '5':       parser.regval = JIT_F5;         break;
+               case 'p':
+                   parser.regtype = type_l;    /* oops */
+                   parser.regval = JIT_FP;                     break;
+               case '(':
+                   num = get_int(skip_none);
+                   if (num < 0 || num >= JIT_F_NUM)            goto fail;
+                   parser.regval = JIT_F(num);
+                   if (getch() != ')')                         goto fail;
+                   check = 0;
+                   break;
+               default:                                        goto fail;
+           }
+           break;
+       default:
+       fail:
+           error("bad register");
+    }
+    if (check) {
+       ch = getch();
+       if ((ch >= 'a' && ch <= 'z') ||
+           (ch >= 'A' && ch <= 'Z') ||
+           (ch >= '0' && ch <= '9') ||
+           ch == '_')
+           goto fail;
+       ungetch(ch);
+    }
+
+    return (tok_register);
+}
+
+static token_t
+identifier(int ch)
+{
+    parser.string[0] = ch;
+    for (parser.offset = 1;;) {
+       switch ((ch = getch())) {
+           case 'a' ... 'z': case 'A' ... 'Z': case '0' ... '9' :  case '_':
+               if (parser.offset + 1 >= MAX_IDENTIFIER) {
+                   parser.string[parser.offset] = '\0';
+                   error("bad identifier %s", parser.string);
+               }
+               parser.string[parser.offset++] = ch;
+               break;
+           default:
+               parser.string[parser.offset] = '\0';
+               ungetch(ch);
+               return (tok_symbol);
+       }
+    }
+}
+
+static void
+get_data(type_t type)
+{
+    int                 ch;
+    token_t     token;
+    char       *test = data;
+
+    for (;;) {
+       switch (type) {
+           case type_c:
+               switch (token = primary(skip_ws)) {
+                   case tok_char: case tok_int:
+                       check_data(sizeof(signed char));
+                       *(signed char *)(data + data_offset) = parser.value.i;
+                       data_offset += sizeof(char);
+                       break;
+                   case tok_string:
+                       check_data(parser.offset);
+                       memcpy(data + data_offset, parser.string,
+                              parser.offset);
+                       data_offset += parser.offset;
+                       break;
+                   case tok_newline:
+                   case tok_semicollon:
+                       if (test == data)       error("syntax error");
+                       return;
+                   default:                    error("bad initializer");
+               }
+               break;
+           case type_s:
+               check_data(sizeof(signed short));
+               *(signed short *)(data + data_offset) = get_int(skip_ws);
+               data_offset += sizeof(short);
+               break;
+           case type_i:
+               check_data(sizeof(signed int));
+               *(signed int *)(data + data_offset) = get_int(skip_ws);
+               data_offset += sizeof(int);
+               break;
+           case type_l:
+               check_data(sizeof(jit_word_t));
+               *(jit_word_t *)(data + data_offset) = get_int(skip_ws);
+               data_offset += sizeof(jit_word_t);
+               break;
+           case type_f:
+               check_data(sizeof(float));
+               *(float *)(data + data_offset) = get_float(skip_ws);
+               data_offset += sizeof(float);
+               break;
+           case type_d:
+               check_data(sizeof(double));
+               *(double *)(data + data_offset) = get_float(skip_ws);
+               data_offset += sizeof(double);
+               break;
+           case type_p:
+               /* FIXME **patch if realloc** */
+               check_data(sizeof(void*));
+               *(void **)(data + data_offset) = get_pointer(skip_ws);
+               data_offset += sizeof(void*);
+               break;
+           default:
+               abort();
+       }
+       ch = skipws();
+       if (ch == '\n' || ch == ';' || ch == EOF)
+           break;
+       ungetch(ch);
+    }
+}
+
+static void
+dot(void)
+{
+    int                ch;
+    size_t     offset, length;
+
+    switch (ch = getch_noeof()) {
+       case '$':
+           /* use .$(expression) for non side effects expression */
+           (void)expression();
+           return;
+       case 'a' ... 'z': case 'A' ... 'Z': case '_':
+           (void)identifier(ch);
+           break;
+       default:
+           ungetch(ch);
+           if (skipws() != '$')
+               error("expecting symbol");
+           /* allow spaces before an expression */
+           (void)expression();
+           return;
+    }
+    if (parser.string[1] == '\0') {
+       switch (parser.string[0]) {
+           case 'c':   get_data(type_c);       break;
+           case 's':   get_data(type_s);       break;
+           case 'i':   get_data(type_i);       break;
+           case 'l':   get_data(type_l);       break;
+           case 'f':   get_data(type_f);       break;
+           case 'd':   get_data(type_d);       break;
+           case 'p':   get_data(type_p);       break;
+           default:    error("bad type .%c", parser.string[0]);
+       }
+    }
+    else if (strcmp(parser.string, "data") == 0) {
+       if (parser.parsing != PARSING_NONE)
+           error(".data must be specified once and be the first section");
+       parser.parsing = PARSING_DATA;
+       data_length = get_int(skip_ws);
+       data = (char *)xcalloc(1, data_length);
+    }
+    else if (strcmp(parser.string, "code") == 0) {
+       if (parser.parsing != PARSING_NONE &&
+           parser.parsing != PARSING_DATA)
+           error(".code must be specified once only");
+       parser.parsing = PARSING_CODE;
+    }
+    else if (strcmp(parser.string, "align") == 0) {
+       length = get_int(skip_ws);
+       if (parser.parsing != PARSING_DATA)
+           error(".align must be in .data");
+       if (length > 1 && length <= 4096 && !(length & (length - 1))) {
+           offset = data_offset;
+           offset += length - ((offset + length) % length);
+           check_data(offset - data_offset);
+           data_offset = offset;
+       }
+       else
+           error("bad .align %ld (must be a power of 2, >= 2 && <= 4096)",
+                 (jit_word_t)length);
+    }
+    else if (strcmp(parser.string, "size") == 0) {
+       length = get_int(skip_ws);
+       if (parser.parsing != PARSING_DATA)
+           error(".size must be in .data");
+       check_data(length);
+       data_offset += length;
+    }
+    else if (strcmp(parser.string, "disasm") == 0)
+       flag_disasm = 1;
+    else
+       error("unknown command .%s", parser.string);
+}
+
+static token_t
+number(int ch)
+{
+    char       buffer[1024], *endptr;
+    int                integer = 1, offset = 0, neg = 0, e = 0, d = 0, base = 10;
+
+    for (;; ch = getch()) {
+       switch (ch) {
+           case '-':
+               if (offset == 0) {
+                   neg = 1;
+                   continue;
+               }
+               if (offset && buffer[offset - 1] != 'e') {
+                   ungetch(ch);
+                   goto done;
+               }
+               break;
+           case '+':
+               if (offset == 0)
+                   continue;
+               if (offset && buffer[offset - 1] != 'e') {
+                   ungetch(ch);
+                   goto done;
+               }
+               break;
+           case '.':
+               if (d)
+                   goto fail;
+               d = 1;
+               base = 10;
+               integer = 0;
+               break;
+           case '0':
+               if (offset == 0 && base == 10) {
+                   base = 8;
+                   continue;
+               }
+               break;
+           case 'b':
+               if (offset == 0 && base == 8) {
+                   base = 2;
+                   continue;
+               }
+               if (base != 16)
+                   goto fail;
+               break;
+           case '1':
+               break;
+           case '2' ... '7':
+               if (base < 8)
+                   goto fail;
+               break;
+           case '8': case '9':
+               if (base < 10)
+                   goto fail;
+               break;
+           case 'x':
+               if (offset == 0 && base == 8) {
+                   base = 16;
+                   continue;
+               }
+               goto fail;
+           case 'a': case 'c': case 'd': case 'f':
+               if (base < 16)
+                   goto fail;
+               break;
+           case 'e':
+               if (e)
+                   goto fail;
+               if (base != 16) {
+                   e = 1;
+                   base = 10;
+                   integer = 0;
+               }
+               break;
+           case '_': case 'g' ... 'w': case 'y': case 'z': case 'A' ... 'Z':
+           fail:
+               buffer[offset++] = '\0';
+               error("bad constant %s", buffer);
+           default:
+               ungetch(ch);
+               goto done;
+       }
+       if (offset + 1 >= (int)sizeof(buffer))
+           goto fail;
+       buffer[offset++] = ch;
+    }
+done:
+    /* check for literal 0 */
+    if (offset == 0 && base == 8)      buffer[offset++] = '0';
+    buffer[offset] = '\0';
+    if (integer) {
+#if _WIN32
+#  define STRTOUL      strtoull
+#else
+#  define STRTOUL      strtoul
+#endif
+       parser.value.ui = STRTOUL(buffer, &endptr, base);
+       parser.type = type_l;
+       if (neg)
+           parser.value.i = -parser.value.i;
+    }
+    else {
+       parser.type = type_d;
+       parser.value.d = strtod(buffer, &endptr);
+       if (neg)
+           parser.value.d = -parser.value.d;
+    }
+    if (*endptr)
+       goto fail;
+
+    return (integer ? tok_int : tok_float);
+}
+
+static int
+escape(int ch)
+{
+    switch (ch) {
+       case 'a':       ch = '\a';      break;
+       case 'b':       ch = '\b';      break;
+       case 'f':       ch = '\f';      break;
+       case 'n':       ch = '\n';      break;
+       case 'r':       ch = '\r';      break;
+       case 't':       ch = '\t';      break;
+       case 'v':       ch = '\v';      break;
+       default:                        break;
+    }
+
+    return (ch);
+}
+
+static token_t
+string(void)
+{
+    int                ch, esc = 0;
+
+    for (parser.offset = 0;;) {
+       switch (ch = getch_noeof()) {
+           case '\\':
+               if (esc)                goto append;
+               esc = 1;
+               break;
+           case '"':
+               if (!esc) {
+                   parser.string[parser.offset++] = '\0';
+                   parser.value.p = parser.string;
+                   parser.type = type_p;
+                   return (tok_string);
+               }
+               /* FALLTHROUGH */
+           default:
+           append:
+               if (esc) {
+                   ch = escape(ch);
+                   esc = 0;
+               }
+               if (parser.offset + 1 >= parser.length) {
+                   parser.length += 4096;
+                   parser.string = (char *)xrealloc(parser.string,
+                                                    parser.length);
+               }
+               parser.string[parser.offset++] = ch;
+               break;
+       }
+    }
+}
+
+static token_t
+character(void)
+{
+    int                ch, esc = 0;
+
+    if ((ch = getch_noeof()) == '\\') {
+       esc = 1;
+       ch = getch();
+    }
+    if (getch_noeof() != '\'')
+       error("bad single byte char");
+    if (esc)
+       ch = escape(ch);
+    parser.type = type_l;
+    parser.value.i = ch & 0xff;
+
+    return (tok_char);
+}
+
+static token_t
+dynamic(void)
+{
+    label_t    *label;
+    void       *value;
+    char       *string;
+    (void)identifier('@');
+    if ((label = get_label_by_name(parser.string)) == NULL) {
+#if __CYGWIN__ ||_WIN32
+       /* FIXME kludge to pass varargs test case, otherwise,
+        * will not print/scan float values */
+       if (strcmp(parser.string + 1, "sprintf") == 0)
+           value = sprintf;
+       else if (strcmp(parser.string + 1, "sscanf") == 0)
+           value = sscanf;
+       else
+#endif
+       {
+           value = dlsym(DL_HANDLE, parser.string + 1);
+           if ((string = dlerror()))
+               error("%s", string);
+       }
+       label = new_label(label_kind_dynamic, parser.string, value);
+    }
+    parser.type = type_p;
+    parser.value.p = label->value;
+
+    return (tok_pointer);
+}
+
+static void
+expression_prim(void)
+{
+    int                 ch;
+    token_t     token;
+    label_t    *label;
+    symbol_t   *symbol;
+
+    if (parser.putback) {
+       parser.expr = parser.putback;
+       parser.putback = (expr_t)0;
+       return;
+    }
+    switch (ch = skipws()) {
+       case '!':
+           if ((ch = getch_noeof()) == '=')    parser.expr = expr_ne;
+           else {
+               ungetch(ch);                    parser.expr = expr_not;
+           }
+           break;
+       case '~':                               parser.expr = expr_com;
+           break;
+       case '*':
+           if ((ch = getch_noeof()) == '=')    parser.expr = expr_mulset;
+           else {
+               ungetch(ch);                    parser.expr = expr_mul;
+           }
+           break;
+       case '/':
+           if ((ch = getch_noeof()) == '=')    parser.expr = expr_divset;
+           else {
+               ungetch(ch);                    parser.expr = expr_div;
+           }
+           break;
+       case '%':
+           if ((ch = getch_noeof()) == '=')    parser.expr = expr_remset;
+           else {
+               ungetch(ch);                    parser.expr = expr_rem;
+           }
+           break;
+       case '+':
+           switch (ch = getch_noeof()) {
+               case '+':                       parser.expr = expr_inc;
+                   break;
+               case '=':                       parser.expr = expr_addset;
+                   break;
+               default:        ungetch(ch);    parser.expr = expr_add;
+                   break;
+           }
+           break;
+       case '-':
+           switch (ch = getch_noeof()) {
+               case '-':                       parser.expr = expr_dec;
+                   break;
+               case '=':                       parser.expr = expr_subset;
+                   break;
+               default:        ungetch(ch);    parser.expr = expr_sub;
+                   break;
+           }
+           break;
+       case '<':
+           switch (ch = getch_noeof()) {
+               case '=':                       parser.expr = expr_le;
+                   break;
+               case '<':                       ch = getch_noeof();
+                   if (ch == '=')              parser.expr = expr_lshset;
+                   else {
+                       ungetch(ch);            parser.expr = expr_lsh;
+                   }
+                   break;
+               default:        ungetch(ch);    parser.expr = expr_lt;
+                   break;
+           }
+           break;
+       case '>':
+           switch (ch = getch_noeof()) {
+               case '=':                       parser.expr = expr_ge;
+                   break;
+               case '>':                       ch = getch_noeof();
+                   if (ch == '=')              parser.expr = expr_rshset;
+                   else {
+                       ungetch(ch);            parser.expr = expr_rsh;
+                   }
+                   break;
+               default:        ungetch(ch);    parser.expr = expr_gt;
+                   break;
+           }
+           break;
+       case '&':
+           switch (ch = getch_noeof()) {
+               case '=':                       parser.expr = expr_andset;
+                   break;
+               case '&':                       parser.expr = expr_andand;
+                   break;
+               default:        ungetch(ch);    parser.expr = expr_and;
+                   break;
+           }
+           break;
+       case '|':
+           switch (ch = getch_noeof()) {
+               case '=':                       parser.expr = expr_orset;
+                   break;
+               case '|':                       parser.expr = expr_oror;
+                   break;
+               default:        ungetch(ch);    parser.expr = expr_or;
+                   break;
+           }
+           break;
+       case '^':
+           if ((ch = getch_noeof()) == '=')    parser.expr = expr_xorset;
+           else {
+               ungetch(ch);                    parser.expr = expr_xor;
+           }
+           break;
+       case '=':
+           if ((ch = getch_noeof()) == '=')    parser.expr = expr_eq;
+           else {
+               ungetch(ch);                    parser.expr = expr_set;
+           }
+           break;
+       case '(':                               parser.expr = expr_lparen;
+           break;
+       case ')':                               parser.expr = expr_rparen;
+           break;
+       case '0' ... '9':
+           token = number(ch);
+           parser.expr = token == tok_int ? expr_int : expr_float;
+           break;
+       case '@':
+           (void)dynamic();
+           parser.expr = expr_pointer;
+           break;
+       case '$':
+           identifier('$');
+           /* no support for nested expressions */
+           if (parser.string[0] == '\0')
+               error("syntax error");
+           parser.expr = expr_symbol;
+           if ((symbol = get_symbol_by_name(parser.string)) != NULL) {
+               parser.type = symbol->type;
+               parser.value = symbol->value;
+           }
+           else
+               /* only create symbol on assignment */
+               parser.type = type_none;
+           break;
+       case 'a' ... 'z': case 'A' ... 'Z': case '_':
+           identifier(ch);
+           if ((label = get_label_by_name(parser.string))) {
+               if (label->kind == label_kind_code_forward)
+                   error("forward value for %s not supported",
+                         parser.string);
+               parser.expr = expr_pointer;
+               parser.type = type_p;
+               parser.value.p = label->value;
+           }
+           else
+               error("invalid identifier %s", parser.string);
+           break;
+       case '\'':
+           character();
+           parser.expr = expr_int;
+           break;
+       case '"':
+           /* not smart enough to put it in data and/or relocate it, etc */
+           error("must declare strings as data");
+       default:
+           error("syntax error");
+    }
+}
+
+static void
+expression_inc(int pre)
+{
+    symbol_t   *symbol;
+
+    if (pre) {
+       expression_prim();
+       if (parser.expr != expr_symbol)
+           error("syntax error");
+    }
+    if ((symbol = get_symbol_by_name(parser.string)) == NULL) {
+       if (!parser.short_circuit)
+           error("undefined symbol %s", symbol->name);
+    }
+    if (!parser.short_circuit) {
+       parser.type = symbol->type;
+       if (!pre)
+           parser.value = symbol->value;
+       switch (symbol->type) {
+           case type_l:
+               ++symbol->value.i;
+               break;
+           case type_d:
+               /* should really be an error */
+               symbol->value.d += 1.0;
+               break;
+           default:
+               ++parser.value.cp;
+               break;
+       }
+       if (pre)
+           parser.value = symbol->value;
+    }
+    expression_prim();
+}
+
+static void
+expression_dec(int pre)
+{
+    symbol_t   *symbol;
+
+    if (pre) {
+       expression_prim();
+       if (parser.expr != expr_symbol)
+           error("syntax error");
+    }
+    if ((symbol = get_symbol_by_name(parser.string)) == NULL) {
+       if (!parser.short_circuit)
+           error("undefined symbol %s", symbol->name);
+    }
+    if (!parser.short_circuit) {
+       parser.type = symbol->type;
+       if (!pre)
+           parser.value = symbol->value;
+       switch (symbol->type) {
+           case type_l:
+               --symbol->value.i;
+               break;
+           case type_d:
+               /* should really be an error */
+               symbol->value.d -= 1.0;
+               break;
+           default:
+               --parser.value.cp;
+               break;
+       }
+       if (pre)
+           parser.value = symbol->value;
+    }
+    expression_prim();
+}
+
+static void
+expression_unary(void)
+{
+    symbol_t   *symbol;
+    char        buffer[256];
+
+    expression_prim();
+    switch (parser.expr) {
+       case expr_add:
+           expression_unary();
+           switch (parser.type) {
+               case type_l:
+               case type_d:
+                   break;
+               default:
+                   error("syntax error");
+           }
+           break;
+       case expr_sub:
+           expression_unary();
+           switch (parser.type) {
+               case type_l:
+                   parser.value.i = -parser.value.i;
+                   break;
+               case type_d:
+                   parser.value.d = -parser.value.d;
+                   break;
+               default:
+                   error("syntax error");
+           }
+           break;
+       case expr_inc:
+           expression_inc(1);
+           break;
+       case expr_dec:
+           expression_dec(1);
+           break;
+       case expr_not:
+           expression_unary();
+           switch (parser.type) {
+               case type_l:
+                   parser.value.i = !parser.value.i;
+                   break;
+               case type_d:
+                   parser.value.i = parser.value.d != 0;
+                   break;
+               case type_p:
+                   parser.value.i = parser.value.p != NULL;
+                   break;
+               default:
+                   error("syntax error");
+           }
+           parser.type = type_l;
+           break;
+       case expr_com:
+           expression_unary();
+           if (parser.type != type_l)
+               error("syntax error");
+           parser.value.i = ~parser.value.i;
+           break;
+       case expr_lparen:
+           expression_cond();
+           if (parser.expr != expr_rparen)
+               error("syntax error");
+           expression_prim();
+           break;
+       case expr_symbol:
+           strcpy(buffer, parser.string);
+           expression_prim();
+           switch (parser.expr) {
+               case expr_set:
+                   if ((symbol = get_symbol_by_name(buffer)) == NULL) {
+                       if (!parser.short_circuit)
+                           symbol = new_symbol(buffer);
+                   }
+                   expression_cond();
+               set:
+                   if (!parser.short_circuit) {
+                       if (symbol == NULL)
+                           error("syntax error");
+                       symbol->type = parser.type;
+                       symbol->value = parser.value;
+                   }
+                   break;
+               case expr_mulset:               parser.putback = expr_mul;
+                   goto check;
+               case expr_divset:               parser.putback = expr_div;
+                   goto check;
+               case expr_remset:               parser.putback = expr_rem;
+                   goto check;
+               case expr_addset:               parser.putback = expr_add;
+                   goto check;
+               case expr_subset:               parser.putback = expr_sub;
+                   goto check;
+               case expr_lshset:               parser.putback = expr_lsh;
+                   goto check;
+               case expr_rshset:               parser.putback = expr_rsh;
+                   goto check;
+               case expr_andset:               parser.putback = expr_and;
+                   goto check;
+               case expr_orset:                parser.putback = expr_or;
+                   goto check;
+               case expr_xorset:               parser.putback = expr_xor;
+               check:
+                   if ((symbol = get_symbol_by_name(buffer)) == NULL) {
+                       if (!parser.short_circuit)
+                           error("undefined symbol %s", buffer);
+                       parser.type = type_l;
+                       parser.value.i = 1;
+                   }
+                   switch (parser.putback) {
+                       case expr_mul:  case expr_div:  case expr_rem:
+                           expression_mul();
+                           break;
+                       case expr_add:  case expr_sub:
+                           expression_add();
+                           break;
+                       case expr_lsh:  case expr_rsh:
+                           expression_shift();
+                           break;
+                       case expr_and:  case expr_or:  case expr_xor:
+                           expression_bit();
+                           break;
+                       default:
+                           abort();
+                   }
+                   goto set;
+               case expr_inc:
+                   expression_inc(0);
+                   break;
+               case expr_dec:
+                   expression_dec(0);
+                   break;
+               default:
+                   break;
+           }
+           break;
+       case expr_int:
+       case expr_float:
+       case expr_pointer:
+           /* make next token available */
+           expression_prim();
+       default:
+           break;
+    }
+}
+
+static void
+expression_mul(void)
+{
+    type_t     type;
+    value_t    value;
+
+    expression_unary();
+    switch (parser.type) {
+       case type_l:    case type_d:    case type_p:    break;
+       default:                                        return;
+    }
+    for (;;) {
+       switch (parser.expr) {
+           case expr_mul:
+               type = parser.type, value = parser.value;
+               expression_unary();
+               switch (parser.type) {
+                   case type_l:
+                       if (type == type_l)
+                           value.i *= parser.value.i;
+                       else
+                           value.d *= parser.value.i;
+                       break;
+                   case type_d:
+                       if (type == type_l) {
+                           type = type_d;
+                           value.d = value.i;
+                       }
+                       value.d *= parser.value.d;
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type, parser.value = value;
+               break;
+           case expr_div:
+               type = parser.type, value = parser.value;
+               expression_unary();
+               switch (parser.type) {
+                   case type_l:
+                       if (type == type_l) {
+                           if (parser.value.i == 0)
+                               error("divide by zero");
+                           value.i /= parser.value.i;
+                       }
+                       else
+                           value.d /= parser.value.i;
+                       break;
+                   case type_d:
+                       if (type == type_l) {
+                           type = type_d;
+                           value.d = value.i;
+                       }
+                       value.d /= parser.value.d;
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type, parser.value = value;
+               break;
+           case expr_rem:
+               type = parser.type, value = parser.value;
+               expression_unary();
+               switch (parser.type) {
+                   case type_l:
+                       if (type == type_l) {
+                           if (parser.value.i == 0)
+                               error("divide by zero");
+                           value.i %= parser.value.i;
+                       }
+                       else
+                           error("invalid operand");
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type, parser.value = value;
+               break;
+           default:
+               return;
+       }
+    }
+}
+
+static void
+expression_add(void)
+{
+    type_t     type;
+    value_t    value;
+
+    expression_mul();
+    switch (parser.type) {
+       case type_l:    case type_d:    case type_p:    break;
+       default:                                        return;
+    }
+    for (;;) {
+       switch (parser.expr) {
+           case expr_add:
+               type = parser.type, value = parser.value;
+               expression_mul();
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i += parser.value.i;
+                               break;
+                           case type_d:
+                               value.d += parser.value.i;
+                               break;
+                           default:
+                               value.cp += parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               type = type_d;
+                               value.d = value.i;
+                               break;
+                           case type_d:
+                               break;
+                           default:
+                               error("invalid operand");
+                       }
+                       value.d += parser.value.d;
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_l:
+                               type = type_p;
+                               value.cp = value.i + parser.value.cp;
+                               break;
+                           default:
+                               error("invalid operand");
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type, parser.value = value;
+               break;
+           case expr_sub:
+               type = parser.type, value = parser.value;
+               expression_mul();
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i -= parser.value.i;
+                               break;
+                           case type_d:
+                               value.d -= parser.value.i;
+                               break;
+                           default:
+                               value.cp -= parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               type = type_d;
+                               value.d = value.i;
+                               break;
+                           case type_d:
+                               break;
+                           default:
+                               error("invalid operand");
+                       }
+                       value.d -= parser.value.d;
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_p:
+                               type = type_l;
+                               value.i = value.cp - parser.value.cp;
+                               break;
+                           default:
+                               error("invalid operand");
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type, parser.value = value;
+               break;
+           default:
+               return;
+       }
+    }
+}
+
+static void
+expression_shift(void)
+{
+    jit_word_t value;
+    expression_add();
+
+    switch (parser.type) {
+       case type_l:    case type_d:    case type_p:    break;
+       default:                                        return;
+    }
+    for (;;) {
+       switch (parser.expr) {
+           case expr_lsh:
+               value = parser.value.i;
+               if (parser.type != type_l)
+                   error("invalid operand");
+               expression_add();
+               if (parser.type != type_l)
+                   error("invalid operand");
+               value <<= parser.value.i;
+               parser.value.i = value;
+               break;
+           case expr_rsh:
+               value = parser.value.i;
+               if (parser.type != type_l)
+                   error("invalid operand");
+               expression_add();
+               if (parser.type != type_l)
+                   error("invalid operand");
+               value >>= parser.value.i;
+               parser.value.i = value;
+               break;
+           default:
+               return;
+       }
+    }
+}
+
+static void
+expression_bit(void)
+{
+    jit_word_t i;
+
+    expression_shift();
+    switch (parser.type) {
+       case type_l:    case type_d:    case type_p:    break;
+       default:                                        return;
+    }
+    for (;;) {
+       switch (parser.expr) {
+           case expr_and:
+               if (parser.type != type_l)
+                   error("invalid operand");
+               i = parser.value.i;
+               expression_shift();
+               if (parser.type != type_l)
+                   error("invalid operand");
+               i &= parser.value.i;
+               parser.value.i = i;
+               break;
+           case expr_or:
+               if (parser.type != type_l)
+                   error("invalid operand");
+               i = parser.value.i;
+               expression_shift();
+               if (parser.type != type_l)
+                   error("invalid operand");
+               i |= parser.value.i;
+               parser.value.i = i;
+               break;
+           case expr_xor:
+               if (parser.type != type_l)
+                   error("invalid operand");
+               i = parser.value.i;
+               expression_shift();
+               if (parser.type != type_l)
+                   error("invalid operand");
+               i ^= parser.value.i;
+               parser.value.i = i;
+               break;
+           default:
+               return;
+       }
+    }
+}
+
+static void
+expression_rel(void)
+{
+    type_t     type;
+    value_t    value;
+
+    expression_bit();
+    switch (parser.type) {
+       case type_l:    case type_d:    case type_p:    break;
+       default:                                        return;
+    }
+    for (;;) {
+       switch (parser.expr) {
+           case expr_lt:
+               type = parser.type, value = parser.value;
+               expression_bit();
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i < parser.value.i;
+                               break;
+                           case type_d:
+                               value.i = value.d < parser.value.i;
+                               break;
+                           default:
+                               value.i = (jit_word_t)value.p < parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i < parser.value.d;
+                               break;
+                           case type_d:
+                               value.i = value.d < parser.value.d;
+                               break;
+                           default:
+                               error("invalid operand");
+                       }
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i < (jit_word_t)parser.value.p;
+                               break;
+                           case type_d:
+                               error("invalid operand");
+                           default:
+                               value.i = (jit_word_t)value.p < (jit_word_t)parser.value.p;
+                               break;
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type_l, parser.value = value;
+               break;
+           case expr_le:
+               type = parser.type, value = parser.value;
+               expression_bit();
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i <= parser.value.i;
+                               break;
+                           case type_d:
+                               value.i = value.d <= parser.value.i;
+                               break;
+                           default:
+                               value.i = (jit_word_t)value.p <= parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i <= parser.value.d;
+                               break;
+                           case type_d:
+                               value.i = value.d <= parser.value.d;
+                               break;
+                           default:
+                               value.i = (jit_word_t)value.p <= parser.value.d;
+                               break;
+                       }
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i <= (jit_word_t)parser.value.p;
+                               break;
+                           case type_d:
+                               error("invalid operand");
+                           default:
+                               value.i = (jit_word_t)value.p <= (jit_word_t)parser.value.p;
+                               break;
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type_l, parser.value = value;
+               break;
+           case expr_eq:
+               type = parser.type, value = parser.value;
+               expression_bit();
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i == parser.value.i;
+                               break;
+                           case type_d:
+                               value.i = value.d == parser.value.i;
+                               break;
+                           default:
+                               value.i = (jit_word_t)value.p == parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i == parser.value.d;
+                               break;
+                           case type_d:
+                               value.i = value.d == parser.value.d;
+                               break;
+                           default:
+                               error("invalid operand");
+                       }
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i == (jit_word_t)parser.value.p;
+                               break;
+                           case type_d:
+                               error("invalid operand");
+                           default:
+                               value.i = value.p == parser.value.p;
+                               break;
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type_l, parser.value = value;
+               break;
+           case expr_ge:
+               type = parser.type, value = parser.value;
+               expression_bit();
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i >= parser.value.i;
+                               break;
+                           case type_d:
+                               value.i = value.d >= parser.value.i;
+                               break;
+                           default:
+                               value.i = (jit_word_t)value.p >= parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i >= parser.value.d;
+                               break;
+                           case type_d:
+                               value.i = value.d >= parser.value.d;
+                               break;
+                           default:
+                               error("invalid operand");
+                       }
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i >= (jit_word_t)parser.value.p;
+                               break;
+                           case type_d:
+                               error("invalid operand");
+                           default:
+                               value.i = (jit_word_t)value.p >= (jit_word_t)parser.value.p;
+                               break;
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type_l, parser.value = value;
+               break;
+           case expr_gt:
+               type = parser.type, value = parser.value;
+               expression_bit();
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i > parser.value.i;
+                               break;
+                           case type_d:
+                               value.i = value.d > parser.value.i;
+                               break;
+                           default:
+                               value.i = (jit_word_t)value.p > parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i > parser.value.d;
+                               break;
+                           case type_d:
+                               value.i = value.d > parser.value.d;
+                               break;
+                           default:
+                               error("invalid operand");
+                       }
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i > (jit_word_t)parser.value.p;
+                               break;
+                           case type_d:
+                               error("invalid operand");
+                           default:
+                               value.i = (jit_word_t)value.p > (jit_word_t)parser.value.p;
+                               break;
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type_l, parser.value = value;
+               break;
+           case expr_ne:
+               type = parser.type, value = parser.value;
+               expression_bit();
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i != parser.value.i;
+                               break;
+                           case type_d:
+                               value.i = value.d != parser.value.i;
+                               break;
+                           default:
+                               value.i = (jit_word_t)value.p != parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i != parser.value.d;
+                               break;
+                           case type_d:
+                               value.i = value.d != parser.value.d;
+                               break;
+                           default:
+                               error("invalid operand");
+                       }
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i != (jit_word_t)parser.value.p;
+                               break;
+                           case type_d:
+                               error("invalid operand");
+                           default:
+                               value.i = value.p != parser.value.p;
+                               break;
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type_l, parser.value = value;
+               break;
+           default:
+               return;
+       }
+    }
+}
+
+static void
+expression_cond(void)
+{
+    type_t     type;
+    value_t    value;
+    int                short_circuit;
+
+    expression_rel();
+    switch (parser.type) {
+       case type_l:    case type_d:    case type_p:    break;
+       default:                                        return;
+    }
+    for (;;) {
+       switch (parser.expr) {
+           case expr_andand:
+               type = parser.type, value = parser.value;
+               switch (type) {
+                   case type_l:
+                       short_circuit = value.i == 0;
+                       break;
+                   case type_d:
+                       short_circuit = value.d == 0.0;
+                       break;
+                   default:
+                       short_circuit = value.p == NULL;
+                       break;
+               }
+               parser.short_circuit += short_circuit;
+               expression_rel();
+               parser.short_circuit -= short_circuit;
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i && parser.value.i;
+                               break;
+                           case type_d:
+                               value.i = value.d && parser.value.i;
+                               break;
+                           default:
+                               value.i = value.p && parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i && parser.value.d;
+                               break;
+                           case type_d:
+                               value.i = value.d && parser.value.d;
+                               break;
+                           default:
+                               value.i = value.p && parser.value.d;
+                               break;
+                       }
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i && parser.value.p;
+                               break;
+                           case type_d:
+                               value.i = value.d && parser.value.p;
+                               break;
+                           default:
+                               value.i = value.p && parser.value.p;
+                               break;
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type_l, parser.value.i = value.i;
+               break;
+           case expr_oror:
+               type = parser.type, value = parser.value;
+               switch (type) {
+                   case type_l:
+                       short_circuit = value.i != 0;
+                       break;
+                   case type_d:
+                       short_circuit = value.d != 0.0;
+                       break;
+                   default:
+                       short_circuit = value.p != NULL;
+                       break;
+               }
+               parser.short_circuit += short_circuit;
+               expression_rel();
+               parser.short_circuit -= short_circuit;
+               switch (parser.type) {
+                   case type_l:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i || parser.value.i;
+                               break;
+                           case type_d:
+                               value.i = value.d || parser.value.i;
+                               break;
+                           default:
+                               value.i = value.p || parser.value.i;
+                               break;
+                       }
+                       break;
+                   case type_d:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i || parser.value.d;
+                               break;
+                           case type_d:
+                               value.i = value.d || parser.value.d;
+                               break;
+                           default:
+                               value.i = value.p || parser.value.d;
+                               break;
+                       }
+                       break;
+                   case type_p:
+                       switch (type) {
+                           case type_l:
+                               value.i = value.i || parser.value.p;
+                               break;
+                           case type_d:
+                               value.i = value.d || parser.value.p;
+                               break;
+                           default:
+                               value.i = value.p || parser.value.p;
+                               break;
+                       }
+                       break;
+                   default:
+                       error("invalid operand");
+               }
+               parser.type = type_l, parser.value.i = value.i;
+               break;
+           default:
+               return;
+       }
+    }
+}
+
+static token_t
+expression(void)
+{
+    symbol_t   *symbol;
+
+    (void)identifier('$');
+    if (parser.string[1] == '\0') {
+       if (getch_noeof() != '(')
+           error("bad symbol or expression");
+       parser.type = type_none;
+       expression_cond();
+       if (parser.expr != expr_rparen)
+           error("bad expression");
+       switch (parser.type) {
+           case type_l:
+               return (tok_int);
+           case type_d:
+               return (tok_float);
+           case type_p:
+               return (tok_pointer);
+           default:
+               error("bad expression");
+       }
+    }
+    else if ((symbol = get_symbol_by_name(parser.string))) {
+       switch (parser.type = symbol->type) {
+           case type_l:
+               parser.value.i = symbol->value.i;
+               return (tok_int);
+           case type_d:
+               parser.value.d = symbol->value.d;
+               return (tok_float);
+           default:
+               parser.value.p = symbol->value.p;
+               return (tok_pointer);
+       }
+    }
+    else
+       error("undefined symbol %s", parser.string);
+}
+
+static token_t
+primary(skip_t skip)
+{
+    int                ch;
+
+    switch (skip) {
+       case skip_none: ch = getch();   break;
+       case skip_ws:   ch = skipws();  break;
+       case skip_nl:   ch = skipnl();  break;
+       default:                        abort();
+    }
+    switch (ch) {
+       case '%':
+           return (regname());
+       case 'a' ... 'z': case 'A' ... 'Z': case '_':
+           return (identifier(ch));
+       case '0' ... '9': case '+': case '-':
+           return (number(ch));
+       case '.':
+           return (tok_dot);
+       case '"':
+           return (string());
+       case '\'':
+           return (character());
+       case '@':
+           return (dynamic());
+       case '$':
+           return (expression());
+       case EOF:
+           return (tok_eof);
+       case '\n':
+           return (tok_newline);
+       case ';':
+           return (tok_semicollon);
+       default:
+           error("syntax error");
+    }
+}
+
+static void
+parse(void)
+{
+    int                 ch;
+    token_t     token;
+    instr_t    *instr;
+    label_t    *label;
+    void       *value;
+
+    for (;;) {
+       switch (token = primary(skip_nl)) {
+           case tok_symbol:
+               ch = getch_noeof();
+               if (ch == ':') {
+                   if ((label = get_label_by_name(parser.string))) {
+                       if (label->kind == label_kind_code_forward) {
+                           label->kind = label_kind_code;
+                           jit_link(label->value);
+                           jit_note(parser.name, parser.line);
+                       }
+                       else
+                           error("label %s: redefined", parser.string);
+                   }
+                   else {
+                       if (parser.parsing == PARSING_DATA) {
+                           value = data + data_offset;
+                           label = new_label(label_kind_data,
+                                             parser.string, value);
+                       }
+                       else if (parser.parsing == PARSING_CODE) {
+                           value = jit_label();
+                           jit_note(parser.name, parser.line);
+                           label = new_label(label_kind_code,
+                                             parser.string, value);
+                       }
+                       else
+                           error("label not in .code or .data");
+                   }
+                   break;
+               }
+               ungetch(ch);
+               if ((instr =
+                    (instr_t *)get_hash(instrs, parser.string)) == NULL)
+                   error("unhandled symbol %s", parser.string);
+               if (parser.parsing != PARSING_CODE)
+                   error(".code must be specified before instructions");
+               (*instr->function)();
+               break;
+           case tok_dot:
+               dot();
+               break;
+           case tok_eof:
+               return;
+           default:
+               error("syntax error");
+       }
+    }
+}
+
+static int
+execute(int argc, char *argv[])
+{
+    int                 result;
+    label_t    *label;
+    function_t  function;
+    patch_t    *patch, *next;
+
+    for (patch = patches; patch; patch = next) {
+       next = patch->next;
+       label = patch->label;
+       if (label->kind == label_kind_code_forward)
+           error("undefined label %s", label->name);
+       switch (patch->kind) {
+           case patch_kind_jmp:
+           case patch_kind_mov:
+           case patch_kind_call:
+               jit_patch_at(patch->value, label->value);
+               break;
+           default:
+               abort();
+       }
+       free(patch);
+       patch = next;
+    }
+
+    if (flag_data == 0) {
+       jit_realize();
+       jit_set_data(NULL, 0, JIT_DISABLE_DATA | JIT_DISABLE_NOTE);
+    }
+
+    function = jit_emit();
+    if (flag_verbose > 1 || flag_disasm) {
+       jit_print();
+       fprintf(stdout, "  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
+    }
+    if (flag_verbose > 0 || flag_disasm) {
+       jit_disassemble();
+       fprintf(stdout, "  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n");
+    }
+
+    jit_clear_state();
+    if (flag_disasm)
+       result = 0;
+    else
+       result = (*function)(argc, argv);
+    jit_destroy_state();
+
+    return (result);
+}
+
+static void *
+xmalloc(size_t size)
+{
+    void       *pointer = malloc(size);
+
+    if (pointer == NULL)
+       error("out of memory");
+
+    return (pointer);
+}
+
+static void *
+xrealloc(void *pointer, size_t size)
+{
+    pointer = realloc(pointer, size);
+
+    if (pointer == NULL)
+       error("out of memory");
+
+    return (pointer);
+}
+
+static void *
+xcalloc(size_t nmemb, size_t size)
+{
+    void       *pointer = calloc(nmemb, size);
+
+    if (pointer == NULL)
+       error("out of memory");
+
+    return (pointer);
+}
+
+static label_t *
+new_label(label_kind_t kind, char *name, void *value)
+{
+    label_t    *label;
+
+    label = (label_t *)xmalloc(sizeof(label_t));
+    label->kind = kind;
+    label->name = strdup(name);
+    label->value = value;
+    put_hash(labels, (entry_t *)label);
+    label_offset++;
+    return (label);
+}
+
+static patch_t *
+new_patch(patch_kind_t kind, label_t *label, void *value)
+{
+    patch_t    *patch = (patch_t *)xmalloc(sizeof(patch_t));
+    patch->kind = kind;
+    patch->label = label;
+    patch->value = value;
+    patch->next = patches;
+    patches = patch;
+
+    return (patch);
+}
+
+static int
+bcmp_symbols(const void *left, const void *right)
+{
+    return (strcmp((char *)left, (*(symbol_t **)right)->name));
+}
+
+static int
+qcmp_symbols(const void *left, const void *right)
+{
+    return (strcmp((*(symbol_t **)left)->name, (*(symbol_t **)right)->name));
+}
+
+static symbol_t *
+new_symbol(char *name)
+{
+    symbol_t   *symbol;
+
+    if ((symbol_offset & 15) == 0) {
+       if ((symbol_length += 16) == 16)
+           symbols = (symbol_t **)xmalloc(sizeof(symbol_t *) *
+                                          symbol_length);
+       else
+           symbols = (symbol_t **)xrealloc(symbols, sizeof(symbol_t *) *
+                                           symbol_length);
+    }
+    symbol = (symbol_t *)xmalloc(sizeof(symbol_t));
+    symbol->name = strdup(name);
+    symbols[symbol_offset++] = symbol;
+    qsort(symbols, symbol_offset, sizeof(symbol_t *), qcmp_symbols);
+
+    return (symbol);
+}
+
+static symbol_t *
+get_symbol_by_name(char *name)
+{
+    symbol_t   **symbol_pointer;
+
+    if (symbols == NULL)
+       return (NULL);
+    symbol_pointer = (symbol_t **)bsearch(name, symbols, symbol_offset,
+                                         sizeof(symbol_t *), bcmp_symbols);
+
+    return (symbol_pointer ? *symbol_pointer : NULL);
+}
+
+static hash_t *
+new_hash(void)
+{
+    hash_t     *hash;
+
+    hash = (hash_t *)xmalloc(sizeof(hash_t));
+    hash->count = 0;
+    hash->entries = (entry_t **)xcalloc(hash->size = 32, sizeof(void *));
+
+    return (hash);
+}
+
+static int
+hash_string(char *name)
+{
+    char       *ptr;
+    int                 key;
+
+    for (key = 0, ptr = name; *ptr; ptr++)
+       key = (key << (key & 1)) ^ *ptr;
+
+    return (key);
+}
+
+static void
+put_hash(hash_t *hash, entry_t *entry)
+{
+    entry_t    *prev, *ptr;
+    int                 key = hash_string(entry->name) & (hash->size - 1);
+
+    for (prev = ptr = hash->entries[key]; ptr; prev = ptr, ptr = ptr->next) {
+       if (strcmp(entry->name, ptr->name) == 0)
+           error("duplicated entry %s", entry->name);
+    }
+    if (prev == NULL)
+       hash->entries[key] = entry;
+    else
+       prev->next = entry;
+    entry->next = NULL;
+    ++hash->count;
+    if (hash->count > hash->size * 0.75)
+       rehash(hash);
+}
+
+static entry_t *
+get_hash(hash_t *hash, char *name)
+{
+    entry_t    *entry;
+    int                 key = hash_string(name) & (hash->size - 1);
+
+    for (entry = hash->entries[key]; entry; entry = entry->next) {
+       if (strcmp(entry->name, name) == 0)
+           return (entry);
+    }
+    return (NULL);
+}
+
+static void
+rehash(hash_t *hash)
+{
+    int                 i, size, key;
+    entry_t    *entry, *next, **entries;
+
+    entries = (entry_t **)xcalloc(size = hash->size * 2, sizeof(void *));
+    for (i = 0; i < hash->size; i++) {
+       for (entry = hash->entries[i]; entry; entry = next) {
+           next = entry->next;
+           key = hash_string(entry->name) & (size - 1);
+           entry->next = entries[key];
+           entries[key] = entry;
+       }
+    }
+    free(hash->entries);
+    hash->entries = entries;
+    hash->size = size;
+}
+
+static void
+usage(void)
+{
+#if HAVE_GETOPT_LONG_ONLY
+    fprintf(stderr, "\
+Usage: %s [jit assembler options] file [jit program options]\n\
+Jit assembler options:\n\
+  -help                    Display this information\n\
+  -v[0-3]                  Verbose output level\n\
+  -d                       Do not use a data buffer\n\
+  -D<macro>[=<val>]        Preprocessor options\n"
+#  if defined(__i386__) && __WORDSIZE == 32
+"  -mx87=1                  Force using x87 when sse2 available\n"
+#  endif
+#  if defined(__i386__) || defined(__x86_64__)
+"  -msse4_1=0               Do not use sse4_1 instructions when available\n"
+#  endif
+#  if defined(__arm__)
+"  -mcpu=<val>              Force cpu version (4, 5, 6 or 7)\n\
+  -mthumb[=0|1]            Enable or disable thumb\n\
+  -mvfp=<val>              Set vpf version (0 to disable)\n\
+  -mneon[=0|1]             Enable or disable neon\n"
+#  endif
+           , progname);
+#else
+    fprintf(stderr, "\
+Usage: %s [jit assembler options] file [jit program options]\n\
+Jit assembler options:\n\
+  -h                       Display this information\n\
+  -v                       Verbose output level\n\
+  -D<macro>[=<val>]        Preprocessor options\n", progname);
+#endif
+    finish_jit();
+    exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+#if HAVE_GETOPT_LONG_ONLY
+    static const char  *short_options = "dv::";
+    static struct option long_options[] = {
+       { "help",               0, 0, 'h' },
+       { "data",               2, 0, 'd' },
+#  if defined(__i386__) && __WORDSIZE == 32
+       { "mx87",               2, 0, '7' },
+#  endif
+#  if defined(__i386__) || defined(__x86_64__)
+       { "msse4_1",            2, 0, '4' },
+#  endif
+#  if defined(__arm__)
+       { "mcpu",               2, 0, 'c' },
+       { "mthumb",             2, 0, 't' },
+       { "mvfp",               2, 0, 'f' },
+       { "mneon",              2, 0, 'n' },
+#  endif
+       { 0,                    0, 0, 0   }
+    };
+#else
+#endif /* HAVE_GETOPT_LONG_ONLY */
+    int                         offset;
+    char               *endptr;
+    int                         opt_index;
+    int                         opt_short;
+    char                cmdline[8192];
+
+#if defined(__CYGWIN__)
+    /* Cause a compile warning about redefinition without dllimport
+     * attribute, *but* cause correct linkage if liblightning.a is
+     * linked to binutils (that happens to have an internal
+     * getopt* implementation and an apparently conflicting
+     * optind global variable) */
+    extern int          optind;
+    optind = 1;
+#endif
+
+    progname = argv[0];
+
+    init_jit(progname);
+
+#if defined(__sgi)
+    DL_HANDLE = dlopen(NULL, RTLD_LAZY);
+#endif
+
+    flag_data = 1;
+#if HAVE_GETOPT_LONG_ONLY
+    for (;;) {
+       if ((opt_short = getopt_long_only(argc, argv, short_options,
+                                         long_options, &opt_index)) < 0)
+           break;
+       switch (opt_short) {
+           case 'h':
+           default:
+               usage();
+               break;
+           case 'v':
+               if (optarg) {
+                   flag_verbose = strtol(optarg, &endptr, 10);
+                   if (*endptr || flag_verbose < 0)
+                       usage();
+               }
+               else
+                   flag_verbose = 1;
+               break;
+           case 'd':
+               flag_data = 0;
+               break;
+#if defined(__i386__) && __WORDSIZE == 32
+           case '7':
+               if (optarg) {
+                   if (strcmp(optarg, "") == 0 || strcmp(optarg, "1") == 0)
+                       jit_cpu.sse2 = 0;
+                   else if (strcmp(optarg, "0"))
+                       usage();
+               }
+               else
+                   jit_cpu.sse2 = 0;
+               break;
+#endif
+#if defined(__i386__) || defined(__x86_64__)
+           case '4':
+               if (optarg) {
+                   if (strcmp(optarg, "0") == 0)
+                       jit_cpu.sse4_2 = 0;
+                   else if (strcmp(optarg, "1"))
+                       usage();
+               }
+               break;
+#endif
+#if defined(__arm__)
+           case 'c':
+               if (optarg) {
+                   offset = strtol(optarg, &endptr, 10);
+                   if (*endptr || offset < 0)
+                       usage();
+                   if (offset < jit_cpu.version)
+                       jit_cpu.version = offset;
+               }
+               break;
+           case 't':
+               if (optarg) {
+                   if (strcmp(optarg, "0") == 0)
+                       jit_cpu.thumb = 0;
+                   else if (strcmp(optarg, "1") && strcmp(optarg, "2"))
+                       usage();
+               }
+               break;
+           case 'f':
+#  if !defined(__ARM_PCS_VFP)
+               /* Do not allow overrinding hard float abi */
+               if (optarg) {
+                   offset = strtol(optarg, &endptr, 10);
+                   if (*endptr || offset < 0)
+                       usage();
+                   if (offset < jit_cpu.vfp)
+                       jit_cpu.vfp = offset;
+               }
+#  endif
+               break;
+           case 'n':
+               if (optarg) {
+                   if (strcmp(optarg, "0") == 0)
+                       jit_cpu.neon = 0;
+                   else if (strcmp(optarg, "1"))
+                       usage();
+               }
+               break;
+#endif
+       }
+    }
+#else
+    while ((opt_short = getopt(argc, argv, "hvd")) >= 0) {
+       if (opt_short == 'v')
+           ++flag_verbose;
+       else if (opt_short == 'd')
+           flag_data = 0;
+       else
+           usage();
+    }
+#endif
+
+    opt_index = optind;
+#if defined(__hpux)
+    /* Workaround */
+    if (opt_index < argc && argv[opt_index][0] == '-')
+       ++opt_index;
+#endif
+    if (opt_index < 0 || opt_index >= argc)
+       usage();
+    if (strcmp(argv[opt_index], "-") == 0)
+       strcpy(parser.name, "<stdin>");
+    else {
+       if ((endptr = strrchr(argv[opt_index], '/')) == NULL)
+           endptr = argv[opt_index];
+       else
+           ++endptr;
+       strncpy(parser.name, endptr, sizeof(parser.name));
+       parser.name[sizeof(parser.name) - 1] = '\0';
+    }
+#if __clang__
+#  define cc "clang"
+#else
+#  define cc "gcc"
+#endif
+    opt_short = snprintf(cmdline, sizeof(cmdline), cc " -E -x c %s", argv[opt_index]);
+    for (++opt_index; opt_index < argc; opt_index++) {
+       if (argv[opt_index][0] == '-')
+           opt_short += snprintf(cmdline + opt_short,
+                                 sizeof(cmdline) - opt_short,
+                                 " %s", argv[opt_index]);
+       else {
+           --opt_index;
+           break;
+       }
+    }
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__WORDSIZE=%d", __WORDSIZE);
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__LITTLE_ENDIAN=%d", __LITTLE_ENDIAN);
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__BIG_ENDIAN=%d", __BIG_ENDIAN);
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__BYTE_ORDER=%d", __BYTE_ORDER);
+#if defined(__i386__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__i386__=1");
+#endif
+#if defined(__x86_64__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__x86_64__=1");
+#endif
+#if defined(__mips__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__mips__=1");
+#endif
+#if defined(__arm__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__arm__=1");
+#endif
+#if defined(__powerpc__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__ppc__=1");
+#endif
+#if defined(__sparc__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__sparc__=1");
+#endif
+#if defined(__ia64__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__ia64__=1");
+#endif
+#if defined(__hppa__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__hppa__=1");
+#endif
+#if defined(_AIX)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D_AIX=1");
+#endif
+#if defined(__sgi__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__sgi__=1");
+#endif
+#if defined(__aarch64__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__aarch64__=1");
+#endif
+#if defined(__s390__) || defined(__s390x__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__s390__=1");
+#endif
+#if defined(__alpha__)
+    opt_short += snprintf(cmdline + opt_short,
+                         sizeof(cmdline) - opt_short,
+                         " -D__alpha__=1");
+#endif
+    if ((parser.fp = popen(cmdline, "r")) == NULL)
+       error("cannot execute %s", cmdline);
+
+    parser.line = 1;
+    parser.string = (char *)xmalloc(parser.length = 4096);
+
+#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
+    /* double precision                0x200
+     * round nearest                   0x000
+     * invalid operation mask          0x001
+     * denormalized operand mask       0x002
+     * zero divide mask                0x004
+     * precision (inexact) mask        0x020
+     */
+    {
+       fpu_control_t fpu_control = 0x027f;
+       _FPU_SETCW(fpu_control);
+    }
+#endif
+
+    _jit = jit_new_state();
+
+    instrs = new_hash();
+    for (offset = 0;
+        offset < (int)(sizeof(instr_vector) / sizeof(instr_vector[0]));
+        offset++)
+       put_hash(instrs, (entry_t *)(instr_vector + offset));
+
+    labels = new_hash();
+
+    parse();
+    pclose(parser.fp);
+    parser.fp = NULL;
+
+    for (opt_short = 0; opt_index < argc; opt_short++, opt_index++)
+       argv[opt_short] = argv[opt_index];
+    argv[opt_short] = NULL;
+    argc = opt_short;
+    execute(argc, argv);
+
+    finish_jit();
+
+    return (0);
+}
diff --git a/deps/lightning/check/nodata.c b/deps/lightning/check/nodata.c
new file mode 100644 (file)
index 0000000..0e594c3
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Simple test of using an alternate buffer for the code.
+ */
+
+#include <lightning.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/mman.h>
+#if defined(__sgi)
+#  include <fcntl.h>
+#endif
+
+#ifndef MAP_ANON
+#  define MAP_ANON                     MAP_ANONYMOUS
+#  ifndef MAP_ANONYMOUS
+#    define MAP_ANONYMOUS              0
+#  endif
+#endif
+
+#if !defined(__sgi)
+#define  mmap_fd                       -1
+#endif
+
+jit_uint8_t             *data;
+jit_state_t             *_jit;
+jit_word_t               data_length;
+jit_word_t               note_length;
+#if defined(__sgi)
+int                      mmap_fd;
+#endif
+void                   (*function)(void);
+
+void
+gencode(jit_word_t flags)
+{
+    jit_word_t         offset;
+    jit_word_t         length;
+
+    _jit = jit_new_state();
+
+    jit_name("main");
+    jit_prolog();
+    jit_prepare();
+    jit_pushargi((jit_word_t)"%f\n");
+    jit_ellipsis();
+    jit_pushargi_d(1.5);
+    jit_finishi(printf);
+    jit_note("nodata.c", __LINE__);
+
+    /* call to jit_realize() is only required when using an alternate
+     * code buffer. Note that not using mmap'ed memory may not work
+     * on several ports and/or operating system versions */
+    jit_realize();
+
+    if (jit_get_data(&data_length, &note_length) != NULL)
+       abort();
+
+    length = 0;
+    if (!(flags & JIT_DISABLE_DATA))
+       length += data_length;
+    if (!(flags & JIT_DISABLE_NOTE))
+       length += note_length;
+
+    /* check that a too small buffer fails */
+    if (flags)
+       jit_set_data(length ? data : NULL, length, flags);
+
+    /* and calling again with enough space works */
+    offset = (length + 7) & -8;
+    function = jit_emit();
+    if (function == NULL)
+       abort();
+
+    jit_clear_state();
+    (*function)();
+    jit_destroy_state();
+}
+
+int
+main(int argc, char *argv[])
+{
+#if defined(__sgi)
+    mmap_fd = open("/dev/zero", O_RDWR);
+#endif
+
+    data = mmap(NULL, 4096,
+               PROT_READ | PROT_WRITE,
+               MAP_PRIVATE | MAP_ANON, mmap_fd, 0);
+    assert(data != MAP_FAILED);
+#if defined(__sgi)
+    close(mmap_fd);
+#endif
+
+    init_jit(argv[0]);
+
+    gencode(0);
+    gencode(JIT_DISABLE_DATA);
+    gencode(JIT_DISABLE_NOTE);
+    gencode(JIT_DISABLE_DATA | JIT_DISABLE_NOTE);
+
+    finish_jit();
+
+    munmap(data, 4096);
+
+    return (0);
+}
diff --git a/deps/lightning/check/put.ok b/deps/lightning/check/put.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/put.tst b/deps/lightning/check/put.tst
new file mode 100644 (file)
index 0000000..a7e39e1
--- /dev/null
@@ -0,0 +1,428 @@
+.data  8
+ok:
+.c     "ok"
+
+.code
+       jmpi main
+
+       name putr
+putr:
+       prolog
+       frame 160
+       arg $ac
+       arg $auc
+       arg $as
+       arg $aus
+       arg $ai
+#if __WORDSIZE == 64
+       arg $aui
+       arg $al
+#endif
+       arg_f $af
+       arg_d $ad
+       arg $a
+#if __WORDSIZE == 64
+       arg $_l
+       arg $_ui
+#endif
+       arg $_i
+       arg $_us
+       arg $_s
+       arg $_uc
+       arg $_c
+       getarg_c %r0 $ac
+       negr %r0 %r0
+       putargr %r0 $ac
+       getarg_uc %r0 $auc
+       negr %r0 %r0
+       putargr %r0 $auc
+       getarg_s %r0 $as
+       negr %r0 %r0
+       putargr %r0 $as
+       getarg_us %r0 $aus
+       negr %r0 %r0
+       putargr %r0 $aus
+       getarg_i %r0 $ai
+       negr %r0 %r0
+       putargr %r0 $ai
+#if __WORDSIZE == 64
+       getarg_ui %r0 $aui
+       negr %r0 %r0
+       putargr %r0 $aui
+       getarg_l %r0 $al
+       negr %r0 %r0
+       putargr %r0 $al
+#endif
+       getarg_f %f0 $af
+       negr_f %f0 %f0
+       putargr_f %f0 $af
+       getarg_d %f0 $ad
+       negr_d %f0 %f0
+       putargr_d %f0 $ad
+       getarg %r0 $a
+       negr %r0 %r0
+       putargr %r0 $a
+#if __WORDSIZE == 64
+       getarg_l %r0 $_l
+       negr %r0 %r0
+       putargr %r0 $_l
+       getarg_ui %r0 $_ui
+       negr %r0 %r0
+       putargr %r0 $_ui
+#endif
+       getarg_i %r0 $_i
+       negr %r0 %r0
+       putargr %r0 $_i
+       getarg_us %r0 $_us
+       negr %r0 %r0
+       putargr %r0 $_us
+       getarg_s %r0 $_s
+       negr %r0 %r0
+       putargr %r0 $_s
+       getarg_uc %r0 $_uc
+       negr %r0 %r0
+       putargr %r0 $_uc
+       getarg_c %r0 $_c
+       negr %r0 %r0
+       putargr %r0 $_c
+       jmpi _putr
+rputr:
+       putargi 17 $ac
+       putargi 16 $auc
+       putargi 15 $as
+       putargi 14 $aus
+       putargi 13 $ai
+#if __WORDSIZE == 64
+       putargi 12 $aui
+       putargi 11 $al
+#endif
+       putargi_f 10 $af
+       putargi_d 9 $ad
+       putargi 8 $a
+#if __WORDSIZE == 64
+       putargi 7 $_l
+       putargi 6 $_ui
+#endif
+       putargi 5 $_i
+       putargi 4 $_us
+       putargi 3 $_s
+       putargi 2 $_uc
+       putargi 1 $_c
+       jmpi _puti
+rputi:
+       ret
+       epilog
+
+       name _putr
+_putr:
+       prolog
+       tramp 160
+       arg $ac
+       arg $auc
+       arg $as
+       arg $aus
+       arg $ai
+#if __WORDSIZE == 64
+       arg $aui
+       arg $al
+#endif
+       arg_f $af
+       arg_d $ad
+       arg $a
+#if __WORDSIZE == 64
+       arg $_l
+       arg $_ui
+#endif
+       arg $_i
+       arg $_us
+       arg $_s
+       arg $_uc
+       arg $_c
+       getarg_c %r0 $ac
+       beqi rac %r0 -1
+       calli @abort
+rac:
+       getarg_uc %r0 $auc
+       beqi rauc %r0 $(-2 & 0xff)
+       calli @abort
+rauc:
+       getarg_s %r0 $as
+       beqi ras %r0 -3
+       calli @abort
+ras:
+       getarg_us %r0 $aus
+       beqi raus %r0 $(-4 & 0xffff)
+       calli @abort
+raus:
+       getarg_i %r0 $ai
+       beqi rai %r0 -5
+       calli @abort
+rai:
+#if __WORDSIZE == 64
+       getarg_ui %r0 $aui
+       beqi raui %r0 $(-6 & 0xffffffff)
+       calli @abort
+raui:
+       getarg_l %r0 $al
+       beqi ral %r0 -7
+       calli @abort
+ral:
+#endif
+       getarg_f %f0 $af
+       beqi_f raf %f0 -8
+       calli @abort
+raf:
+       getarg_d %f0 $ad
+       beqi_d rad %f0 -9
+       calli @abort
+rad:
+       getarg %r0 $a
+       beqi ra %r0 -10
+       calli @abort
+ra:
+#if __WORDSIZE == 64
+       getarg %r0 $_l
+       beqi r_l %r0 -11
+       calli @abort
+r_l:
+       getarg_ui %r0 $_ui
+       beqi r_ui %r0 $(-12 & 0xffffffff)
+       calli @abort
+r_ui:
+#endif
+       getarg_i %r0 $_i
+       beqi r_i %r0 -13
+       calli @abort
+r_i:
+       getarg_us %r0 $_us
+       beqi r_us %r0 $(-14 & 0xffff)
+       calli @abort
+r_us:
+       getarg_s %r0 $_s
+       beqi r_s %r0 -15
+       calli @abort
+r_s:
+       getarg_uc %r0 $_uc
+       beqi r_uc %r0 $(-16 & 0xff)
+       calli @abort
+r_uc:
+       getarg_c %r0 $_c
+       beqi r_c %r0 -17
+       calli @abort
+r_c:
+       jmpi rputr
+       epilog
+
+       name _puti
+_puti:
+       prolog
+       tramp 160
+       arg $ac
+       arg $auc
+       arg $as
+       arg $aus
+       arg $ai
+#if __WORDSIZE == 64
+       arg $aui
+       arg $al
+#endif
+       arg_f $af
+       arg_d $ad
+       arg $a
+#if __WORDSIZE == 64
+       arg $_l
+       arg $_ui
+#endif
+       arg $_i
+       arg $_us
+       arg $_s
+       arg $_uc
+       arg $_c
+       getarg_c %r0 $ac
+       beqi iac %r0 17
+       calli @abort
+iac:
+       getarg_uc %r0 $auc
+       beqi iauc %r0 16
+       calli @abort
+iauc:
+       getarg_s %r0 $as
+       beqi ias %r0 15
+       calli @abort
+ias:
+       getarg_us %r0 $aus
+       beqi iaus %r0 14
+       calli @abort
+iaus:
+       getarg_i %r0 $ai
+       beqi iai %r0 13
+       calli @abort
+iai:
+#if __WORDSIZE == 64
+       getarg_ui %r0 $aui
+       beqi iaui %r0 12
+       calli @abort
+iaui:
+       getarg_l %r0 $al
+       beqi ial %r0 11
+       calli @abort
+ial:
+#endif
+       getarg_f %f0 $af
+       beqi_f iaf %f0 10
+       calli @abort
+iaf:
+       getarg_d %f0 $ad
+       beqi_d iad %f0 9
+       calli @abort
+iad:
+       getarg %r0 $a
+       beqi ia %r0 8
+       calli @abort
+ia:
+#if __WORDSIZE == 64
+       getarg %r0 $_l
+       beqi i_l %r0 7
+       calli @abort
+i_l:
+       getarg_ui %r0 $_ui
+       beqi i_ui %r0 6
+       calli @abort
+i_ui:
+#endif
+       getarg_i %r0 $_i
+       beqi i_i %r0 5
+       calli @abort
+i_i:
+       getarg_us %r0 $_us
+       beqi i_us %r0 4
+       calli @abort
+i_us:
+       getarg_s %r0 $_s
+       beqi i_s %r0 3
+       calli @abort
+i_s:
+       getarg_uc %r0 $_uc
+       beqi i_uc %r0 2
+       calli @abort
+i_uc:
+       getarg_c %r0 $_c
+       beqi i_c %r0 1
+       calli @abort
+i_c:
+       jmpi rputi
+       epilog
+
+       name putf
+putf:
+       prolog
+       frame 56
+       arg $i1
+       arg_d $d1
+       arg_f $f1
+       arg_f $f2
+       arg_f $f3
+       arg $i2
+       arg_d $d2
+       getarg %r0 $i1
+       addi %r0 %r0 1
+       putargr %r0 $i1
+       getarg_d %f0 $d1
+       addi_d %f0 %f0 1
+       putargr_d %f0 $d1
+       getarg_f %f0 $f1
+       addi_f %f0 %f0 1
+       putargr_f %f0 $f1
+       getarg_f %f0 $f2
+       subi_f %f0 %f0 1
+       putargr_f %f0 $f2
+       putargi_f -5 $f3
+       putargi -6 $i2
+       putargi_d -7 $d2
+       jmpi _putf
+rputf:
+       ret
+       epilog
+
+       name _putf
+_putf:
+       prolog
+       tramp 56
+       arg $i1
+       arg_d $d1
+       arg_f $f1
+       arg_f $f2
+       arg_f $f3
+       arg $i2
+       arg_d $d2
+       getarg %r0 $i1
+       beqi fi1 %r0 2
+       calli @abort
+fi1:
+       getarg_d %f0 $d1
+       beqi_d fd1 %f0 3
+       calli @abort
+fd1:
+       getarg_f %f0 $f1
+       beqi_f ff1 %f0 4
+       calli @abort
+ff1:
+       getarg_f %f0 $f2
+       beqi_f ff2 %f0 3
+       calli @abort
+ff2:
+       getarg_f %f0 $f3
+       beqi_f ff3 %f0 -5
+       calli @abort
+ff3:
+       getarg %r0 $i2
+       beqi fi2 %r0 -6
+       calli @abort
+fi2:
+       getarg_d %f0 $d2
+       beqi_d fd2 %f0 -7
+       calli @abort
+fd2:
+       jmpi rputf
+       epilog
+
+       name main
+main:
+       prolog
+       prepare
+               pushargi 1
+               pushargi 2
+               pushargi 3
+               pushargi 4
+               pushargi 5
+#if __WORDSIZE == 64
+               pushargi 6
+               pushargi 7
+#endif
+               pushargi_f 8
+               pushargi_d 9
+               pushargi 10
+#if __WORDSIZE == 64
+               pushargi 11
+               pushargi 12
+#endif
+               pushargi 13
+               pushargi 14
+               pushargi 15
+               pushargi 16
+               pushargi 17
+       finishi putr
+       prepare
+               pushargi 1
+               pushargi_d 2
+               pushargi_f 3
+               pushargi_f 4
+               pushargi_f 5
+               pushargi 6
+               pushargi_d 7
+       finishi putf
+       prepare
+               pushargi ok
+       finishi @puts
+       ret
+       epilog
diff --git a/deps/lightning/check/qalu.inc b/deps/lightning/check/qalu.inc
new file mode 100644 (file)
index 0000000..9daca82
--- /dev/null
@@ -0,0 +1,122 @@
+.data  8
+ok:
+.c     "ok\n"
+
+/* r0,r1 = r2 op r3 */
+#define QALUR(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3)        \
+       movi %R2 I0                                     \
+       movi %R3 I1                                     \
+       OP##r##T %R0 %R1 %R2 %R3                        \
+       bnei OP##T##N##rlo##R0##R1##R2##R3 %R0 LO       \
+       bnei OP##T##N##rlo##R0##R1##R2##R3 %R1 HI       \
+       bnei OP##T##N##rlo##R0##R1##R2##R3 %R2 I0       \
+       beqi OP##T##N##rhi##R0##R1##R2##R3 %R3 I1       \
+OP##T##N##rlo##R0##R1##R2##R3:                         \
+       calli @abort                                    \
+OP##T##N##rhi##R0##R1##R2##R3:
+
+/* r0,r1 = r2 op i0 */
+#define QALUI(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3)        \
+       movi %R2 I0                                     \
+       movi %R3 HI                                     \
+       OP##i##T %R0 %R1 %R2 I1                         \
+       bnei OP##T##N##ilo##R0##R1##R2##R3 %R0 LO       \
+       bner OP##T##N##ilo##R0##R1##R2##R3 %R1 %R3      \
+       beqi OP##T##N##ihi##R0##R1##R2##R3 %R2 I0       \
+OP##T##N##ilo##R0##R1##R2##R3:                         \
+       calli @abort                                    \
+OP##T##N##ihi##R0##R1##R2##R3:
+
+/* r0,r1 = r0 op r1 */
+#define QALUX(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3)        \
+       movi %R0 I0                                     \
+       movi %R1 I1                                     \
+       movi %R2 LO                                     \
+       movi %R3 HI                                     \
+       OP##r##T %R0 %R1 %R0 %R1                        \
+       bner OP##T##N##0lo##R0##R1##R2##R3 %R0 %R2      \
+       beqr OP##T##N##0hi##R0##R1##R2##R3 %R1 %R3      \
+OP##T##N##0lo##R0##R1##R2##R3:                         \
+       calli @abort                                    \
+OP##T##N##0hi##R0##R1##R2##R3:
+
+/* r0,r1 = r1 op r0 */
+#define QALUY(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3)        \
+       movi %R1 I0                                     \
+       movi %R0 I1                                     \
+       movi %R2 LO                                     \
+       movi %R3 HI                                     \
+       OP##r##T %R0 %R1 %R1 %R0                        \
+       bner OP##T##N##1lo##R0##R1##R2##R3 %R0 %R2      \
+       beqr OP##T##N##1hi##R0##R1##R2##R3 %R1 %R3      \
+OP##T##N##1lo##R0##R1##R2##R3:                         \
+       calli @abort                                    \
+OP##T##N##1hi##R0##R1##R2##R3:
+
+/* r0,r1 = r0 op r3 */
+#define QALUZ(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3)        \
+       movi %R0 I0                                     \
+       movi %R3 I1                                     \
+       movi %R2 LO                                     \
+       OP##r##T %R0 %R1 %R0 %R3                        \
+       bner OP##T##N##2lo##R0##R1##R2##R3 %R0 %R2      \
+       bnei OP##T##N##2lo##R0##R1##R2##R3 %R1 HI       \
+       beqi OP##T##N##2hi##R0##R1##R2##R3 %R3 I1       \
+OP##T##N##2lo##R0##R1##R2##R3:                         \
+       calli @abort                                    \
+OP##T##N##2hi##R0##R1##R2##R3:
+
+/* r0,r1 = r2 op r1 */
+#define QALUW(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3)        \
+       movi %R2 I0                                     \
+       movi %R1 I1                                     \
+       movi %R3 LO                                     \
+       OP##r##T %R0 %R1 %R2 %R1                        \
+       bner OP##T##N##3lo##R0##R1##R2##R3 %R0 %R3      \
+       bnei OP##T##N##3lo##R0##R1##R2##R3 %R1 HI       \
+       beqi OP##T##N##3hi##R0##R1##R2##R3 %R2 I0       \
+OP##T##N##3lo##R0##R1##R2##R3:                         \
+       calli @abort                                    \
+OP##T##N##3hi##R0##R1##R2##R3:
+
+#define QALU2(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3)        \
+       QALUR(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3) \
+       QALUI(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3) \
+       QALUX(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3) \
+       QALUY(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3) \
+       QALUZ(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3) \
+       QALUW(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3)
+
+#define QALU1(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3)        \
+       QALU2(N, T, OP, I0, I1, LO, HI, R0, R1, R2, R3) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R0, R1, R3, R2) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R0, R2, R1, R3) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R0, R2, R3, R1) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R0, R3, R1, R2) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R0, R3, R2, R1) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R1, R0, R2, R3) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R1, R0, R3, R2) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R1, R2, R0, R3) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R1, R2, R3, R0) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R1, R3, R0, R2) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R1, R3, R2, R0) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R2, R1, R0, R3) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R2, R1, R3, R0) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R2, R0, R1, R3) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R2, R0, R3, R1) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R2, R3, R1, R0) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R2, R3, R0, R1) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R3, R1, R2, R0) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R3, R1, R0, R2) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R3, R2, R1, R0) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R3, R2, R0, R1) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R3, R0, R1, R2) \
+       QALU2(N, T, OP, I0, I1, LO, HI, R3, R0, R2, R1)
+
+#define QALU(N, T, OP, I0, I1, LO, HI)                 \
+       QALU1(N, T, OP, I0, I1, LO, HI, v0, v1, v2, r0) \
+       QALU1(N, T, OP, I0, I1, LO, HI, v0, v1, v2, r1) \
+       QALU1(N, T, OP, I0, I1, LO, HI, v0, v1, v2, r2) \
+       QALU1(N, T, OP, I0, I1, LO, HI, v1, v2, r0, r1) \
+       QALU1(N, T, OP, I0, I1, LO, HI, v1, v2, r0, r2) \
+       QALU1(N, T, OP, I0, I1, LO, HI, v2, r0, r1, r2)
diff --git a/deps/lightning/check/qalu_div.ok b/deps/lightning/check/qalu_div.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/qalu_div.tst b/deps/lightning/check/qalu_div.tst
new file mode 100644 (file)
index 0000000..198dfbb
--- /dev/null
@@ -0,0 +1,18 @@
+#include "qalu.inc"
+
+.code
+       prolog
+#define QDIV(N, I0, I1, LO, HI)                QALU(N, , qdiv, I0, I1, LO, HI)
+#define UQDIV(N, I0, I1, LO, HI)       QALU(N, _u, qdiv, I0, I1, LO, HI)
+        QDIV(0, 10, 3, 3, 1)
+        QDIV(1, -33, 9, -3, -6)
+        QDIV(2, -41, -7, 5, -6)
+        QDIV(3, 65536, 4096, 16, 0)
+       UQDIV(4, -1, -2, 1, 1)
+       UQDIV(5, -2, -5, 1, 3)
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/qalu_mul.ok b/deps/lightning/check/qalu_mul.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/qalu_mul.tst b/deps/lightning/check/qalu_mul.tst
new file mode 100644 (file)
index 0000000..64b95a9
--- /dev/null
@@ -0,0 +1,31 @@
+#include "qalu.inc"
+
+.code
+       prolog
+#define QMUL(N, I0, I1, LO, HI)                QALU(N, , qmul, I0, I1, LO, HI)
+#define UQMUL(N, I0, I1, LO, HI)       QALU(N, _u, qmul, I0, I1, LO, HI)
+       QMUL(0, -2, -1, 2, 0)
+       QMUL(1, 0, -1, 0, 0)
+       QMUL(2, -1, 0, 0, 0)
+       QMUL(3, 1, -1, -1, -1)
+#if __WORDSIZE == 32
+        QMUL(4, 0x7ffff, 0x7ffff, 0xfff00001, 0x3f)
+       UQMUL(5, 0xffffff, 0xffffff, 0xfe000001, 0xffff)
+        QMUL(6, 0x80000000, -2, 0, 1)
+        QMUL(7, 0x80000000, 2, 0, -1)
+        QMUL(8, 0x80000001, 3, 0x80000003, -2)
+        QMUL(9, 0x80000001, -3, 0x7ffffffd, 1)
+#else
+        QMUL(4, 0x7ffffffff, 0x7ffffffff, 0xfffffff000000001, 0x3f)
+       UQMUL(5, 0xffffffffff, 0xffffffffff, 0xfffffe0000000001, 0xffff)
+        QMUL(6, 0x8000000000000000, -2, 0, 1)
+        QMUL(7, 0x8000000000000000, 2, 0, -1)
+        QMUL(8, 0x8000000000000001, 3, 0x8000000000000003, -2)
+        QMUL(9, 0x8000000000000001, -3, 0x7ffffffffffffffd, 1)
+#endif
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/range.ok b/deps/lightning/check/range.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/range.tst b/deps/lightning/check/range.tst
new file mode 100644 (file)
index 0000000..35ddf64
--- /dev/null
@@ -0,0 +1,504 @@
+#define M64    67108864
+
+#define aB1    (1<<1)
+#define aB2    (1<<2)
+#define aB3    (1<<3)
+#define aB4    (1<<4)
+#define aB5    (1<<5)
+#define aB6    (1<<6)
+#define aB7    (1<<7)
+#define aB8    (1<<8)
+#define aB9    (1<<9)
+#define aB10   (1<<10)
+#define aB11   (1<<11)
+#define aB12   (1<<12)
+#define aB13   (1<<13)
+#define aB14   (1<<14)
+#define aB15   (1<<15)
+#define aB16   (1<<16)
+#define aB17   (1<<17)
+#define aB18   (1<<18)
+#define aB19   (1<<19)
+#define aB20   (1<<20)
+#define aB21   (1<<21)
+#define aB22   (1<<22)
+#define aB23   (1<<23)
+#define aB24   (1<<24)
+#define aB25   (1<<25)
+#define aB26   (1<<26)
+#define bB1    (-aB1)
+#define bB2    (-aB2)
+#define bB3    (-aB3)
+#define bB4    (-aB4)
+#define bB5    (-aB5)
+#define bB6    (-aB6)
+#define bB7    (-aB7)
+#define bB8    (-aB8)
+#define bB9    (-aB9)
+#define bB10   (-aB10)
+#define bB11   (-aB11)
+#define bB12   (-aB12)
+#define bB13   (-aB13)
+#define bB14   (-aB14)
+#define bB15   (-aB15)
+#define bB16   (-aB16)
+#define bB17   (-aB17)
+#define bB18   (-aB18)
+#define bB19   (-aB19)
+#define bB20   (-aB20)
+#define bB21   (-aB21)
+#define bB22   (-aB22)
+#define bB23   (-aB23)
+#define bB24   (-aB24)
+#define bB25   (-aB25)
+#define bB26   (-aB26)
+#define cB1    (aB1-1)
+#define cB2    (aB2-1)
+#define cB3    (aB3-1)
+#define cB4    (aB4-1)
+#define cB5    (aB5-1)
+#define cB6    (aB6-1)
+#define cB7    (aB7-1)
+#define cB8    (aB8-1)
+#define cB9    (aB9-1)
+#define cB10   (aB10-1)
+#define cB11   (aB11-1)
+#define cB12   (aB12-1)
+#define cB13   (aB13-1)
+#define cB14   (aB14-1)
+#define cB15   (aB15-1)
+#define cB16   (aB16-1)
+#define cB17   (aB17-1)
+#define cB18   (aB18-1)
+#define cB19   (aB19-1)
+#define cB20   (aB20-1)
+#define cB21   (aB21-1)
+#define cB22   (aB22-1)
+#define cB23   (aB23-1)
+#define cB24   (aB24-1)
+#define cB25   (aB25-1)
+#define cB26   (aB26-1)
+#define dB1    (-aB1+1)
+#define dB2    (-aB2+1)
+#define dB3    (-aB3+1)
+#define dB4    (-aB4+1)
+#define dB5    (-aB5+1)
+#define dB6    (-aB6+1)
+#define dB7    (-aB7+1)
+#define dB8    (-aB8+1)
+#define dB9    (-aB9+1)
+#define dB10   (-aB10+1)
+#define dB11   (-aB11+1)
+#define dB12   (-aB12+1)
+#define dB13   (-aB13+1)
+#define dB14   (-aB14+1)
+#define dB15   (-aB15+1)
+#define dB16   (-aB16+1)
+#define dB17   (-aB17+1)
+#define dB18   (-aB18+1)
+#define dB19   (-aB19+1)
+#define dB20   (-aB20+1)
+#define dB21   (-aB21+1)
+#define dB22   (-aB22+1)
+#define dB23   (-aB23+1)
+#define dB24   (-aB24+1)
+#define dB25   (-aB25+1)
+#define dB26   (-aB26+1)
+
+#define add(a, b)              $(a + b)
+#define sub(a, b)              $(a - b)
+#define rsb(a, b)              $(b - a)
+#define mul(a, b)              $(a * b)
+#define div(a, b)              $(a / b)
+#define rem(a, b)              $(a % b)
+#define and(a, b)              $(a & b)
+#define or(a, b)               $(a | b)
+#define xor(a, b)              $(a ^ b)
+
+#define alu2(N, X, L, R, V)                                    \
+       movi %r1 L                                              \
+       N##i %r0 %r1 R                                          \
+       beqi X %r0 V                                            \
+       calli @abort                                            \
+X:
+#define alu1(N, M)                                             \
+       alu2(N, N##M##1, 3, $(M##1), N(3, M##1))                \
+       alu2(N, N##M##2, 3, $(M##2), N(3, M##2))                \
+       alu2(N, N##M##3, 3, $(M##3), N(3, M##3))                \
+       alu2(N, N##M##4, 3, $(M##4), N(3, M##4))                \
+       alu2(N, N##M##5, 3, $(M##5), N(3, M##5))                \
+       alu2(N, N##M##6, 3, $(M##6), N(3, M##6))                \
+       alu2(N, N##M##7, 3, $(M##7), N(3, M##7))                \
+       alu2(N, N##M##8, 3, $(M##8), N(3, M##8))                \
+       alu2(N, N##M##9, 3, $(M##9), N(3, M##9))                \
+       alu2(N, N##M##10, 3, $(M##10), N(3, M##10))             \
+       alu2(N, N##M##11, 3, $(M##11), N(3, M##11))             \
+       alu2(N, N##M##12, 3, $(M##12), N(3, M##12))             \
+       alu2(N, N##M##13, 3, $(M##13), N(3, M##13))             \
+       alu2(N, N##M##14, 3, $(M##14), N(3, M##14))             \
+       alu2(N, N##M##15, 3, $(M##15), N(3, M##15))             \
+       alu2(N, N##M##16, 3, $(M##16), N(3, M##16))             \
+       alu2(N, N##M##17, 3, $(M##17), N(3, M##17))             \
+       alu2(N, N##M##18, 3, $(M##18), N(3, M##18))             \
+       alu2(N, N##M##19, 3, $(M##19), N(3, M##19))             \
+       alu2(N, N##M##20, 3, $(M##20), N(3, M##20))             \
+       alu2(N, N##M##21, 3, $(M##21), N(3, M##21))             \
+       alu2(N, N##M##22, 3, $(M##22), N(3, M##22))             \
+       alu2(N, N##M##23, 3, $(M##23), N(3, M##23))             \
+       alu2(N, N##M##24, 3, $(M##24), N(3, M##24))             \
+       alu2(N, N##M##25, 3, $(M##25), N(3, M##25))             \
+       alu2(N, N##M##26, 3, $(M##26), N(3, M##26))
+
+#define alu(N)                                                 \
+       alu1(N, aB)                                             \
+       alu1(N, bB)                                             \
+       alu1(N, cB)                                             \
+       alu1(N, dB)
+
+#define _lsh(N)                                                        \
+       alu2(lsh, L##N, 3, N, $(3<<N))
+#define _rsh(N)                                                        \
+       alu2(rsh, R##N, $(1<<63), N, $((1<<63)>>N))
+
+#if __WORDSIZE == 32
+#  define xsh64(X)                     /**/
+#else
+#  define xsh64(X)                                             \
+       _##X##sh(32)                                            \
+       _##X##sh(33)                                            \
+       _##X##sh(34)                                            \
+       _##X##sh(35)                                            \
+       _##X##sh(36)                                            \
+       _##X##sh(37)                                            \
+       _##X##sh(38)                                            \
+       _##X##sh(39)                                            \
+       _##X##sh(40)                                            \
+       _##X##sh(41)                                            \
+       _##X##sh(42)                                            \
+       _##X##sh(43)                                            \
+       _##X##sh(44)                                            \
+       _##X##sh(45)                                            \
+       _##X##sh(46)                                            \
+       _##X##sh(47)                                            \
+       _##X##sh(48)                                            \
+       _##X##sh(49)                                            \
+       _##X##sh(50)                                            \
+       _##X##sh(51)                                            \
+       _##X##sh(52)                                            \
+       _##X##sh(53)                                            \
+       _##X##sh(54)                                            \
+       _##X##sh(55)                                            \
+       _##X##sh(56)                                            \
+       _##X##sh(57)                                            \
+       _##X##sh(58)                                            \
+       _##X##sh(59)                                            \
+       _##X##sh(60)                                            \
+       _##X##sh(61)                                            \
+       _##X##sh(62)                                            \
+       _##X##sh(63)
+#endif
+
+#define xsh(X)                                                 \
+       _##X##sh(0)                                             \
+       _##X##sh(1)                                             \
+       _##X##sh(2)                                             \
+       _##X##sh(3)                                             \
+       _##X##sh(4)                                             \
+       _##X##sh(5)                                             \
+       _##X##sh(6)                                             \
+       _##X##sh(7)                                             \
+       _##X##sh(8)                                             \
+       _##X##sh(9)                                             \
+       _##X##sh(10)                                            \
+       _##X##sh(11)                                            \
+       _##X##sh(12)                                            \
+       _##X##sh(13)                                            \
+       _##X##sh(14)                                            \
+       _##X##sh(15)                                            \
+       _##X##sh(16)                                            \
+       _##X##sh(17)                                            \
+       _##X##sh(18)                                            \
+       _##X##sh(19)                                            \
+       _##X##sh(20)                                            \
+       _##X##sh(21)                                            \
+       _##X##sh(22)                                            \
+       _##X##sh(23)                                            \
+       _##X##sh(24)                                            \
+       _##X##sh(25)                                            \
+       _##X##sh(26)                                            \
+       _##X##sh(27)                                            \
+       _##X##sh(28)                                            \
+       _##X##sh(29)                                            \
+       _##X##sh(30)                                            \
+       _##X##sh(31)                                            \
+       xsh64(X)
+
+#define lsh()                                                  \
+       xsh(l)
+#define rsh()                                                  \
+       xsh(r)
+
+#define reset(V)                                               \
+       prepare                                                 \
+               pushargi buf                                    \
+               pushargi V                                      \
+               pushargi $(M64 + 8)                             \
+       finishi @memset
+
+#define stx(T, N, O, V)                                                \
+       movi %r0 V                                              \
+       stxi##T O %v0 %r0
+#define stx8(T, M, V)                                          \
+       stx(T, 3, $(M##B3), V)                                  \
+       stx(T, 4, $(M##B4), V)                                  \
+       stx(T, 5, $(M##B5), V)                                  \
+       stx(T, 6, $(M##B6), V)                                  \
+       stx(T, 7, $(M##B7), V)                                  \
+       stx(T, 8, $(M##B8), V)                                  \
+       stx(T, 9, $(M##B9), V)                                  \
+       stx(T, 10, $(M##B10), V)                                \
+       stx(T, 11, $(M##B11), V)                                \
+       stx(T, 12, $(M##B12), V)                                \
+       stx(T, 13, $(M##B13), V)                                \
+       stx(T, 14, $(M##B14), V)                                \
+       stx(T, 15, $(M##B15), V)                                \
+       stx(T, 16, $(M##B16), V)                                \
+       stx(T, 17, $(M##B17), V)                                \
+       stx(T, 18, $(M##B18), V)                                \
+       stx(T, 19, $(M##B19), V)                                \
+       stx(T, 20, $(M##B20), V)                                \
+       stx(T, 21, $(M##B21), V)                                \
+       stx(T, 22, $(M##B22), V)                                \
+       stx(T, 23, $(M##B23), V)                                \
+       stx(T, 24, $(M##B24), V)                                \
+       stx(T, 25, $(M##B25), V)                                \
+       stx(T, 26, $(M##B26), V)
+#define stx4(T, M, V)                                          \
+       stx(T, 2, $(M##B2), V)                                  \
+       stx8(T, M, V)
+#define stx2(T, M, V)                                          \
+       stx(T, 1, $(M##B1), V)                                  \
+       stx4(T, M, V)
+#define ldx(T, N, M, O, V)                                     \
+       movi %r0 0                                              \
+       ldxi##T %r0 %v0 O                                       \
+       beqi ldx##T##N##M %r0 V                                 \
+       calli @abort                                            \
+ldx##T##N##M:
+#define ldx8(T, M, V)                                          \
+       ldx(T, 3, M, $(M##B3), V)                               \
+       ldx(T, 4, M, $(M##B4), V)                               \
+       ldx(T, 5, M, $(M##B5), V)                               \
+       ldx(T, 6, M, $(M##B6), V)                               \
+       ldx(T, 7, M, $(M##B7), V)                               \
+       ldx(T, 8, M, $(M##B8), V)                               \
+       ldx(T, 9, M, $(M##B9), V)                               \
+       ldx(T, 10, M, $(M##B10), V)                             \
+       ldx(T, 11, M, $(M##B11), V)                             \
+       ldx(T, 12, M, $(M##B12), V)                             \
+       ldx(T, 13, M, $(M##B13), V)                             \
+       ldx(T, 14, M, $(M##B14), V)                             \
+       ldx(T, 15, M, $(M##B15), V)                             \
+       ldx(T, 16, M, $(M##B16), V)                             \
+       ldx(T, 17, M, $(M##B17), V)                             \
+       ldx(T, 18, M, $(M##B18), V)                             \
+       ldx(T, 19, M, $(M##B19), V)                             \
+       ldx(T, 20, M, $(M##B20), V)                             \
+       ldx(T, 21, M, $(M##B21), V)                             \
+       ldx(T, 22, M, $(M##B22), V)                             \
+       ldx(T, 23, M, $(M##B23), V)                             \
+       ldx(T, 24, M, $(M##B24), V)                             \
+       ldx(T, 25, M, $(M##B25), V)                             \
+       ldx(T, 26, M, $(M##B26), V)
+#define ldx4(T, M, V)                                          \
+       ldx(T, 2, M, $(M##B2), V)                               \
+       ldx8(T, M, V)
+#define ldx2(T, M, V)                                          \
+       ldx(T, 1, M, $(M##B1), V)                               \
+       ldx4(T, M, V)
+
+#define stf(T, N, O, V)                                                \
+       movi##T %f0 V                                           \
+       stxi##T O %v0 %f0
+#define stf8(T, M, V)                                          \
+       stf(T, 3, $(M##B3), V)                                  \
+       stf(T, 4, $(M##B4), V)                                  \
+       stf(T, 5, $(M##B5), V)                                  \
+       stf(T, 6, $(M##B6), V)                                  \
+       stf(T, 7, $(M##B7), V)                                  \
+       stf(T, 8, $(M##B8), V)                                  \
+       stf(T, 9, $(M##B9), V)                                  \
+       stf(T, 10, $(M##B10), V)                                \
+       stf(T, 11, $(M##B11), V)                                \
+       stf(T, 12, $(M##B12), V)                                \
+       stf(T, 13, $(M##B13), V)                                \
+       stf(T, 14, $(M##B14), V)                                \
+       stf(T, 15, $(M##B15), V)                                \
+       stf(T, 16, $(M##B16), V)                                \
+       stf(T, 17, $(M##B17), V)                                \
+       stf(T, 18, $(M##B18), V)                                \
+       stf(T, 19, $(M##B19), V)                                \
+       stf(T, 20, $(M##B20), V)                                \
+       stf(T, 21, $(M##B21), V)                                \
+       stf(T, 22, $(M##B22), V)                                \
+       stf(T, 23, $(M##B23), V)                                \
+       stf(T, 24, $(M##B24), V)                                \
+       stf(T, 25, $(M##B25), V)                                \
+       stf(T, 26, $(M##B26), V)
+#define stf4(T, M, V)                                          \
+       stf(T, 2, $(M##B2), V)                                  \
+       stf8(T, M, V)
+#define ldf(T, N, M, O, V)                                     \
+       movi##T %f0 0                                           \
+       ldxi##T %f0 %v0 O                                       \
+       beqi##T ldf##T##N##M %f0 V                              \
+       calli @abort                                            \
+ldf##T##N##M:
+#define ldf8(T, M, V)                                          \
+       ldf(T, 3, M, $(M##B3), V)                               \
+       ldf(T, 4, M, $(M##B4), V)                               \
+       ldf(T, 5, M, $(M##B5), V)                               \
+       ldf(T, 6, M, $(M##B6), V)                               \
+       ldf(T, 7, M, $(M##B7), V)                               \
+       ldf(T, 8, M, $(M##B8), V)                               \
+       ldf(T, 9, M, $(M##B9), V)                               \
+       ldf(T, 10, M, $(M##B10), V)                             \
+       ldf(T, 11, M, $(M##B11), V)                             \
+       ldf(T, 12, M, $(M##B12), V)                             \
+       ldf(T, 13, M, $(M##B13), V)                             \
+       ldf(T, 14, M, $(M##B14), V)                             \
+       ldf(T, 15, M, $(M##B15), V)                             \
+       ldf(T, 16, M, $(M##B16), V)                             \
+       ldf(T, 17, M, $(M##B17), V)                             \
+       ldf(T, 18, M, $(M##B18), V)                             \
+       ldf(T, 19, M, $(M##B19), V)                             \
+       ldf(T, 20, M, $(M##B20), V)                             \
+       ldf(T, 21, M, $(M##B21), V)                             \
+       ldf(T, 22, M, $(M##B22), V)                             \
+       ldf(T, 23, M, $(M##B23), V)                             \
+       ldf(T, 24, M, $(M##B24), V)                             \
+       ldf(T, 25, M, $(M##B25), V)                             \
+       ldf(T, 26, M, $(M##B26), V)
+#define ldf4(T, M, V)                                          \
+       ldf(T, 2, M, $(M##B2), V)                               \
+       ldf8(T, M, V)
+
+#define ldst_c()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx2(_c, a, 0x5a)                                       \
+       ldx2(_c, a, 0x5a)                                       \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx2(_c, b, 0x5a)                                       \
+       ldx2(_c, b, 0x5a)
+#define ldst_uc()                                              \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx2(_c, a, 0x5a)                                       \
+       ldx2(_uc, a, 0x5a)                                      \
+       movi %v0 $(buf + M64)                                   \
+       stx2(_c, b, 0x5a)                                       \
+       ldx2(_uc, b, 0x5a)
+#define ldst_s()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx2(_s, a, 0x5a5a)                                     \
+       ldx2(_s, a, 0x5a5a)                                     \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx2(_s, b, 0x5a5a)                                     \
+       ldx2(_s, b, 0x5a5a)
+#define ldst_us()                                              \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx2(_s, a, 0x5a5a)                                     \
+       ldx2(_us, a, 0x5a5a)                                    \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx2(_s, b, 0x5a5a)                                     \
+       ldx2(_us, b, 0x5a5a)
+#define ldst_i()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx4(_i, a, 0x5a5a5a5a)                                 \
+       ldx4(_i, a, 0x5a5a5a5a)                                 \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx4(_i, b, 0x5a5a5a5a)                                 \
+       ldx4(_i, b, 0x5a5a5a5a)
+#define ldst_ui()                                              \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx4(_i, a, 0x5a5a5a5a)                                 \
+       ldx4(_ui, a, 0x5a5a5a5a)                                \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx4(_i, b, 0x5a5a5a5a)                                 \
+       ldx4(_ui, b, 0x5a5a5a5a)
+#define ldst_l()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx8(_l, a, 0x5a5a5a5a5a5a5a5a)                         \
+       ldx8(_l, a, 0x5a5a5a5a5a5a5a5a)                         \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx8(_l, b, 0x5a5a5a5a5a5a5a5a)                         \
+       ldx8(_l, b, 0x5a5a5a5a5a5a5a5a)
+#define ldst_f()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stf4(_f, a, 0.5)                                        \
+       ldf4(_f, a, 0.5)                                        \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stf4(_f, b, 0.5)                                        \
+       ldf4(_f, b, 0.5)
+#define ldst_d()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stf8(_d, a, 0.5)                                        \
+       ldf8(_d, a, 0.5)                                        \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stf8(_d, b, 0.5)                                        \
+       ldf8(_d, b, 0.5)
+
+.data          67112960
+buf:
+.size          M64
+.size          8
+ok:
+.c             "ok"
+
+.code
+       prolog
+
+       alu(add)
+       alu(sub)
+       alu(rsb)
+       alu(mul)
+       alu(div)
+       alu(rem)
+       lsh()
+       rsh()
+       alu(and)
+       alu(or)
+       alu(xor)
+       ldst_c()
+       ldst_uc()
+       ldst_s()
+       ldst_us()
+       ldst_i()
+#if __WORDSIZE == 64
+       ldst_ui()
+       ldst_l()
+#endif
+       ldst_f()
+       ldst_d()
+
+       prepare
+               pushargi ok
+       finishi @puts
+       ret
+       epilog
diff --git a/deps/lightning/check/ranger.ok b/deps/lightning/check/ranger.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/ranger.tst b/deps/lightning/check/ranger.tst
new file mode 100644 (file)
index 0000000..de80196
--- /dev/null
@@ -0,0 +1,507 @@
+#define M64    67108864
+
+#define aB1    (1<<1)
+#define aB2    (1<<2)
+#define aB3    (1<<3)
+#define aB4    (1<<4)
+#define aB5    (1<<5)
+#define aB6    (1<<6)
+#define aB7    (1<<7)
+#define aB8    (1<<8)
+#define aB9    (1<<9)
+#define aB10   (1<<10)
+#define aB11   (1<<11)
+#define aB12   (1<<12)
+#define aB13   (1<<13)
+#define aB14   (1<<14)
+#define aB15   (1<<15)
+#define aB16   (1<<16)
+#define aB17   (1<<17)
+#define aB18   (1<<18)
+#define aB19   (1<<19)
+#define aB20   (1<<20)
+#define aB21   (1<<21)
+#define aB22   (1<<22)
+#define aB23   (1<<23)
+#define aB24   (1<<24)
+#define aB25   (1<<25)
+#define aB26   (1<<26)
+#define bB1    (-aB1)
+#define bB2    (-aB2)
+#define bB3    (-aB3)
+#define bB4    (-aB4)
+#define bB5    (-aB5)
+#define bB6    (-aB6)
+#define bB7    (-aB7)
+#define bB8    (-aB8)
+#define bB9    (-aB9)
+#define bB10   (-aB10)
+#define bB11   (-aB11)
+#define bB12   (-aB12)
+#define bB13   (-aB13)
+#define bB14   (-aB14)
+#define bB15   (-aB15)
+#define bB16   (-aB16)
+#define bB17   (-aB17)
+#define bB18   (-aB18)
+#define bB19   (-aB19)
+#define bB20   (-aB20)
+#define bB21   (-aB21)
+#define bB22   (-aB22)
+#define bB23   (-aB23)
+#define bB24   (-aB24)
+#define bB25   (-aB25)
+#define bB26   (-aB26)
+#define cB1    (aB1-1)
+#define cB2    (aB2-1)
+#define cB3    (aB3-1)
+#define cB4    (aB4-1)
+#define cB5    (aB5-1)
+#define cB6    (aB6-1)
+#define cB7    (aB7-1)
+#define cB8    (aB8-1)
+#define cB9    (aB9-1)
+#define cB10   (aB10-1)
+#define cB11   (aB11-1)
+#define cB12   (aB12-1)
+#define cB13   (aB13-1)
+#define cB14   (aB14-1)
+#define cB15   (aB15-1)
+#define cB16   (aB16-1)
+#define cB17   (aB17-1)
+#define cB18   (aB18-1)
+#define cB19   (aB19-1)
+#define cB20   (aB20-1)
+#define cB21   (aB21-1)
+#define cB22   (aB22-1)
+#define cB23   (aB23-1)
+#define cB24   (aB24-1)
+#define cB25   (aB25-1)
+#define cB26   (aB26-1)
+#define dB1    (-aB1+1)
+#define dB2    (-aB2+1)
+#define dB3    (-aB3+1)
+#define dB4    (-aB4+1)
+#define dB5    (-aB5+1)
+#define dB6    (-aB6+1)
+#define dB7    (-aB7+1)
+#define dB8    (-aB8+1)
+#define dB9    (-aB9+1)
+#define dB10   (-aB10+1)
+#define dB11   (-aB11+1)
+#define dB12   (-aB12+1)
+#define dB13   (-aB13+1)
+#define dB14   (-aB14+1)
+#define dB15   (-aB15+1)
+#define dB16   (-aB16+1)
+#define dB17   (-aB17+1)
+#define dB18   (-aB18+1)
+#define dB19   (-aB19+1)
+#define dB20   (-aB20+1)
+#define dB21   (-aB21+1)
+#define dB22   (-aB22+1)
+#define dB23   (-aB23+1)
+#define dB24   (-aB24+1)
+#define dB25   (-aB25+1)
+#define dB26   (-aB26+1)
+
+#define add(a, b)              $(a + b)
+#define sub(a, b)              $(a - b)
+#define rsb(a, b)              $(b - a)
+#define mul(a, b)              $(a * b)
+#define div(a, b)              $(a / b)
+#define rem(a, b)              $(a % b)
+#define and(a, b)              $(a & b)
+#define or(a, b)               $(a | b)
+#define xor(a, b)              $(a ^ b)
+
+#define alu2(N, X, L, R, V)                                    \
+       movi %r1 L                                              \
+       movi %r2 R                                              \
+       N##r %r0 %r1 %r2                                        \
+       beqi X %r0 V                                            \
+       calli @abort                                            \
+X:
+#define alu1(N, M)                                             \
+       alu2(N, N##M##1, 3, $(M##1), N(3, M##1))                \
+       alu2(N, N##M##2, 3, $(M##2), N(3, M##2))                \
+       alu2(N, N##M##3, 3, $(M##3), N(3, M##3))                \
+       alu2(N, N##M##4, 3, $(M##4), N(3, M##4))                \
+       alu2(N, N##M##5, 3, $(M##5), N(3, M##5))                \
+       alu2(N, N##M##6, 3, $(M##6), N(3, M##6))                \
+       alu2(N, N##M##7, 3, $(M##7), N(3, M##7))                \
+       alu2(N, N##M##8, 3, $(M##8), N(3, M##8))                \
+       alu2(N, N##M##9, 3, $(M##9), N(3, M##9))                \
+       alu2(N, N##M##10, 3, $(M##10), N(3, M##10))             \
+       alu2(N, N##M##11, 3, $(M##11), N(3, M##11))             \
+       alu2(N, N##M##12, 3, $(M##12), N(3, M##12))             \
+       alu2(N, N##M##13, 3, $(M##13), N(3, M##13))             \
+       alu2(N, N##M##14, 3, $(M##14), N(3, M##14))             \
+       alu2(N, N##M##15, 3, $(M##15), N(3, M##15))             \
+       alu2(N, N##M##16, 3, $(M##16), N(3, M##16))             \
+       alu2(N, N##M##17, 3, $(M##17), N(3, M##17))             \
+       alu2(N, N##M##18, 3, $(M##18), N(3, M##18))             \
+       alu2(N, N##M##19, 3, $(M##19), N(3, M##19))             \
+       alu2(N, N##M##20, 3, $(M##20), N(3, M##20))             \
+       alu2(N, N##M##21, 3, $(M##21), N(3, M##21))             \
+       alu2(N, N##M##22, 3, $(M##22), N(3, M##22))             \
+       alu2(N, N##M##23, 3, $(M##23), N(3, M##23))             \
+       alu2(N, N##M##24, 3, $(M##24), N(3, M##24))             \
+       alu2(N, N##M##25, 3, $(M##25), N(3, M##25))             \
+       alu2(N, N##M##26, 3, $(M##26), N(3, M##26))
+
+#define alu(N)                                                 \
+       alu1(N, aB)                                             \
+       alu1(N, bB)                                             \
+       alu1(N, cB)                                             \
+       alu1(N, dB)
+
+#define _lsh(N)                                                        \
+       alu2(lsh, L##N, 3, N, $(3<<N))
+#define _rsh(N)                                                        \
+       alu2(rsh, R##N, $(1<<63), N, $((1<<63)>>N))
+
+#if __WORDSIZE == 32
+#  define xsh64(X)                     /**/
+#else
+#  define xsh64(X)                                             \
+       _##X##sh(32)                                            \
+       _##X##sh(33)                                            \
+       _##X##sh(34)                                            \
+       _##X##sh(35)                                            \
+       _##X##sh(36)                                            \
+       _##X##sh(37)                                            \
+       _##X##sh(38)                                            \
+       _##X##sh(39)                                            \
+       _##X##sh(40)                                            \
+       _##X##sh(41)                                            \
+       _##X##sh(42)                                            \
+       _##X##sh(43)                                            \
+       _##X##sh(44)                                            \
+       _##X##sh(45)                                            \
+       _##X##sh(46)                                            \
+       _##X##sh(47)                                            \
+       _##X##sh(48)                                            \
+       _##X##sh(49)                                            \
+       _##X##sh(50)                                            \
+       _##X##sh(51)                                            \
+       _##X##sh(52)                                            \
+       _##X##sh(53)                                            \
+       _##X##sh(54)                                            \
+       _##X##sh(55)                                            \
+       _##X##sh(56)                                            \
+       _##X##sh(57)                                            \
+       _##X##sh(58)                                            \
+       _##X##sh(59)                                            \
+       _##X##sh(60)                                            \
+       _##X##sh(61)                                            \
+       _##X##sh(62)                                            \
+       _##X##sh(63)
+#endif
+
+#define xsh(X)                                                 \
+       _##X##sh(0)                                             \
+       _##X##sh(1)                                             \
+       _##X##sh(2)                                             \
+       _##X##sh(3)                                             \
+       _##X##sh(4)                                             \
+       _##X##sh(5)                                             \
+       _##X##sh(6)                                             \
+       _##X##sh(7)                                             \
+       _##X##sh(8)                                             \
+       _##X##sh(9)                                             \
+       _##X##sh(10)                                            \
+       _##X##sh(11)                                            \
+       _##X##sh(12)                                            \
+       _##X##sh(13)                                            \
+       _##X##sh(14)                                            \
+       _##X##sh(15)                                            \
+       _##X##sh(16)                                            \
+       _##X##sh(17)                                            \
+       _##X##sh(18)                                            \
+       _##X##sh(19)                                            \
+       _##X##sh(20)                                            \
+       _##X##sh(21)                                            \
+       _##X##sh(22)                                            \
+       _##X##sh(23)                                            \
+       _##X##sh(24)                                            \
+       _##X##sh(25)                                            \
+       _##X##sh(26)                                            \
+       _##X##sh(27)                                            \
+       _##X##sh(28)                                            \
+       _##X##sh(29)                                            \
+       _##X##sh(30)                                            \
+       _##X##sh(31)                                            \
+       xsh64(X)
+
+#define lsh()                                                  \
+       xsh(l)
+#define rsh()                                                  \
+       xsh(r)
+
+#define reset(V)                                               \
+       prepare                                                 \
+               pushargi buf                                    \
+               pushargi V                                      \
+               pushargi $(M64 + 8)                             \
+       finishi @memset
+
+#define stx(T, N, O, V)                                                \
+       movi %r0 V                                              \
+       movi %r1 O                                              \
+       stxr##T %r1 %v0 %r0
+#define stx8(T, M, V)                                          \
+       stx(T, 3, $(M##B3), V)                                  \
+       stx(T, 4, $(M##B4), V)                                  \
+       stx(T, 5, $(M##B5), V)                                  \
+       stx(T, 6, $(M##B6), V)                                  \
+       stx(T, 7, $(M##B7), V)                                  \
+       stx(T, 8, $(M##B8), V)                                  \
+       stx(T, 9, $(M##B9), V)                                  \
+       stx(T, 10, $(M##B10), V)                                \
+       stx(T, 11, $(M##B11), V)                                \
+       stx(T, 12, $(M##B12), V)                                \
+       stx(T, 13, $(M##B13), V)                                \
+       stx(T, 14, $(M##B14), V)                                \
+       stx(T, 15, $(M##B15), V)                                \
+       stx(T, 16, $(M##B16), V)                                \
+       stx(T, 17, $(M##B17), V)                                \
+       stx(T, 18, $(M##B18), V)                                \
+       stx(T, 19, $(M##B19), V)                                \
+       stx(T, 20, $(M##B20), V)                                \
+       stx(T, 21, $(M##B21), V)                                \
+       stx(T, 22, $(M##B22), V)                                \
+       stx(T, 23, $(M##B23), V)                                \
+       stx(T, 24, $(M##B24), V)                                \
+       stx(T, 25, $(M##B25), V)                                \
+       stx(T, 26, $(M##B26), V)
+#define stx4(T, M, V)                                          \
+       stx(T, 2, $(M##B2), V)                                  \
+       stx8(T, M, V)
+#define stx2(T, M, V)                                          \
+       stx(T, 1, $(M##B1), V)                                  \
+       stx4(T, M, V)
+#define ldx(T, N, M, O, V)                                     \
+       movi %r0 0                                              \
+       ldxi##T %r0 %v0 O                                       \
+       beqi ldx##T##N##M %r0 V                                 \
+       calli @abort                                            \
+ldx##T##N##M:
+#define ldx8(T, M, V)                                          \
+       ldx(T, 3, M, $(M##B3), V)                               \
+       ldx(T, 4, M, $(M##B4), V)                               \
+       ldx(T, 5, M, $(M##B5), V)                               \
+       ldx(T, 6, M, $(M##B6), V)                               \
+       ldx(T, 7, M, $(M##B7), V)                               \
+       ldx(T, 8, M, $(M##B8), V)                               \
+       ldx(T, 9, M, $(M##B9), V)                               \
+       ldx(T, 10, M, $(M##B10), V)                             \
+       ldx(T, 11, M, $(M##B11), V)                             \
+       ldx(T, 12, M, $(M##B12), V)                             \
+       ldx(T, 13, M, $(M##B13), V)                             \
+       ldx(T, 14, M, $(M##B14), V)                             \
+       ldx(T, 15, M, $(M##B15), V)                             \
+       ldx(T, 16, M, $(M##B16), V)                             \
+       ldx(T, 17, M, $(M##B17), V)                             \
+       ldx(T, 18, M, $(M##B18), V)                             \
+       ldx(T, 19, M, $(M##B19), V)                             \
+       ldx(T, 20, M, $(M##B20), V)                             \
+       ldx(T, 21, M, $(M##B21), V)                             \
+       ldx(T, 22, M, $(M##B22), V)                             \
+       ldx(T, 23, M, $(M##B23), V)                             \
+       ldx(T, 24, M, $(M##B24), V)                             \
+       ldx(T, 25, M, $(M##B25), V)                             \
+       ldx(T, 26, M, $(M##B26), V)
+#define ldx4(T, M, V)                                          \
+       ldx(T, 2, M, $(M##B2), V)                               \
+       ldx8(T, M, V)
+#define ldx2(T, M, V)                                          \
+       ldx(T, 1, M, $(M##B1), V)                               \
+       ldx4(T, M, V)
+
+#define stf(T, N, O, V)                                                \
+       movi##T %f0 V                                           \
+       movi %r0 O                                              \
+       stxr##T %r0 %v0 %f0
+#define stf8(T, M, V)                                          \
+       stf(T, 3, $(M##B3), V)                                  \
+       stf(T, 4, $(M##B4), V)                                  \
+       stf(T, 5, $(M##B5), V)                                  \
+       stf(T, 6, $(M##B6), V)                                  \
+       stf(T, 7, $(M##B7), V)                                  \
+       stf(T, 8, $(M##B8), V)                                  \
+       stf(T, 9, $(M##B9), V)                                  \
+       stf(T, 10, $(M##B10), V)                                \
+       stf(T, 11, $(M##B11), V)                                \
+       stf(T, 12, $(M##B12), V)                                \
+       stf(T, 13, $(M##B13), V)                                \
+       stf(T, 14, $(M##B14), V)                                \
+       stf(T, 15, $(M##B15), V)                                \
+       stf(T, 16, $(M##B16), V)                                \
+       stf(T, 17, $(M##B17), V)                                \
+       stf(T, 18, $(M##B18), V)                                \
+       stf(T, 19, $(M##B19), V)                                \
+       stf(T, 20, $(M##B20), V)                                \
+       stf(T, 21, $(M##B21), V)                                \
+       stf(T, 22, $(M##B22), V)                                \
+       stf(T, 23, $(M##B23), V)                                \
+       stf(T, 24, $(M##B24), V)                                \
+       stf(T, 25, $(M##B25), V)                                \
+       stf(T, 26, $(M##B26), V)
+#define stf4(T, M, V)                                          \
+       stf(T, 2, $(M##B2), V)                                  \
+       stf8(T, M, V)
+#define ldf(T, N, M, O, V)                                     \
+       movi##T %f0 0                                           \
+       ldxi##T %f0 %v0 O                                       \
+       beqi##T ldf##T##N##M %f0 V                              \
+       calli @abort                                            \
+ldf##T##N##M:
+#define ldf8(T, M, V)                                          \
+       ldf(T, 3, M, $(M##B3), V)                               \
+       ldf(T, 4, M, $(M##B4), V)                               \
+       ldf(T, 5, M, $(M##B5), V)                               \
+       ldf(T, 6, M, $(M##B6), V)                               \
+       ldf(T, 7, M, $(M##B7), V)                               \
+       ldf(T, 8, M, $(M##B8), V)                               \
+       ldf(T, 9, M, $(M##B9), V)                               \
+       ldf(T, 10, M, $(M##B10), V)                             \
+       ldf(T, 11, M, $(M##B11), V)                             \
+       ldf(T, 12, M, $(M##B12), V)                             \
+       ldf(T, 13, M, $(M##B13), V)                             \
+       ldf(T, 14, M, $(M##B14), V)                             \
+       ldf(T, 15, M, $(M##B15), V)                             \
+       ldf(T, 16, M, $(M##B16), V)                             \
+       ldf(T, 17, M, $(M##B17), V)                             \
+       ldf(T, 18, M, $(M##B18), V)                             \
+       ldf(T, 19, M, $(M##B19), V)                             \
+       ldf(T, 20, M, $(M##B20), V)                             \
+       ldf(T, 21, M, $(M##B21), V)                             \
+       ldf(T, 22, M, $(M##B22), V)                             \
+       ldf(T, 23, M, $(M##B23), V)                             \
+       ldf(T, 24, M, $(M##B24), V)                             \
+       ldf(T, 25, M, $(M##B25), V)                             \
+       ldf(T, 26, M, $(M##B26), V)
+#define ldf4(T, M, V)                                          \
+       ldf(T, 2, M, $(M##B2), V)                               \
+       ldf8(T, M, V)
+
+#define ldst_c()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx2(_c, a, 0x5a)                                       \
+       ldx2(_c, a, 0x5a)                                       \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx2(_c, b, 0x5a)                                       \
+       ldx2(_c, b, 0x5a)
+#define ldst_uc()                                              \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx2(_c, a, 0x5a)                                       \
+       ldx2(_uc, a, 0x5a)                                      \
+       movi %v0 $(buf + M64)                                   \
+       stx2(_c, b, 0x5a)                                       \
+       ldx2(_uc, b, 0x5a)
+#define ldst_s()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx2(_s, a, 0x5a5a)                                     \
+       ldx2(_s, a, 0x5a5a)                                     \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx2(_s, b, 0x5a5a)                                     \
+       ldx2(_s, b, 0x5a5a)
+#define ldst_us()                                              \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx2(_s, a, 0x5a5a)                                     \
+       ldx2(_us, a, 0x5a5a)                                    \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx2(_s, b, 0x5a5a)                                     \
+       ldx2(_us, b, 0x5a5a)
+#define ldst_i()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx4(_i, a, 0x5a5a5a5a)                                 \
+       ldx4(_i, a, 0x5a5a5a5a)                                 \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx4(_i, b, 0x5a5a5a5a)                                 \
+       ldx4(_i, b, 0x5a5a5a5a)
+#define ldst_ui()                                              \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx4(_i, a, 0x5a5a5a5a)                                 \
+       ldx4(_ui, a, 0x5a5a5a5a)                                \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx4(_i, b, 0x5a5a5a5a)                                 \
+       ldx4(_ui, b, 0x5a5a5a5a)
+#define ldst_l()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stx8(_l, a, 0x5a5a5a5a5a5a5a5a)                         \
+       ldx8(_l, a, 0x5a5a5a5a5a5a5a5a)                         \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stx8(_l, b, 0x5a5a5a5a5a5a5a5a)                         \
+       ldx8(_l, b, 0x5a5a5a5a5a5a5a5a)
+#define ldst_f()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stf4(_f, a, 0.5)                                        \
+       ldf4(_f, a, 0.5)                                        \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stf4(_f, b, 0.5)                                        \
+       ldf4(_f, b, 0.5)
+#define ldst_d()                                               \
+       reset(0xa5)                                             \
+       movi %v0 buf                                            \
+       stf8(_d, a, 0.5)                                        \
+       ldf8(_d, a, 0.5)                                        \
+       reset(0xa5)                                             \
+       movi %v0 $(buf + M64)                                   \
+       stf8(_d, b, 0.5)                                        \
+       ldf8(_d, b, 0.5)
+
+.data          67112960
+buf:
+.size          M64
+.size          8
+ok:
+.c             "ok"
+
+.code
+       prolog
+
+       alu(add)
+       alu(sub)
+       alu(rsb)
+       alu(mul)
+       alu(div)
+       alu(rem)
+       lsh()
+       rsh()
+       alu(and)
+       alu(or)
+       alu(xor)
+       ldst_c()
+       ldst_uc()
+       ldst_s()
+       ldst_us()
+       ldst_i()
+#if __WORDSIZE == 64
+       ldst_ui()
+       ldst_l()
+#endif
+       ldst_f()
+       ldst_d()
+
+       prepare
+               pushargi ok
+       finishi @puts
+       ret
+       epilog
diff --git a/deps/lightning/check/ret.ok b/deps/lightning/check/ret.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/ret.tst b/deps/lightning/check/ret.tst
new file mode 100644 (file)
index 0000000..de1d82c
--- /dev/null
@@ -0,0 +1,51 @@
+.data  16
+ok:
+.c     "ok"
+
+.code
+       jmpi main
+
+/*
+ * very simple test on purpose because otherwise it would not trigger
+ * the bug where the retr %r0 or retr_d %f0 would be omitted because
+ * the argument was already the return register, but the register end
+ * clobbered by another instruction, like the div*, and the wrong
+ * value returned because the retr* was removed and this way, lost
+ * information that the register was live at function exit.
+ */
+
+check_r0:
+       prolog
+       movi %r0 1
+       movi %r2 10
+       // on x86 this changes %rax on other arches could use %r0 as temporary
+       divi %r1 %r2 3
+       // %r0 must still be 1
+       retr %r0
+       epilog
+
+check_f0:
+       prolog
+       movi_d %f0 0.5
+       movi_d %f2 10
+       divi_d %f1 %f2 3
+       retr_d %f0
+       epilog
+
+main:
+       prolog
+       calli check_r0
+       retval %r1
+       beqi r0_ok %r1 1
+       calli @abort
+r0_ok:
+       calli check_f0
+       retval_d %f1
+       beqi_d f0_ok %f1 0.5
+       calli @abort
+f0_ok:
+       prepare
+               pushargi ok
+       finishi @puts
+       ret
+       epilog
diff --git a/deps/lightning/check/rpn.ok b/deps/lightning/check/rpn.ok
new file mode 100644 (file)
index 0000000..b686c13
--- /dev/null
@@ -0,0 +1,6 @@
+
+C:  0  10  20  30  40  50  60  70  80  90 100 
+F: 32  50  68  86 104 122 140 158 176 194 212 
+
+F: 32  50  68  86 104 122 140 158 176 194 212 
+C:  0  10  20  30  40  50  60  70  80  90 100 
diff --git a/deps/lightning/check/rpn.tst b/deps/lightning/check/rpn.tst
new file mode 100644 (file)
index 0000000..62ef8d6
--- /dev/null
@@ -0,0 +1,183 @@
+.data  256
+.$($int = 4)
+C:
+.c "\nC:"
+F:
+.c "\nF:"
+format:
+.c "%3d "
+newline:
+.c "\n"
+
+.code
+       jmpi main
+
+       name c2f
+c2f:
+       prolog
+       arg $in
+
+       allocai $(32 * $int) $index
+
+       getarg %r2 $in
+
+       // 32x9*5/+
+       movi %r0 32
+
+       // x9*5/+
+       stxi_i $index %fp %r0
+.      $($index = $index + $int)
+       movr %r0 %r2
+
+       // 9*5/+
+       stxi_i $index %fp %r0
+.      $($index = $index + $int)
+       movi %r0 9
+
+       // *5/+
+.      $($index = $index - $int)
+       ldxi_i %r1 %fp $index
+       mulr %r0 %r1 %r0
+
+       // 5/+
+       stxi_i $index %fp %r0
+.      $($index = $index + $int)
+       movi %r0 5
+
+       // /+
+.      $($index = $index - $int)
+       ldxi_i %r1 %fp $index
+       divr %r0 %r1 %r0
+
+       // +
+.      $($index = $index - $int)
+       ldxi_i %r1 %fp $index
+       addr %r0 %r1 %r0
+
+       retr %r0
+       epilog
+
+       name f2c
+f2c:
+       prolog
+       arg $in
+
+       allocai $(32 * $int) $index
+
+       getarg %r2 $in
+
+       // x32-5*9/
+       stxi_i $index %fp %r0
+.      $($index = $index + $int)
+       movr %r0 %r2
+
+       // 32-5*9/
+       stxi_i $index %fp %r0
+.      $($index = $index + $int)
+       movi %r0 32
+
+       // -5*9/
+.      $($index = $index - $int)
+       ldxi_i %r1 %fp $index
+       subr %r0 %r1 %r0
+
+       // 5*9/
+       stxi_i $index %fp %r0
+.      $($index = $index + $int)
+       movi %r0 5
+
+       // *9/
+.      $($index = $index - $int)
+       ldxi_i %r1 %fp $index
+       mulr %r0 %r1 %r0
+
+       // 9/
+       stxi_i $index %fp %r0
+.      $($index = $index + $int)
+       movi %r0 9
+
+       // /
+.      $($index = $index - $int)
+       ldxi_i %r1 %fp $index
+       divr %r0 %r1 %r0
+
+       retr %r0
+       epilog
+
+//-----------------------------------------------------------------------
+       name main
+main:
+       prolog
+
+       prepare
+               pushargi C
+               ellipsis
+       finishi @printf
+       movi %v0 0
+loopC:
+       prepare
+               pushargi format
+               ellipsis
+               pushargr %v0
+       finishi @printf
+       addi %v0 %v0 10
+       blei loopC %v0 100
+       prepare
+               pushargi F
+               ellipsis
+       finishi @printf
+       movi %v0 0
+loopC2F:
+       prepare
+               pushargr %v0
+       finishi c2f
+       retval %r0
+       prepare
+               pushargi format
+               ellipsis
+               pushargr %r0
+       finishi @printf
+       addi %v0 %v0 10
+       blei loopC2F %v0 100
+       prepare
+               pushargi newline
+               ellipsis
+       finishi @printf
+
+       prepare
+               pushargi F
+               ellipsis
+       finishi @printf
+       movi %v0 32
+loopF:
+       prepare
+               pushargi format
+               ellipsis
+               pushargr %v0
+       finishi @printf
+       addi %v0 %v0 18
+       blei loopF %v0 212
+       prepare
+               pushargi C
+               ellipsis
+       finishi @printf
+       movi %v0 32
+loopF2C:
+       prepare
+               pushargr %v0
+       finishi f2c
+       retval %r0
+       prepare
+               pushargi format
+               ellipsis
+               pushargr %r0
+       finishi @printf
+       addi %v0 %v0 18
+       blei loopF2C %v0 212
+       prepare
+               pushargi newline
+               ellipsis
+       finishi @printf
+
+       ret
+       epilog
diff --git a/deps/lightning/check/run-test b/deps/lightning/check/run-test
new file mode 100755 (executable)
index 0000000..e8369d6
--- /dev/null
@@ -0,0 +1,10 @@
+#! /bin/sh
+
+ok=`echo $1 | sed -e 's@\.\(x87\|arm\|swf\)@@'`
+$1 | tr -d \\r > $1.log
+if cmp -s $srcdir/$ok.ok $1.log; then
+  rm $1.log
+else
+  diff $srcdir/$ok.ok $1.log
+  exit 1
+fi
diff --git a/deps/lightning/check/self.c b/deps/lightning/check/self.c
new file mode 100644 (file)
index 0000000..7cfbb94
--- /dev/null
@@ -0,0 +1,136 @@
+#include <lightning.h>
+#include <stdio.h>
+#include <assert.h>
+
+int
+main(int argc, char *argv[])
+{
+    jit_state_t                *_jit;
+
+    /* Same JIT_XY are not constants */
+    init_jit(argv[0]);
+
+    _jit = jit_new_state();
+    assert(JIT_R0 == jit_r(0));
+    (void)jit_callee_save_p(JIT_R0);
+    assert(JIT_R1 == jit_r(1));
+    (void)jit_callee_save_p(JIT_R1);
+    assert(JIT_R2 == jit_r(2));
+    (void)jit_callee_save_p(JIT_R2);
+#if defined(JIT_R3)
+    assert(JIT_R3 == jit_r(3));
+    (void)jit_callee_save_p(JIT_R3);
+#  if defined(JIT_R4)
+    assert(JIT_R4 == jit_r(4));
+    (void)jit_callee_save_p(JIT_R4);
+#    if defined(JIT_R5)
+    assert(JIT_R5 == jit_r(5));
+    (void)jit_callee_save_p(JIT_R5);
+#      if defined(JIT_R6)
+    assert(JIT_R6 == jit_r(6));
+    (void)jit_callee_save_p(JIT_R6);
+#        if defined(JIT_R7)
+    assert(JIT_R7 == jit_r(7));
+    (void)jit_callee_save_p(JIT_R7);
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+    assert(JIT_V0 == jit_v(0));
+    assert(jit_callee_save_p(JIT_V0));
+    assert(JIT_V1 == jit_v(1));
+    assert(jit_callee_save_p(JIT_V1));
+    assert(JIT_V2 == jit_v(2));
+    assert(jit_callee_save_p(JIT_V2));
+#if defined(JIT_V3)
+    assert(JIT_V3 == jit_v(3));
+    assert(jit_callee_save_p(JIT_V3));
+#  if defined(JIT_V4)
+    assert(JIT_V4 == jit_v(4));
+    assert(jit_callee_save_p(JIT_V4));
+#    if defined(JIT_V5)
+    assert(JIT_V5 == jit_v(5));
+    assert(jit_callee_save_p(JIT_V5));
+#      if defined(JIT_V6)
+    assert(JIT_V6 == jit_v(6));
+    assert(jit_callee_save_p(JIT_V6));
+#        if defined(JIT_V7)
+    assert(JIT_V7 == jit_v(7));
+    assert(jit_callee_save_p(JIT_V7));
+#          if defined(JIT_V8)
+    assert(JIT_V8 == jit_v(8));
+    assert(jit_callee_save_p(JIT_V8));
+#            if defined(JIT_V9)
+    assert(JIT_V9 == jit_v(9));
+    assert(jit_callee_save_p(JIT_V9));
+#              if defined(JIT_V10)
+    assert(JIT_V10 == jit_v(10));
+    assert(jit_callee_save_p(JIT_V10));
+#                if defined(JIT_V11)
+    assert(JIT_V11 == jit_v(11));
+    assert(jit_callee_save_p(JIT_V11));
+#                  if defined(JIT_V12)
+    assert(JIT_V12 == jit_v(12));
+    assert(jit_callee_save_p(JIT_V12));
+#                    if defined(JIT_V13)
+    assert(JIT_V13 == jit_v(13));
+    assert(jit_callee_save_p(JIT_V13));
+#                      if defined(JIT_V14)
+    assert(JIT_V14 == jit_v(14));
+    assert(jit_callee_save_p(JIT_V14));
+#                        if defined(JIT_V15)
+    assert(JIT_V15 == jit_v(15));
+    assert(jit_callee_save_p(JIT_V15));
+#                          if defined(JIT_V16)
+    assert(JIT_V16 == jit_v(16));
+    assert(jit_callee_save_p(JIT_V16));
+#                          endif
+#                        endif
+#                      endif
+#                    endif
+#                  endif
+#                endif
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+    assert(JIT_F0 == jit_f(0));
+    (void)jit_callee_save_p(JIT_F0);
+    assert(JIT_F1 == jit_f(1));
+    (void)jit_callee_save_p(JIT_F1);
+    assert(JIT_F2 == jit_f(2));
+    (void)jit_callee_save_p(JIT_F2);
+    assert(JIT_F3 == jit_f(3));
+    (void)jit_callee_save_p(JIT_F3);
+    assert(JIT_F4 == jit_f(4));
+    (void)jit_callee_save_p(JIT_F4);
+    assert(JIT_F5 == jit_f(5));
+    (void)jit_callee_save_p(JIT_F5);
+#if defined(JIT_F6)
+    assert(JIT_F6 == jit_f(6));
+    (void)jit_callee_save_p(JIT_F6);
+#  if defined(JIT_F7)
+    assert(JIT_F7 == jit_f(7));
+    (void)jit_callee_save_p(JIT_F7);
+#    if defined(JIT_F8)
+    assert(JIT_F8 == jit_f(8));
+    (void)jit_callee_save_p(JIT_F8);
+#      if defined(JIT_F9)
+    assert(JIT_F9 == jit_f(9));
+    (void)jit_callee_save_p(JIT_F9);
+#      endif
+#    endif
+#  endif
+#endif
+
+    jit_clear_state();
+    jit_destroy_state();
+    finish_jit();
+
+    return (0);
+}
diff --git a/deps/lightning/check/setcode.c b/deps/lightning/check/setcode.c
new file mode 100644 (file)
index 0000000..0047f34
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Simple test of using an alternate buffer for the code.
+ */
+
+#include <lightning.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/mman.h>
+#if defined(__sgi)
+#  include <fcntl.h>
+#endif
+
+#ifndef MAP_ANON
+#  define MAP_ANON                     MAP_ANONYMOUS
+#  ifndef MAP_ANONYMOUS
+#    define MAP_ANONYMOUS              0
+#  endif
+#endif
+
+#if !defined(__sgi)
+#define  mmap_fd                       -1
+#endif
+
+int
+main(int argc, char *argv[])
+{
+    jit_uint8_t                 *ptr;
+    jit_state_t                 *_jit;
+    jit_word_t           length;
+#if defined(__sgi)
+    int                          mmap_fd;
+#endif
+    void               (*function)(void);
+
+#if defined(__sgi)
+    mmap_fd = open("/dev/zero", O_RDWR);
+#endif
+
+    ptr = mmap(NULL, 1024 * 1024,
+              PROT_EXEC | PROT_READ | PROT_WRITE,
+              MAP_PRIVATE | MAP_ANON, mmap_fd, 0);
+    assert(ptr != MAP_FAILED);
+#if defined(__sgi)
+    close(mmap_fd);
+#endif
+
+    init_jit(argv[0]);
+    _jit = jit_new_state();
+
+    jit_prolog();
+    jit_prepare();
+    jit_pushargi((jit_word_t)"%s\n");
+    jit_ellipsis();
+    jit_pushargi((jit_word_t)"ok");
+    jit_finishi(printf);
+
+    /* call to jit_realize() is only required when using an alternate
+     * code buffer. Note that not using mmap'ed memory may not work
+     * on several ports and/or operating system versions */
+    jit_realize();
+
+    length = 0;
+    if (jit_get_code(&length) != NULL)
+       abort();
+
+    if (length <= 4)
+       abort();
+
+    /* check that a too small buffer fails */
+    jit_set_code(ptr, 4);
+    function = jit_emit();
+    if (function != NULL)
+       abort();
+
+    /* and calling again with enough space works */
+    jit_set_code(ptr, 1024 * 1024);
+    function = jit_emit();
+    if (function == NULL)
+       abort();
+
+    jit_clear_state();
+    (*function)();
+    jit_destroy_state();
+    finish_jit();
+
+    munmap(ptr, 1024 * 1024);
+
+    return (0);
+}
diff --git a/deps/lightning/check/stack.ok b/deps/lightning/check/stack.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/stack.tst b/deps/lightning/check/stack.tst
new file mode 100644 (file)
index 0000000..e699719
--- /dev/null
@@ -0,0 +1,358 @@
+#define szof_c                 1
+#define szof_uc                        szof_c
+#define szof_s                 2
+#define szof_us                        szof_s
+#define szof_i                 4
+#if __WORDSIZE == 64
+#  define szof_ui              szof_i
+#  define szof_l               8
+#endif
+#define szof_f                 4
+#define szof_d                 8
+
+#define FILL(T)                                                        \
+       name fill##T                                            \
+fill##T:                                                       \
+       prolog                                                  \
+       arg $argp                                               \
+       getarg %v0 $argp                                        \
+       arg $argi                                               \
+       getarg %r0 $argi                                        \
+       muli %r0 %r0 szof##T                                    \
+       addr %v1 %v0 %r0                                        \
+       movi %r0 0                                              \
+fill##T##loop:                                                 \
+       bger fill##T##done %v0 %v1                              \
+       str##T %v0 %r0                                          \
+       addi %r0 %r0 1                                          \
+       addi %v0 %v0 szof##T                                    \
+       jmpi fill##T##loop                                      \
+fill##T##done:                                                 \
+       ret                                                     \
+       epilog
+#define FILLF(T)                                               \
+       name fill##T                                            \
+fill##T:                                                       \
+       prolog                                                  \
+       arg $argp                                               \
+       getarg %v0 $argp                                        \
+       arg $argi                                               \
+       getarg %r0 $argi                                        \
+       muli %r0 %r0 szof##T                                    \
+       addr %v1 %v0 %r0                                        \
+       movi##T %f0 0.0                                         \
+fill##T##loop:                                                 \
+       bger fill##T##done %v0 %v1                              \
+       str##T %v0 %f0                                          \
+       addi##T %f0 %f0 1.0                                     \
+       addi %v0 %v0 szof##T                                    \
+       jmpi fill##T##loop                                      \
+fill##T##done:                                                 \
+       ret                                                     \
+       epilog
+
+#define fill_uc                fill_c
+#define fill_us                fill_s
+#define fill_ui                fill_i
+
+#define ARG(  T, N)                    arg    $arg##T##N
+#define ARGF( T, N)                    arg##T $arg##T##N
+#define ARG1( K, T)                    ARG##K(T, 0)
+#define ARG2( K, T)    ARG1( K, T)     ARG##K(T, 1)
+#define ARG3( K, T)    ARG2( K, T)     ARG##K(T, 2)
+#define ARG4( K, T)    ARG3( K, T)     ARG##K(T, 3)
+#define ARG5( K, T)    ARG4( K, T)     ARG##K(T, 4)
+#define ARG6( K, T)    ARG5( K, T)     ARG##K(T, 5)
+#define ARG7( K, T)    ARG6( K, T)     ARG##K(T, 6)
+#define ARG8( K, T)    ARG7( K, T)     ARG##K(T, 7)
+#define ARG9( K, T)    ARG8( K, T)     ARG##K(T, 8)
+#define ARG10(K, T)    ARG9( K, T)     ARG##K(T, 9)
+#define ARG11(K, T)    ARG10(K, T)     ARG##K(T, 10)
+#define ARG12(K, T)    ARG11(K, T)     ARG##K(T, 11)
+#define ARG13(K, T)    ARG12(K, T)     ARG##K(T, 12)
+#define ARG14(K, T)    ARG13(K, T)     ARG##K(T, 13)
+#define ARG15(K, T)    ARG14(K, T)     ARG##K(T, 14)
+#define ARG16(K, T)    ARG15(K, T)     ARG##K(T, 15)
+#define ARG_c(N)                       ARG##N( , _c)
+#define ARG_uc(N)                      ARG##N( , _uc)
+#define ARG_s(N)                       ARG##N( , _s)
+#define ARG_us(N)                      ARG##N( , _us)
+#define ARG_i(N)                       ARG##N( , _i)
+#define ARG_ui(N)                      ARG##N( , _ui)
+#define ARG_l(N)                       ARG##N( , _l)
+#define ARG_f(N)                       ARG##N(F, _f)
+#define ARG_d(N)                       ARG##N(F, _d)
+
+#define CHK(N, T, V)                                           \
+       getarg %r0 $arg##T##V                                   \
+       ldxi##T %r1 %v0 $(V * szof##T)                          \
+       beqr N##T##V %r0 %r1                                    \
+       calli @abort                                            \
+N##T##V:
+#define CHKF(N, T, V)                                          \
+       getarg##T %f0 $arg##T##V                                \
+       ldxi##T %f1 %v0 $(V * szof##T)                          \
+       beqr##T N##T##V %f0 %f1                                 \
+       calli @abort                                            \
+N##T##V:
+
+#define GET1( K, N, T, V)                              CHK##K(N, T, 0)
+#define GET2( K, N, T, V)      GET1( K, N, T, V)       CHK##K(N, T, 1)
+#define GET3( K, N, T, V)      GET2( K, N, T, V)       CHK##K(N, T, 2)
+#define GET4( K, N, T, V)      GET3( K, N, T, V)       CHK##K(N, T, 3)
+#define GET5( K, N, T, V)      GET4( K, N, T, V)       CHK##K(N, T, 4)
+#define GET6( K, N, T, V)      GET5( K, N, T, V)       CHK##K(N, T, 5)
+#define GET7( K, N, T, V)      GET6( K, N, T, V)       CHK##K(N, T, 6)
+#define GET8( K, N, T, V)      GET7( K, N, T, V)       CHK##K(N, T, 7)
+#define GET9( K, N, T, V)      GET8( K, N, T, V)       CHK##K(N, T, 8)
+#define GET10(K, N, T, V)      GET9( K, N, T, V)       CHK##K(N, T, 9)
+#define GET11(K, N, T, V)      GET10(K, N, T, V)       CHK##K(N, T, 10)
+#define GET12(K, N, T, V)      GET11(K, N, T, V)       CHK##K(N, T, 11)
+#define GET13(K, N, T, V)      GET12(K, N, T, V)       CHK##K(N, T, 12)
+#define GET14(K, N, T, V)      GET13(K, N, T, V)       CHK##K(N, T, 13)
+#define GET15(K, N, T, V)      GET14(K, N, T, V)       CHK##K(N, T, 14)
+#define GET16(K, N, T, V)      GET15(K, N, T, V)       CHK##K(N, T, 15)
+
+#define GET_c(N, M)            GET##N( , c##N,  _c,  M)
+#define GET_uc(N, M)           GET##N( , uc##N, _uc, M)
+#define GET_s(N, M)            GET##N( , s##N,  _s,  M)
+#define GET_us(N, M)           GET##N( , us##N, _us, M)
+#define GET_i(N, M)            GET##N( , i##N,  _i,  M)
+#define GET_ui(N, M)           GET##N( , ui##N, _ui, M)
+#define GET_l(N, M)            GET##N( , l##N,  _l,  M)
+#define GET_f(N, M)            GET##N(F, f##N,  _f,  M)
+#define GET_d(N, M)            GET##N(F, d##N,  _d,  M)
+
+#define PUSH(  T, V)           pushargi    V
+#define PUSHF( T, V)           pushargi##T V
+#define PUSH0( K, T)           /**/
+#define PUSH1( K, T)                                   PUSH##K(T, 0)
+#define PUSH2( K, T)           PUSH1( K, T)            PUSH##K(T, 1)
+#define PUSH3( K, T)           PUSH2( K, T)            PUSH##K(T, 2)
+#define PUSH4( K, T)           PUSH3( K, T)            PUSH##K(T, 3)
+#define PUSH5( K, T)           PUSH4( K, T)            PUSH##K(T, 4)
+#define PUSH6( K, T)           PUSH5( K, T)            PUSH##K(T, 5)
+#define PUSH7( K, T)           PUSH6( K, T)            PUSH##K(T, 6)
+#define PUSH8( K, T)           PUSH7( K, T)            PUSH##K(T, 7)
+#define PUSH9( K, T)           PUSH8( K, T)            PUSH##K(T, 8)
+#define PUSH10(K, T)           PUSH9( K, T)            PUSH##K(T, 9)
+#define PUSH11(K, T)           PUSH10(K, T)            PUSH##K(T, 10)
+#define PUSH12(K, T)           PUSH11(K, T)            PUSH##K(T, 11)
+#define PUSH13(K, T)           PUSH12(K, T)            PUSH##K(T, 12)
+#define PUSH14(K, T)           PUSH13(K, T)            PUSH##K(T, 13)
+#define PUSH15(K, T)           PUSH14(K, T)            PUSH##K(T, 14)
+#define PUSH16(K, T)           PUSH15(K, T)            PUSH##K(T, 15)
+
+#define PUSH_c( N)             PUSH##N( , _c)
+#define PUSH_uc(N)             PUSH##N( , _uc)
+#define PUSH_s( N)             PUSH##N( , _s)
+#define PUSH_us(N)             PUSH##N( , _us)
+#define PUSH_i( N)             PUSH##N( , _i)
+#define PUSH_ui(N)             PUSH##N( , _ui)
+#define PUSH_l( N)             PUSH##N( , _l)
+#define PUSH_f( N)             PUSH##N(F, _f)
+#define PUSH_d( N)             PUSH##N(F, _d)
+
+/* bottom function */
+#define DEF0(T)                                                        \
+       name test##T##_0                                        \
+test##T##_0:                                                   \
+       prolog                                                  \
+       ret                                                     \
+       epilog
+
+#define DEFN(N, M, T)                                          \
+       name test##T##_##N                                      \
+test##T##_##N:                                                 \
+       prolog                                                  \
+       arg $argp                                               \
+       /* stack buffer in %v0 */                               \
+       getarg %v0 $argp                                        \
+       ARG##T(N)                                               \
+       /* validate arguments */                                \
+       GET##T(N, M)                                            \
+       /* heap buffer in %v1 */                                \
+       prepare                                                 \
+               pushargi $(N * szof##T)                         \
+       finishi @malloc                                         \
+       retval %v1                                              \
+       /* copy stack bufer to heap buffer */                   \
+       prepare                                                 \
+               pushargr %v1                                    \
+               pushargr %v0                                    \
+               pushargi $(N * szof##T)                         \
+       finishi MEMCPY                                          \
+       /* stack buffer for next function in %v2 */             \
+       allocai $(M * szof##T) $index                           \
+       addi %v2 %fp $index                                     \
+       /* fill stack buffer for next function */               \
+       prepare                                                 \
+               pushargr %v2                                    \
+               pushargi M                                      \
+       finishi fill##T                                         \
+       /* call next function */                                \
+       prepare                                                 \
+               pushargr %v2                                    \
+               PUSH##T(M)                                      \
+       finishi test##T##_##M                                   \
+       /* validate stack buffer */                             \
+       prepare                                                 \
+               pushargr %v1                                    \
+               pushargr %v0                                    \
+               pushargi $(N * szof##T)                         \
+       finishi @memcmp                                         \
+       retval %r0                                              \
+       beqi test##T##_##N##_done %r0 0                         \
+       calli @abort                                            \
+test##T##_##N##_done:                                          \
+       /* release heap bufer */                                \
+       prepare                                                 \
+               pushargr %v1                                    \
+       finishi @free                                           \
+       ret                                                     \
+       epilog
+
+/* top function */
+#define DEFX(T)                                                        \
+       name test##T##_17                                       \
+test##T##_17:                                                  \
+       prolog                                                  \
+       /* heap buffer in %v1 */                                \
+       prepare                                                 \
+               pushargi $(16 * szof##T)                        \
+       finishi @malloc                                         \
+       retval %v1                                              \
+       /* stack buffer for next function in %v2 */             \
+       allocai $(16 * szof##T) $index                          \
+       addi %v2 %fp $index                                     \
+       /* fill stack buffer for next function */               \
+       prepare                                                 \
+               pushargr %v2                                    \
+               pushargi 16                                     \
+       finishi fill##T                                         \
+       /* copy stack buffer to heap buffer */                  \
+       prepare                                                 \
+               pushargr %v1                                    \
+               pushargr %v2                                    \
+               pushargi $(16 * szof##T)                        \
+       finishi MEMCPY                                          \
+       /* call next function */                                \
+       prepare                                                 \
+               pushargr %v2                                    \
+               PUSH##T(16)                                     \
+       finishi test##T##_16                                    \
+       /* validate stack buffer */                             \
+       prepare                                                 \
+               pushargr %v1                                    \
+               pushargr %v2                                    \
+               pushargi $(16 * szof##T)                        \
+       finishi @memcmp                                         \
+       retval %r0                                              \
+       beqi test##T##_17_done %r0 0                            \
+       calli @abort                                            \
+test##T##_17_done:                                             \
+       /* release heap bufer */                                \
+       prepare                                                 \
+               pushargr %v1                                    \
+       finishi @free                                           \
+       ret                                                     \
+       epilog
+
+#define DEF(  T)                                               \
+       DEF0( T)                                                \
+       DEFN( 1,  0, T)                                         \
+       DEFN( 2,  1, T)                                         \
+       DEFN( 3,  2, T)                                         \
+       DEFN( 4,  3, T)                                         \
+       DEFN( 5,  4, T)                                         \
+       DEFN( 6,  5, T)                                         \
+       DEFN( 7,  6, T)                                         \
+       DEFN( 8,  7, T)                                         \
+       DEFN( 9,  8, T)                                         \
+       DEFN(10,  9, T)                                         \
+       DEFN(11, 10, T)                                         \
+       DEFN(12, 11, T)                                         \
+       DEFN(13, 12, T)                                         \
+       DEFN(14, 13, T)                                         \
+       DEFN(15, 14, T)                                         \
+       DEFN(16, 15, T)                                         \
+       DEFX(T)
+
+#define CALL(T)                        calli test##T##_17
+
+.data  16
+ok:
+.c     "ok\n"
+.code
+       jmpi main
+
+#if _AIX
+#  define MEMCPY               memcpy
+/* error: Function not implemented (memcpy) */
+       name memcpy
+memcpy:
+       prolog
+       arg $dst
+       arg $src
+       arg $len
+       getarg %r0 $dst
+       getarg %r1 $src
+       getarg %r2 $len
+       movr %v1 %r0
+       blti memcpy_done %r2 1
+memcpy_loop:
+       subi %r2 %r2 1
+       ldxr_c %v0 %r1 %r2
+       stxr_c %r2 %r0 %v0
+       bgti memcpy_loop %r2 0
+memcpy_done:
+       retr %v1
+       epilog
+#else
+#  define MEMCPY               @memcpy
+#endif
+
+       FILL(_c)
+       FILL(_s)
+       FILL(_i)
+#if __WORDSIZE == 64
+       FILL(_l)
+#endif
+       FILLF(_f)
+       FILLF(_d)
+
+       DEF(_c)
+       DEF(_uc)
+       DEF(_s)
+       DEF(_us)
+       DEF(_i)
+#if __WORDSIZE == 64
+       DEF(_ui)
+       DEF(_l)
+#endif
+       DEF(_f)
+       DEF(_d)
+
+       name main
+main:
+       prolog
+
+       CALL(_c)
+       CALL(_uc)
+       CALL(_s)
+       CALL(_us)
+       CALL(_i)
+#if __WORDSIZE == 64
+       CALL(_ui)
+       CALL(_l)
+#endif
+       CALL(_f)
+       CALL(_d)
+
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+
+       ret
+       epilog
diff --git a/deps/lightning/check/tramp.ok b/deps/lightning/check/tramp.ok
new file mode 100644 (file)
index 0000000..6adb29f
--- /dev/null
@@ -0,0 +1 @@
+xfibs(32) = 7049155
diff --git a/deps/lightning/check/tramp.tst b/deps/lightning/check/tramp.tst
new file mode 100644 (file)
index 0000000..faf63d2
--- /dev/null
@@ -0,0 +1,111 @@
+#if __WORDSIZE == 32
+#  define SIZE 4
+#else
+#  define SIZE 8
+#endif
+.data  8192
+fmt:
+.c     "xfibs(%d) = %d\n"
+/* Simulate a language specific stack */
+.align SIZE
+top:
+/* Top, or base of the stack */
+.size  SIZE
+stk:
+.size  8160
+
+.code
+       jmpi main
+
+/* Usually a trampoline is created before the code that uses it, but
+ * for testing purposes it is not required.
+ * In this test case, it would mean "main" would be converted in a
+ * different jit_state_t to native code, before xfibs was know.
+ */
+       name xfibs
+xfibs:
+       /* return address is in %r0 */
+       /* argument and return value in %v0 */
+       prolog
+       tramp 64
+       blti_u out %v0 2
+       subi %v1 %v0 1          /* V1 = N-1 */
+       subi %v2 %v0 2          /* V1 = N-2 */
+
+       /* save return address */
+       ldi %r1 top
+       stxi $(SIZE * 0) %r1 %r0
+       /* save operands */
+       stxi $(SIZE * 1) %r1 %v0
+       stxi $(SIZE * 2) %r1 %v1
+       stxi $(SIZE * 3) %r1 %v2
+       /* adjust "language" stack */
+       addi %r1 %r1 $(SIZE * 4)
+       sti top %r1
+
+       /* return address */
+       movi %r0 ret1
+       /* argument */
+       movr %v0 %v1
+       /* indirect goto */
+       jmpi xfibs
+ret1:
+       movr %v1 %v0            /* V1 = rfibs(N-1) */
+       /* save V1 */
+       ldi %r1 top
+       stxi $(-SIZE * 2) %r1 %v1
+
+       /* reload V2 */
+       ldxi %v2 %r1 $(-SIZE * 1)
+
+       /* return address */
+       movi %r0 ret2
+       /* argument */
+       movr %v0 %v2
+       /* indirect goto */
+       jmpi xfibs
+ret2:
+       movr %v2 %v0            /* V2 = rfibs(N-2) */
+
+       /* reload return address */
+       ldi %r1 top
+       subi %r1 %r1 $(SIZE * 4)
+       ldxi %r0 %r1 $(SIZE * 0)
+       /* reload operands */
+       ldxi %v0 %r1 $(SIZE * 1)
+       ldxi %v1 %r1 $(SIZE * 2)
+       /* V2 already loaded */
+       /* update "language" stack */
+       sti top %r1
+
+       addi %v1 %v1 1
+       addr %v0 %v1 %v2
+       jmpr %r0
+out:
+       movi %v0 1
+       jmpr %r0
+       epilog
+
+       name main
+main:
+       prolog
+       frame 64
+
+       /* Initialize language stack */
+       movi %r0 stk
+       sti top %r0
+
+       /* return address */
+       movi %r0 done
+       /* argument */
+       movi %v0 32
+       jmpi xfibs
+done:
+       prepare
+               pushargi fmt
+               ellipsis
+               pushargi 32
+               pushargr %v0
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/va_list.ok b/deps/lightning/check/va_list.ok
new file mode 100644 (file)
index 0000000..9766475
--- /dev/null
@@ -0,0 +1 @@
+ok
diff --git a/deps/lightning/check/va_list.tst b/deps/lightning/check/va_list.tst
new file mode 100644 (file)
index 0000000..ad704c9
--- /dev/null
@@ -0,0 +1,743 @@
+.data  8
+ok:
+.c     "ok\n"
+.code
+       jmpi main
+
+#define BEGIN(L)                                               \
+L:                                                             \
+       prolog
+#define VA_START()                                             \
+       ellipsis                                                \
+       va_start %v0
+#define VARG(L,N)                                              \
+       va_arg %r0 %v0                                          \
+       beqi L##N %r0 N                                         \
+       calli @abort                                            \
+L##N:
+#define VARGD(L,N)                                             \
+       va_arg_d %f0 %v0                                        \
+       beqi_d L##N %f0 N                                       \
+       calli @abort                                            \
+L##N:
+#define VA_END()                                               \
+       va_end %v0                                              \
+       ret                                                     \
+       epilog
+#define ARG(N)                 arg $arg##N
+#define ARGD(N)                        arg_d $arg##N
+#define GET(L,N)                                               \
+       getarg %r0 $arg##N                                      \
+       beqi L##N %r0 N                                         \
+       calli @abort                                            \
+L##N:
+#define GETD(L,N)                                              \
+       getarg_d %f0 $arg##N                                    \
+       beqi_d L##N %f0 N                                       \
+       calli @abort                                            \
+L##N:
+
+#define ARG1()                         ARG(1)
+#define ARG2()         ARG1()          ARG(2)
+#define ARG3()         ARG2()          ARG(3)
+#define ARG4()         ARG3()          ARG(4)
+#define ARG5()         ARG4()          ARG(5)
+#define ARG6()         ARG5()          ARG(6)
+#define ARG7()         ARG6()          ARG(7)
+#define ARG8()         ARG7()          ARG(8)
+#define ARG9()         ARG8()          ARG(9)
+#define GET1(L)                                GET(L,1)
+#define GET2(L)                GET1(L)         GET(L,2)
+#define GET3(L)                GET2(L)         GET(L,3)
+#define GET4(L)                GET3(L)         GET(L,4)
+#define GET5(L)                GET4(L)         GET(L,5)
+#define GET6(L)                GET5(L)         GET(L,6)
+#define GET7(L)                GET6(L)         GET(L,7)
+#define GET8(L)                GET7(L)         GET(L,8)
+#define GET9(L)                GET8(L)         GET(L,9)
+#define ARGD1()                                ARGD(1)
+#define ARGD2()                ARGD1()         ARGD(2)
+#define ARGD3()                ARGD2()         ARGD(3)
+#define ARGD4()                ARGD3()         ARGD(4)
+#define ARGD5()                ARGD4()         ARGD(5)
+#define ARGD6()                ARGD5()         ARGD(6)
+#define ARGD7()                ARGD6()         ARGD(7)
+#define ARGD8()                ARGD7()         ARGD(8)
+#define ARGD9()                ARGD8()         ARGD(9)
+#define GETD1(L)                       GETD(L,1)
+#define GETD2(L)       GETD1(L)        GETD(L,2)
+#define GETD3(L)       GETD2(L)        GETD(L,3)
+#define GETD4(L)       GETD3(L)        GETD(L,4)
+#define GETD5(L)       GETD4(L)        GETD(L,5)
+#define GETD6(L)       GETD5(L)        GETD(L,6)
+#define GETD7(L)       GETD6(L)        GETD(L,7)
+#define GETD8(L)       GETD7(L)        GETD(L,8)
+#define GETD9(L)       GETD8(L)        GETD(L,9)
+#define IDARG1()                       ARG(1)
+#define IDARG2()       IDARG1()        ARGD(2)
+#define IDARG3()       IDARG2()        ARG(3)
+#define IDARG4()       IDARG3()        ARGD(4)
+#define IDARG5()       IDARG4()        ARG(5)
+#define IDARG6()       IDARG5()        ARGD(6)
+#define IDARG7()       IDARG6()        ARG(7)
+#define IDARG8()       IDARG7()        ARGD(8)
+#define IDARG9()       IDARG8()        ARG(9)
+#define IDGET1(L)                      GET(L,1)
+#define IDGET2(L)      IDGET1(L)       GETD(L,2)
+#define IDGET3(L)      IDGET2(L)       GET(L,3)
+#define IDGET4(L)      IDGET3(L)       GETD(L,4)
+#define IDGET5(L)      IDGET4(L)       GET(L,5)
+#define IDGET6(L)      IDGET5(L)       GETD(L,6)
+#define IDGET7(L)      IDGET6(L)       GET(L,7)
+#define IDGET8(L)      IDGET7(L)       GETD(L,8)
+#define IDGET9(L)      IDGET8(L)       GET(L,9)
+#define DIARG1()                       ARGD(1)
+#define DIARG2()       DIARG1()        ARG(2)
+#define DIARG3()       DIARG2()        ARGD(3)
+#define DIARG4()       DIARG3()        ARG(4)
+#define DIARG5()       DIARG4()        ARGD(5)
+#define DIARG6()       DIARG5()        ARG(6)
+#define DIARG7()       DIARG6()        ARGD(7)
+#define DIARG8()       DIARG7()        ARG(8)
+#define DIARG9()       DIARG8()        ARGD(9)
+#define DIGET1(L)                      GETD(L,1)
+#define DIGET2(L)      DIGET1(L)       GET(L,2)
+#define DIGET3(L)      DIGET2(L)       GETD(L,3)
+#define DIGET4(L)      DIGET3(L)       GET(L,4)
+#define DIGET5(L)      DIGET4(L)       GETD(L,5)
+#define DIGET6(L)      DIGET5(L)       GET(L,6)
+#define DIGET7(L)      DIGET6(L)       GETD(L,7)
+#define DIGET8(L)      DIGET7(L)       GET(L,8)
+#define DIGET9(L)      DIGET8(L)       GETD(L,9)
+
+#define VARG1(L)                                               \
+       VARG(L, 10)
+#define VARG2(L)                                               \
+       VARG(L, 9)                                              \
+       VARG1(L)
+#define VARG3(L)                                               \
+       VARG(L, 8)                                              \
+       VARG2(L)
+#define VARG4(L)                                               \
+       VARG(L, 7)                                              \
+       VARG3(L)
+#define VARG5(L)                                               \
+       VARG(L, 6)                                              \
+       VARG4(L)
+#define VARG6(L)                                               \
+       VARG(L, 5)                                              \
+       VARG5(L)
+#define VARG7(L)                                               \
+       VARG(L, 4)                                              \
+       VARG6(L)
+#define VARG8(L)                                               \
+       VARG(L, 3)                                              \
+       VARG7(L)
+#define VARG9(L)                                               \
+       VARG(L, 2)                                              \
+       VARG8(L)
+#define VARG10(L)                                              \
+       VARG(L, 1)                                              \
+       VARG9(L)
+#define VARGD1(L)                                              \
+       VARGD(L, 10)
+#define VARGD2(L)                                              \
+       VARGD(L, 9)                                             \
+       VARGD1(L)
+#define VARGD3(L)                                              \
+       VARGD(L, 8)                                             \
+       VARGD2(L)
+#define VARGD4(L)                                              \
+       VARGD(L, 7)                                             \
+       VARGD3(L)
+#define VARGD5(L)                                              \
+       VARGD(L, 6)                                             \
+       VARGD4(L)
+#define VARGD6(L)                                              \
+       VARGD(L, 5)                                             \
+       VARGD5(L)
+#define VARGD7(L)                                              \
+       VARGD(L, 4)                                             \
+       VARGD6(L)
+#define VARGD8(L)                                              \
+       VARGD(L, 3)                                             \
+       VARGD7(L)
+#define VARGD9(L)                                              \
+       VARGD(L, 2)                                             \
+       VARGD8(L)
+#define VARGD10(L)                                             \
+       VARGD(L, 1)                                             \
+       VARGD9(L)
+#define IDVARG1(L)                                             \
+       VARGD(L, 10)
+#define IDVARG2(L)                                             \
+       VARG(L, 9)                                              \
+       IDVARG1(L)
+#define IDVARG3(L)                                             \
+       VARGD(L, 8)                                             \
+       IDVARG2(L)
+#define IDVARG4(L)                                             \
+       VARG(L, 7)                                              \
+       IDVARG3(L)
+#define IDVARG5(L)                                             \
+       VARGD(L, 6)                                             \
+       IDVARG4(L)
+#define IDVARG6(L)                                             \
+       VARG(L, 5)                                              \
+       IDVARG5(L)
+#define IDVARG7(L)                                             \
+       VARGD(L, 4)                                             \
+       IDVARG6(L)
+#define IDVARG8(L)                                             \
+       VARG(L, 3)                                              \
+       IDVARG7(L)
+#define IDVARG9(L)                                             \
+       VARGD(L, 2)                                             \
+       IDVARG8(L)
+#define IDVARG10(L)                                            \
+       VARG(L, 1)                                              \
+       IDVARG9(L)
+#define DIVARG1(L)                                             \
+       VARG(L, 10)
+#define DIVARG2(L)                                             \
+       VARGD(L, 9)                                             \
+       DIVARG1(L)
+#define DIVARG3(L)                                             \
+       VARG(L, 8)                                              \
+       DIVARG2(L)
+#define DIVARG4(L)                                             \
+       VARGD(L, 7)                                             \
+       DIVARG3(L)
+#define DIVARG5(L)                                             \
+       VARG(L, 6)                                              \
+       DIVARG4(L)
+#define DIVARG6(L)                                             \
+       VARGD(L, 5)                                             \
+       DIVARG5(L)
+#define DIVARG7(L)                                             \
+       VARG(L, 4)                                              \
+       DIVARG6(L)
+#define DIVARG8(L)                                             \
+       VARGD(L, 3)                                             \
+       DIVARG7(L)
+#define DIVARG9(L)                                             \
+       VARG(L, 2)                                              \
+       DIVARG8(L)
+#define DIVARG10(L)                                            \
+       VARGD(L, 1)                                             \
+       DIVARG9(L)
+
+BEGIN(_iiiiiiiiii)
+       VA_START()
+       VARG10(_iiiiiiiiii)
+       VA_END()
+BEGIN(i_iiiiiiiii)
+       ARG1()
+       GET1(i_iiiiiiiii)
+       VA_START()
+       VARG9(i_iiiiiiiii)
+       VA_END()
+BEGIN(ii_iiiiiiii)
+       ARG2()
+       GET2(ii_iiiiiiii)
+       VA_START()
+       VARG8(ii_iiiiiiii)
+       VA_END()
+BEGIN(iii_iiiiiii)
+       ARG3()
+       GET3(iii_iiiiiii)
+       VA_START()
+       VARG7(iii_iiiiiii)
+       VA_END()
+BEGIN(iiii_iiiiii)
+       ARG4()
+       GET4(iiii_iiiiii)
+       VA_START()
+       VARG6(iiii_iiiiii)
+       VA_END()
+BEGIN(iiiii_iiiii)
+       ARG5()
+       GET5(iiiii_iiiii)
+       VA_START()
+       VARG5(iiiii_iiiii)
+       VA_END()
+BEGIN(iiiiii_iiii)
+       ARG6()
+       GET6(iiiiii_iiii)
+       VA_START()
+       VARG4(iiiiii_iiii)
+       VA_END()
+BEGIN(iiiiiii_iii)
+       ARG7()
+       GET7(iiiiiii_iii)
+       VA_START()
+       VARG3(iiiiiii_iii)
+       VA_END()
+BEGIN(iiiiiiii_ii)
+       ARG8()
+       GET8(iiiiiiii_ii)
+       VA_START()
+       VARG2(iiiiiiii_ii)
+       VA_END()
+BEGIN(iiiiiiiii_i)
+       ARG9()
+       GET9(iiiiiiiii_i)
+       VA_START()
+       VARG1(iiiiiiiii_i)
+       VA_END()
+BEGIN(_dddddddddd)
+       VA_START()
+       VARGD10(_dddddddddd)
+       VA_END()
+BEGIN(d_ddddddddd)
+       ARGD1()
+       GETD1(d_ddddddddd)
+       VA_START()
+       VARGD9(d_ddddddddd)
+       VA_END()
+BEGIN(dd_dddddddd)
+       ARGD2()
+       GETD2(dd_dddddddd)
+       VA_START()
+       VARGD8(dd_dddddddd)
+       VA_END()
+BEGIN(ddd_ddddddd)
+       ARGD3()
+       GETD3(ddd_ddddddd)
+       VA_START()
+       VARGD7(ddd_ddddddd)
+       VA_END()
+BEGIN(dddd_dddddd)
+       ARGD4()
+       GETD4(dddd_dddddd)
+       VA_START()
+       VARGD6(dddd_dddddd)
+       VA_END()
+BEGIN(ddddd_ddddd)
+       ARGD5()
+       GETD5(ddddd_ddddd)
+       VA_START()
+       VARGD5(ddddd_ddddd)
+       VA_END()
+BEGIN(dddddd_dddd)
+       ARGD6()
+       GETD6(dddddd_dddd)
+       VA_START()
+       VARGD4(dddddd_dddd)
+       VA_END()
+BEGIN(ddddddd_ddd)
+       ARGD7()
+       GETD7(ddddddd_ddd)
+       VA_START()
+       VARGD3(ddddddd_ddd)
+       VA_END()
+BEGIN(dddddddd_dd)
+       ARGD8()
+       GETD8(dddddddd_dd)
+       VA_START()
+       VARGD2(dddddddd_dd)
+       VA_END()
+BEGIN(ddddddddd_d)
+       ARGD9()
+       GETD9(ddddddddd_d)
+       VA_START()
+       VARGD1(ddddddddd_d)
+       VA_END()
+BEGIN(_ididididid)
+       VA_START()
+       IDVARG10(_ididididid)
+       VA_END()
+BEGIN(i_didididid)
+       IDARG1()
+       IDGET1(i_didididid)
+       VA_START()
+       IDVARG9(i_didididid)
+       VA_END()
+BEGIN(id_idididid)
+       IDARG2()
+       IDGET2(id_idididid)
+       VA_START()
+       IDVARG8(id_idididid)
+       VA_END()
+BEGIN(idi_dididid)
+       IDARG3()
+       IDGET3(idi_dididid)
+       VA_START()
+       IDVARG7(idi_dididid)
+       VA_END()
+BEGIN(idid_ididid)
+       IDARG4()
+       IDGET4(idid_ididid)
+       VA_START()
+       IDVARG6(idid_ididid)
+       VA_END()
+BEGIN(ididi_didid)
+       IDARG5()
+       IDGET5(ididi_didid)
+       VA_START()
+       IDVARG5(ididi_didid)
+       VA_END()
+BEGIN(ididid_idid)
+       IDARG6()
+       IDGET6(ididid_idid)
+       VA_START()
+       IDVARG4(ididid_idid)
+       VA_END()
+BEGIN(idididi_did)
+       IDARG7()
+       IDGET7(idididi_did)
+       VA_START()
+       IDVARG3(idididi_did)
+       VA_END()
+BEGIN(idididid_id)
+       IDARG8()
+       IDGET8(idididid_id)
+       VA_START()
+       IDVARG2(idididid_id)
+       VA_END()
+BEGIN(ididididi_d)
+       IDARG9()
+       IDGET9(ididididi_d)
+       VA_START()
+       IDVARG1(ididididi_d)
+       VA_END()
+BEGIN(_dididididi)
+       VA_START()
+       DIVARG10(_dididididi)
+       VA_END()
+BEGIN(d_ididididi)
+       DIARG1()
+       DIGET1(d_ididididi)
+       VA_START()
+       DIVARG9(d_ididididi)
+       VA_END()
+BEGIN(di_didididi)
+       DIARG2()
+       DIGET2(di_didididi)
+       VA_START()
+       DIVARG8(di_didididi)
+       VA_END()
+BEGIN(did_idididi)
+       DIARG3()
+       DIGET3(did_idididi)
+       VA_START()
+       DIVARG7(did_idididi)
+       VA_END()
+BEGIN(didi_dididi)
+       DIARG4()
+       DIGET4(didi_dididi)
+       VA_START()
+       DIVARG6(didi_dididi)
+       VA_END()
+BEGIN(didid_ididi)
+       DIARG5()
+       DIGET5(didid_ididi)
+       VA_START()
+       DIVARG5(didid_ididi)
+       VA_END()
+BEGIN(dididi_didi)
+       DIARG6()
+       DIGET6(dididi_didi)
+       VA_START()
+       DIVARG4(dididi_didi)
+       VA_END()
+BEGIN(dididid_idi)
+       DIARG7()
+       DIGET7(dididid_idi)
+       VA_START()
+       DIVARG3(dididid_idi)
+       VA_END()
+BEGIN(didididi_di)
+       DIARG8()
+       DIGET8(didididi_di)
+       VA_START()
+       DIVARG2(didididi_di)
+       VA_END()
+BEGIN(didididid_i)
+       DIARG9()
+       DIGET9(didididid_i)
+       VA_START()
+       DIVARG1(didididid_i)
+       VA_END()
+
+#define PUSH1()                pushargi 1
+#define PUSH2()                PUSH1()         pushargi 2
+#define PUSH3()                PUSH2()         pushargi 3
+#define PUSH4()                PUSH3()         pushargi 4
+#define PUSH5()                PUSH4()         pushargi 5
+#define PUSH6()                PUSH5()         pushargi 6
+#define PUSH7()                PUSH6()         pushargi 7
+#define PUSH8()                PUSH7()         pushargi 8
+#define PUSH9()                PUSH8()         pushargi 9
+#define VPUSH1()       pushargi 1      VPUSH2()
+#define VPUSH2()       pushargi 2      VPUSH3()
+#define VPUSH3()       pushargi 3      VPUSH4()
+#define VPUSH4()       pushargi 4      VPUSH5()
+#define VPUSH5()       pushargi 5      VPUSH6()
+#define VPUSH6()       pushargi 6      VPUSH7()
+#define VPUSH7()       pushargi 7      VPUSH8()
+#define VPUSH8()       pushargi 8      VPUSH9()
+#define VPUSH9()       pushargi 9      VPUSH10()
+#define VPUSH10()      pushargi 10
+#define PUSHD1()       pushargi_d 1
+#define PUSHD2()       PUSHD1()        pushargi_d 2
+#define PUSHD3()       PUSHD2()        pushargi_d 3
+#define PUSHD4()       PUSHD3()        pushargi_d 4
+#define PUSHD5()       PUSHD4()        pushargi_d 5
+#define PUSHD6()       PUSHD5()        pushargi_d 6
+#define PUSHD7()       PUSHD6()        pushargi_d 7
+#define PUSHD8()       PUSHD7()        pushargi_d 8
+#define PUSHD9()       PUSHD8()        pushargi_d 9
+#define VPUSHD1()      pushargi_d 1    VPUSHD2()
+#define VPUSHD2()      pushargi_d 2    VPUSHD3()
+#define VPUSHD3()      pushargi_d 3    VPUSHD4()
+#define VPUSHD4()      pushargi_d 4    VPUSHD5()
+#define VPUSHD5()      pushargi_d 5    VPUSHD6()
+#define VPUSHD6()      pushargi_d 6    VPUSHD7()
+#define VPUSHD7()      pushargi_d 7    VPUSHD8()
+#define VPUSHD8()      pushargi_d 8    VPUSHD9()
+#define VPUSHD9()      pushargi_d 9    VPUSHD10()
+#define VPUSHD10()     pushargi_d 10
+#define IDPUSH1()      pushargi 1
+#define IDPUSH2()      IDPUSH1()       pushargi_d 2
+#define IDPUSH3()      IDPUSH2()       pushargi 3
+#define IDPUSH4()      IDPUSH3()       pushargi_d 4
+#define IDPUSH5()      IDPUSH4()       pushargi 5
+#define IDPUSH6()      IDPUSH5()       pushargi_d 6
+#define IDPUSH7()      IDPUSH6()       pushargi 7
+#define IDPUSH8()      IDPUSH7()       pushargi_d 8
+#define IDPUSH9()      IDPUSH8()       pushargi 9
+#define IDVPUSH1()     pushargi 1      IDVPUSH2()
+#define IDVPUSH2()     pushargi_d 2    IDVPUSH3()
+#define IDVPUSH3()     pushargi 3      IDVPUSH4()
+#define IDVPUSH4()     pushargi_d 4    IDVPUSH5()
+#define IDVPUSH5()     pushargi 5      IDVPUSH6()
+#define IDVPUSH6()     pushargi_d 6    IDVPUSH7()
+#define IDVPUSH7()     pushargi 7      IDVPUSH8()
+#define IDVPUSH8()     pushargi_d 8    IDVPUSH9()
+#define IDVPUSH9()     pushargi 9      IDVPUSH10()
+#define IDVPUSH10()    pushargi_d 10
+#define DIPUSH1()      pushargi_d 1
+#define DIPUSH2()      DIPUSH1()       pushargi 2
+#define DIPUSH3()      DIPUSH2()       pushargi_d 3
+#define DIPUSH4()      DIPUSH3()       pushargi 4
+#define DIPUSH5()      DIPUSH4()       pushargi_d 5
+#define DIPUSH6()      DIPUSH5()       pushargi 6
+#define DIPUSH7()      DIPUSH6()       pushargi_d 7
+#define DIPUSH8()      DIPUSH7()       pushargi 8
+#define DIPUSH9()      DIPUSH8()       pushargi_d 9
+#define DIVPUSH1()     pushargi_d 1    DIVPUSH2()
+#define DIVPUSH2()     pushargi 2      DIVPUSH3()
+#define DIVPUSH3()     pushargi_d 3    DIVPUSH4()
+#define DIVPUSH4()     pushargi 4      DIVPUSH5()
+#define DIVPUSH5()     pushargi_d 5    DIVPUSH6()
+#define DIVPUSH6()     pushargi 6      DIVPUSH7()
+#define DIVPUSH7()     pushargi_d 7    DIVPUSH8()
+#define DIVPUSH8()     pushargi 8      DIVPUSH9()
+#define DIVPUSH9()     pushargi_d 9    DIVPUSH10()
+#define DIVPUSH10()    pushargi 10
+
+main:
+       prolog
+       prepare
+               ellipsis
+               VPUSH1()
+       finishi _iiiiiiiiii
+       prepare
+               PUSH1()
+               ellipsis
+               VPUSH2()
+       finishi i_iiiiiiiii
+       prepare
+               PUSH2()
+               ellipsis
+               VPUSH3()
+       finishi ii_iiiiiiii
+       prepare
+               PUSH3()
+               ellipsis
+               VPUSH4()
+       finishi iii_iiiiiii
+       prepare
+               PUSH4()
+               ellipsis
+               VPUSH5()
+       finishi iiii_iiiiii
+       prepare
+               PUSH5()
+               ellipsis
+               VPUSH6()
+       finishi iiiii_iiiii
+       prepare
+               PUSH6()
+               ellipsis
+               VPUSH7()
+       finishi iiiiii_iiii
+       prepare
+               PUSH7()
+               ellipsis
+               VPUSH8()
+       finishi iiiiiii_iii
+       prepare
+               PUSH8()
+               ellipsis
+               VPUSH9()
+       finishi iiiiiiii_ii
+       prepare
+               PUSH9()
+               ellipsis
+               VPUSH10()
+       finishi iiiiiiiii_i
+       prepare
+               ellipsis
+               VPUSHD1()
+       finishi _dddddddddd
+       prepare
+               PUSHD1()
+               ellipsis
+               VPUSHD2()
+       finishi d_ddddddddd
+       prepare
+               PUSHD2()
+               ellipsis
+               VPUSHD3()
+       finishi dd_dddddddd
+       prepare
+               PUSHD3()
+               ellipsis
+               VPUSHD4()
+       finishi ddd_ddddddd
+       prepare
+               PUSHD4()
+               ellipsis
+               VPUSHD5()
+       finishi dddd_dddddd
+       prepare
+               PUSHD5()
+               ellipsis
+               VPUSHD6()
+       finishi ddddd_ddddd
+       prepare
+               PUSHD6()
+               ellipsis
+               VPUSHD7()
+       finishi dddddd_dddd
+       prepare
+               PUSHD7()
+               ellipsis
+               VPUSHD8()
+       finishi ddddddd_ddd
+       prepare
+               PUSHD8()
+               ellipsis
+               VPUSHD9()
+       finishi dddddddd_dd
+       prepare
+               PUSHD9()
+               ellipsis
+               VPUSHD10()
+       finishi ddddddddd_d
+       prepare
+               ellipsis
+               IDVPUSH1()
+       finishi _ididididid
+       prepare
+               IDPUSH1()
+               ellipsis
+               IDVPUSH2()
+       finishi i_didididid
+       prepare
+               IDPUSH2()
+               ellipsis
+               IDVPUSH3()
+       finishi id_idididid
+       prepare
+               IDPUSH3()
+               ellipsis
+               IDVPUSH4()
+       finishi idi_dididid
+       prepare
+               IDPUSH4()
+               ellipsis
+               IDVPUSH5()
+       finishi idid_ididid
+       prepare
+               IDPUSH5()
+               ellipsis
+               IDVPUSH6()
+       finishi ididi_didid
+       prepare
+               IDPUSH6()
+               ellipsis
+               IDVPUSH7()
+       finishi ididid_idid
+       prepare
+               IDPUSH7()
+               ellipsis
+               IDVPUSH8()
+       finishi idididi_did
+       prepare
+               IDPUSH8()
+               ellipsis
+               IDVPUSH9()
+       finishi idididid_id
+       prepare
+               IDPUSH9()
+               ellipsis
+               IDVPUSH10()
+       finishi ididididi_d
+       prepare
+               ellipsis
+               DIVPUSH1()
+       finishi _dididididi
+       prepare
+               DIPUSH1()
+               ellipsis
+               DIVPUSH2()
+       finishi d_ididididi
+       prepare
+               DIPUSH2()
+               ellipsis
+               DIVPUSH3()
+       finishi di_didididi
+       prepare
+               DIPUSH3()
+               ellipsis
+               DIVPUSH4()
+       finishi did_idididi
+       prepare
+               DIPUSH4()
+               ellipsis
+               DIVPUSH5()
+       finishi didi_dididi
+       prepare
+               DIPUSH5()
+               ellipsis
+               DIVPUSH6()
+       finishi didid_ididi
+       prepare
+               DIPUSH6()
+               ellipsis
+               DIVPUSH7()
+       finishi dididi_didi
+       prepare
+               DIPUSH7()
+               ellipsis
+               DIVPUSH8()
+       finishi dididid_idi
+       prepare
+               DIPUSH8()
+               ellipsis
+               DIVPUSH9()
+       finishi didididi_di
+       prepare
+               DIPUSH9()
+               ellipsis
+               DIVPUSH10()
+       finishi didididid_i
+       prepare
+               pushargi ok
+               ellipsis
+       finishi @printf
+       ret
+       epilog
diff --git a/deps/lightning/check/varargs.ok b/deps/lightning/check/varargs.ok
new file mode 100644 (file)
index 0000000..e103283
--- /dev/null
@@ -0,0 +1,4 @@
+0 1 2 3 4 5 6 7 8 9
+0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0
+0 0.0 1 1.0 2 2.0 3 3.0 4 4.0 5 5.0 6 6.0 7 7.0 8 8.0 9 9.0
+0.0 0 1.0 1 2.0 2 3.0 3 4.0 4 5.0 5 6.0 6 7.0 7 8.0 8 9.0 9
diff --git a/deps/lightning/check/varargs.tst b/deps/lightning/check/varargs.tst
new file mode 100644 (file)
index 0000000..11131d9
--- /dev/null
@@ -0,0 +1,398 @@
+.data  1024
+ifmt:
+.c     "%d %d %d %d %d %d %d %d %d %d\n"
+.align 4
+ichk:
+.i     9 8 7 6 5 4 3 2 1 0
+dfmt:
+.c     "%.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f %.1f\n"
+lfmt:
+.c     "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n"
+.align 8
+dchk:
+.d     9.0 8.0 7.0 6.0 5.0 4.0 3.0 2.0 1.0 0.0
+idfmt:
+.c     "%d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f\n"
+ldfmt:
+.c     "%d %lf %d %lf %d %lf %d %lf %d %lf %d %lf %d %lf %d %lf %d %lf %d %lf\n"
+difmt:
+.c     "%.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d %.1f %d\n"
+dlfmt:
+.c     "%lf %d %lf %d %lf %d %lf %d %lf %d %lf %d %lf %d %lf %d %lf %d %lf %d\n"
+.align 8
+buff:
+.size  256
+
+.code
+       prolog
+
+       /*
+               sprintf(buff, "%d %d %d %d %d %d %d %d %d %d\n",
+                       0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+        */
+       prepare
+               pushargi buff
+               pushargi ifmt
+               ellipsis
+               pushargi 0
+               pushargi 1
+               pushargi 2
+               pushargi 3
+               pushargi 4
+               pushargi 5
+               pushargi 6
+               pushargi 7
+               pushargi 8
+               pushargi 9
+       finishi @sprintf
+
+       /*
+               sscanf(buff, "%d %d %d %d %d %d %d %d %d %d\n",
+                      ichk+0, ichk+1, ichk+2, ichk+3, ichk+4,
+                      ichk+5, ichk+6, ichk+7, ichk+8, ichk+9);
+        */
+       movi %v0 ichk
+       prepare
+               pushargi buff
+               pushargi ifmt
+               ellipsis
+               pushargr %v0            /* 0 */
+               addi %v0 %v0 4
+               pushargr %v0            /* 1 */
+               addi %v0 %v0 4
+               pushargr %v0            /* 2 */
+               addi %v0 %v0 4
+               pushargr %v0            /* 3 */
+               addi %v0 %v0 4
+               pushargr %v0            /* 4 */
+               addi %v0 %v0 4
+               pushargr %v0            /* 5 */
+               addi %v0 %v0 4
+               pushargr %v0            /* 6 */
+               addi %v0 %v0 4
+               pushargr %v0            /* 7 */
+               addi %v0 %v0 4
+               pushargr %v0            /* 8 */
+               addi %v0 %v0 4
+               pushargr %v0            /* 9 */
+       finishi @sscanf
+
+       movi %v0 ichk
+       movi %r0 0
+loopi:
+       ldr_i %r1 %v0
+       beqr nexti %r0 %r1
+       calli @abort
+nexti:
+       addi %r0 %r0 1
+       bgei outi %r0 10
+       addi %v0 %v0 4
+       jmpi loopi
+outi:
+
+       prepare
+               pushargi buff
+               ellipsis
+       finishi @printf
+
+       /*
+               sprintf(buff,
+                       "%.1f %.1f %.1f %.1f %.1f "
+                       "%.1f %.1f %.1f %.1f %.1f\n",
+                       0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
+        */
+       prepare
+               pushargi buff
+               pushargi dfmt
+               ellipsis
+               pushargi_d 0.0
+               pushargi_d 1.0
+               pushargi_d 2.0
+               pushargi_d 3.0
+               pushargi_d 4.0
+               pushargi_d 5.0
+               pushargi_d 6.0
+               pushargi_d 7.0
+               pushargi_d 8.0
+               pushargi_d 9.0
+       finishi @sprintf
+
+       /*
+               sscanf(buff, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n",
+                      dchk+0, dchk+1, dchk+2, dchk+3, dchk+4,
+                      dchk+5, dchk+6, dchk+7, dchk+8, dchk+9);
+        */
+       movi %v0 dchk
+       prepare
+               pushargi buff
+               pushargi lfmt
+               ellipsis
+               pushargr %v0            /* 0 */
+               addi %v0 %v0 8
+               pushargr %v0            /* 1 */
+               addi %v0 %v0 8
+               pushargr %v0            /* 2 */
+               addi %v0 %v0 8
+               pushargr %v0            /* 3 */
+               addi %v0 %v0 8
+               pushargr %v0            /* 4 */
+               addi %v0 %v0 8
+               pushargr %v0            /* 5 */
+               addi %v0 %v0 8
+               pushargr %v0            /* 6 */
+               addi %v0 %v0 8
+               pushargr %v0            /* 7 */
+               addi %v0 %v0 8
+               pushargr %v0            /* 8 */
+               addi %v0 %v0 8
+               pushargr %v0            /* 9 */
+       finishi @sscanf
+
+       movi %v0 dchk
+       movi_d %f0 0.0
+loopd:
+       ldr_d %f1 %v0
+       beqr_d nextd %f0 %f1
+       calli @abort
+nextd:
+       addi_d %f0 %f0 1.0
+       bgei_d outd %f0 10.0
+       addi %v0 %v0 8
+       jmpi loopd
+outd:
+
+       prepare
+               pushargi buff
+               ellipsis
+       finishi @printf
+
+       /*
+           sprintf(buff,
+                  "%d %.1f %d %.1f %d %.1f %d %.1f %d %.1f "
+                  "%d %.1f %d %.1f %d %.1f %d %.1f %d %.1f\n",
+                  0, 0.0, 1, 1.0, 2, 2.0, 3, 3.0, 4, 4.0,
+                  5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0, 9, 9.0);
+        */
+       prepare
+               pushargi buff
+               pushargi idfmt
+               ellipsis
+               pushargi 0
+               pushargi_d 0.0
+               pushargi 1
+               pushargi_d 1.0
+               pushargi 2
+               pushargi_d 2.0
+               pushargi 3
+               pushargi_d 3.0
+               pushargi 4
+               pushargi_d 4.0
+               pushargi 5
+               pushargi_d 5.0
+               pushargi 6
+               pushargi_d 6.0
+               pushargi 7
+               pushargi_d 7.0
+               pushargi 8
+               pushargi_d 8.0
+               pushargi 9
+               pushargi_d 9.0
+       finishi @sprintf
+
+       /*
+               sscanf(buff,
+                     "%d %lf %d %lf %d %lf %d %lf %d %lf "
+                     "%d %lf %d %lf %d %lf %d %lf %d %lf\n",
+                     ichk+0, dchk+0, ichk+1, dchk+1, ichk+2,
+                     dchk+2, ichk+3, dchk+3, ichk+4, dchk+4,
+                     ichk+5, dchk+5, ichk+6, dchk+6, ichk+7,
+                     dchk+7, ichk+8, dchk+8, ichk+9, dchk+9);
+        */
+       movi %v0 ichk
+       movi %v1 dchk
+       prepare
+               pushargi buff
+               pushargi ldfmt
+               ellipsis
+               pushargr %v0            /* 0 */
+               addi %v0 %v0 4
+               pushargr %v1
+               addi %v1 %v1 8
+               pushargr %v0            /* 1 */
+               addi %v0 %v0 4
+               pushargr %v1
+               addi %v1 %v1 8
+               pushargr %v0            /* 2 */
+               addi %v0 %v0 4
+               pushargr %v1
+               addi %v1 %v1 8
+               pushargr %v0            /* 3 */
+               addi %v0 %v0 4
+               pushargr %v1
+               addi %v1 %v1 8
+               pushargr %v0            /* 4 */
+               addi %v0 %v0 4
+               pushargr %v1
+               addi %v1 %v1 8
+               pushargr %v0            /* 5 */
+               addi %v0 %v0 4
+               pushargr %v1
+               addi %v1 %v1 8
+               pushargr %v0            /* 6 */
+               addi %v0 %v0 4
+               pushargr %v1
+               addi %v1 %v1 8
+               pushargr %v0            /* 7 */
+               addi %v0 %v0 4
+               pushargr %v1
+               addi %v1 %v1 8
+               pushargr %v0            /* 8 */
+               addi %v0 %v0 4
+               pushargr %v1
+               addi %v1 %v1 8
+               pushargr %v0            /* 9 */
+               pushargr %v1
+       finishi @sscanf
+
+       movi %v0 ichk
+       movi %v1 dchk
+       movi %r0 0
+       movi_d %f0 0.0
+loopid:
+       ldr_i %r1 %v0
+       beqr checkd %r0 %r1
+       calli @abort
+checkd:
+       ldr_d %f1 %v1
+       beqr_d nextid %f0 %f1
+       calli @abort
+nextid:
+       addi %r0 %r0 1
+       addi_d %f0 %f0 1.0
+       bgei outid %r0 10
+       addi %v0 %v0 4
+       addi %v1 %v1 8
+       jmpi loopid
+outid:
+
+       prepare
+               pushargi buff
+               ellipsis
+       finishi @printf
+
+       /*
+           sprintf(buff,
+                  "%.1f %d %.1f %d %.1f %d %.1f %d %.1f %d "
+                  "%.1f %d %.1f %d %.1f %d %.1f %d %.1f %d\n",
+                  0.0, 0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4,
+                  5, 5.0, 6.0, 6, 7.0, 7, 8.0, 8, 9.0, 9);
+        */
+       prepare
+               pushargi buff
+               pushargi difmt
+               ellipsis
+               pushargi_d 0.0
+               pushargi 0
+               pushargi_d 1.0
+               pushargi 1
+               pushargi_d 2.0
+               pushargi 2
+               pushargi_d 3.0
+               pushargi 3
+               pushargi_d 4.0
+               pushargi 4
+               pushargi_d 5.0
+               pushargi 5
+               pushargi_d 6.0
+               pushargi 6
+               pushargi_d 7.0
+               pushargi 7
+               pushargi_d 8.0
+               pushargi 8
+               pushargi_d 9.0
+               pushargi 9
+       finishi @sprintf
+
+       /*
+               sscanf(buff,
+                     "%lf %d %lf %d %lf %d %lf %d %lf %d "
+                     "%lf %d %lf %d %lf %d %lf %d %lf %d \n",
+                     dchk+0, ichk+0, dchk+1, ichk+1, dchk+2,
+                     ichk+2, dchk+3, ichk+3, dchk+4, ichk+4,
+                     dchk+5, ichk+5, dchk+6, ichk+6, dchk+7,
+                     ichk+7, dchk+8, ichk+8, dchk+9, ichk+9);
+        */
+       movi %v0 dchk
+       movi %v1 ichk
+       prepare
+               pushargi buff
+               pushargi dlfmt
+               ellipsis
+               pushargr %v0            /* 0 */
+               addi %v0 %v0 8
+               pushargr %v1
+               addi %v1 %v1 4
+               pushargr %v0            /* 1 */
+               addi %v0 %v0 8
+               pushargr %v1
+               addi %v1 %v1 4
+               pushargr %v0            /* 2 */
+               addi %v0 %v0 8
+               pushargr %v1
+               addi %v1 %v1 4
+               pushargr %v0            /* 3 */
+               addi %v0 %v0 8
+               pushargr %v1
+               addi %v1 %v1 4
+               pushargr %v0            /* 4 */
+               addi %v0 %v0 8
+               pushargr %v1
+               addi %v1 %v1 4
+               pushargr %v0            /* 5 */
+               addi %v0 %v0 8
+               pushargr %v1
+               addi %v1 %v1 4
+               pushargr %v0            /* 6 */
+               addi %v0 %v0 8
+               pushargr %v1
+               addi %v1 %v1 4
+               pushargr %v0            /* 7 */
+               addi %v0 %v0 8
+               pushargr %v1
+               addi %v1 %v1 4
+               pushargr %v0            /* 8 */
+               addi %v0 %v0 8
+               pushargr %v1
+               addi %v1 %v1 4
+               pushargr %v0            /* 9 */
+               pushargr %v1
+       finishi @sscanf
+
+       movi %v0 ichk
+       movi %v1 dchk
+       movi %r0 0
+       movi_d %f0 0.0
+loopdi:
+       ldr_i %r1 %v0
+       beqr check_d %r0 %r1
+       calli @abort
+check_d:
+       ldr_d %f1 %v1
+       beqr_d nextdi %f0 %f1
+       calli @abort
+nextdi:
+       addi %r0 %r0 1
+       addi_d %f0 %f0 1.0
+       bgei outdi %r0 10
+       addi %v0 %v0 4
+       addi %v1 %v1 8
+       jmpi loopdi
+outdi:
+
+       prepare
+               pushargi buff
+               ellipsis
+       finishi @printf
+
+       ret
+       epilog
diff --git a/deps/lightning/configure.ac b/deps/lightning/configure.ac
new file mode 100644 (file)
index 0000000..9261255
--- /dev/null
@@ -0,0 +1,299 @@
+dnl
+dnl Copyright 2000, 2001, 2002, 2012-2019 Free Software Foundation, Inc.
+dnl
+dnl This file is part of GNU lightning.
+dnl
+dnl GNU lightning is free software; you can redistribute it and/or modify it
+dnl under the terms of the GNU Lesser General Public License as published
+dnl by the Free Software Foundation; either version 3, or (at your option)
+dnl any later version.
+dnl 
+dnl GNU lightning is distributed in the hope that it will be useful, but
+dnl WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+dnl or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+dnl License for more details.
+dnl
+
+AC_PREREQ(2.57)
+AC_INIT([GNU lightning], 2.1.3, pcpa@gnu.org, lightning)
+AC_CANONICAL_TARGET
+AC_CONFIG_SRCDIR([Makefile.am])
+AM_INIT_AUTOMAKE([dist-bzip2])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+AC_CONFIG_MACRO_DIR(m4)
+
+AC_CONFIG_HEADERS(config.h)
+
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+case "$target_cpu" in
+    ia64)
+       case "$host_os" in
+           # Only supported mode
+           *hpux*)
+               LIGHTNING_CFLAGS="$LIGHTNING_CFLAGS -mlp64"             ;;
+           *)                                  ;;
+       esac                                    ;;
+    *mips*)
+       case "$host_os" in
+           # (Hack) Flags to pass configure with gcc 3.x
+           # Should not set LIGHTNINT_CFLAGS
+           *irix*)
+               CFLAGS="$CFLAGS -D__c99 -Drestrict=";;
+           *)                                  ;;
+       esac                                    ;;
+    alpha*)
+       case "$host_os" in
+           osf*)
+               # Get proper varargs and mmap prototypes and definitions
+               CFLAGS="$CFLAGS -D_ANSI_C_SOURCE -D_XOPEN_SOURCE_EXTENDED -D_OSF_SOURCE -D_POSIX_C_SOURCE=199309L"
+               # Want to generate NaN with 0.0/0.0 and Inf with 1.0/0.0
+               if test x$GCC = "xyes"; then
+                   CFLAGS="$CFLAGS -mieee"
+               else
+                   CFLAGS="$CFLAGS -ieee_with_no_inexact"
+               fi                              ;;
+           *)                                  ;;
+       esac                                    ;;
+    *)                                         ;;
+esac
+
+AC_CHECK_FUNCS(mremap ffsl getopt_long_only isnan isinf,,)
+
+AC_CHECK_HEADERS([getopt.h stdint.h],,,)
+
+AC_ARG_ENABLE(disassembler,
+             AS_HELP_STRING([--enable-disassembler],
+                            [Enable jit disassembler using binutils]),
+             [DISASSEMBLER=$enableval], [DISASSEMBLER=auto])
+if test "x$DISASSEMBLER" != "xno"; then
+    # FIXME need to check for libiberty first or will fail to link
+    AC_CHECK_LIB(iberty, htab_try_create, ,
+                [HAVE_IBERTY="no"])
+    AC_CHECK_LIB(bfd, bfd_init, ,
+                [HAVE_BFD="no"])
+    AC_CHECK_LIB(z, compressBound, ,
+                [HAVE_Z="no"])
+    AC_CHECK_LIB(opcodes, init_disassemble_info, ,
+                [HAVE_OPCODES="no"])
+    if test "x$HAVE_IBERTY"  = "xno" -o \
+           "x$HAVE_BFD"     = "xno" -o \
+           "x$HAVE_Z"       = "xno" -o \
+           "x$HAVE_OPCODES" = "xno"; then
+       if test "x$DISASSEMBLER" != "xauto"; then
+           AC_MSG_ERROR([binutils not found, see http://www.gnu.org/software/binutils/])
+       else
+           AC_MSG_WARN([binutils not found, see http://www.gnu.org/software/binutils/])
+           DISASSEMBLER="no"
+       fi
+    fi
+fi
+AM_CONDITIONAL(with_disassembler, [test "x$DISASSEMBLER" != "xno"])
+if test "x$DISASSEMBLER" != "xno"; then
+    LIGHTNING_CFLAGS="$LIGHTNING_CFLAGS -DDISASSEMBLER=1"
+    save_CFLAGS=$CFLAGS
+    CFLAGS="$CFLAGS -I$PWD/include -D_GNU_SOURCE"
+    AC_COMPILE_IFELSE([AC_LANG_SOURCE(
+       #include <lightning.h>
+       #include <lightning/jit_private.h>
+       #include <dis-asm.h>
+       int main(int argc, char *argv[])
+       {
+               disassembler_ftype       print;
+               bfd                     *abfd;
+               print = disassembler(abfd);
+               return 0;
+       }
+    )], [ac_cv_test_new_disassembler=no],,)
+    CFLAGS="$save_CFLAGS"
+    if test "x$ac_cv_test_new_disassembler" != "xno"; then
+       LIGHTNING_CFLAGS="$LIGHTNING_CFLAGS -DBINUTILS_2_29=1"
+    fi
+fi
+
+AC_ARG_ENABLE(devel-disassembler,
+             AS_HELP_STRING([--enable-devel-disassembler],
+                            [Enable extra disassembly options]),
+             [DEVEL_DISASSEMBLER=$enableval], [DEVEL_DISASSEMBLER=no])
+if test "x$DEVEL_DISASSEMBLER" != "xno"; then
+    if test "x$DISASSEMBLER" = "xno"; then
+       AC_MSG_ERROR(devel-disassembler needs disassembler enabled)
+    fi
+    LIGHTNING_CFLAGS="$LIGHTNING_CFLAGS -DDEVEL_DISASSEMBLER=1"
+fi
+
+AC_ARG_ENABLE(assertions,
+             AS_HELP_STRING([--enable-assertions],
+                            [Enable runtime code generation assertions]),
+             [DEBUG=$enableval], [DEBUG=auto])
+if test "x$DEBUG" = xyes; then
+    LIGHTNING_CFLAGS="$LIGHTNING_CFLAGS -DDEBUG=1"
+else
+    LIGHTNING_CFLAGS="$LIGHTNING_CFLAGS -DNDEBUG"
+    DEBUG=no
+fi
+
+# This option is only useful during development.
+AC_ARG_ENABLE(devel-get-jit-size,
+             AS_HELP_STRING([--enable-devel-get-jit-size],
+                            [Devel mode to regenerate jit size information]),
+             [GET_JIT_SIZE=$enableval], [GET_JIT_SIZE=no])
+AM_CONDITIONAL(get_jit_size, [test $GET_JIT_SIZE = yes])
+
+case "$host_os" in
+    *bsd*|osf*)                SHLIB=""        ;;
+    *hpux*)            SHLIB="-ldld"   ;;
+    *)                 SHLIB="-ldl"    ;;
+esac
+AC_SUBST(SHLIB)
+
+cpu=
+case "$target_cpu" in
+    i?86|x86_64|amd64) cpu=x86         ;;
+    *arm*)             cpu=arm         ;;
+    *mips*)            cpu=mips        ;;
+    *powerpc*)         cpu=ppc         ;;
+    *sparc*)           cpu=sparc       ;;
+    ia64)              cpu=ia64        ;;
+    hppa*)             cpu=hppa        ;;
+    aarch64)           cpu=aarch64     ;;
+    s390*)             cpu=s390        ;;
+    alpha*)            cpu=alpha       ;;
+    riscv*)            cpu=riscv       ;;
+    *)                                 ;;
+esac
+AM_CONDITIONAL(cpu_arm,     [test cpu-$cpu = cpu-arm])
+AM_CONDITIONAL(cpu_mips,    [test cpu-$cpu = cpu-mips])
+AM_CONDITIONAL(cpu_ppc,     [test cpu-$cpu = cpu-ppc])
+AM_CONDITIONAL(cpu_sparc,   [test cpu-$cpu = cpu-sparc])
+AM_CONDITIONAL(cpu_x86,     [test cpu-$cpu = cpu-x86])
+AM_CONDITIONAL(cpu_ia64,    [test cpu-$cpu = cpu-ia64])
+AM_CONDITIONAL(cpu_hppa,    [test cpu-$cpu = cpu-hppa])
+AM_CONDITIONAL(cpu_aarch64, [test cpu-$cpu = cpu-aarch64])
+AM_CONDITIONAL(cpu_s390,    [test cpu-$cpu = cpu-s390])
+AM_CONDITIONAL(cpu_alpha,   [test cpu-$cpu = cpu-alpha])
+AM_CONDITIONAL(cpu_riscv,   [test cpu-$cpu = cpu-riscv])
+
+# Test x87 if both, x87 and sse2 available
+ac_cv_test_x86_x87=
+# Test arm instruction set if thumb instruction set available
+ac_cv_test_arm_arm=
+# Test sofware float if vfp available and not using hard float abi
+ac_cv_test_arm_swf=
+
+save_CFLAGS=$CFLAGS
+CFLAGS="$CFLAGS -I$PWD/include -D_GNU_SOURCE"
+if test x$cpu = x; then
+    AC_MSG_ERROR([cpu $target_cpu not supported])
+elif test $cpu = x86; then
+    AC_RUN_IFELSE([AC_LANG_SOURCE([[
+    #include <lightning.h>
+    int main(void) {
+       int                 ac, flags;
+       unsigned int        eax, ebx, ecx, edx;
+       if (__WORDSIZE == 64)
+           return 1;
+       __asm__ volatile ("pushfl;\n\t"
+                         "popl %0;\n\t"
+                         "movl \$0x240000, %1;\n\t"
+                         "xorl %0, %1;\n\t"
+                         "pushl %1;\n\t"
+                         "popfl;\n\t"
+                         "pushfl;\n\t"
+                         "popl %1;\n\t"
+                         "xorl %0, %1;\n\t"
+                         "pushl %0;\n\t"
+                         "popfl"
+                         : "=r" (flags), "=r" (ac));
+       if ((ac & (1 << 21)) == 0)
+           return 1;
+       __asm__ volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
+                         : "=a" (eax), "=r" (ebx),
+                         "=c" (ecx), "=d" (edx)
+                         : "0" (1));
+       return (edx & 1 << 26) ? 0 : 1;
+    }
+    ]])],[ac_cv_test_x86_x87=yes],[],[ac_cv_test_x86_x87=no])
+elif test $cpu = arm; then
+    AC_RUN_IFELSE([AC_LANG_SOURCE([[
+    #include <stdio.h>
+    int main(void) {
+    #if defined(__linux__)
+       FILE    *fp;
+       char     buf[128];
+       if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
+           return 1;
+       while (fgets(buf, sizeof(buf), fp)) {
+           if (strncmp(buf, "Features\t:", 10) == 0 &&
+               strstr(buf + 10, "thumb")) {
+               fclose(fp);
+               return 0;
+           }
+       }
+       fclose(fp);
+    #elif defined(__thumb2__)
+       return 0;
+    #endif
+       return 1;
+    }
+    ]])],[ac_cv_test_arm_arm=yes],[],[ac_cv_test_arm_arm=no])
+    AC_RUN_IFELSE([AC_LANG_SOURCE([[
+    #include <stdio.h>
+    int main(void) {
+    #if defined(__linux__)
+       FILE    *fp;
+       char     buf[128];
+    #  if !defined(__ARM_PCS_VFP)
+       if ((fp = fopen("/proc/cpuinfo", "r")) == NULL)
+           return 1;
+       while (fgets(buf, sizeof(buf), fp)) {
+           if (strncmp(buf, "Features\t:", 10) == 0 &&
+               strstr(buf + 10, "vfp")) {
+               fclose(fp);
+               return 0;
+           }
+       }
+       fclose(fp);
+    #  endif
+    #endif
+       return 1;
+    }
+    ]])],[ac_cv_test_arm_swf=yes],[],[ac_cv_test_arm_swf=no])
+elif test $cpu = ppc; then
+    if test "x$DISASSEMBLER" != "xno"; then
+       save_LIBS="$LIBS"
+       LIBS="$LIBS $SHLIB"
+       AC_CHECK_FUNCS(disassemble_init_for_target disassemble_init_powerpc)
+       LIBS="$save_LIBS"
+    fi
+fi
+CFLAGS=$save_CFLAGS
+
+AM_CONDITIONAL(test_x86_x87, [test x$ac_cv_test_x86_x87 = xyes])
+AM_CONDITIONAL(test_arm_arm, [test x$ac_cv_test_arm_arm = xyes])
+AM_CONDITIONAL(test_arm_swf, [test x$ac_cv_test_arm_swf = xyes])
+
+AM_CONDITIONAL(test_nodata, [test cpu-$cpu = cpu-mips -o cpu-$cpu = cpu-ppc -o cpu-$cpu = cpu-sparc -o cpu-$cpu = cpu-x86 -o cpu-$cpu = cpu-ia64 -o cpu-$cpu = cpu-hppa -o cpu-$cpu = cpu-s390 -o cpu-$cpu = cpu-alpha])
+
+if test $cpu = arm; then
+     AC_CHECK_LIB(m, sqrtf, ,
+        [AC_MSG_ERROR([sqrtf required but not available])])
+fi
+AC_SUBST(cpu)
+
+AC_SUBST([LIGHTNING_CFLAGS])
+
+if test $ac_cv_header_stdint_h = yes; then
+    AC_SUBST(MAYBE_INCLUDE_STDINT_H, ["#include <stdint.h>"])
+fi
+
+AC_OUTPUT([Makefile
+          lightning.pc
+          doc/Makefile
+          include/Makefile
+          include/lightning/Makefile
+          include/lightning.h
+          lib/Makefile
+          check/Makefile])
diff --git a/deps/lightning/doc/.cvsignore b/deps/lightning/doc/.cvsignore
new file mode 100644 (file)
index 0000000..01e2da8
--- /dev/null
@@ -0,0 +1,3 @@
+*.info*
+stamp-*
+version.texi
diff --git a/deps/lightning/doc/.gitignore b/deps/lightning/doc/.gitignore
new file mode 100644 (file)
index 0000000..f62c13f
--- /dev/null
@@ -0,0 +1,2 @@
+*.info*
+stamp-*
diff --git a/deps/lightning/doc/Makefile.am b/deps/lightning/doc/Makefile.am
new file mode 100644 (file)
index 0000000..20d4456
--- /dev/null
@@ -0,0 +1,45 @@
+#
+# Copyright 2012-2019 Free Software Foundation, Inc.
+#
+# This file is part of GNU lightning.
+#
+# GNU lightning is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU lightning is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+#
+
+AM_CFLAGS = -I$(top_srcdir)/include -D_GNU_SOURCE
+
+info_TEXINFOS = lightning.texi
+MOSTLYCLEANFILES = lightning.tmp
+
+lightning_TEXINFOS = body.texi version.texi
+
+noinst_PROGRAMS = incr printf rpn rfib ifib fact
+
+$(top_builddir)/lib/liblightning.la:
+       cd $(top_builddir)/lib; $(MAKE) $(AM_MAKEFLAGS) liblightning.la
+
+incr_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+incr_SOURCES = incr.c
+
+printf_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+printf_SOURCES = printf.c
+
+rpn_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+rpn_SOURCES = rpn.c
+
+rfib_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+rfib_SOURCES = rfib.c
+
+ifib_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+ifib_SOURCES = ifib.c
+
+fact_LDADD = $(top_builddir)/lib/liblightning.la -lm $(SHLIB)
+fact_SOURCES = fact.c
diff --git a/deps/lightning/doc/body.texi b/deps/lightning/doc/body.texi
new file mode 100644 (file)
index 0000000..4aef7a3
--- /dev/null
@@ -0,0 +1,1680 @@
+@ifnottex
+@dircategory Software development
+@direntry
+* lightning: (lightning).       Library for dynamic code generation.
+@end direntry
+@end ifnottex
+
+@ifnottex
+@node Top
+@top @lightning{}
+
+@iftex
+@macro comma
+@verbatim{|,|}
+@end macro
+@end iftex
+
+@ifnottex
+@macro comma
+@verb{|,|}
+@end macro
+@end ifnottex
+
+This document describes @value{TOPIC} the @lightning{} library for
+dynamic code generation.
+
+@menu
+* Overview::                What GNU lightning is
+* Installation::            Configuring and installing GNU lightning
+* The instruction set::     The RISC instruction set used in GNU lightning
+* GNU lightning examples::  GNU lightning's examples
+* Reentrancy::              Re-entrant usage of GNU lightning
+* Customizations::          Advanced code generation customizations
+* Acknowledgements::        Acknowledgements for GNU lightning
+@end menu
+@end ifnottex
+
+@node Overview
+@chapter Introduction to @lightning{}
+
+@iftex
+This document describes @value{TOPIC} the @lightning{} library for
+dynamic code generation.
+@end iftex
+
+Dynamic code generation is the generation of machine code 
+at runtime. It is typically used to strip a layer of interpretation 
+by allowing compilation to occur at runtime.  One of the most
+well-known applications of dynamic code generation is perhaps that
+of interpreters that compile source code to an intermediate bytecode
+form, which is then recompiled to machine code at run-time: this
+approach effectively combines the portability of bytecode
+representations with the speed of machine code.  Another common
+application of dynamic code generation is in the field of hardware
+simulators and binary emulators, which can use the same techniques
+to translate simulated instructions to the instructions of the 
+underlying machine.
+
+Yet other applications come to mind: for example, windowing
+@dfn{bitblt} operations, matrix manipulations, and network packet
+filters.  Albeit very powerful and relatively well known within the
+compiler community, dynamic code generation techniques are rarely
+exploited to their full potential and, with the exception of the
+two applications described above, have remained curiosities because
+of their portability and functionality barriers: binary instructions
+are generated, so programs using dynamic code generation must be
+retargeted for each machine; in addition, coding a run-time code
+generator is a tedious and error-prone task more than a difficult one.
+
+@lightning{} provides a portable, fast and easily retargetable dynamic
+code generation system. 
+
+To be portable, @lightning{} abstracts over current architectures'
+quirks and unorthogonalities.  The interface that it exposes to is that
+of a standardized RISC architecture loosely based on the SPARC and MIPS
+chips.  There are a few general-purpose registers (six, not including
+those used to receive and pass parameters between subroutines), and
+arithmetic operations involve three operands---either three registers
+or two registers and an arbitrarily sized immediate value.
+
+On one hand, this architecture is general enough that it is possible to
+generate pretty efficient code even on CISC architectures such as the
+Intel x86 or the Motorola 68k families.  On the other hand, it matches
+real architectures closely enough that, most of the time, the
+compiler's constant folding pass ends up generating code which
+assembles machine instructions without further tests.
+
+@node Installation
+@chapter Configuring and installing @lightning{}
+
+The first thing to do to use @lightning{} is to configure the
+program, picking the set of macros to be used on the host
+architecture; this configuration is automatically performed by
+the @file{configure} shell script; to run it, merely type:
+@example
+     ./configure
+@end example
+
+@lightning{} supports the @code{--enable-disassembler} option, that
+enables linking to GNU binutils and optionally print human readable
+disassembly of the jit code. This option can be disabled by the
+@code{--disable-disassembler} option.
+
+Another option that @file{configure} accepts is
+@code{--enable-assertions}, which enables several consistency checks in
+the run-time assemblers.  These are not usually needed, so you can
+decide to simply forget about it; also remember that these consistency
+checks tend to slow down your code generator.
+
+After you've configured @lightning{}, run @file{make} as usual.
+
+@lightning{} has an extensive set of tests to validate it is working
+correctly in the build host. To test it run:
+@example
+    make check
+@end example
+
+The next important step is:
+@example
+    make install
+@end example
+
+This ends the process of installing @lightning{}.
+
+@node The instruction set
+@chapter @lightning{}'s instruction set
+
+@lightning{}'s instruction set was designed by deriving instructions
+that closely match those of most existing RISC architectures, or
+that can be easily syntesized if absent.  Each instruction is composed
+of:
+@itemize @bullet
+@item
+an operation, like @code{sub} or @code{mul}
+
+@item
+most times, a register/immediate flag (@code{r} or @code{i})
+
+@item
+an unsigned modifier (@code{u}), a type identifier or two, when applicable.
+@end itemize
+
+Examples of legal mnemonics are @code{addr} (integer add, with three
+register operands) and @code{muli} (integer multiply, with two
+register operands and an immediate operand).  Each instruction takes
+two or three operands; in most cases, one of them can be an immediate
+value instead of a register.
+
+Most @lightning{} integer operations are signed wordsize operations,
+with the exception of operations that convert types, or load or store
+values to/from memory. When applicable, the types and C types are as
+follow:
+
+@example
+     _c         @r{signed char}
+     _uc        @r{unsigned char}
+     _s         @r{short}
+     _us        @r{unsigned short}
+     _i         @r{int}
+     _ui        @r{unsigned int}
+     _l         @r{long}
+     _f         @r{float}
+     _d         @r{double}
+@end example
+
+Most integer operations do not need a type modifier, and when loading or
+storing values to memory there is an alias to the proper operation
+using wordsize operands, that is, if ommited, the type is @r{int} on
+32-bit architectures and @r{long} on 64-bit architectures.  Note
+that lightning also expects @code{sizeof(void*)} to match the wordsize.
+
+When an unsigned operation result differs from the equivalent signed
+operation, there is a the @code{_u} modifier.
+
+There are at least seven integer registers, of which six are
+general-purpose, while the last is used to contain the frame pointer
+(@code{FP}).  The frame pointer can be used to allocate and access local
+variables on the stack, using the @code{allocai} or @code{allocar}
+instruction.
+
+Of the general-purpose registers, at least three are guaranteed to be
+preserved across function calls (@code{V0}, @code{V1} and
+@code{V2}) and at least three are not (@code{R0}, @code{R1} and
+@code{R2}).  Six registers are not very much, but this
+restriction was forced by the need to target CISC architectures
+which, like the x86, are poor of registers; anyway, backends can
+specify the actual number of available registers with the calls
+@code{JIT_R_NUM} (for caller-save registers) and @code{JIT_V_NUM}
+(for callee-save registers).
+
+There are at least six floating-point registers, named @code{F0} to
+@code{F5}.  These are usually caller-save and are separate from the integer
+registers on the supported architectures; on Intel architectures,
+in 32 bit mode if SSE2 is not available or use of X87 is forced,
+the register stack is mapped to a flat register file.  As for the
+integer registers, the macro @code{JIT_F_NUM} yields the number of
+floating-point registers.
+
+The complete instruction set follows; as you can see, most non-memory
+operations only take integers (either signed or unsigned) as operands;
+this was done in order to reduce the instruction set, and because most
+architectures only provide word and long word operations on registers.
+There are instructions that allow operands to be extended to fit a larger
+data type, both in a signed and in an unsigned way.
+
+@table @b
+@item Binary ALU operations
+These accept three operands; the last one can be an immediate.
+@code{addx} operations must directly follow @code{addc}, and
+@code{subx} must follow @code{subc}; otherwise, results are undefined.
+Most, if not all, architectures do not support @r{float} or @r{double}
+immediate operands; lightning emulates those operations by moving the
+immediate to a temporary register and emiting the call with only
+register operands.
+@example
+addr         _f  _d  O1 = O2 + O3
+addi         _f  _d  O1 = O2 + O3
+addxr                O1 = O2 + (O3 + carry)
+addxi                O1 = O2 + (O3 + carry)
+addcr                O1 = O2 + O3, set carry
+addci                O1 = O2 + O3, set carry
+subr         _f  _d  O1 = O2 - O3
+subi         _f  _d  O1 = O2 - O3
+subxr                O1 = O2 - (O3 + carry)
+subxi                O1 = O2 - (O3 + carry)
+subcr                O1 = O2 - O3, set carry
+subci                O1 = O2 - O3, set carry
+rsbr         _f  _d  O1 = O3 - O1
+rsbi         _f  _d  O1 = O3 - O1
+mulr         _f  _d  O1 = O2 * O3
+muli         _f  _d  O1 = O2 * O3
+divr     _u  _f  _d  O1 = O2 / O3
+divi     _u  _f  _d  O1 = O2 / O3
+remr     _u          O1 = O2 % O3
+remi     _u          O1 = O2 % O3
+andr                 O1 = O2 & O3
+andi                 O1 = O2 & O3
+orr                  O1 = O2 | O3
+ori                  O1 = O2 | O3
+xorr                 O1 = O2 ^ O3
+xori                 O1 = O2 ^ O3
+lshr                 O1 = O2 << O3
+lshi                 O1 = O2 << O3
+rshr     _u          O1 = O2 >> O3@footnote{The sign bit is propagated unless using the @code{_u} modifier.}
+rshi     _u          O1 = O2 >> O3@footnote{The sign bit is propagated unless using the @code{_u} modifier.}
+@end example
+
+@item Four operand binary ALU operations
+These accept two result registers, and two operands; the last one can
+be an immediate. The first two arguments cannot be the same register.
+
+@code{qmul} stores the low word of the result in @code{O1} and the
+high word in @code{O2}. For unsigned multiplication, @code{O2} zero
+means there was no overflow. For signed multiplication, no overflow
+check is based on sign, and can be detected if @code{O2} is zero or
+minus one.
+
+@code{qdiv} stores the quotient in @code{O1} and the remainder in
+@code{O2}. It can be used as quick way to check if a division is
+exact, in which case the remainder is zero.
+
+@example
+qmulr    _u       O1 O2 = O3 * O4
+qmuli    _u       O1 O2 = O3 * O4
+qdivr    _u       O1 O2 = O3 / O4
+qdivi    _u       O1 O2 = O3 / O4
+@end example
+
+@item Unary ALU operations
+These accept two operands, both of which must be registers.
+@example
+negr         _f  _d  O1 = -O2
+comr                 O1 = ~O2
+@end example
+
+These unary ALU operations are only defined for float operands.
+@example
+absr         _f  _d  O1 = fabs(O2)
+sqrtr                O1 = sqrt(O2)
+@end example
+
+Besides requiring the @code{r} modifier, there are no unary operations
+with an immediate operand.
+
+@item Compare instructions
+These accept three operands; again, the last can be an immediate.
+The last two operands are compared, and the first operand, that must be
+an integer register, is set to either 0 or 1, according to whether the
+given condition was met or not.
+
+The conditions given below are for the standard behavior of C,
+where the ``unordered'' comparison result is mapped to false.
+
+@example
+ltr       _u  _f  _d  O1 =  (O2 <  O3)
+lti       _u  _f  _d  O1 =  (O2 <  O3)
+ler       _u  _f  _d  O1 =  (O2 <= O3)
+lei       _u  _f  _d  O1 =  (O2 <= O3)
+gtr       _u  _f  _d  O1 =  (O2 >  O3)
+gti       _u  _f  _d  O1 =  (O2 >  O3)
+ger       _u  _f  _d  O1 =  (O2 >= O3)
+gei       _u  _f  _d  O1 =  (O2 >= O3)
+eqr           _f  _d  O1 =  (O2 == O3)
+eqi           _f  _d  O1 =  (O2 == O3)
+ner           _f  _d  O1 =  (O2 != O3)
+nei           _f  _d  O1 =  (O2 != O3)
+unltr         _f  _d  O1 = !(O2 >= O3)
+unler         _f  _d  O1 = !(O2 >  O3)
+ungtr         _f  _d  O1 = !(O2 <= O3)
+unger         _f  _d  O1 = !(O2 <  O3)
+uneqr         _f  _d  O1 = !(O2 <  O3) && !(O2 >  O3)
+ltgtr         _f  _d  O1 = !(O2 >= O3) || !(O2 <= O3)
+ordr          _f  _d  O1 =  (O2 == O2) &&  (O3 == O3)
+unordr        _f  _d  O1 =  (O2 != O2) ||  (O3 != O3)
+@end example
+
+@item Transfer operations
+These accept two operands; for @code{ext} both of them must be
+registers, while @code{mov} accepts an immediate value as the second
+operand.
+
+Unlike @code{movr} and @code{movi}, the other instructions are used
+to truncate a wordsize operand to a smaller integer data type or to
+convert float data types. You can also use @code{extr} to convert an
+integer to a floating point value: the usual options are @code{extr_f}
+and @code{extr_d}.
+
+@example
+movr                                 _f  _d  O1 = O2
+movi                                 _f  _d  O1 = O2
+extr      _c  _uc  _s  _us  _i  _ui  _f  _d  O1 = O2
+truncr                               _f  _d  O1 = trunc(O2)
+@end example
+
+In 64-bit architectures it may be required to use @code{truncr_f_i},
+@code{truncr_f_l}, @code{truncr_d_i} and @code{truncr_d_l} to match
+the equivalent C code.  Only the @code{_i} modifier is available in
+32-bit architectures.
+
+@example
+truncr_f_i    = <int> O1 = <float> O2
+truncr_f_l    = <long>O1 = <float> O2
+truncr_d_i    = <int> O1 = <double>O2
+truncr_d_l    = <long>O1 = <double>O2
+@end example
+
+The float conversion operations are @emph{destination first,
+source second}, but the order of the types is reversed.  This happens
+for historical reasons.
+
+@example
+extr_f_d    = <double>O1 = <float> O2
+extr_d_f    = <float> O1 = <double>O2
+@end example
+
+@item Network extensions
+These accept two operands, both of which must be registers; these
+two instructions actually perform the same task, yet they are
+assigned to two mnemonics for the sake of convenience and
+completeness.  As usual, the first operand is the destination and
+the second is the source.
+The @code{_ul} variant is only available in 64-bit architectures.
+@example
+htonr    _us _ui _ul @r{Host-to-network (big endian) order}
+ntohr    _us _ui _ul @r{Network-to-host order }
+@end example
+
+@item Load operations
+@code{ld} accepts two operands while @code{ldx} accepts three;
+in both cases, the last can be either a register or an immediate
+value. Values are extended (with or without sign, according to
+the data type specification) to fit a whole register.
+The @code{_ui} and @code{_l} types are only available in 64-bit
+architectures.  For convenience, there is a version without a
+type modifier for integer or pointer operands that uses the
+appropriate wordsize call.
+@example
+ldr     _c  _uc  _s  _us  _i  _ui  _l  _f  _d  O1 = *O2
+ldi     _c  _uc  _s  _us  _i  _ui  _l  _f  _d  O1 = *O2
+ldxr    _c  _uc  _s  _us  _i  _ui  _l  _f  _d  O1 = *(O2+O3)
+ldxi    _c  _uc  _s  _us  _i  _ui  _l  _f  _d  O1 = *(O2+O3)
+@end example
+
+@item Store operations
+@code{st} accepts two operands while @code{stx} accepts three; in
+both cases, the first can be either a register or an immediate
+value. Values are sign-extended to fit a whole register.
+@example
+str     _c  _uc  _s  _us  _i  _ui  _l  _f  _d  *O1 = O2
+sti     _c  _uc  _s  _us  _i  _ui  _l  _f  _d  *O1 = O2
+stxr    _c  _uc  _s  _us  _i  _ui  _l  _f  _d  *(O1+O2) = O3
+stxi    _c  _uc  _s  _us  _i  _ui  _l  _f  _d  *(O1+O2) = O3
+@end example
+As for the load operations, the @code{_ui} and @code{_l} types are
+only available in 64-bit architectures, and for convenience, there
+is a version without a type modifier for integer or pointer operands
+that uses the appropriate wordsize call.
+
+@item Argument management
+These are:
+@example
+prepare     (not specified)
+va_start    (not specified)
+pushargr                                   _f  _d
+pushargi                                   _f  _d
+va_push     (not specified)
+arg                                        _f  _d
+getarg      _c  _uc  _s  _us  _i  _ui  _l  _f  _d
+va_arg                                         _d
+putargr                                    _f  _d
+putargi                                    _f  _d
+ret         (not specified)
+retr                                       _f  _d
+reti                                       _f  _d
+va_end      (not specified)
+retval      _c  _uc  _s  _us  _i  _ui  _l  _f  _d
+epilog      (not specified)
+@end example
+As with other operations that use a type modifier, the @code{_ui} and
+@code{_l} types are only available in 64-bit architectures, but there
+are operations without a type modifier that alias to the appropriate
+integer operation with wordsize operands.
+
+@code{prepare}, @code{pusharg}, and @code{retval} are used by the caller,
+while @code{arg}, @code{getarg} and @code{ret} are used by the callee.
+A code snippet that wants to call another procedure and has to pass
+arguments must, in order: use the @code{prepare} instruction and use
+the @code{pushargr} or @code{pushargi} to push the arguments @strong{in
+left to right order}; and use @code{finish} or @code{call} (explained below)
+to perform the actual call.
+
+@code{va_start} returns a @code{C} compatible @code{va_list}. To fetch
+arguments, use @code{va_arg} for integers and @code{va_arg_d} for doubles.
+@code{va_push} is required when passing a @code{va_list} to another function,
+because not all architectures expect it as a single pointer. Known case
+is DEC Alpha, that requires it as a structure passed by value.
+
+@code{arg}, @code{getarg} and @code{putarg} are used by the callee.
+@code{arg} is different from other instruction in that it does not
+actually generate any code: instead, it is a function which returns
+a value to be passed to @code{getarg} or @code{putarg}. @footnote{``Return
+a value'' means that @lightning{} code that compile these
+instructions return a value when expanded.} You should call
+@code{arg} as soon as possible, before any function call or, more
+easily, right after the @code{prolog} instructions
+(which is treated later).
+
+@code{getarg} accepts a register argument and a value returned by
+@code{arg}, and will move that argument to the register, extending
+it (with or without sign, according to the data type specification)
+to fit a whole register.  These instructions are more intimately
+related to the usage of the @lightning{} instruction set in code
+that generates other code, so they will be treated more
+specifically in @ref{GNU lightning examples, , Generating code at
+run-time}.
+
+@code{putarg} is a mix of @code{getarg} and @code{pusharg} in that
+it accepts as first argument a register or immediate, and as
+second argument a value returned by @code{arg}. It allows changing,
+or restoring an argument to the current function, and is a
+construct required to implement tail call optimization. Note that
+arguments in registers are very cheap, but will be overwritten
+at any moment, including on some operations, for example division,
+that on several ports is implemented as a function call.
+
+Finally, the @code{retval} instruction fetches the return value of a
+called function in a register.  The @code{retval} instruction takes a
+register argument and copies the return value of the previously called
+function in that register.  A function with a return value should use
+@code{retr} or @code{reti} to put the return value in the return register
+before returning.  @xref{Fibonacci, the Fibonacci numbers}, for an example.
+
+@code{epilog} is an optional call, that marks the end of a function
+body. It is automatically generated by @lightning{} if starting a new
+function (what should be done after a @code{ret} call) or finishing
+generating jit.
+It is very important to note that the fact that @code{epilog} being
+optional may cause a common mistake. Consider this:
+@example
+fun1:
+    prolog
+    ...
+    ret
+fun2:
+    prolog
+@end example
+Because @code{epilog} is added when finding a new @code{prolog},
+this will cause the @code{fun2} label to actually be before the
+return from @code{fun1}. Because @lightning{} will actually
+understand it as:
+@example
+fun1:
+    prolog
+    ...
+    ret
+fun2:
+    epilog
+    prolog
+@end example
+
+You should observe a few rules when using these macros.  First of
+all, if calling a varargs function, you should use the @code{ellipsis}
+call to mark the position of the ellipsis in the C prototype.
+
+You should not nest calls to @code{prepare} inside a
+@code{prepare/finish} block.  Doing this will result in undefined
+behavior. Note that for functions with zero arguments you can use
+just @code{call}.
+
+@item Branch instructions
+Like @code{arg}, these also return a value which, in this case,
+is to be used to compile forward branches as explained in
+@ref{Fibonacci, , Fibonacci numbers}.  They accept two operands to be
+compared; of these, the last can be either a register or an immediate.
+They are:
+@example
+bltr      _u  _f  _d  @r{if }(O2 <  O3)@r{ goto }O1
+blti      _u  _f  _d  @r{if }(O2 <  O3)@r{ goto }O1
+bler      _u  _f  _d  @r{if }(O2 <= O3)@r{ goto }O1
+blei      _u  _f  _d  @r{if }(O2 <= O3)@r{ goto }O1
+bgtr      _u  _f  _d  @r{if }(O2 >  O3)@r{ goto }O1
+bgti      _u  _f  _d  @r{if }(O2 >  O3)@r{ goto }O1
+bger      _u  _f  _d  @r{if }(O2 >= O3)@r{ goto }O1
+bgei      _u  _f  _d  @r{if }(O2 >= O3)@r{ goto }O1
+beqr          _f  _d  @r{if }(O2 == O3)@r{ goto }O1
+beqi          _f  _d  @r{if }(O2 == O3)@r{ goto }O1
+bner          _f  _d  @r{if }(O2 != O3)@r{ goto }O1
+bnei          _f  _d  @r{if }(O2 != O3)@r{ goto }O1
+
+bunltr        _f  _d  @r{if }!(O2 >= O3)@r{ goto }O1
+bunler        _f  _d  @r{if }!(O2 >  O3)@r{ goto }O1
+bungtr        _f  _d  @r{if }!(O2 <= O3)@r{ goto }O1
+bunger        _f  _d  @r{if }!(O2 <  O3)@r{ goto }O1
+buneqr        _f  _d  @r{if }!(O2 <  O3) && !(O2 >  O3)@r{ goto }O1
+bltgtr        _f  _d  @r{if }!(O2 >= O3) || !(O2 <= O3)@r{ goto }O1
+bordr         _f  _d  @r{if } (O2 == O2) &&  (O3 == O3)@r{ goto }O1
+bunordr       _f  _d  @r{if }!(O2 != O2) ||  (O3 != O3)@r{ goto }O1
+
+bmsr                  @r{if }O2 &  O3@r{ goto }O1
+bmsi                  @r{if }O2 &  O3@r{ goto }O1
+bmcr                  @r{if }!(O2 & O3)@r{ goto }O1
+bmci                  @r{if }!(O2 & O3)@r{ goto }O1@footnote{These mnemonics mean, respectively, @dfn{branch if mask set} and @dfn{branch if mask cleared}.}
+boaddr    _u          O2 += O3@r{, goto }O1@r{ if overflow}
+boaddi    _u          O2 += O3@r{, goto }O1@r{ if overflow}
+bxaddr    _u          O2 += O3@r{, goto }O1@r{ if no overflow}
+bxaddi    _u          O2 += O3@r{, goto }O1@r{ if no overflow}
+bosubr    _u          O2 -= O3@r{, goto }O1@r{ if overflow}
+bosubi    _u          O2 -= O3@r{, goto }O1@r{ if overflow}
+bxsubr    _u          O2 -= O3@r{, goto }O1@r{ if no overflow}
+bxsubi    _u          O2 -= O3@r{, goto }O1@r{ if no overflow}
+@end example
+
+@item Jump and return operations
+These accept one argument except @code{ret} and @code{jmpi} which
+have none; the difference between @code{finishi} and @code{calli}
+is that the latter does not clean the stack from pushed parameters
+(if any) and the former must @strong{always} follow a @code{prepare}
+instruction.
+@example
+callr     (not specified)                @r{function call to register O1}
+calli     (not specified)                @r{function call to immediate O1}
+finishr   (not specified)                @r{function call to register O1}
+finishi   (not specified)                @r{function call to immediate O1}
+jmpr      (not specified)                @r{unconditional jump to register}
+jmpi      (not specified)                @r{unconditional jump}
+ret       (not specified)                @r{return from subroutine}
+retr      _c _uc _s _us _i _ui _l _f _d
+reti      _c _uc _s _us _i _ui _l _f _d
+retval    _c _uc _s _us _i _ui _l _f _d  @r{move return value}
+                                         @r{to register}
+@end example
+
+Like branch instruction, @code{jmpi} also returns a value which is to
+be used to compile forward branches. @xref{Fibonacci, , Fibonacci
+numbers}.
+
+@item Labels
+There are 3 @lightning{} instructions to create labels:
+@example
+label     (not specified)                @r{simple label}
+forward   (not specified)                @r{forward label}
+indirect  (not specified)                @r{special simple label}
+@end example
+
+@code{label} is normally used as @code{patch_at} argument for backward
+jumps.
+
+@example
+        jit_node_t *jump, *label;
+label = jit_label();
+        ...
+        jump = jit_beqr(JIT_R0, JIT_R1);
+        jit_patch_at(jump, label);
+@end example
+
+@code{forward} is used to patch code generation before the actual
+position of the label is known.
+
+@example
+        jit_node_t *jump, *label;
+label = jit_forward();
+        jump = jit_beqr(JIT_R0, JIT_R1);
+        jit_patch_at(jump, label);
+        ...
+        jit_link(label);
+@end example
+
+@code{indirect} is useful when creating jump tables, and tells
+@lightning{} to not optimize out a label that is not the target of
+any jump, because an indirect jump may land where it is defined.
+
+@example
+        jit_node_t *jump, *label;
+        ...
+        jmpr(JIT_R0);                    @rem{/* may jump to label */}
+        ...
+label = jit_indirect();
+@end example
+
+@code{indirect} is an special case of @code{note} and @code{name}
+because it is a valid argument to @code{address}.
+
+Note that the usual idiom to write the previous example is
+@example
+        jit_node_t *addr, *jump;
+addr  = jit_movi(JIT_R0, 0);             @rem{/* immediate is ignored */}
+        ...
+        jmpr(JIT_R0);
+        ...
+        jit_patch(addr);                 @rem{/* implicit label added */}
+@end example
+
+that automatically binds the implicit label added by @code{patch} with
+the @code{movi}, but on some special conditions it is required to create
+an "unbound" label.
+
+@item Function prolog
+
+These macros are used to set up a function prolog.  The @code{allocai}
+call accept a single integer argument and returns an offset value
+for stack storage access.  The @code{allocar} accepts two registers
+arguments, the first is set to the offset for stack access, and the
+second is the size in bytes argument.
+
+@example
+prolog    (not specified)                @r{function prolog}
+allocai   (not specified)                @r{reserve space on the stack}
+allocar   (not specified)                @r{allocate space on the stack}
+@end example
+
+@code{allocai} receives the number of bytes to allocate and returns
+the offset from the frame pointer register @code{FP} to the base of
+the area.
+
+@code{allocar} receives two register arguments.  The first is where
+to store the offset from the frame pointer register @code{FP} to the
+base of the area.  The second argument is the size in bytes.  Note
+that @code{allocar} is dynamic allocation, and special attention
+should be taken when using it.  If called in a loop, every iteration
+will allocate stack space.  Stack space is aligned from 8 to 64 bytes
+depending on backend requirements, even if allocating only one byte.
+It is advisable to not use it with @code{frame} and @code{tramp}; it
+should work with @code{frame} with special care to call only once,
+but is not supported if used in @code{tramp}, even if called only
+once.
+
+As a small appetizer, here is a small function that adds 1 to the input
+parameter (an @code{int}).  I'm using an assembly-like syntax here which
+is a bit different from the one used when writing real subroutines with
+@lightning{}; the real syntax will be introduced in @xref{GNU lightning
+examples, , Generating code at run-time}.
+
+@example
+incr:
+     prolog
+in = arg                     @rem{! We have an integer argument}
+     getarg    R0, in        @rem{! Move it to R0}
+     addi      R0, R0, 1     @rem{! Add 1}
+     retr      R0            @rem{! And return the result}
+@end example
+
+And here is another function which uses the @code{printf} function from
+the standard C library to write a number in hexadecimal notation:
+
+@example
+printhex:
+     prolog
+in = arg                     @rem{! Same as above}
+     getarg    R0, in
+     prepare                 @rem{! Begin call sequence for printf}
+     pushargi  "%x"          @rem{! Push format string}
+     ellipsis                @rem{! Varargs start here}
+     pushargr  R0            @rem{! Push second argument}
+     finishi   printf        @rem{! Call printf}
+     ret                     @rem{! Return to caller}
+@end example
+
+@item Trampolines, continuations and tail call optimization
+
+Frequently it is required to generate jit code that must jump to
+code generated later, possibly from another @code{jit_context_t}.
+These require compatible stack frames.
+
+@lightning{} provides two primitives from where trampolines,
+continuations and tail call optimization can be implemented.
+
+@example
+frame   (not specified)                  @r{create stack frame}
+tramp   (not specified)                  @r{assume stack frame}
+@end example
+
+@code{frame} receives an integer argument@footnote{It is not
+automatically computed because it does not know about the
+requirement of later generated code.} that defines the size in
+bytes for the stack frame of the current, @code{C} callable,
+jit function. To calculate this value, a good formula is maximum
+number of arguments to any called native function times
+eight@footnote{Times eight so that it works for double arguments.
+And would not need conditionals for ports that pass arguments in
+the stack.}, plus the sum of the arguments to any call to
+@code{jit_allocai}. @lightning{} automatically adjusts this value
+for any backend specific stack memory it may need, or any
+alignment constraint.
+
+@code{frame} also instructs @lightning{} to save all callee
+save registers in the prolog and reload in the epilog.
+
+@example
+main:                        @rem{! jit entry point}
+     prolog                  @rem{! function prolog}
+     frame  256              @rem{! save all callee save registers and}
+                             @rem{! reserve at least 256 bytes in stack}
+main_loop:
+     ...
+     jmpi   handler          @rem{! jumps to external code}
+     ...
+     ret                     @rem{! return to the caller}
+@end example
+
+@code{tramp} differs from @code{frame} only that a prolog and epilog
+will not be generated. Note that @code{prolog} must still be used.
+The code under @code{tramp} must be ready to be entered with a jump
+at the prolog position, and instead of a return, it must end with
+a non conditional jump. @code{tramp} exists solely for the fact
+that it allows optimizing out prolog and epilog code that would
+never be executed.
+
+@example
+handler:                     @rem{! handler entry point}
+     prolog                  @rem{! function prolog}
+     tramp  256              @rem{! assumes all callee save registers}
+                             @rem{! are saved and there is at least}
+                             @rem{! 256 bytes in stack}
+     ...
+     jmpi   main_loop        @rem{! return to the main loop}
+@end example
+
+@lightning{} only supports Tail Call Optimization using the
+@code{tramp} construct. Any other way is not guaranteed to
+work on all ports.
+
+An example of a simple (recursive) tail call optimization:
+
+@example
+factorial:                   @rem{! Entry point of the factorial function}
+     prolog
+in = arg                     @rem{! Receive an integer argument}
+     getarg R0, in           @rem{! Move argument to RO}
+     prepare
+         pushargi 1          @rem{! This is the accumulator}
+         pushargr R0         @rem{! This is the argument}
+     finishi fact            @rem{! Call the tail call optimized function}
+     retval R0               @rem{! Fetch the result}
+     retr R0                 @rem{! Return it}
+     epilog                  @rem{! Epilog *before* label before prolog}
+
+fact:                        @rem{! Entry point of the helper function}
+     prolog
+     frame 16                @rem{! Reserve 16 bytes in the stack}
+fact_entry:                  @rem{! This is the tail call entry point}
+ac = arg                     @rem{! The accumulator is the first argument}
+in = arg                     @rem{! The factorial argument}
+     getarg R0, ac           @rem{! Move the accumulator to R0}
+     getarg R1, in           @rem{! Move the argument to R1}
+     blei fact_out, R1, 1    @rem{! Done if argument is one or less}
+     mulr R0, R0, R1         @rem{! accumulator *= argument}
+     putargr R0, ac          @rem{! Update the accumulator}
+     subi R1, R1, 1          @rem{! argument -= 1}
+     putargr R1, in          @rem{! Update the argument}
+     jmpi fact_entry         @rem{! Tail Call Optimize it!}
+fact_out:
+     retr R0                 @rem{! Return the accumulator}
+@end example
+
+@item Predicates
+@example
+forward_p      (not specified)           @r{forward label predicate}
+indirect_p     (not specified)           @r{indirect label predicate}
+target_p       (not specified)           @r{used label predicate}
+arg_register_p (not specified)           @r{argument kind predicate}
+callee_save_p  (not specified)           @r{callee save predicate}
+pointer_p      (not specified)           @r{pointer predicate}
+@end example
+
+@code{forward_p} expects a @code{jit_node_t*} argument, and
+returns non zero if it is a forward label reference, that is,
+a label returned by @code{forward}, that still needs a
+@code{link} call.
+
+@code{indirect_p} expects a @code{jit_node_t*} argument, and returns
+non zero if it is an indirect label reference, that is, a label that
+was returned by @code{indirect}.
+
+@code{target_p} expects a @code{jit_node_t*} argument, that is any
+kind of label, and will return non zero if there is at least one
+jump or move referencing it.
+
+@code{arg_register_p} expects a @code{jit_node_t*} argument, that must
+have been returned by @code{arg}, @code{arg_f} or @code{arg_d}, and
+will return non zero if the argument lives in a register. This call
+is useful to know the live range of register arguments, as those
+are very fast to read and write, but have volatile values.
+
+@code{callee_save_p} exects a valid @code{JIT_Rn}, @code{JIT_Vn}, or
+@code{JIT_Fn}, and will return non zero if the register is callee
+save. This call is useful because on several ports, the @code{JIT_Rn}
+and @code{JIT_Fn} registers are actually callee save; no need
+to save and load the values when making function calls.
+
+@code{pointer_p} expects a pointer argument, and will return non
+zero if the pointer is inside the generated jit code. Must be
+called after @code{jit_emit} and before @code{jit_destroy_state}.
+@end table
+
+@node GNU lightning examples
+@chapter Generating code at run-time
+
+To use @lightning{}, you should include the @file{lightning.h} file that
+is put in your include directory by the @samp{make install} command.
+
+Each of the instructions above translates to a macro or function call.
+All you have to do is prepend @code{jit_} (lowercase) to opcode names
+and @code{JIT_} (uppercase) to register names.  Of course, parameters
+are to be put between parentheses.
+
+This small tutorial presents three examples:
+
+@iftex
+@itemize @bullet
+@item
+The @code{incr} function found in @ref{The instruction set, ,
+@lightning{}'s instruction set}:
+
+@item
+A simple function call to @code{printf}
+
+@item
+An RPN calculator.
+
+@item
+Fibonacci numbers
+@end itemize
+@end iftex
+@ifnottex
+@menu
+* incr::             A function which increments a number by one
+* printf::           A simple function call to printf
+* RPN calculator::   A more complex example, an RPN calculator
+* Fibonacci::        Calculating Fibonacci numbers
+@end menu
+@end ifnottex
+
+@node incr
+@section A function which increments a number by one
+
+Let's see how to create and use the sample @code{incr} function created
+in @ref{The instruction set, , @lightning{}'s instruction set}:
+
+@example
+#include <stdio.h>
+#include <lightning.h>
+
+static jit_state_t *_jit;
+
+typedef int (*pifi)(int);    @rem{/* Pointer to Int Function of Int */}
+
+int main(int argc, char *argv[])
+@{
+  jit_node_t  *in;
+  pifi         incr;
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+  jit_prolog();                    @rem{/* @t{     prolog             } */}
+  in = jit_arg();                  @rem{/* @t{     in = arg           } */}
+  jit_getarg(JIT_R0, in);          @rem{/* @t{     getarg R0          } */}
+  jit_addi(JIT_R0, JIT_R0, 1);     @rem{/* @t{     addi   R0@comma{} R0@comma{} 1   } */}
+  jit_retr(JIT_R0);                @rem{/* @t{     retr   R0          } */}
+
+  incr = jit_emit();
+  jit_clear_state();
+
+  @rem{/* call the generated code@comma{} passing 5 as an argument */}
+  printf("%d + 1 = %d\n", 5, incr(5));
+
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+@}
+@end example
+
+Let's examine the code line by line (well, almost@dots{}):
+
+@table @t
+@item #include <lightning.h>
+You already know about this.  It defines all of @lightning{}'s macros.
+
+@item static jit_state_t *_jit;
+You might wonder about what is @code{jit_state_t}.  It is a structure
+that stores jit code generation information.  The name @code{_jit} is
+special, because since multiple jit generators can run at the same
+time, you must either @r{#define _jit my_jit_state} or name it
+@code{_jit}.
+
+@item typedef int (*pifi)(int);
+Just a handy typedef for a pointer to a function that takes an
+@code{int} and returns another.
+
+@item jit_node_t  *in;
+Declares a variable to hold an identifier for a function argument. It
+is an opaque pointer, that will hold the return of a call to @code{arg}
+and be used as argument to @code{getarg}.
+
+@item pifi         incr;
+Declares a function pointer variable to a function that receives an
+@code{int} and returns an @code{int}.
+
+@item init_jit(argv[0]);
+You must call this function before creating a @code{jit_state_t}
+object. This function does global state initialization, and may need
+to detect CPU or Operating System features.  It receives a string
+argument that is later used to read symbols from a shared object using
+GNU binutils if disassembly was enabled at configure time. If no
+disassembly will be performed a NULL pointer can be used as argument.
+
+@item _jit = jit_new_state();
+This call initializes a @lightning{} jit state.
+
+@item jit_prolog();
+Ok, so we start generating code for our beloved function@dots{}
+
+@item in = jit_arg();
+@itemx jit_getarg(JIT_R0, in);
+We retrieve the first (and only) argument, an integer, and store it
+into the general-purpose register @code{R0}.
+
+@item jit_addi(JIT_R0, JIT_R0, 1);
+We add one to the content of the register.
+
+@item jit_retr(JIT_R0);
+This instruction generates a standard function epilog that returns
+the contents of the @code{R0} register.
+
+@item incr = jit_emit();
+This instruction is very important.  It actually translates the
+@lightning{} macros used before to machine code, flushes the generated
+code area out of the processor's instruction cache and return a
+pointer to the start of the code.
+
+@item jit_clear_state();
+This call cleanups any data not required for jit execution. Note
+that it must be called after any call to @code{jit_print} or
+@code{jit_address}, as this call destroy the @lightning{}
+intermediate representation.
+
+@item printf("%d + 1 = %d", 5, incr(5));
+Calling our function is this simple---it is not distinguishable from
+a normal C function call, the only difference being that @code{incr}
+is a variable.
+
+@item jit_destroy_state();
+Releases all memory associated with the jit context. It should be
+called after known the jit will no longer be called.
+
+@item finish_jit();
+This call cleanups any global state hold by @lightning{}, and is
+advisable to call it once jit code will no longer be generated.
+@end table
+
+@lightning{} abstracts two phases of dynamic code generation: selecting
+instructions that map the standard representation, and emitting binary
+code for these instructions.  The client program has the responsibility
+of describing the code to be generated using the standard @lightning{}
+instruction set.
+
+Let's examine the code generated for @code{incr} on the SPARC and x86_64
+architecture (on the right is the code that an assembly-language
+programmer would write):
+
+@table @b
+@item SPARC
+@example
+      save  %sp, -112, %sp
+      mov  %i0, %g2                 retl
+      inc  %g2                      inc %o0
+      mov  %g2, %i0
+      restore 
+      retl 
+      nop 
+@end example
+In this case, @lightning{} introduces overhead to create a register
+window (not knowing that the procedure is a leaf procedure) and to
+move the argument to the general purpose register @code{R0} (which
+maps to @code{%g2} on the SPARC).
+@end table
+
+@table @b
+@item x86_64
+@example
+    sub   $0x30,%rsp
+    mov   %rbp,(%rsp)
+    mov   %rsp,%rbp
+    sub   $0x18,%rsp
+    mov   %rdi,%rax            mov %rdi, %rax
+    add   $0x1,%rax            inc %rax
+    mov   %rbp,%rsp
+    mov   (%rsp),%rbp
+    add   $0x30,%rsp
+    retq                       retq
+@end example
+In this case, the main overhead is due to the function's prolog and
+epilog, and stack alignment after reserving stack space for word
+to/from float conversions or moving data from/to x87 to/from SSE.
+Note that besides allocating space to save callee saved registers,
+no registers are saved/restored because @lightning{} notices those
+registers are not modified. There is currently no logic to detect
+if it needs to allocate stack space for type conversions neither
+proper leaf function detection, but these are subject to change
+(FIXME).
+@end table
+
+@node printf
+@section A simple function call to @code{printf}
+
+Again, here is the code for the example:
+
+@example
+#include <stdio.h>
+#include <lightning.h>
+
+static jit_state_t *_jit;
+
+typedef void (*pvfi)(int);      @rem{/* Pointer to Void Function of Int */}
+
+int main(int argc, char *argv[])
+@{
+  pvfi          myFunction;             @rem{/* ptr to generated code */}
+  jit_node_t    *start, *end;           @rem{/* a couple of labels */}
+  jit_node_t    *in;                    @rem{/* to get the argument */}
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+  start = jit_note(__FILE__, __LINE__);
+  jit_prolog();
+  in = jit_arg();
+  jit_getarg(JIT_R1, in);
+  jit_prepare();
+  jit_pushargi((jit_word_t)"generated %d bytes\n");
+  jit_ellipsis();
+  jit_pushargr(JIT_R1);
+  jit_finishi(printf);
+  jit_ret();
+  jit_epilog();
+  end = jit_note(__FILE__, __LINE__);
+
+  myFunction = jit_emit();
+
+  @rem{/* call the generated code@comma{} passing its size as argument */}
+  myFunction((char*)jit_address(end) - (char*)jit_address(start));
+  jit_clear_state();
+
+  jit_disassemble();
+
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+@}
+@end example
+
+The function shows how many bytes were generated.  Most of the code
+is not very interesting, as it resembles very closely the program
+presented in @ref{incr, , A function which increments a number by one}.
+
+For this reason, we're going to concentrate on just a few statements.
+
+@table @t
+@item start = jit_note(__FILE__, __LINE__);
+@itemx @r{@dots{}}
+@itemx end = jit_note(__FILE__, __LINE__);
+These two instruction call the @code{jit_note} macro, which creates
+a note in the jit code; arguments to @code{jit_note} usually are a
+filename string and line number integer, but using NULL for the
+string argument is perfectly valid if only need to create a simple
+marker in the code.
+
+@item jit_ellipsis();
+@code{ellipsis} usually is only required if calling varargs functions
+with double arguments, but it is a good practice to properly describe
+the @r{@dots{}} in the call sequence.
+
+@item jit_pushargi((jit_word_t)"generated %d bytes\n");
+Note the use of the @code{(jit_word_t)} cast, that is used only
+to avoid a compiler warning, due to using a pointer where a
+wordsize integer type was expected.
+
+@item jit_prepare();
+@itemx @r{@dots{}}
+@itemx jit_finishi(printf);
+Once the arguments to @code{printf} have been pushed, what means
+moving them to stack or register arguments, the @code{printf}
+function is called and the stack cleaned.  Note how @lightning{}
+abstracts the differences between different architectures and
+ABI's -- the client program does not know how parameter passing
+works on the host architecture.
+
+@item jit_epilog();
+Usually it is not required to call @code{epilog}, but because it
+is implicitly called when noticing the end of a function, if the
+@code{end} variable was set with a @code{note} call after the
+@code{ret}, it would not consider the function epilog.
+
+@item myFunction((char*)jit_address(end) - (char*)jit_address(start));
+This calls the generate jit function passing as argument the offset
+difference from the @code{start} and @code{end} notes. The @code{address}
+call must be done after the @code{emit} call or either a fatal error
+will happen (if @lightning{} is built with assertions enable) or an
+undefined value will be returned.
+
+@item jit_clear_state();
+Note that @code{jit_clear_state} was called after executing jit in
+this example. It was done because it must be called after any call
+to @code{jit_address} or @code{jit_print}.
+
+@item jit_disassemble();
+@code{disassemble} will dump the generated code to standard output,
+unless @lightning{} was built with the disassembler disabled, in which
+case no output will be shown.
+@end table
+
+@node RPN calculator
+@section A more complex example, an RPN calculator
+
+We create a small stack-based RPN calculator which applies a series
+of operators to a given parameter and to other numeric operands.
+Unlike previous examples, the code generator is fully parameterized
+and is able to compile different formulas to different functions.
+Here is the code for the expression compiler; a sample usage will
+follow.
+
+Since @lightning{} does not provide push/pop instruction, this
+example uses a stack-allocated area to store the data.  Such an
+area can be allocated using the macro @code{allocai}, which
+receives the number of bytes to allocate and returns the offset
+from the frame pointer register @code{FP} to the base of the
+area.
+
+Usually, you will use the @code{ldxi} and @code{stxi} instruction
+to access stack-allocated variables.  However, it is possible to
+use operations such as @code{add} to compute the address of the
+variables, and pass the address around.
+
+@example
+#include <stdio.h>
+#include <lightning.h>
+
+typedef int (*pifi)(int);       @rem{/* Pointer to Int Function of Int */}
+
+static jit_state_t *_jit;
+
+void stack_push(int reg, int *sp)
+@{
+  jit_stxi_i (*sp, JIT_FP, reg);
+  *sp += sizeof (int);
+@}
+
+void stack_pop(int reg, int *sp)
+@{
+  *sp -= sizeof (int);
+  jit_ldxi_i (reg, JIT_FP, *sp);
+@}
+
+jit_node_t *compile_rpn(char *expr)
+@{
+  jit_node_t *in, *fn;
+  int stack_base, stack_ptr;
+
+  fn = jit_note(NULL, 0);
+  jit_prolog();
+  in = jit_arg();
+  stack_ptr = stack_base = jit_allocai (32 * sizeof (int));
+
+  jit_getarg_i(JIT_R2, in);
+
+  while (*expr) @{
+    char buf[32];
+    int n;
+    if (sscanf(expr, "%[0-9]%n", buf, &n)) @{
+      expr += n - 1;
+      stack_push(JIT_R0, &stack_ptr);
+      jit_movi(JIT_R0, atoi(buf));
+    @} else if (*expr == 'x') @{
+      stack_push(JIT_R0, &stack_ptr);
+      jit_movr(JIT_R0, JIT_R2);
+    @} else if (*expr == '+') @{
+      stack_pop(JIT_R1, &stack_ptr);
+      jit_addr(JIT_R0, JIT_R1, JIT_R0);
+    @} else if (*expr == '-') @{
+      stack_pop(JIT_R1, &stack_ptr);
+      jit_subr(JIT_R0, JIT_R1, JIT_R0);
+    @} else if (*expr == '*') @{
+      stack_pop(JIT_R1, &stack_ptr);
+      jit_mulr(JIT_R0, JIT_R1, JIT_R0);
+    @} else if (*expr == '/') @{
+      stack_pop(JIT_R1, &stack_ptr);
+      jit_divr(JIT_R0, JIT_R1, JIT_R0);
+    @} else @{
+      fprintf(stderr, "cannot compile: %s\n", expr);
+      abort();
+    @}
+    ++expr;
+  @}
+  jit_retr(JIT_R0);
+  jit_epilog();
+  return fn;
+@}
+@end example
+
+The principle on which the calculator is based is easy: the stack top
+is held in R0, while the remaining items of the stack are held in the
+memory area that we allocate with @code{allocai}.  Compiling a numeric
+operand or the argument @code{x} pushes the old stack top onto the
+stack and moves the operand into R0; compiling an operator pops the
+second operand off the stack into R1, and compiles the operation so
+that the result goes into R0, thus becoming the new stack top.
+
+This example allocates a fixed area for 32 @code{int}s.  This is not
+a problem when the function is a leaf like in this case; in a full-blown
+compiler you will want to analyze the input and determine the number
+of needed stack slots---a very simple example of register allocation.
+The area is then managed like a stack using @code{stack_push} and
+@code{stack_pop}.
+
+Source code for the client (which lies in the same source file) follows:
+
+@example
+int main(int argc, char *argv[])
+@{
+  jit_node_t *nc, *nf;
+  pifi c2f, f2c;
+  int i;
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+  nc = compile_rpn("32x9*5/+");
+  nf = compile_rpn("x32-5*9/");
+  (void)jit_emit();
+  c2f = (pifi)jit_address(nc);
+  f2c = (pifi)jit_address(nf);
+  jit_clear_state();
+
+  printf("\nC:");
+  for (i = 0; i <= 100; i += 10) printf("%3d ", i);
+  printf("\nF:");
+  for (i = 0; i <= 100; i += 10) printf("%3d ", c2f(i));
+  printf("\n");
+
+  printf("\nF:");
+  for (i = 32; i <= 212; i += 18) printf("%3d ", i);
+  printf("\nC:");
+  for (i = 32; i <= 212; i += 18) printf("%3d ", f2c(i));
+  printf("\n");
+
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+@}
+@end example
+
+The client displays a conversion table between Celsius and Fahrenheit
+degrees (both Celsius-to-Fahrenheit and Fahrenheit-to-Celsius). The
+formulas are, @math{F(c) = c*9/5+32} and @math{C(f) = (f-32)*5/9},
+respectively.
+
+Providing the formula as an argument to @code{compile_rpn} effectively
+parameterizes code generation, making it possible to use the same code
+to compile different functions; this is what makes dynamic code
+generation so powerful.
+
+@node Fibonacci
+@section Fibonacci numbers
+
+The code in this section calculates the Fibonacci sequence. That is
+modeled by the recurrence relation:
+@display
+     f(0) = 0
+     f(1) = f(2) = 1
+     f(n) = f(n-1) + f(n-2)
+@end display
+
+The purpose of this example is to introduce branches.  There are two
+kind of branches: backward branches and forward branches.  We'll
+present the calculation in a recursive and iterative form; the
+former only uses forward branches, while the latter uses both.
+
+@example
+#include <stdio.h>
+#include <lightning.h>
+
+static jit_state_t *_jit;
+
+typedef int (*pifi)(int);       @rem{/* Pointer to Int Function of Int */}
+
+int main(int argc, char *argv[])
+@{
+  pifi       fib;
+  jit_node_t *label;
+  jit_node_t *call;
+  jit_node_t *in;                 @rem{/* offset of the argument */}
+  jit_node_t *ref;                @rem{/* to patch the forward reference */}
+  jit_node_t *zero;               @rem{/* to patch the forward reference */}
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+  label = jit_label();
+        jit_prolog   ();
+  in =  jit_arg      ();
+        jit_getarg   (JIT_V0, in);              @rem{/* R0 = n */}
+ zero = jit_beqi     (JIT_R0, 0);
+        jit_movr     (JIT_V0, JIT_R0);          /* V0 = R0 */
+        jit_movi     (JIT_R0, 1);
+  ref = jit_blei     (JIT_V0, 2);
+        jit_subi     (JIT_V1, JIT_V0, 1);       @rem{/* V1 = n-1 */}
+        jit_subi     (JIT_V2, JIT_V0, 2);       @rem{/* V2 = n-2 */}
+        jit_prepare();
+          jit_pushargr(JIT_V1);
+        call = jit_finishi(NULL);
+        jit_patch_at(call, label);
+        jit_retval(JIT_V1);                     @rem{/* V1 = fib(n-1) */}
+        jit_prepare();
+          jit_pushargr(JIT_V2);
+        call = jit_finishi(NULL);
+        jit_patch_at(call, label);
+        jit_retval(JIT_R0);                     @rem{/* R0 = fib(n-2) */}
+        jit_addr(JIT_R0, JIT_R0, JIT_V1);       @rem{/* R0 = R0 + V1 */}
+
+  jit_patch(ref);                               @rem{/* patch jump */}
+  jit_patch(zero);                              @rem{/* patch jump */}
+        jit_retr(JIT_R0);
+
+  @rem{/* call the generated code@comma{} passing 32 as an argument */}
+  fib = jit_emit();
+  jit_clear_state();
+  printf("fib(%d) = %d\n", 32, fib(32));
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+@}
+@end example
+
+As said above, this is the first example of dynamically compiling
+branches.  Branch instructions have two operands containing the
+values to be compared, and return a @code{jit_note_t *} object
+to be patched.
+
+Because labels final address are only known after calling @code{emit},
+it is required to call @code{patch} or @code{patch_at}, what does
+tell @lightning{} that the target to patch is actually a pointer to
+a @code{jit_node_t *} object, otherwise, it would assume that is
+a pointer to a C function. Note that conditional branches do not
+receive a label argument, so they must be patched.
+
+You need to call @code{patch_at} on the return of value @code{calli},
+@code{finishi}, and @code{calli} if it is actually referencing a label
+in the jit code. All branch instructions do not receive a label
+argument. Note that @code{movi} is an special case, and patching it
+is usually done to get the final address of a label, usually to later
+call @code{jmpr}.
+
+Now, here is the iterative version:
+
+@example
+#include <stdio.h>
+#include <lightning.h>
+
+static jit_state_t *_jit;
+
+typedef int (*pifi)(int);       @rem{/* Pointer to Int Function of Int */}
+
+int main(int argc, char *argv[])
+@{
+  pifi       fib;
+  jit_node_t *in;               @rem{/* offset of the argument */}
+  jit_node_t *ref;              @rem{/* to patch the forward reference */}
+  jit_node_t *zero;             @rem{/* to patch the forward reference */}
+  jit_node_t *jump;             @rem{/* jump to start of loop */}
+  jit_node_t *loop;             @rem{/* start of the loop */}
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+        jit_prolog   ();
+  in =  jit_arg      ();
+        jit_getarg   (JIT_R0, in);              @rem{/* R0 = n */}
+ zero = jit_beqi     (JIT_R0, 0);
+        jit_movr     (JIT_R1, JIT_R0);
+        jit_movi     (JIT_R0, 1);
+  ref = jit_blti     (JIT_R1, 2);
+        jit_subi     (JIT_R2, JIT_R2, 2);
+        jit_movr     (JIT_R1, JIT_R0);
+
+  loop= jit_label();
+        jit_subi     (JIT_R2, JIT_R2, 1);       @rem{/* decr. counter */}
+        jit_movr     (JIT_V0, JIT_R0);          /* V0 = R0 */
+        jit_addr     (JIT_R0, JIT_R0, JIT_R1);  /* R0 = R0 + R1 */
+        jit_movr     (JIT_R1, JIT_V0);          /* R1 = V0 */
+  jump= jit_bnei     (JIT_R2, 0);               /* if (R2) goto loop; */
+  jit_patch_at(jump, loop);
+
+  jit_patch(ref);                               @rem{/* patch forward jump */}
+  jit_patch(zero);                              @rem{/* patch forward jump */}
+        jit_retr     (JIT_R0);
+
+  @rem{/* call the generated code@comma{} passing 36 as an argument */}
+  fib = jit_emit();
+  jit_clear_state();
+  printf("fib(%d) = %d\n", 36, fib(36));
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+@}
+@end example
+
+This code calculates the recurrence relation using iteration (a
+@code{for} loop in high-level languages).  There are no function
+calls anymore: instead, there is a backward jump (the @code{bnei} at
+the end of the loop).
+
+Note that the program must remember the address for backward jumps;
+for forward jumps it is only required to remember the jump code,
+and call @code{patch} for the implicit label.
+
+@node Reentrancy
+@chapter Re-entrant usage of @lightning{}
+
+@lightning{} uses the special @code{_jit} identifier. To be able
+to be able to use multiple jit generation states at the same
+time, it is required to used code similar to:
+
+@example
+    struct jit_state lightning;
+    #define lightning _jit
+@end example
+
+This will cause the symbol defined to @code{_jit} to be passed as
+the first argument to the underlying @lightning{} implementation,
+that is usually a function with an @code{_} (underscode) prefix
+and with an argument named @code{_jit}, in the pattern:
+
+@example
+    static void _jit_mnemonic(jit_state_t *, jit_gpr_t, jit_gpr_t);
+    #define jit_mnemonic(u, v) _jit_mnemonic(_jit, u, v);
+@end example
+
+The reason for this is to use the same syntax as the initial lightning
+implementation and to avoid needing the user to keep adding an extra
+argument to every call, as multiple jit states generating code in
+paralell should be very uncommon.
+
+@section Registers
+@chapter Accessing the whole register file
+
+As mentioned earlier in this chapter, all @lightning{} back-ends are
+guaranteed to have at least six general-purpose integer registers and
+six floating-point registers, but many back-ends will have more.
+
+To access the entire register files, you can use the
+@code{JIT_R}, @code{JIT_V} and @code{JIT_F} macros.  They
+accept a parameter that identifies the register number, which
+must be strictly less than @code{JIT_R_NUM}, @code{JIT_V_NUM}
+and @code{JIT_F_NUM} respectively; the number need not be
+constant.  Of course, expressions like @code{JIT_R0} and
+@code{JIT_R(0)} denote the same register, and likewise for
+integer callee-saved, or floating-point, registers.
+
+@node Customizations
+@chapter Customizations
+
+Frequently it is desirable to have more control over how code is
+generated or how memory is used during jit generation or execution.
+
+@section Memory functions
+To aid in complete control of memory allocation and deallocation
+@lightning{} provides wrappers that default to standard @code{malloc},
+@code{realloc} and @code{free}. These are loosely based on the
+GNU GMP counterparts, with the difference that they use the same
+prototype of the system allocation functions, that is, no @code{size}
+for @code{free} or @code{old_size} for @code{realloc}.
+
+@deftypefun void jit_set_memory_functions (@* void *(*@var{alloc_func_ptr}) (size_t), @* void *(*@var{realloc_func_ptr}) (void *, size_t), @* void (*@var{free_func_ptr}) (void *))
+@lightning{} guarantees that memory is only allocated or released
+using these wrapped functions, but you must note that if lightning
+was linked to GNU binutils, malloc is probably will be called multiple
+times from there when initializing the disassembler.
+
+Because @code{init_jit} may call memory functions, if you need to call
+@code{jit_set_memory_functions}, it must be called before @code{init_jit},
+otherwise, when calling @code{finish_jit}, a pointer allocated with the
+previous or default wrappers will be passed.
+@end deftypefun
+
+@deftypefun void jit_get_memory_functions (@* void *(**@var{alloc_func_ptr}) (size_t), @* void *(**@var{realloc_func_ptr}) (void *, size_t), @* void (**@var{free_func_ptr}) (void *))
+Get the current memory allocation function. Also, unlike the GNU GMP
+counterpart, it is an error to pass @code{NULL} pointers as arguments.
+@end deftypefun
+
+@section Alternate code buffer
+To instruct @lightning{} to use an alternate code buffer it is required
+to call @code{jit_realize} before @code{jit_emit}, and then query states
+and customize as appropriate.
+
+@deftypefun void jit_realize ()
+Must be called once, before @code{jit_emit}, to instruct @lightning{}
+that no other @code{jit_xyz} call will be made.
+@end deftypefun
+
+@deftypefun jit_pointer_t jit_get_code (jit_word_t *@var{code_size})
+Returns NULL or the previous value set with @code{jit_set_code}, and
+sets the @var{code_size} argument to an appropriate value.
+If @code{jit_get_code} is called before @code{jit_emit}, the
+@var{code_size} argument is set to the expected amount of bytes
+required to generate code.
+If @code{jit_get_code} is called after @code{jit_emit}, the
+@var{code_size} argument is set to the exact amount of bytes used
+by the code.
+@end deftypefun
+
+@deftypefun void jit_set_code (jit_ponter_t @var{code}, jit_word_t @var{size})
+Instructs @lightning{} to output to the @var{code} argument and
+use @var{size} as a guard to not write to invalid memory. If during
+@code{jit_emit} @lightning{} finds out that the code would not fit
+in @var{size} bytes, it halts code emit and returns @code{NULL}.
+@end deftypefun
+
+A simple example of a loop using an alternate buffer is:
+
+@example
+  jit_uint8_t   *code;
+  int           *(func)(int);      @rem{/* function pointer */}
+  jit_word_t     code_size;
+  jit_word_t     real_code_size;
+  @rem{...}
+  jit_realize();                   @rem{/* ready to generate code */}
+  jit_get_code(&code_size);        @rem{/* get expected code size */}
+  code_size = (code_size + 4095) & -4096;
+  do (;;) @{
+    code = mmap(NULL, code_size, PROT_EXEC | PROT_READ | PROT_WRITE,
+                MAP_PRIVATE | MAP_ANON, -1, 0);
+    jit_set_code(code, code_size);
+    if ((func = jit_emit()) == NULL) @{
+      munmap(code, code_size);
+      code_size += 4096;
+    @}
+  @} while (func == NULL);
+  jit_get_code(&real_code_size);   @rem{/* query exact size of the code */}
+@end example
+
+The first call to @code{jit_get_code} should return @code{NULL} and set
+the @code{code_size} argument to the expected amount of bytes required
+to emit code.
+The second call to @code{jit_get_code} is after a successful call to
+@code{jit_emit}, and will return the value previously set with
+@code{jit_set_code} and set the @code{real_code_size} argument to the
+exact amount of bytes used to emit the code.
+
+@section Alternate data buffer
+Sometimes it may be desirable to customize how, or to prevent
+@lightning{} from using an extra buffer for constants or debug
+annotation. Usually when also using an alternate code buffer.
+
+@deftypefun jit_pointer_t jit_get_data (jit_word_t *@var{data_size}, jit_word_t *@var{note_size})
+Returns @code{NULL} or the previous value set with @code{jit_set_data},
+and sets the @var{data_size} argument to how many bytes are required
+for the constants data buffer, and @var{note_size} to how many bytes
+are required to store the debug note information.
+Note that it always preallocate one debug note entry even if
+@code{jit_name} or @code{jit_note} are never called, but will return
+zero in the @var{data_size} argument if no constant is required;
+constants are only used for the @code{float} and @code{double} operations
+that have an immediate argument, and not in all @lightning{} ports.
+@end deftypefun
+
+@deftypefun void jit_set_data (jit_pointer_t @var{data}, jit_word_t @var{size}, jit_word_t @var{flags})
+
+@var{data} can be NULL if disabling constants and annotations, otherwise,
+a valid pointer must be passed. An assertion is done that the data will
+fit in @var{size} bytes (but that is a noop if @lightning{} was built
+with @code{-DNDEBUG}).
+
+@var{size} tells the space in bytes available in @var{data}.
+
+@var{flags} can be zero to tell to just use the alternate data buffer,
+or a composition of @code{JIT_DISABLE_DATA} and @code{JIT_DISABLE_NOTE}
+
+@table @t
+@item JIT_DISABLE_DATA
+@cindex JIT_DISABLE_DATA
+Instructs @lightning{} to not use a constant table, but to use an
+alternate method to synthesize those, usually with a larger code
+sequence using stack space to transfer the value from a GPR to a
+FPR register.
+
+@item JIT_DISABLE_NOTE
+@cindex JIT_DISABLE_NOTE
+Instructs @lightning{} to not store file or function name, and
+line numbers in the constant buffer.
+@end table
+@end deftypefun
+
+A simple example of a preventing usage of a data buffer is:
+
+@example
+  @rem{...}
+  jit_realize();                        @rem{/* ready to generate code */}
+  jit_get_data(NULL, NULL);
+  jit_set_data(NULL, 0, JIT_DISABLE_DATA | JIT_DISABLE_NOTE);
+  @rem{...}
+@end example
+
+Or to only use a data buffer, if required:
+
+@example
+  jit_uint8_t   *data;
+  jit_word_t     data_size;
+  @rem{...}
+  jit_realize();                        @rem{/* ready to generate code */}
+  jit_get_data(&data_size, NULL);
+  if (data_size)
+    data = malloc(data_size);
+  else
+    data = NULL;
+  jit_set_data(data, data_size, JIT_DISABLE_NOTE);
+  @rem{...}
+  if (data)
+    free(data);
+  @rem{...}
+@end example
+
+@node Acknowledgements
+@chapter Acknowledgements
+
+As far as I know, the first general-purpose portable dynamic code
+generator is @sc{dcg}, by Dawson R.@: Engler and T.@: A.@: Proebsting.
+Further work by Dawson R. Engler resulted in the @sc{vcode} system;
+unlike @sc{dcg}, @sc{vcode} used no intermediate representation and
+directly inspired @lightning{}.
+
+Thanks go to Ian Piumarta, who kindly accepted to release his own
+program @sc{ccg} under the GNU General Public License, thereby allowing
+@lightning{} to use the run-time assemblers he had wrote for @sc{ccg}.
+@sc{ccg} provides a way of dynamically assemble programs written in the
+underlying architecture's assembly language.  So it is not portable,
+yet very interesting.
+
+I also thank Steve Byrne for writing GNU Smalltalk, since @lightning{}
+was first developed as a tool to be used in GNU Smalltalk's dynamic
+translator from bytecodes to native code.
diff --git a/deps/lightning/doc/fact.c b/deps/lightning/doc/fact.c
new file mode 100644 (file)
index 0000000..375905b
--- /dev/null
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <lightning.h>
+
+static jit_state_t *_jit;
+
+typedef long (*pwfw_t)(long);          /* Pointer to Long Function of Long */
+
+int main(int argc, char *argv[])
+{
+    pwfw_t      factorial;
+    long        arg;
+    jit_node_t *ac;                    /* Accumulator */
+    jit_node_t *in;                    /* Argument */
+    jit_node_t *call;
+    jit_node_t *fact;
+    jit_node_t *jump;
+    jit_node_t *fact_entry;
+    jit_node_t *fact_out;
+
+    init_jit(argv[0]);
+    _jit = jit_new_state();
+
+    /* declare a forward label */
+    fact = jit_forward();
+
+    jit_prolog();                      /* Entry point of the factorial function */
+    in = jit_arg();                    /* Receive an integer argument */
+    jit_getarg(JIT_R0, in);            /* Move argument to RO */
+    jit_prepare();
+    jit_pushargi(1);                   /* This is the accumulator */
+    jit_pushargr(JIT_R0);              /* This is the argument */
+    call = jit_finishi(NULL);          /* Call the tail call optimized function */
+    jit_patch_at(call, fact);          /* Patch call to forward defined function */
+    /* the above could have been written as:
+     *         jit_patch_at(jit_finishi(NULL), fact);
+     */
+    jit_retval(JIT_R0);                        /* Fetch the result */
+    jit_retr(JIT_R0);                  /* Return it */
+    jit_epilog();                      /* Epilog *before* label before prolog */
+
+    /* define the forward label */
+    jit_link(fact);                    /* Entry point of the helper function */
+    jit_prolog();
+    jit_frame(16);                     /* Reserve 16 bytes in the stack */
+    fact_entry = jit_label();          /* This is the tail call entry point */
+    ac = jit_arg();                    /* The accumulator is the first argument */
+    in = jit_arg();                    /* The factorial argument */
+    jit_getarg(JIT_R0, ac);            /* Move the accumulator to R0 */
+    jit_getarg(JIT_R1, in);            /* Move the argument to R1 */
+    fact_out = jit_blei(JIT_R1, 1);    /* Done if argument is one or less */
+    jit_mulr(JIT_R0, JIT_R0, JIT_R1);  /* accumulator *= argument */
+    jit_putargr(JIT_R0, ac);           /* Update the accumulator */
+    jit_subi(JIT_R1, JIT_R1, 1);       /* argument -= 1 */
+    jit_putargr(JIT_R1, in);           /* Update the argument */
+    jump = jit_jmpi();
+    jit_patch_at(jump, fact_entry);    /* Tail Call Optimize it! */
+    jit_patch(fact_out);
+    jit_retr(JIT_R0);                  /* Return the accumulator */
+
+    factorial = jit_emit();
+    /* no need to query information about resolved addresses */
+    jit_clear_state();
+
+    if (argc == 2)
+       arg = atoi(argv[1]);
+    else
+       arg = 5;
+
+    /* call the generated code */
+    printf("factorial(%ld) = %ld\n", arg, factorial(arg));
+    /* release all memory associated with the _jit identifier */
+    jit_destroy_state();
+    finish_jit();
+    return 0;
+}
diff --git a/deps/lightning/doc/ifib.c b/deps/lightning/doc/ifib.c
new file mode 100644 (file)
index 0000000..745c80b
--- /dev/null
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <lightning.h>
+
+static jit_state_t *_jit;
+
+typedef int (*pifi)(int);       /* Pointer to Int Function of Int */
+
+int main(int argc, char *argv[])
+{
+  pifi       fib;
+  jit_node_t *in;               /* offset of the argument */
+  jit_node_t *ref;              /* to patch the forward reference */
+  jit_node_t *zero;             /* to patch the forward reference */
+  jit_node_t *jump;             /* jump to start of loop */
+  jit_node_t *loop;             /* start of the loop */
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+        jit_prolog   ();
+  in =  jit_arg      ();
+        jit_getarg   (JIT_R0, in);              /* R0 = n */
+ zero = jit_beqi     (JIT_R0, 0);
+        jit_movr     (JIT_R1, JIT_R0);
+        jit_movi     (JIT_R0, 1);
+  ref = jit_blei     (JIT_R1, 2);
+        jit_subi     (JIT_R2, JIT_R1, 2);
+        jit_movr     (JIT_R1, JIT_R0);
+
+  loop= jit_label();
+        jit_subi     (JIT_R2, JIT_R2, 1);       /* decr. counter */
+        jit_movr     (JIT_V0, JIT_R0);          /* V0 = R0 */
+        jit_addr     (JIT_R0, JIT_R0, JIT_R1);  /* R0 = R0 + R1 */
+        jit_movr     (JIT_R1, JIT_V0);          /* R1 = V0 */
+  jump= jit_bnei     (JIT_R2, 0);               /* if (R2) goto loop; */
+  jit_patch_at(jump, loop);
+
+  jit_patch(ref);                               /* patch forward jump */
+  jit_patch(zero);                              /* patch forward jump */
+        jit_retr     (JIT_R0);
+
+  /* call the generated code, passing 36 as an argument */
+  fib = jit_emit();
+  jit_clear_state();
+  printf("fib(%d) = %d\n", 36, fib(36));
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+}
diff --git a/deps/lightning/doc/incr.c b/deps/lightning/doc/incr.c
new file mode 100644 (file)
index 0000000..88859a8
--- /dev/null
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <lightning.h>
+
+static jit_state_t *_jit;
+
+typedef int (*pifi)(int);    /* Pointer to Int Function of Int */
+
+int main(int argc, char *argv[])
+{
+  jit_node_t  *in;
+  pifi         incr;
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+  jit_prolog();                    /* @t{     prolog             } */
+  in = jit_arg();                  /* @t{     in = arg           } */
+  jit_getarg(JIT_R0, in);          /* @t{     getarg R0          } */
+  jit_addi(JIT_R0, JIT_R0, 1);     /* @t{     addi   R0\, R0\, 1 } */
+  jit_retr(JIT_R0);                /* @t{     retr   R0          } */
+
+  incr = jit_emit();
+  jit_clear_state();
+
+  /* call the generated code\, passing 5 as an argument */
+  printf("%d + 1 = %d\n", 5, incr(5));
+
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+}
diff --git a/deps/lightning/doc/lightning.texi b/deps/lightning/doc/lightning.texi
new file mode 100644 (file)
index 0000000..c7d8f98
--- /dev/null
@@ -0,0 +1,78 @@
+\input texinfo.tex  @c -*- texinfo -*-
+@c %**start of header (This is for running Texinfo on a region.)
+
+@setfilename lightning.info
+
+@set TITLE       Using @sc{gnu} @i{lightning}
+@set TOPIC       installing and using
+
+@settitle @value{TITLE}
+
+@c ---------------------------------------------------------------------
+@c Common macros
+@c ---------------------------------------------------------------------
+
+@macro bulletize{a}
+@item
+\a\
+@end macro
+
+@macro rem{a}
+@r{@i{\a\}}
+@end macro
+
+@macro gnu{}
+@sc{gnu}
+@end macro
+
+@macro lightning{}
+@gnu{} @i{lightning}
+@end macro
+
+@c ---------------------------------------------------------------------
+@c Macros for Texinfo 3.1/4.0 compatibility
+@c ---------------------------------------------------------------------
+
+@c @hlink (macro), @url and @email are used instead of @uref for Texinfo 3.1
+@c compatibility
+@macro hlink{url, link}
+\link\ (\url\)
+@end macro
+
+@c ifhtml can only be true in Texinfo 4.0, which has uref
+@ifhtml
+@unmacro hlink
+
+@macro hlink{url, link}
+@uref{\url\, \link\}
+@end macro
+
+@macro email{mail}
+@uref{mailto:\mail\, , \mail\}
+@end macro
+
+@macro url{url}
+@uref{\url\}
+@end macro
+@end ifhtml
+
+@c ---------------------------------------------------------------------
+@c References to the other half of the manual
+@c ---------------------------------------------------------------------
+
+@macro usingref{node, name}
+@ref{\node\, , \name\}
+@end macro
+
+@c ---------------------------------------------------------------------
+@c End of macro section
+@c ---------------------------------------------------------------------
+
+@include version.texi
+@include body.texi
+
+@c %**end of header (This is for running Texinfo on a region.)
+
+@c ***********************************************************************
+
+@bye
diff --git a/deps/lightning/doc/printf.c b/deps/lightning/doc/printf.c
new file mode 100644 (file)
index 0000000..b36eec0
--- /dev/null
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <lightning.h>
+
+static jit_state_t *_jit;
+
+typedef void (*pvfi)(int);    /* Pointer to Void Function of Int */
+
+int main(int argc, char *argv[])
+{
+  pvfi          myFunction;             /* ptr to generated code */
+  jit_node_t    *start, *end;           /* a couple of labels */
+  jit_node_t    *in;                    /* to get the argument */
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+  start = jit_note(__FILE__, __LINE__);
+  jit_prolog();
+  in = jit_arg();
+  jit_getarg(JIT_R1, in);
+  jit_prepare();
+  jit_pushargi((jit_word_t)"generated %d bytes\n");
+  jit_ellipsis();
+  jit_pushargr(JIT_R1);
+  jit_finishi(printf);
+  jit_ret();
+  jit_epilog();
+  end = jit_note(__FILE__, __LINE__);
+
+  myFunction = jit_emit();
+
+  /* call the generated code, passing its size as argument */
+  myFunction((char*)jit_address(end) - (char*)jit_address(start));
+  jit_clear_state();
+
+  jit_disassemble();
+
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+}
diff --git a/deps/lightning/doc/rfib.c b/deps/lightning/doc/rfib.c
new file mode 100644 (file)
index 0000000..f14da42
--- /dev/null
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <lightning.h>
+
+static jit_state_t *_jit;
+
+typedef int (*pifi)(int);       /* Pointer to Int Function of Int */
+
+int main(int argc, char *argv[])
+{
+  pifi       fib;
+  jit_node_t *label;
+  jit_node_t *call;
+  jit_node_t *in;                 /* offset of the argument */
+  jit_node_t *ref;                /* to patch the forward reference */
+  jit_node_t *zero;             /* to patch the forward reference */
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+  label = jit_label();
+        jit_prolog   ();
+  in =  jit_arg      ();
+        jit_getarg   (JIT_R0, in);              /* R0 = n */
+ zero = jit_beqi     (JIT_R0, 0);
+        jit_movr     (JIT_V0, JIT_R0);          /* V0 = R0 */
+        jit_movi     (JIT_R0, 1);
+  ref = jit_blei     (JIT_V0, 2);
+        jit_subi     (JIT_V1, JIT_V0, 1);       /* V1 = n-1 */
+        jit_subi     (JIT_V2, JIT_V0, 2);       /* V2 = n-2 */
+        jit_prepare();
+          jit_pushargr(JIT_V1);
+        call = jit_finishi(NULL);
+        jit_patch_at(call, label);
+        jit_retval(JIT_V1);                     /* V1 = fib(n-1) */
+        jit_prepare();
+          jit_pushargr(JIT_V2);
+        call = jit_finishi(NULL);
+        jit_patch_at(call, label);
+        jit_retval(JIT_R0);                     /* R0 = fib(n-2) */
+        jit_addr(JIT_R0, JIT_R0, JIT_V1);       /* R0 = R0 + V1 */
+
+  jit_patch(ref);                               /* patch jump */
+  jit_patch(zero);                              /* patch jump */
+        jit_retr(JIT_R0);
+
+  /* call the generated code, passing 32 as an argument */
+  fib = jit_emit();
+  jit_clear_state();
+  printf("fib(%d) = %d\n", 32, fib(32));
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+}
diff --git a/deps/lightning/doc/rpn.c b/deps/lightning/doc/rpn.c
new file mode 100644 (file)
index 0000000..8131484
--- /dev/null
@@ -0,0 +1,96 @@
+#include <stdio.h>
+#include <lightning.h>
+
+typedef int (*pifi)(int);       /* Pointer to Int Function of Int */
+
+static jit_state_t *_jit;
+
+void stack_push(int reg, int *sp)
+{
+  jit_stxi_i (*sp, JIT_FP, reg);
+  *sp += sizeof (int);
+}
+
+void stack_pop(int reg, int *sp)
+{
+  *sp -= sizeof (int);
+  jit_ldxi_i (reg, JIT_FP, *sp);
+}
+
+jit_node_t *compile_rpn(char *expr)
+{
+  jit_node_t *in, *fn;
+  int stack_base, stack_ptr;
+
+  fn = jit_note(NULL, 0);
+  jit_prolog();
+  in = jit_arg();
+  stack_ptr = stack_base = jit_allocai (32 * sizeof (int));
+
+  jit_getarg_i(JIT_R2, in);
+
+  while (*expr) {
+    char buf[32];
+    int n;
+    if (sscanf(expr, "%[0-9]%n", buf, &n)) {
+      expr += n - 1;
+      stack_push(JIT_R0, &stack_ptr);
+      jit_movi(JIT_R0, atoi(buf));
+    } else if (*expr == 'x') {
+      stack_push(JIT_R0, &stack_ptr);
+      jit_movr(JIT_R0, JIT_R2);
+    } else if (*expr == '+') {
+      stack_pop(JIT_R1, &stack_ptr);
+      jit_addr(JIT_R0, JIT_R1, JIT_R0);
+    } else if (*expr == '-') {
+      stack_pop(JIT_R1, &stack_ptr);
+      jit_subr(JIT_R0, JIT_R1, JIT_R0);
+    } else if (*expr == '*') {
+      stack_pop(JIT_R1, &stack_ptr);
+      jit_mulr(JIT_R0, JIT_R1, JIT_R0);
+    } else if (*expr == '/') {
+      stack_pop(JIT_R1, &stack_ptr);
+      jit_divr(JIT_R0, JIT_R1, JIT_R0);
+    } else {
+      fprintf(stderr, "cannot compile: %s\n", expr);
+      abort();
+    }
+    ++expr;
+  }
+  jit_retr(JIT_R0);
+  jit_epilog();
+  return fn;
+}
+
+int main(int argc, char *argv[])
+{
+  jit_node_t *nc, *nf;
+  pifi c2f, f2c;
+  int i;
+
+  init_jit(argv[0]);
+  _jit = jit_new_state();
+
+  nc = compile_rpn("32x9*5/+");
+  nf = compile_rpn("x32-5*9/");
+  (void)jit_emit();
+  c2f = (pifi)jit_address(nc);
+  f2c = (pifi)jit_address(nf);
+  jit_clear_state();
+
+  printf("\nC:");
+  for (i = 0; i <= 100; i += 10) printf("%3d ", i);
+  printf("\nF:");
+  for (i = 0; i <= 100; i += 10) printf("%3d ", c2f(i));
+  printf("\n");
+
+  printf("\nF:");
+  for (i = 32; i <= 212; i += 18) printf("%3d ", i);
+  printf("\nC:");
+  for (i = 32; i <= 212; i += 18) printf("%3d ", f2c(i));
+  printf("\n");
+
+  jit_destroy_state();
+  finish_jit();
+  return 0;
+}
diff --git a/deps/lightning/doc/version.texi b/deps/lightning/doc/version.texi
new file mode 100644 (file)
index 0000000..b4a0c22
--- /dev/null
@@ -0,0 +1,4 @@
+@set UPDATED 3 October 2017
+@set UPDATED-MONTH October 2017
+@set EDITION 2.1.3
+@set VERSION 2.1.3
diff --git a/deps/lightning/include/Makefile.am b/deps/lightning/include/Makefile.am
new file mode 100644 (file)
index 0000000..8f91594
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# Copyright 2000, 2001, 2002, 2012-2019 Free Software Foundation, Inc.
+#
+# This file is part of GNU lightning.
+#
+# GNU lightning is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU lightning is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+#
+
+SUBDIRS =              \
+       lightning
+
+nodist_include_HEADERS = lightning.h
diff --git a/deps/lightning/include/lightning.h b/deps/lightning/include/lightning.h
new file mode 100644 (file)
index 0000000..4c7cac0
--- /dev/null
@@ -0,0 +1,1112 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _lightning_h
+#define _lightning_h
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#if defined(__hpux) && defined(__hppa__)
+#  include <machine/param.h>
+#endif
+#if defined(__alpha__) && defined(__osf__)
+#  include <machine/endian.h>
+#endif
+
+#ifndef __WORDSIZE
+#  if defined(WORDSIZE)                                /* ppc darwin */
+#    define __WORDSIZE         WORDSIZE
+#  elif defined(__SIZEOF_POINTER__)            /* ppc aix */
+#    define __WORDSIZE         (__SIZEOF_POINTER__ << 3)
+#  elif defined(_ILP32)                                /* hppa hp-ux */
+#    define __WORDSIZE         32
+#  elif defined(_LP64)                         /* ia64 hp-ux (with cc +DD64) */
+#    define __WORDSIZE         64
+#  elif defined(_MIPS_SZPTR)                   /* mips irix */
+#    if _MIPS_SZPTR == 32
+#      define __WORDSIZE       32
+#    else
+#      define __WORDSIZE       64
+#    endif
+#  else                                                /* From FreeBSD 9.1 stdint.h */
+#    if defined(UINTPTR_MAX) && defined(UINT64_MAX) && \
+       (UINTPTR_MAX == UINT64_MAX)
+#      define __WORDSIZE       64
+#    else
+#      define __WORDSIZE       32
+#    endif
+#  endif
+#endif
+#ifndef __LITTLE_ENDIAN
+#  if defined(LITTLE_ENDIAN)                   /* ppc darwin */
+#    define __LITTLE_ENDIAN    LITTLE_ENDIAN
+#  elif defined(__ORDER_LITTLE_ENDIAN__)       /* ppc aix */
+#    define __LITTLE_ENDIAN    __ORDER_LITTLE_ENDIAN__
+#  else
+#    define __LITTLE_ENDIAN    1234
+#  endif
+#endif
+#ifndef __BIG_ENDIAN
+#  if defined(BIG_ENDIAN)                      /* ppc darwin */
+#    define __BIG_ENDIAN       BIG_ENDIAN
+#  elif defined(__ORDER_BIG_ENDIAN__)          /* ppc aix */
+#    define __BIG_ENDIAN       __ORDER_BIG_ENDIAN__
+#  else
+#    define __BIG_ENDIAN       4321
+#  endif
+#endif
+#ifndef __BYTE_ORDER
+#  if defined(BYTE_ORDER)                      /* ppc darwin */
+#    define __BYTE_ORDER       BYTE_ORDER
+#  elif defined(__BYTE_ORDER__)                        /* ppc aix */
+#    define __BYTE_ORDER       __BYTE_ORDER__
+#  elif defined(_BIG_ENDIAN)                   /* hppa hp-ux */
+#    define __BYTE_ORDER       __BIG_ENDIAN
+#  elif defined(__BIG_ENDIAN__)                        /* ia64 hp-ux */
+#    define __BYTE_ORDER       __BIG_ENDIAN
+#  elif defined(__i386__)                      /* 32 bit x86 solaris */
+#    define __BYTE_ORDER       __LITTLE_ENDIAN
+#  elif defined(__x86_64__)                    /* 64 bit x86 solaris */
+#    define __BYTE_ORDER       __LITTLE_ENDIAN
+#  elif defined(__MIPSEB)                      /* mips irix */
+#    define __BYTE_ORDER       __BIG_ENDIAN
+#  else
+#    error cannot figure __BYTE_ORDER
+#  endif
+#endif
+
+typedef signed char            jit_int8_t;
+typedef unsigned char          jit_uint8_t;
+typedef signed short           jit_int16_t;
+typedef unsigned short         jit_uint16_t;
+typedef signed int             jit_int32_t;
+typedef unsigned int           jit_uint32_t;
+#if __WORDSIZE == 32
+typedef signed long long       jit_int64_t;
+typedef unsigned long long     jit_uint64_t;
+typedef jit_int32_t            jit_word_t;
+typedef jit_uint32_t           jit_uword_t;
+#elif (_WIN32 && !__CYGWIN__)
+typedef signed long long       jit_int64_t;
+typedef unsigned long long     jit_uint64_t;
+typedef jit_int64_t            jit_word_t;
+typedef jit_uint64_t           jit_uword_t;
+#else
+typedef signed long            jit_int64_t;
+typedef unsigned long          jit_uint64_t;
+typedef jit_int64_t            jit_word_t;
+typedef jit_uint64_t           jit_uword_t;
+#endif
+typedef float                  jit_float32_t;
+typedef double                 jit_float64_t;
+typedef void*                  jit_pointer_t;
+typedef jit_int32_t            jit_bool_t;
+typedef jit_int32_t            jit_gpr_t;
+typedef jit_int32_t            jit_fpr_t;
+
+#if defined(__i386__) || defined(__x86_64__)
+#  include <lightning/jit_x86.h>
+#elif defined(__mips__)
+#  include <lightning/jit_mips.h>
+#elif defined(__arm__)
+#  include <lightning/jit_arm.h>
+#elif defined(__powerpc__)
+#  include <lightning/jit_ppc.h>
+#elif defined(__sparc__)
+#  include <lightning/jit_sparc.h>
+#elif defined(__ia64__)
+#  include <lightning/jit_ia64.h>
+#elif defined(__hppa__)
+#  include <lightning/jit_hppa.h>
+#elif defined(__aarch64__)
+#  include <lightning/jit_aarch64.h>
+#elif defined(__s390__) || defined(__s390x__)
+#  include <lightning/jit_s390.h>
+#elif defined(__alpha__)
+#  include <lightning/jit_alpha.h>
+#elif defined(__riscv)
+#  include <lightning/jit_riscv.h>
+#elif defined(__sh__)
+#  include <lightning/jit_sh.h>
+#endif
+
+#define jit_flag_node          0x0001  /* patch node not absolute */
+#define jit_flag_patch         0x0002  /* jump already patched */
+#define jit_flag_data          0x0004  /* data in the constant pool */
+#define jit_flag_use           0x0008  /* do not remove marker label */
+#define jit_flag_synth         0x0010  /* synthesized instruction */
+#define jit_flag_head          0x1000  /* label reached by normal flow */
+#define jit_flag_varargs       0x2000  /* call{r,i} to varargs function */
+
+#define JIT_R(index)           jit_r(index)
+#define JIT_V(index)           jit_v(index)
+#define JIT_A(index)           jit_a(index)
+#define JIT_F(index)           jit_f(index)
+#define JIT_R_NUM              jit_r_num()
+#define JIT_V_NUM              jit_v_num()
+#define JIT_A_NUM              jit_a_num()
+#define JIT_F_NUM              jit_f_num()
+
+#define JIT_DISABLE_DATA       1       /* force synthesize of constants */
+#define JIT_DISABLE_NOTE       2       /* disable debug info generation */
+
+#define jit_class_chk          0x02000000      /* just checking */
+#define jit_class_arg          0x08000000      /* argument register */
+#define jit_class_sav          0x10000000      /* callee save */
+#define jit_class_gpr          0x20000000      /* general purpose */
+#define jit_class_fpr          0x40000000      /* float */
+#define jit_class(reg)         ((reg) & 0xffff0000)
+#define jit_regno(reg)         ((reg) & 0x00007fff)
+
+typedef struct jit_node                jit_node_t;
+typedef struct jit_state       jit_state_t;
+
+typedef enum {
+    jit_code_data,
+#define jit_live(u)            jit_new_node_w(jit_code_live, u)
+#define jit_align(u)           jit_new_node_w(jit_code_align, u)
+    jit_code_live,             jit_code_align,
+    jit_code_save,             jit_code_load,
+#define jit_name(u)            _jit_name(_jit,u)
+    jit_code_name,
+#define jit_note(u, v)         _jit_note(_jit, u, v)
+#define jit_label()            _jit_label(_jit)
+#define jit_forward()          _jit_forward(_jit)
+#define jit_indirect()         _jit_indirect(_jit)
+#define jit_link(u)            _jit_link(_jit,u)
+    jit_code_note,             jit_code_label,
+
+#define jit_prolog()           _jit_prolog(_jit)
+    jit_code_prolog,
+
+#define jit_ellipsis()         _jit_ellipsis(_jit)
+    jit_code_ellipsis,
+#define jit_va_push(u)         _jit_va_push(_jit,u)
+    jit_code_va_push,
+#define jit_allocai(u)         _jit_allocai(_jit,u)
+#define jit_allocar(u, v)      _jit_allocar(_jit,u,v)
+    jit_code_allocai,          jit_code_allocar,
+
+#define jit_arg()              _jit_arg(_jit)
+    jit_code_arg,
+#define jit_getarg_c(u,v)      _jit_getarg_c(_jit,u,v)
+#define jit_getarg_uc(u,v)     _jit_getarg_uc(_jit,u,v)
+    jit_code_getarg_c,         jit_code_getarg_uc,
+#define jit_getarg_s(u,v)      _jit_getarg_s(_jit,u,v)
+#define jit_getarg_us(u,v)     _jit_getarg_us(_jit,u,v)
+    jit_code_getarg_s,         jit_code_getarg_us,
+#define jit_getarg_i(u,v)      _jit_getarg_i(_jit,u,v)
+#if __WORDSIZE == 32
+#  define jit_getarg(u,v)      jit_getarg_i(u,v)
+#  define jit_getarg_ui(u,v)   jit_getarg_i(u,v)
+#else
+#  define jit_getarg(u,v)      jit_getarg_l(u,v)
+#  define jit_getarg_ui(u,v)   _jit_getarg_ui(_jit,u,v)
+#  define jit_getarg_l(u,v)    _jit_getarg_l(_jit,u,v)
+#endif
+    jit_code_getarg_i,         jit_code_getarg_ui,
+    jit_code_getarg_l,
+#  define jit_putargr(u,v)     _jit_putargr(_jit,u,v)
+#  define jit_putargi(u,v)     _jit_putargi(_jit,u,v)
+    jit_code_putargr,          jit_code_putargi,
+
+#define jit_va_start(u)                jit_new_node_w(jit_code_va_start, u)
+    jit_code_va_start,
+#define jit_va_arg(u, v)       jit_new_node_ww(jit_code_va_arg, u, v)
+#define jit_va_arg_d(u, v)     jit_new_node_ww(jit_code_va_arg_d, u, v)
+    jit_code_va_arg,           jit_code_va_arg_d,
+#define jit_va_end(u)          jit_new_node_w(jit_code_va_end, u)
+    jit_code_va_end,
+
+#define jit_addr(u,v,w)                jit_new_node_www(jit_code_addr,u,v,w)
+#define jit_addi(u,v,w)                jit_new_node_www(jit_code_addi,u,v,w)
+    jit_code_addr,             jit_code_addi,
+#define jit_addcr(u,v,w)       jit_new_node_www(jit_code_addcr,u,v,w)
+#define jit_addci(u,v,w)       jit_new_node_www(jit_code_addci,u,v,w)
+    jit_code_addcr,            jit_code_addci,
+#define jit_addxr(u,v,w)       jit_new_node_www(jit_code_addxr,u,v,w)
+#define jit_addxi(u,v,w)       jit_new_node_www(jit_code_addxi,u,v,w)
+    jit_code_addxr,            jit_code_addxi,
+#define jit_subr(u,v,w)                jit_new_node_www(jit_code_subr,u,v,w)
+#define jit_subi(u,v,w)                jit_new_node_www(jit_code_subi,u,v,w)
+    jit_code_subr,             jit_code_subi,
+#define jit_subcr(u,v,w)       jit_new_node_www(jit_code_subcr,u,v,w)
+#define jit_subci(u,v,w)       jit_new_node_www(jit_code_subci,u,v,w)
+    jit_code_subcr,            jit_code_subci,
+#define jit_subxr(u,v,w)       jit_new_node_www(jit_code_subxr,u,v,w)
+#define jit_subxi(u,v,w)       jit_new_node_www(jit_code_subxi,u,v,w)
+    jit_code_subxr,            jit_code_subxi,
+#define jit_rsbr(u,v,w)                jit_subr(u,w,v)
+#define jit_rsbi(u,v,w)                jit_new_node_www(jit_code_rsbi,u,v,w)
+    jit_code_rsbi,
+#define jit_mulr(u,v,w)                jit_new_node_www(jit_code_mulr,u,v,w)
+#define jit_muli(u,v,w)                jit_new_node_www(jit_code_muli,u,v,w)
+    jit_code_mulr,             jit_code_muli,
+#define jit_qmulr(l,h,v,w)     jit_new_node_qww(jit_code_qmulr,l,h,v,w)
+#define jit_qmuli(l,h,v,w)     jit_new_node_qww(jit_code_qmuli,l,h,v,w)
+    jit_code_qmulr,            jit_code_qmuli,
+#define jit_qmulr_u(l,h,v,w)   jit_new_node_qww(jit_code_qmulr_u,l,h,v,w)
+#define jit_qmuli_u(l,h,v,w)   jit_new_node_qww(jit_code_qmuli_u,l,h,v,w)
+    jit_code_qmulr_u,          jit_code_qmuli_u,
+#define jit_divr(u,v,w)                jit_new_node_www(jit_code_divr,u,v,w)
+#define jit_divi(u,v,w)                jit_new_node_www(jit_code_divi,u,v,w)
+    jit_code_divr,             jit_code_divi,
+#define jit_divr_u(u,v,w)      jit_new_node_www(jit_code_divr_u,u,v,w)
+#define jit_divi_u(u,v,w)      jit_new_node_www(jit_code_divi_u,u,v,w)
+    jit_code_divr_u,           jit_code_divi_u,
+#define jit_qdivr(l,h,v,w)     jit_new_node_qww(jit_code_qdivr,l,h,v,w)
+#define jit_qdivi(l,h,v,w)     jit_new_node_qww(jit_code_qdivi,l,h,v,w)
+    jit_code_qdivr,            jit_code_qdivi,
+#define jit_qdivr_u(l,h,v,w)   jit_new_node_qww(jit_code_qdivr_u,l,h,v,w)
+#define jit_qdivi_u(l,h,v,w)   jit_new_node_qww(jit_code_qdivi_u,l,h,v,w)
+    jit_code_qdivr_u,          jit_code_qdivi_u,
+#define jit_remr(u,v,w)                jit_new_node_www(jit_code_remr,u,v,w)
+#define jit_remi(u,v,w)                jit_new_node_www(jit_code_remi,u,v,w)
+    jit_code_remr,             jit_code_remi,
+#define jit_remr_u(u,v,w)      jit_new_node_www(jit_code_remr_u,u,v,w)
+#define jit_remi_u(u,v,w)      jit_new_node_www(jit_code_remi_u,u,v,w)
+    jit_code_remr_u,           jit_code_remi_u,
+
+#define jit_andr(u,v,w)                jit_new_node_www(jit_code_andr,u,v,w)
+#define jit_andi(u,v,w)                jit_new_node_www(jit_code_andi,u,v,w)
+    jit_code_andr,             jit_code_andi,
+#define jit_orr(u,v,w)         jit_new_node_www(jit_code_orr,u,v,w)
+#define jit_ori(u,v,w)         jit_new_node_www(jit_code_ori,u,v,w)
+    jit_code_orr,              jit_code_ori,
+#define jit_xorr(u,v,w)                jit_new_node_www(jit_code_xorr,u,v,w)
+#define jit_xori(u,v,w)                jit_new_node_www(jit_code_xori,u,v,w)
+    jit_code_xorr,             jit_code_xori,
+
+#define jit_lshr(u,v,w)                jit_new_node_www(jit_code_lshr,u,v,w)
+#define jit_lshi(u,v,w)                jit_new_node_www(jit_code_lshi,u,v,w)
+    jit_code_lshr,             jit_code_lshi,
+#define jit_rshr(u,v,w)                jit_new_node_www(jit_code_rshr,u,v,w)
+#define jit_rshi(u,v,w)                jit_new_node_www(jit_code_rshi,u,v,w)
+    jit_code_rshr,             jit_code_rshi,
+#define jit_rshr_u(u,v,w)      jit_new_node_www(jit_code_rshr_u,u,v,w)
+#define jit_rshi_u(u,v,w)      jit_new_node_www(jit_code_rshi_u,u,v,w)
+    jit_code_rshr_u,           jit_code_rshi_u,
+
+#define jit_negr(u,v)          jit_new_node_ww(jit_code_negr,u,v)
+#define jit_comr(u,v)          jit_new_node_ww(jit_code_comr,u,v)
+    jit_code_negr,             jit_code_comr,
+
+#define jit_ltr(u,v,w)         jit_new_node_www(jit_code_ltr,u,v,w)
+#define jit_lti(u,v,w)         jit_new_node_www(jit_code_lti,u,v,w)
+    jit_code_ltr,              jit_code_lti,
+#define jit_ltr_u(u,v,w)       jit_new_node_www(jit_code_ltr_u,u,v,w)
+#define jit_lti_u(u,v,w)       jit_new_node_www(jit_code_lti_u,u,v,w)
+    jit_code_ltr_u,            jit_code_lti_u,
+#define jit_ler(u,v,w)         jit_new_node_www(jit_code_ler,u,v,w)
+#define jit_lei(u,v,w)         jit_new_node_www(jit_code_lei,u,v,w)
+    jit_code_ler,              jit_code_lei,
+#define jit_ler_u(u,v,w)       jit_new_node_www(jit_code_ler_u,u,v,w)
+#define jit_lei_u(u,v,w)       jit_new_node_www(jit_code_lei_u,u,v,w)
+    jit_code_ler_u,            jit_code_lei_u,
+#define jit_eqr(u,v,w)         jit_new_node_www(jit_code_eqr,u,v,w)
+#define jit_eqi(u,v,w)         jit_new_node_www(jit_code_eqi,u,v,w)
+    jit_code_eqr,              jit_code_eqi,
+#define jit_ger(u,v,w)         jit_new_node_www(jit_code_ger,u,v,w)
+#define jit_gei(u,v,w)         jit_new_node_www(jit_code_gei,u,v,w)
+    jit_code_ger,              jit_code_gei,
+#define jit_ger_u(u,v,w)       jit_new_node_www(jit_code_ger_u,u,v,w)
+#define jit_gei_u(u,v,w)       jit_new_node_www(jit_code_gei_u,u,v,w)
+    jit_code_ger_u,            jit_code_gei_u,
+#define jit_gtr(u,v,w)         jit_new_node_www(jit_code_gtr,u,v,w)
+#define jit_gti(u,v,w)         jit_new_node_www(jit_code_gti,u,v,w)
+    jit_code_gtr,              jit_code_gti,
+#define jit_gtr_u(u,v,w)       jit_new_node_www(jit_code_gtr_u,u,v,w)
+#define jit_gti_u(u,v,w)       jit_new_node_www(jit_code_gti_u,u,v,w)
+    jit_code_gtr_u,            jit_code_gti_u,
+#define jit_ner(u,v,w)         jit_new_node_www(jit_code_ner,u,v,w)
+#define jit_nei(u,v,w)         jit_new_node_www(jit_code_nei,u,v,w)
+    jit_code_ner,              jit_code_nei,
+
+#define jit_movr(u,v)          jit_new_node_ww(jit_code_movr,u,v)
+#define jit_movi(u,v)          jit_new_node_ww(jit_code_movi,u,v)
+    jit_code_movr,             jit_code_movi,
+#define jit_extr_c(u,v)                jit_new_node_ww(jit_code_extr_c,u,v)
+#define jit_extr_uc(u,v)       jit_new_node_ww(jit_code_extr_uc,u,v)
+    jit_code_extr_c,           jit_code_extr_uc,
+#define jit_extr_s(u,v)                jit_new_node_ww(jit_code_extr_s,u,v)
+#define jit_extr_us(u,v)       jit_new_node_ww(jit_code_extr_us,u,v)
+    jit_code_extr_s,           jit_code_extr_us,
+#  define jit_extr_i(u,v)      jit_new_node_ww(jit_code_extr_i,u,v)
+#  define jit_extr_ui(u,v)     jit_new_node_ww(jit_code_extr_ui,u,v)
+    jit_code_extr_i,           jit_code_extr_ui,
+
+#define jit_htonr_us(u,v)      jit_new_node_ww(jit_code_htonr_us,u,v)
+#define jit_ntohr_us(u,v)      jit_new_node_ww(jit_code_htonr_us,u,v)
+    jit_code_htonr_us,
+#define jit_htonr_ui(u,v)      jit_new_node_ww(jit_code_htonr_ui,u,v)
+#define jit_ntohr_ui(u,v)      jit_new_node_ww(jit_code_htonr_ui,u,v)
+#if __WORDSIZE == 32
+#  define jit_htonr(u,v)       jit_new_node_ww(jit_code_htonr_ui,u,v)
+#  define jit_ntohr(u,v)       jit_new_node_ww(jit_code_htonr_ui,u,v)
+#else
+#  define jit_htonr_ul(u,v)    jit_new_node_ww(jit_code_htonr_ul,u,v)
+#  define jit_ntohr_ul(u,v)    jit_new_node_ww(jit_code_htonr_ul,u,v)
+#  define jit_htonr(u,v)       jit_new_node_ww(jit_code_htonr_ul,u,v)
+#  define jit_ntohr(u,v)       jit_new_node_ww(jit_code_htonr_ul,u,v)
+#endif
+    jit_code_htonr_ui,         jit_code_htonr_ul,
+
+#define jit_ldr_c(u,v)         jit_new_node_ww(jit_code_ldr_c,u,v)
+#define jit_ldi_c(u,v)         jit_new_node_wp(jit_code_ldi_c,u,v)
+    jit_code_ldr_c,            jit_code_ldi_c,
+#define jit_ldr_uc(u,v)                jit_new_node_ww(jit_code_ldr_uc,u,v)
+#define jit_ldi_uc(u,v)                jit_new_node_wp(jit_code_ldi_uc,u,v)
+    jit_code_ldr_uc,           jit_code_ldi_uc,
+#define jit_ldr_s(u,v)         jit_new_node_ww(jit_code_ldr_s,u,v)
+#define jit_ldi_s(u,v)         jit_new_node_wp(jit_code_ldi_s,u,v)
+    jit_code_ldr_s,            jit_code_ldi_s,
+#define jit_ldr_us(u,v)                jit_new_node_ww(jit_code_ldr_us,u,v)
+#define jit_ldi_us(u,v)                jit_new_node_wp(jit_code_ldi_us,u,v)
+    jit_code_ldr_us,           jit_code_ldi_us,
+#define jit_ldr_i(u,v)         jit_new_node_ww(jit_code_ldr_i,u,v)
+#define jit_ldi_i(u,v)         jit_new_node_wp(jit_code_ldi_i,u,v)
+    jit_code_ldr_i,            jit_code_ldi_i,
+#if __WORDSIZE == 32
+#  define jit_ldr(u,v)         jit_ldr_i(u,v)
+#  define jit_ldr_ui(u,v)      jit_ldr_i(u,v)
+#  define jit_ldi(u,v)         jit_ldi_i(u,v)
+#  define jit_ldi_ui(u,v)      jit_ldi_i(u,v)
+#else
+#  define jit_ldr(u,v)         jit_ldr_l(u,v)
+#  define jit_ldi(u,v)         jit_ldi_l(u,v)
+#  define jit_ldr_ui(u,v)      jit_new_node_ww(jit_code_ldr_ui,u,v)
+#  define jit_ldi_ui(u,v)      jit_new_node_wp(jit_code_ldi_ui,u,v)
+#define jit_ldr_l(u,v)         jit_new_node_ww(jit_code_ldr_l,u,v)
+#define jit_ldi_l(u,v)         jit_new_node_wp(jit_code_ldi_l,u,v)
+#endif
+    jit_code_ldr_ui,           jit_code_ldi_ui,
+    jit_code_ldr_l,            jit_code_ldi_l,
+
+#define jit_ldxr_c(u,v,w)      jit_new_node_www(jit_code_ldxr_c,u,v,w)
+#define jit_ldxi_c(u,v,w)      jit_new_node_www(jit_code_ldxi_c,u,v,w)
+    jit_code_ldxr_c,           jit_code_ldxi_c,
+#define jit_ldxr_uc(u,v,w)     jit_new_node_www(jit_code_ldxr_uc,u,v,w)
+#define jit_ldxi_uc(u,v,w)     jit_new_node_www(jit_code_ldxi_uc,u,v,w)
+    jit_code_ldxr_uc,          jit_code_ldxi_uc,
+#define jit_ldxr_s(u,v,w)      jit_new_node_www(jit_code_ldxr_s,u,v,w)
+#define jit_ldxi_s(u,v,w)      jit_new_node_www(jit_code_ldxi_s,u,v,w)
+    jit_code_ldxr_s,           jit_code_ldxi_s,
+#define jit_ldxr_us(u,v,w)     jit_new_node_www(jit_code_ldxr_us,u,v,w)
+#define jit_ldxi_us(u,v,w)     jit_new_node_www(jit_code_ldxi_us,u,v,w)
+    jit_code_ldxr_us,          jit_code_ldxi_us,
+#define jit_ldxr_i(u,v,w)      jit_new_node_www(jit_code_ldxr_i,u,v,w)
+#define jit_ldxi_i(u,v,w)      jit_new_node_www(jit_code_ldxi_i,u,v,w)
+    jit_code_ldxr_i,           jit_code_ldxi_i,
+#if __WORDSIZE == 32
+#  define jit_ldxr(u,v,w)      jit_ldxr_i(u,v,w)
+#  define jit_ldxr_ui(u,v,w)   jit_ldxr_i(u,v,w)
+#  define jit_ldxi(u,v,w)      jit_ldxi_i(u,v,w)
+#  define jit_ldxi_ui(u,v,w)   jit_ldxi_i(u,v,w)
+#else
+#  define jit_ldxr_ui(u,v,w)   jit_new_node_www(jit_code_ldxr_ui,u,v,w)
+#  define jit_ldxi_ui(u,v,w)   jit_new_node_www(jit_code_ldxi_ui,u,v,w)
+#  define jit_ldxr_l(u,v,w)    jit_new_node_www(jit_code_ldxr_l,u,v,w)
+#  define jit_ldxi_l(u,v,w)    jit_new_node_www(jit_code_ldxi_l,u,v,w)
+#  define jit_ldxr(u,v,w)      jit_ldxr_l(u,v,w)
+#  define jit_ldxi(u,v,w)      jit_ldxi_l(u,v,w)
+#endif
+    jit_code_ldxr_ui,          jit_code_ldxi_ui,
+    jit_code_ldxr_l,           jit_code_ldxi_l,
+
+#define jit_str_c(u,v)         jit_new_node_ww(jit_code_str_c,u,v)
+#define jit_sti_c(u,v)         jit_new_node_pw(jit_code_sti_c,u,v)
+    jit_code_str_c,            jit_code_sti_c,
+#define jit_str_s(u,v)         jit_new_node_ww(jit_code_str_s,u,v)
+#define jit_sti_s(u,v)         jit_new_node_pw(jit_code_sti_s,u,v)
+    jit_code_str_s,            jit_code_sti_s,
+#define jit_str_i(u,v)         jit_new_node_ww(jit_code_str_i,u,v)
+#define jit_sti_i(u,v)         jit_new_node_pw(jit_code_sti_i,u,v)
+    jit_code_str_i,            jit_code_sti_i,
+#if __WORDSIZE == 32
+#  define jit_str(u,v)         jit_str_i(u,v)
+#  define jit_sti(u,v)         jit_sti_i(u,v)
+#else
+#  define jit_str(u,v)         jit_str_l(u,v)
+#  define jit_sti(u,v)         jit_sti_l(u,v)
+#  define jit_str_l(u,v)       jit_new_node_ww(jit_code_str_l,u,v)
+#  define jit_sti_l(u,v)       jit_new_node_pw(jit_code_sti_l,u,v)
+#endif
+    jit_code_str_l,            jit_code_sti_l,
+
+#define jit_stxr_c(u,v,w)      jit_new_node_www(jit_code_stxr_c,u,v,w)
+#define jit_stxi_c(u,v,w)      jit_new_node_www(jit_code_stxi_c,u,v,w)
+    jit_code_stxr_c,           jit_code_stxi_c,
+#define jit_stxr_s(u,v,w)      jit_new_node_www(jit_code_stxr_s,u,v,w)
+#define jit_stxi_s(u,v,w)      jit_new_node_www(jit_code_stxi_s,u,v,w)
+    jit_code_stxr_s,           jit_code_stxi_s,
+#define jit_stxr_i(u,v,w)      jit_new_node_www(jit_code_stxr_i,u,v,w)
+#define jit_stxi_i(u,v,w)      jit_new_node_www(jit_code_stxi_i,u,v,w)
+    jit_code_stxr_i,           jit_code_stxi_i,
+#if __WORDSIZE == 32
+#  define jit_stxr(u,v,w)      jit_stxr_i(u,v,w)
+#  define jit_stxi(u,v,w)      jit_stxi_i(u,v,w)
+#else
+#  define jit_stxr(u,v,w)      jit_stxr_l(u,v,w)
+#  define jit_stxi(u,v,w)      jit_stxi_l(u,v,w)
+#  define jit_stxr_l(u,v,w)    jit_new_node_www(jit_code_stxr_l,u,v,w)
+#  define jit_stxi_l(u,v,w)    jit_new_node_www(jit_code_stxi_l,u,v,w)
+#endif
+    jit_code_stxr_l,           jit_code_stxi_l,
+
+#define jit_bltr(v,w)          jit_new_node_pww(jit_code_bltr,NULL,v,w)
+#define jit_blti(v,w)          jit_new_node_pww(jit_code_blti,NULL,v,w)
+    jit_code_bltr,             jit_code_blti,
+#define jit_bltr_u(v,w)                jit_new_node_pww(jit_code_bltr_u,NULL,v,w)
+#define jit_blti_u(v,w)                jit_new_node_pww(jit_code_blti_u,NULL,v,w)
+    jit_code_bltr_u,           jit_code_blti_u,
+#define jit_bler(v,w)          jit_new_node_pww(jit_code_bler,NULL,v,w)
+#define jit_blei(v,w)          jit_new_node_pww(jit_code_blei,NULL,v,w)
+    jit_code_bler,             jit_code_blei,
+#define jit_bler_u(v,w)                jit_new_node_pww(jit_code_bler_u,NULL,v,w)
+#define jit_blei_u(v,w)                jit_new_node_pww(jit_code_blei_u,NULL,v,w)
+    jit_code_bler_u,           jit_code_blei_u,
+#define jit_beqr(v,w)          jit_new_node_pww(jit_code_beqr,NULL,v,w)
+#define jit_beqi(v,w)          jit_new_node_pww(jit_code_beqi,NULL,v,w)
+    jit_code_beqr,             jit_code_beqi,
+#define jit_bger(v,w)          jit_new_node_pww(jit_code_bger,NULL,v,w)
+#define jit_bgei(v,w)          jit_new_node_pww(jit_code_bgei,NULL,v,w)
+    jit_code_bger,             jit_code_bgei,
+#define jit_bger_u(v,w)                jit_new_node_pww(jit_code_bger_u,NULL,v,w)
+#define jit_bgei_u(v,w)                jit_new_node_pww(jit_code_bgei_u,NULL,v,w)
+    jit_code_bger_u,           jit_code_bgei_u,
+#define jit_bgtr(v,w)          jit_new_node_pww(jit_code_bgtr,NULL,v,w)
+#define jit_bgti(v,w)          jit_new_node_pww(jit_code_bgti,NULL,v,w)
+    jit_code_bgtr,             jit_code_bgti,
+#define jit_bgtr_u(v,w)                jit_new_node_pww(jit_code_bgtr_u,NULL,v,w)
+#define jit_bgti_u(v,w)                jit_new_node_pww(jit_code_bgti_u,NULL,v,w)
+    jit_code_bgtr_u,           jit_code_bgti_u,
+#define jit_bner(v,w)          jit_new_node_pww(jit_code_bner,NULL,v,w)
+#define jit_bnei(v,w)          jit_new_node_pww(jit_code_bnei,NULL,v,w)
+    jit_code_bner,             jit_code_bnei,
+
+#define jit_bmsr(v,w)          jit_new_node_pww(jit_code_bmsr,NULL,v,w)
+#define jit_bmsi(v,w)          jit_new_node_pww(jit_code_bmsi,NULL,v,w)
+    jit_code_bmsr,             jit_code_bmsi,
+#define jit_bmcr(v,w)          jit_new_node_pww(jit_code_bmcr,NULL,v,w)
+#define jit_bmci(v,w)          jit_new_node_pww(jit_code_bmci,NULL,v,w)
+    jit_code_bmcr,             jit_code_bmci,
+
+#define jit_boaddr(v,w)                jit_new_node_pww(jit_code_boaddr,NULL,v,w)
+#define jit_boaddi(v,w)                jit_new_node_pww(jit_code_boaddi,NULL,v,w)
+    jit_code_boaddr,           jit_code_boaddi,
+#define jit_boaddr_u(v,w)      jit_new_node_pww(jit_code_boaddr_u,NULL,v,w)
+#define jit_boaddi_u(v,w)      jit_new_node_pww(jit_code_boaddi_u,NULL,v,w)
+    jit_code_boaddr_u,         jit_code_boaddi_u,
+#define jit_bxaddr(v,w)                jit_new_node_pww(jit_code_bxaddr,NULL,v,w)
+#define jit_bxaddi(v,w)                jit_new_node_pww(jit_code_bxaddi,NULL,v,w)
+    jit_code_bxaddr,           jit_code_bxaddi,
+#define jit_bxaddr_u(v,w)      jit_new_node_pww(jit_code_bxaddr_u,NULL,v,w)
+#define jit_bxaddi_u(v,w)      jit_new_node_pww(jit_code_bxaddi_u,NULL,v,w)
+    jit_code_bxaddr_u,         jit_code_bxaddi_u,
+#define jit_bosubr(v,w)                jit_new_node_pww(jit_code_bosubr,NULL,v,w)
+#define jit_bosubi(v,w)                jit_new_node_pww(jit_code_bosubi,NULL,v,w)
+    jit_code_bosubr,           jit_code_bosubi,
+#define jit_bosubr_u(v,w)      jit_new_node_pww(jit_code_bosubr_u,NULL,v,w)
+#define jit_bosubi_u(v,w)      jit_new_node_pww(jit_code_bosubi_u,NULL,v,w)
+    jit_code_bosubr_u,         jit_code_bosubi_u,
+#define jit_bxsubr(v,w)                jit_new_node_pww(jit_code_bxsubr,NULL,v,w)
+#define jit_bxsubi(v,w)                jit_new_node_pww(jit_code_bxsubi,NULL,v,w)
+    jit_code_bxsubr,           jit_code_bxsubi,
+#define jit_bxsubr_u(v,w)      jit_new_node_pww(jit_code_bxsubr_u,NULL,v,w)
+#define jit_bxsubi_u(v,w)      jit_new_node_pww(jit_code_bxsubi_u,NULL,v,w)
+    jit_code_bxsubr_u,         jit_code_bxsubi_u,
+
+#define jit_jmpr(u)            jit_new_node_w(jit_code_jmpr,u)
+#define jit_jmpi()             jit_new_node_p(jit_code_jmpi,NULL)
+    jit_code_jmpr,             jit_code_jmpi,
+#define jit_callr(u)           jit_new_node_w(jit_code_callr,u)
+#define jit_calli(u)           jit_new_node_p(jit_code_calli,u)
+    jit_code_callr,            jit_code_calli,
+
+#define jit_prepare()          _jit_prepare(_jit)
+    jit_code_prepare,
+#define jit_pushargr(u)                _jit_pushargr(_jit,u)
+#define jit_pushargi(u)                _jit_pushargi(_jit,u)
+    jit_code_pushargr,         jit_code_pushargi,
+#define jit_finishr(u)         _jit_finishr(_jit,u)
+#define jit_finishi(u)         _jit_finishi(_jit,u)
+    jit_code_finishr,          jit_code_finishi,
+#define jit_ret()              _jit_ret(_jit)
+    jit_code_ret,
+#define jit_retr(u)            _jit_retr(_jit,u)
+#define jit_reti(u)            _jit_reti(_jit,u)
+    jit_code_retr,             jit_code_reti,
+#define jit_retval_c(u)                _jit_retval_c(_jit,u)
+#define jit_retval_uc(u)       _jit_retval_uc(_jit,u)
+    jit_code_retval_c,         jit_code_retval_uc,
+#define jit_retval_s(u)                _jit_retval_s(_jit,u)
+#define jit_retval_us(u)       _jit_retval_us(_jit,u)
+    jit_code_retval_s,         jit_code_retval_us,
+#define jit_retval_i(u)                _jit_retval_i(_jit,u)
+#if __WORDSIZE == 32
+#  define jit_retval(u)                jit_retval_i(u)
+#  define jit_retval_ui(u)     jit_retval_i(u)
+#else
+#  define jit_retval(u)                jit_retval_l(u)
+#  define jit_retval_ui(u)     _jit_retval_ui(_jit,u)
+#  define jit_retval_l(u)      _jit_retval_l(_jit,u)
+#endif
+    jit_code_retval_i,         jit_code_retval_ui,
+    jit_code_retval_l,
+
+#define jit_epilog()           _jit_epilog(_jit)
+    jit_code_epilog,
+
+#define jit_arg_f()            _jit_arg_f(_jit)
+    jit_code_arg_f,
+#define jit_getarg_f(u,v)      _jit_getarg_f(_jit,u,v)
+    jit_code_getarg_f,
+#define jit_putargr_f(u,v)     _jit_putargr_f(_jit,u,v)
+#define jit_putargi_f(u,v)     _jit_putargi_f(_jit,u,v)
+    jit_code_putargr_f,                jit_code_putargi_f,
+
+#define jit_addr_f(u,v,w)      jit_new_node_www(jit_code_addr_f,u,v,w)
+#define jit_addi_f(u,v,w)      jit_new_node_wwf(jit_code_addi_f,u,v,w)
+    jit_code_addr_f,           jit_code_addi_f,
+#define jit_subr_f(u,v,w)      jit_new_node_www(jit_code_subr_f,u,v,w)
+#define jit_subi_f(u,v,w)      jit_new_node_wwf(jit_code_subi_f,u,v,w)
+    jit_code_subr_f,           jit_code_subi_f,
+#define jit_rsbr_f(u,v,w)      jit_subr_f(u,w,v)
+#define jit_rsbi_f(u,v,w)      jit_new_node_wwf(jit_code_rsbi_f,u,v,w)
+    jit_code_rsbi_f,
+#define jit_mulr_f(u,v,w)      jit_new_node_www(jit_code_mulr_f,u,v,w)
+#define jit_muli_f(u,v,w)      jit_new_node_wwf(jit_code_muli_f,u,v,w)
+    jit_code_mulr_f,           jit_code_muli_f,
+#define jit_divr_f(u,v,w)      jit_new_node_www(jit_code_divr_f,u,v,w)
+#define jit_divi_f(u,v,w)      jit_new_node_wwf(jit_code_divi_f,u,v,w)
+    jit_code_divr_f,           jit_code_divi_f,
+#define jit_negr_f(u,v)                jit_new_node_ww(jit_code_negr_f,u,v)
+#define jit_absr_f(u,v)                jit_new_node_ww(jit_code_absr_f,u,v)
+#define jit_sqrtr_f(u,v)       jit_new_node_ww(jit_code_sqrtr_f,u,v)
+    jit_code_negr_f,           jit_code_absr_f,        jit_code_sqrtr_f,
+
+#define jit_ltr_f(u,v,w)       jit_new_node_www(jit_code_ltr_f,u,v,w)
+#define jit_lti_f(u,v,w)       jit_new_node_wwf(jit_code_lti_f,u,v,w)
+    jit_code_ltr_f,            jit_code_lti_f,
+#define jit_ler_f(u,v,w)       jit_new_node_www(jit_code_ler_f,u,v,w)
+#define jit_lei_f(u,v,w)       jit_new_node_wwf(jit_code_lei_f,u,v,w)
+    jit_code_ler_f,            jit_code_lei_f,
+#define jit_eqr_f(u,v,w)       jit_new_node_www(jit_code_eqr_f,u,v,w)
+#define jit_eqi_f(u,v,w)       jit_new_node_wwf(jit_code_eqi_f,u,v,w)
+    jit_code_eqr_f,            jit_code_eqi_f,
+#define jit_ger_f(u,v,w)       jit_new_node_www(jit_code_ger_f,u,v,w)
+#define jit_gei_f(u,v,w)       jit_new_node_wwf(jit_code_gei_f,u,v,w)
+    jit_code_ger_f,            jit_code_gei_f,
+#define jit_gtr_f(u,v,w)       jit_new_node_www(jit_code_gtr_f,u,v,w)
+#define jit_gti_f(u,v,w)       jit_new_node_wwf(jit_code_gti_f,u,v,w)
+    jit_code_gtr_f,            jit_code_gti_f,
+#define jit_ner_f(u,v,w)       jit_new_node_www(jit_code_ner_f,u,v,w)
+#define jit_nei_f(u,v,w)       jit_new_node_wwf(jit_code_nei_f,u,v,w)
+    jit_code_ner_f,            jit_code_nei_f,
+#define jit_unltr_f(u,v,w)     jit_new_node_www(jit_code_unltr_f,u,v,w)
+#define jit_unlti_f(u,v,w)     jit_new_node_wwf(jit_code_unlti_f,u,v,w)
+    jit_code_unltr_f,          jit_code_unlti_f,
+#define jit_unler_f(u,v,w)     jit_new_node_www(jit_code_unler_f,u,v,w)
+#define jit_unlei_f(u,v,w)     jit_new_node_wwf(jit_code_unlei_f,u,v,w)
+    jit_code_unler_f,          jit_code_unlei_f,
+#define jit_uneqr_f(u,v,w)     jit_new_node_www(jit_code_uneqr_f,u,v,w)
+#define jit_uneqi_f(u,v,w)     jit_new_node_wwf(jit_code_uneqi_f,u,v,w)
+    jit_code_uneqr_f,          jit_code_uneqi_f,
+#define jit_unger_f(u,v,w)     jit_new_node_www(jit_code_unger_f,u,v,w)
+#define jit_ungei_f(u,v,w)     jit_new_node_wwf(jit_code_ungei_f,u,v,w)
+    jit_code_unger_f,          jit_code_ungei_f,
+#define jit_ungtr_f(u,v,w)     jit_new_node_www(jit_code_ungtr_f,u,v,w)
+#define jit_ungti_f(u,v,w)     jit_new_node_wwf(jit_code_ungti_f,u,v,w)
+    jit_code_ungtr_f,          jit_code_ungti_f,
+#define jit_ltgtr_f(u,v,w)     jit_new_node_www(jit_code_ltgtr_f,u,v,w)
+#define jit_ltgti_f(u,v,w)     jit_new_node_wwf(jit_code_ltgti_f,u,v,w)
+    jit_code_ltgtr_f,          jit_code_ltgti_f,
+#define jit_ordr_f(u,v,w)      jit_new_node_www(jit_code_ordr_f,u,v,w)
+#define jit_ordi_f(u,v,w)      jit_new_node_wwf(jit_code_ordi_f,u,v,w)
+    jit_code_ordr_f,           jit_code_ordi_f,
+#define jit_unordr_f(u,v,w)    jit_new_node_www(jit_code_unordr_f,u,v,w)
+#define jit_unordi_f(u,v,w)    jit_new_node_wwf(jit_code_unordi_f,u,v,w)
+    jit_code_unordr_f,         jit_code_unordi_f,
+
+#define jit_truncr_f_i(u,v)    jit_new_node_ww(jit_code_truncr_f_i,u,v)
+    jit_code_truncr_f_i,
+#if __WORDSIZE == 32
+#  define jit_truncr_f(u,v)    jit_truncr_f_i(u,v)
+#else
+#  define jit_truncr_f(u,v)    jit_truncr_f_l(u,v)
+#  define jit_truncr_f_l(u,v)  jit_new_node_ww(jit_code_truncr_f_l,u,v)
+#endif
+    jit_code_truncr_f_l,
+#define jit_extr_f(u,v)                jit_new_node_ww(jit_code_extr_f,u,v)
+#define jit_extr_d_f(u,v)      jit_new_node_ww(jit_code_extr_d_f,u,v)
+    jit_code_extr_f,           jit_code_extr_d_f,
+#define jit_movr_f(u,v)                jit_new_node_ww(jit_code_movr_f,u,v)
+#define jit_movi_f(u,v)                jit_new_node_wf(jit_code_movi_f,u,v)
+    jit_code_movr_f,           jit_code_movi_f,
+
+#define jit_ldr_f(u,v)         jit_new_node_ww(jit_code_ldr_f,u,v)
+#define jit_ldi_f(u,v)         jit_new_node_wp(jit_code_ldi_f,u,v)
+    jit_code_ldr_f,            jit_code_ldi_f,
+#define jit_ldxr_f(u,v,w)      jit_new_node_www(jit_code_ldxr_f,u,v,w)
+#define jit_ldxi_f(u,v,w)      jit_new_node_www(jit_code_ldxi_f,u,v,w)
+    jit_code_ldxr_f,           jit_code_ldxi_f,
+#define jit_str_f(u,v)         jit_new_node_ww(jit_code_str_f,u,v)
+#define jit_sti_f(u,v)         jit_new_node_pw(jit_code_sti_f,u,v)
+    jit_code_str_f,            jit_code_sti_f,
+#define jit_stxr_f(u,v,w)      jit_new_node_www(jit_code_stxr_f,u,v,w)
+#define jit_stxi_f(u,v,w)      jit_new_node_www(jit_code_stxi_f,u,v,w)
+    jit_code_stxr_f,           jit_code_stxi_f,
+
+#define jit_bltr_f(v,w)                jit_new_node_pww(jit_code_bltr_f,NULL,v,w)
+#define jit_blti_f(v,w)                jit_new_node_pwf(jit_code_blti_f,NULL,v,w)
+    jit_code_bltr_f,           jit_code_blti_f,
+#define jit_bler_f(v,w)                jit_new_node_pww(jit_code_bler_f,NULL,v,w)
+#define jit_blei_f(v,w)                jit_new_node_pwf(jit_code_blei_f,NULL,v,w)
+    jit_code_bler_f,           jit_code_blei_f,
+#define jit_beqr_f(v,w)                jit_new_node_pww(jit_code_beqr_f,NULL,v,w)
+#define jit_beqi_f(v,w)                jit_new_node_pwf(jit_code_beqi_f,NULL,v,w)
+    jit_code_beqr_f,           jit_code_beqi_f,
+#define jit_bger_f(v,w)                jit_new_node_pww(jit_code_bger_f,NULL,v,w)
+#define jit_bgei_f(v,w)                jit_new_node_pwf(jit_code_bgei_f,NULL,v,w)
+    jit_code_bger_f,           jit_code_bgei_f,
+#define jit_bgtr_f(v,w)                jit_new_node_pww(jit_code_bgtr_f,NULL,v,w)
+#define jit_bgti_f(v,w)                jit_new_node_pwf(jit_code_bgti_f,NULL,v,w)
+    jit_code_bgtr_f,           jit_code_bgti_f,
+#define jit_bner_f(v,w)                jit_new_node_pww(jit_code_bner_f,NULL,v,w)
+#define jit_bnei_f(v,w)                jit_new_node_pwf(jit_code_bnei_f,NULL,v,w)
+    jit_code_bner_f,           jit_code_bnei_f,
+#define jit_bunltr_f(v,w)      jit_new_node_pww(jit_code_bunltr_f,NULL,v,w)
+#define jit_bunlti_f(v,w)      jit_new_node_pwf(jit_code_bunlti_f,NULL,v,w)
+    jit_code_bunltr_f,         jit_code_bunlti_f,
+#define jit_bunler_f(v,w)      jit_new_node_pww(jit_code_bunler_f,NULL,v,w)
+#define jit_bunlei_f(v,w)      jit_new_node_pwf(jit_code_bunlei_f,NULL,v,w)
+    jit_code_bunler_f,         jit_code_bunlei_f,
+#define jit_buneqr_f(v,w)      jit_new_node_pww(jit_code_buneqr_f,NULL,v,w)
+#define jit_buneqi_f(v,w)      jit_new_node_pwf(jit_code_buneqi_f,NULL,v,w)
+    jit_code_buneqr_f,         jit_code_buneqi_f,
+#define jit_bunger_f(v,w)      jit_new_node_pww(jit_code_bunger_f,NULL,v,w)
+#define jit_bungei_f(v,w)      jit_new_node_pwf(jit_code_bungei_f,NULL,v,w)
+    jit_code_bunger_f,         jit_code_bungei_f,
+#define jit_bungtr_f(v,w)      jit_new_node_pww(jit_code_bungtr_f,NULL,v,w)
+#define jit_bungti_f(v,w)      jit_new_node_pwf(jit_code_bungti_f,NULL,v,w)
+    jit_code_bungtr_f,         jit_code_bungti_f,
+#define jit_bltgtr_f(v,w)      jit_new_node_pww(jit_code_bltgtr_f,NULL,v,w)
+#define jit_bltgti_f(v,w)      jit_new_node_pwf(jit_code_bltgti_f,NULL,v,w)
+    jit_code_bltgtr_f,         jit_code_bltgti_f,
+#define jit_bordr_f(v,w)       jit_new_node_pww(jit_code_bordr_f,NULL,v,w)
+#define jit_bordi_f(v,w)       jit_new_node_pwf(jit_code_bordi_f,NULL,v,w)
+    jit_code_bordr_f,          jit_code_bordi_f,
+#define jit_bunordr_f(v,w)     jit_new_node_pww(jit_code_bunordr_f,NULL,v,w)
+#define jit_bunordi_f(v,w)     jit_new_node_pwf(jit_code_bunordi_f,NULL,v,w)
+    jit_code_bunordr_f,                jit_code_bunordi_f,
+
+#define jit_pushargr_f(u)      _jit_pushargr_f(_jit,u)
+#define jit_pushargi_f(u)      _jit_pushargi_f(_jit,u)
+    jit_code_pushargr_f,       jit_code_pushargi_f,
+#define jit_retr_f(u)          _jit_retr_f(_jit,u)
+#define jit_reti_f(u)          _jit_reti_f(_jit,u)
+    jit_code_retr_f,           jit_code_reti_f,
+#define jit_retval_f(u)                _jit_retval_f(_jit,u)
+    jit_code_retval_f,
+
+#define jit_arg_d()            _jit_arg_d(_jit)
+    jit_code_arg_d,
+#define jit_getarg_d(u,v)      _jit_getarg_d(_jit,u,v)
+    jit_code_getarg_d,
+#define jit_putargr_d(u,v)     _jit_putargr_d(_jit,u,v)
+#define jit_putargi_d(u,v)     _jit_putargi_d(_jit,u,v)
+    jit_code_putargr_d,                jit_code_putargi_d,
+
+#define jit_addr_d(u,v,w)      jit_new_node_www(jit_code_addr_d,u,v,w)
+#define jit_addi_d(u,v,w)      jit_new_node_wwd(jit_code_addi_d,u,v,w)
+    jit_code_addr_d,           jit_code_addi_d,
+#define jit_subr_d(u,v,w)      jit_new_node_www(jit_code_subr_d,u,v,w)
+#define jit_subi_d(u,v,w)      jit_new_node_wwd(jit_code_subi_d,u,v,w)
+    jit_code_subr_d,           jit_code_subi_d,
+#define jit_rsbr_d(u,v,w)      jit_subr_d(u,w,v)
+#define jit_rsbi_d(u,v,w)      jit_new_node_wwd(jit_code_rsbi_d,u,v,w)
+    jit_code_rsbi_d,
+#define jit_mulr_d(u,v,w)      jit_new_node_www(jit_code_mulr_d,u,v,w)
+#define jit_muli_d(u,v,w)      jit_new_node_wwd(jit_code_muli_d,u,v,w)
+    jit_code_mulr_d,           jit_code_muli_d,
+#define jit_divr_d(u,v,w)      jit_new_node_www(jit_code_divr_d,u,v,w)
+#define jit_divi_d(u,v,w)      jit_new_node_wwd(jit_code_divi_d,u,v,w)
+    jit_code_divr_d,           jit_code_divi_d,
+
+#define jit_negr_d(u,v)                jit_new_node_ww(jit_code_negr_d,u,v)
+#define jit_absr_d(u,v)                jit_new_node_ww(jit_code_absr_d,u,v)
+#define jit_sqrtr_d(u,v)       jit_new_node_ww(jit_code_sqrtr_d,u,v)
+    jit_code_negr_d,           jit_code_absr_d,        jit_code_sqrtr_d,
+
+#define jit_ltr_d(u,v,w)       jit_new_node_www(jit_code_ltr_d,u,v,w)
+#define jit_lti_d(u,v,w)       jit_new_node_wwd(jit_code_lti_d,u,v,w)
+    jit_code_ltr_d,            jit_code_lti_d,
+#define jit_ler_d(u,v,w)       jit_new_node_www(jit_code_ler_d,u,v,w)
+#define jit_lei_d(u,v,w)       jit_new_node_wwd(jit_code_lei_d,u,v,w)
+    jit_code_ler_d,            jit_code_lei_d,
+#define jit_eqr_d(u,v,w)       jit_new_node_www(jit_code_eqr_d,u,v,w)
+#define jit_eqi_d(u,v,w)       jit_new_node_wwd(jit_code_eqi_d,u,v,w)
+    jit_code_eqr_d,            jit_code_eqi_d,
+#define jit_ger_d(u,v,w)       jit_new_node_www(jit_code_ger_d,u,v,w)
+#define jit_gei_d(u,v,w)       jit_new_node_wwd(jit_code_gei_d,u,v,w)
+    jit_code_ger_d,            jit_code_gei_d,
+#define jit_gtr_d(u,v,w)       jit_new_node_www(jit_code_gtr_d,u,v,w)
+#define jit_gti_d(u,v,w)       jit_new_node_wwd(jit_code_gti_d,u,v,w)
+    jit_code_gtr_d,            jit_code_gti_d,
+#define jit_ner_d(u,v,w)       jit_new_node_www(jit_code_ner_d,u,v,w)
+#define jit_nei_d(u,v,w)       jit_new_node_wwd(jit_code_nei_d,u,v,w)
+    jit_code_ner_d,            jit_code_nei_d,
+#define jit_unltr_d(u,v,w)     jit_new_node_www(jit_code_unltr_d,u,v,w)
+#define jit_unlti_d(u,v,w)     jit_new_node_wwd(jit_code_unlti_d,u,v,w)
+    jit_code_unltr_d,          jit_code_unlti_d,
+#define jit_unler_d(u,v,w)     jit_new_node_www(jit_code_unler_d,u,v,w)
+#define jit_unlei_d(u,v,w)     jit_new_node_wwd(jit_code_unlei_d,u,v,w)
+    jit_code_unler_d,          jit_code_unlei_d,
+#define jit_uneqr_d(u,v,w)     jit_new_node_www(jit_code_uneqr_d,u,v,w)
+#define jit_uneqi_d(u,v,w)     jit_new_node_wwd(jit_code_uneqi_d,u,v,w)
+    jit_code_uneqr_d,          jit_code_uneqi_d,
+#define jit_unger_d(u,v,w)     jit_new_node_www(jit_code_unger_d,u,v,w)
+#define jit_ungei_d(u,v,w)     jit_new_node_wwd(jit_code_ungei_d,u,v,w)
+    jit_code_unger_d,          jit_code_ungei_d,
+#define jit_ungtr_d(u,v,w)     jit_new_node_www(jit_code_ungtr_d,u,v,w)
+#define jit_ungti_d(u,v,w)     jit_new_node_wwd(jit_code_ungti_d,u,v,w)
+    jit_code_ungtr_d,          jit_code_ungti_d,
+#define jit_ltgtr_d(u,v,w)     jit_new_node_www(jit_code_ltgtr_d,u,v,w)
+#define jit_ltgti_d(u,v,w)     jit_new_node_wwd(jit_code_ltgti_d,u,v,w)
+    jit_code_ltgtr_d,          jit_code_ltgti_d,
+#define jit_ordr_d(u,v,w)      jit_new_node_www(jit_code_ordr_d,u,v,w)
+#define jit_ordi_d(u,v,w)      jit_new_node_wwd(jit_code_ordi_d,u,v,w)
+    jit_code_ordr_d,           jit_code_ordi_d,
+#define jit_unordr_d(u,v,w)    jit_new_node_www(jit_code_unordr_d,u,v,w)
+#define jit_unordi_d(u,v,w)    jit_new_node_wwd(jit_code_unordi_d,u,v,w)
+    jit_code_unordr_d,         jit_code_unordi_d,
+
+#define jit_truncr_d_i(u,v)    jit_new_node_ww(jit_code_truncr_d_i,u,v)
+    jit_code_truncr_d_i,
+#if __WORDSIZE == 32
+#  define jit_truncr_d(u,v)    jit_truncr_d_i(u,v)
+#else
+#  define jit_truncr_d(u,v)    jit_truncr_d_l(u,v)
+#  define jit_truncr_d_l(u,v)  jit_new_node_ww(jit_code_truncr_d_l,u,v)
+#endif
+    jit_code_truncr_d_l,
+#define jit_extr_d(u,v)                jit_new_node_ww(jit_code_extr_d,u,v)
+#define jit_extr_f_d(u,v)      jit_new_node_ww(jit_code_extr_f_d,u,v)
+    jit_code_extr_d,           jit_code_extr_f_d,
+#define jit_movr_d(u,v)                jit_new_node_ww(jit_code_movr_d,u,v)
+#define jit_movi_d(u,v)                jit_new_node_wd(jit_code_movi_d,u,v)
+    jit_code_movr_d,           jit_code_movi_d,
+
+#define jit_ldr_d(u,v)         jit_new_node_ww(jit_code_ldr_d,u,v)
+#define jit_ldi_d(u,v)         jit_new_node_wp(jit_code_ldi_d,u,v)
+    jit_code_ldr_d,            jit_code_ldi_d,
+#define jit_ldxr_d(u,v,w)      jit_new_node_www(jit_code_ldxr_d,u,v,w)
+#define jit_ldxi_d(u,v,w)      jit_new_node_www(jit_code_ldxi_d,u,v,w)
+    jit_code_ldxr_d,           jit_code_ldxi_d,
+#define jit_str_d(u,v)         jit_new_node_ww(jit_code_str_d,u,v)
+#define jit_sti_d(u,v)         jit_new_node_pw(jit_code_sti_d,u,v)
+    jit_code_str_d,            jit_code_sti_d,
+#define jit_stxr_d(u,v,w)      jit_new_node_www(jit_code_stxr_d,u,v,w)
+#define jit_stxi_d(u,v,w)      jit_new_node_www(jit_code_stxi_d,u,v,w)
+    jit_code_stxr_d,           jit_code_stxi_d,
+
+#define jit_bltr_d(v,w)                jit_new_node_pww(jit_code_bltr_d,NULL,v,w)
+#define jit_blti_d(v,w)                jit_new_node_pwd(jit_code_blti_d,NULL,v,w)
+    jit_code_bltr_d,           jit_code_blti_d,
+#define jit_bler_d(v,w)                jit_new_node_pww(jit_code_bler_d,NULL,v,w)
+#define jit_blei_d(v,w)                jit_new_node_pwd(jit_code_blei_d,NULL,v,w)
+    jit_code_bler_d,           jit_code_blei_d,
+#define jit_beqr_d(v,w)                jit_new_node_pww(jit_code_beqr_d,NULL,v,w)
+#define jit_beqi_d(v,w)                jit_new_node_pwd(jit_code_beqi_d,NULL,v,w)
+    jit_code_beqr_d,           jit_code_beqi_d,
+#define jit_bger_d(v,w)                jit_new_node_pww(jit_code_bger_d,NULL,v,w)
+#define jit_bgei_d(v,w)                jit_new_node_pwd(jit_code_bgei_d,NULL,v,w)
+    jit_code_bger_d,           jit_code_bgei_d,
+#define jit_bgtr_d(v,w)                jit_new_node_pww(jit_code_bgtr_d,NULL,v,w)
+#define jit_bgti_d(v,w)                jit_new_node_pwd(jit_code_bgti_d,NULL,v,w)
+    jit_code_bgtr_d,           jit_code_bgti_d,
+#define jit_bner_d(v,w)                jit_new_node_pww(jit_code_bner_d,NULL,v,w)
+#define jit_bnei_d(v,w)                jit_new_node_pwd(jit_code_bnei_d,NULL,v,w)
+    jit_code_bner_d,           jit_code_bnei_d,
+#define jit_bunltr_d(v,w)      jit_new_node_pww(jit_code_bunltr_d,NULL,v,w)
+#define jit_bunlti_d(v,w)      jit_new_node_pwd(jit_code_bunlti_d,NULL,v,w)
+    jit_code_bunltr_d,         jit_code_bunlti_d,
+#define jit_bunler_d(v,w)      jit_new_node_pww(jit_code_bunler_d,NULL,v,w)
+#define jit_bunlei_d(v,w)      jit_new_node_pwd(jit_code_bunlei_d,NULL,v,w)
+    jit_code_bunler_d,         jit_code_bunlei_d,
+#define jit_buneqr_d(v,w)      jit_new_node_pww(jit_code_buneqr_d,NULL,v,w)
+#define jit_buneqi_d(v,w)      jit_new_node_pwd(jit_code_buneqi_d,NULL,v,w)
+    jit_code_buneqr_d,         jit_code_buneqi_d,
+#define jit_bunger_d(v,w)      jit_new_node_pww(jit_code_bunger_d,NULL,v,w)
+#define jit_bungei_d(v,w)      jit_new_node_pwd(jit_code_bungei_d,NULL,v,w)
+    jit_code_bunger_d,         jit_code_bungei_d,
+#define jit_bungtr_d(v,w)      jit_new_node_pww(jit_code_bungtr_d,NULL,v,w)
+#define jit_bungti_d(v,w)      jit_new_node_pwd(jit_code_bungti_d,NULL,v,w)
+    jit_code_bungtr_d,         jit_code_bungti_d,
+#define jit_bltgtr_d(v,w)      jit_new_node_pww(jit_code_bltgtr_d,NULL,v,w)
+#define jit_bltgti_d(v,w)      jit_new_node_pwd(jit_code_bltgti_d,NULL,v,w)
+    jit_code_bltgtr_d,         jit_code_bltgti_d,
+#define jit_bordr_d(v,w)       jit_new_node_pww(jit_code_bordr_d,NULL,v,w)
+#define jit_bordi_d(v,w)       jit_new_node_pwd(jit_code_bordi_d,NULL,v,w)
+    jit_code_bordr_d,          jit_code_bordi_d,
+#define jit_bunordr_d(v,w)     jit_new_node_pww(jit_code_bunordr_d,NULL,v,w)
+#define jit_bunordi_d(v,w)     jit_new_node_pwd(jit_code_bunordi_d,NULL,v,w)
+    jit_code_bunordr_d,                jit_code_bunordi_d,
+
+#define jit_pushargr_d(u)      _jit_pushargr_d(_jit,u)
+#define jit_pushargi_d(u)      _jit_pushargi_d(_jit,u)
+    jit_code_pushargr_d,       jit_code_pushargi_d,
+#define jit_retr_d(u)          _jit_retr_d(_jit,u)
+#define jit_reti_d(u)          _jit_reti_d(_jit,u)
+    jit_code_retr_d,           jit_code_reti_d,
+#define jit_retval_d(u)                _jit_retval_d(_jit,u)
+    jit_code_retval_d,
+
+#define jit_bswapr_us(u,v)     jit_new_node_ww(jit_code_bswapr_us,u,v)
+    jit_code_bswapr_us,
+#define jit_bswapr_ui(u,v)     jit_new_node_ww(jit_code_bswapr_ui,u,v)
+    jit_code_bswapr_ui,
+#define jit_bswapr_ul(u,v)     jit_new_node_ww(jit_code_bswapr_ul,u,v)
+    jit_code_bswapr_ul,
+#if __WORDSIZE == 32
+#define jit_bswapr(u,v)                jit_new_node_ww(jit_code_bswapr_ui,u,v)
+#else
+#define jit_bswapr(u,v)                jit_new_node_ww(jit_code_bswapr_ul,u,v)
+#endif
+
+    /* Special internal backend specific codes */
+    jit_code_movr_w_f,         jit_code_movr_ww_d,     /* w* -> f|d */
+#define jit_movr_w_f(u, v)     jit_new_node_ww(jit_code_movr_w_f, u, v)
+#define jit_movr_ww_d(u, v, w) jit_new_node_www(jit_code_movr_ww_d, u, v, w)
+    jit_code_movr_w_d,                                 /* w -> d */
+#define jit_movr_w_d(u, v)     jit_new_node_ww(jit_code_movr_w_d, u, v)
+
+    jit_code_movr_f_w,         jit_code_movi_f_w,      /* f|d -> w* */
+#define jit_movr_f_w(u, v)     jit_new_node_ww(jit_code_movr_f_w, u, v)
+#define jit_movi_f_w(u, v)     jit_new_node_wf(jit_code_movi_f_w, u, v)
+    jit_code_movr_d_ww,                jit_code_movi_d_ww,
+#define jit_movr_d_ww(u, v, w) jit_new_node_www(jit_code_movr_d_ww, u, v, w)
+#define jit_movi_d_ww(u, v, w) jit_new_node_wwd(jit_code_movi_d_ww, u, v, w)
+
+    jit_code_movr_d_w,         jit_code_movi_d_w,      /* d -> w */
+#define jit_movr_d_w(u, v)     jit_new_node_ww(jit_code_movr_d_w, u, v)
+#define jit_movi_d_w(u, v)     jit_new_node_wd(jit_code_movi_d_w, u, v)
+
+    jit_code_last_code
+} jit_code_t;
+
+typedef void* (*jit_alloc_func_ptr)    (size_t);
+typedef void* (*jit_realloc_func_ptr)  (void*, size_t);
+typedef void  (*jit_free_func_ptr)     (void*);
+
+/*
+ * Prototypes
+ */
+extern void init_jit(const char*);
+extern void finish_jit(void);
+
+extern jit_state_t *jit_new_state(void);
+#define jit_clear_state()      _jit_clear_state(_jit)
+extern void _jit_clear_state(jit_state_t*);
+#define jit_destroy_state()    _jit_destroy_state(_jit)
+extern void _jit_destroy_state(jit_state_t*);
+
+#define jit_address(node)      _jit_address(_jit, node)
+extern jit_pointer_t _jit_address(jit_state_t*, jit_node_t*);
+extern jit_node_t *_jit_name(jit_state_t*, const char*);
+extern jit_node_t *_jit_note(jit_state_t*, const char*, int);
+extern jit_node_t *_jit_label(jit_state_t*);
+extern jit_node_t *_jit_forward(jit_state_t*);
+extern jit_node_t *_jit_indirect(jit_state_t*);
+extern void _jit_link(jit_state_t*, jit_node_t*);
+#define jit_forward_p(u)       _jit_forward_p(_jit,u)
+extern jit_bool_t _jit_forward_p(jit_state_t*,jit_node_t*);
+#define jit_indirect_p(u)      _jit_indirect_p(_jit,u)
+extern jit_bool_t _jit_indirect_p(jit_state_t*,jit_node_t*);
+#define jit_target_p(u)                _jit_target_p(_jit,u)
+extern jit_bool_t _jit_target_p(jit_state_t*,jit_node_t*);
+
+extern void _jit_prolog(jit_state_t*);
+
+extern jit_int32_t _jit_allocai(jit_state_t*, jit_int32_t);
+extern void _jit_allocar(jit_state_t*, jit_int32_t, jit_int32_t);
+extern void _jit_ellipsis(jit_state_t*);
+
+extern jit_node_t *_jit_arg(jit_state_t*);
+extern void _jit_getarg_c(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_uc(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_s(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_us(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_i(jit_state_t*, jit_gpr_t, jit_node_t*);
+#if __WORDSIZE == 64
+extern void _jit_getarg_ui(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_l(jit_state_t*, jit_gpr_t, jit_node_t*);
+#endif
+extern void _jit_putargr(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_putargi(jit_state_t*, jit_word_t, jit_node_t*);
+
+extern void _jit_prepare(jit_state_t*);
+extern void _jit_ellipsis(jit_state_t*);
+extern void _jit_va_push(jit_state_t*, jit_gpr_t);
+extern void _jit_pushargr(jit_state_t*, jit_gpr_t);
+extern void _jit_pushargi(jit_state_t*, jit_word_t);
+extern void _jit_finishr(jit_state_t*, jit_gpr_t);
+extern jit_node_t *_jit_finishi(jit_state_t*, jit_pointer_t);
+extern void _jit_ret(jit_state_t*);
+extern void _jit_retr(jit_state_t*, jit_gpr_t);
+extern void _jit_reti(jit_state_t*, jit_word_t);
+extern void _jit_retval_c(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_uc(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_s(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_us(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_i(jit_state_t*, jit_gpr_t);
+#if __WORDSIZE == 64
+extern void _jit_retval_ui(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_l(jit_state_t*, jit_gpr_t);
+#endif
+extern void _jit_epilog(jit_state_t*);
+
+#define jit_patch(u)           _jit_patch(_jit,u)
+extern void _jit_patch(jit_state_t*, jit_node_t*);
+#define jit_patch_at(u,v)      _jit_patch_at(_jit,u,v)
+extern void _jit_patch_at(jit_state_t*, jit_node_t*, jit_node_t*);
+#define jit_patch_abs(u,v)     _jit_patch_abs(_jit,u,v)
+extern void _jit_patch_abs(jit_state_t*, jit_node_t*, jit_pointer_t);
+#define jit_realize()          _jit_realize(_jit)
+extern void _jit_realize(jit_state_t*);
+#define jit_get_code(u)                _jit_get_code(_jit,u)
+extern jit_pointer_t _jit_get_code(jit_state_t*, jit_word_t*);
+#define jit_set_code(u,v)      _jit_set_code(_jit,u,v)
+extern void _jit_set_code(jit_state_t*, jit_pointer_t, jit_word_t);
+#define jit_get_data(u,v)      _jit_get_data(_jit,u,v)
+extern jit_pointer_t _jit_get_data(jit_state_t*, jit_word_t*, jit_word_t*);
+#define jit_set_data(u,v,w)    _jit_set_data(_jit,u,v,w)
+extern void _jit_set_data(jit_state_t*, jit_pointer_t, jit_word_t, jit_word_t);
+#define jit_frame(u)           _jit_frame(_jit,u)
+extern void _jit_frame(jit_state_t*, jit_int32_t);
+#define jit_tramp(u)           _jit_tramp(_jit,u)
+extern void _jit_tramp(jit_state_t*, jit_int32_t);
+#define jit_emit()             _jit_emit(_jit)
+extern jit_pointer_t _jit_emit(jit_state_t*);
+
+#define jit_print()            _jit_print(_jit)
+extern void _jit_print(jit_state_t*);
+
+extern jit_node_t *_jit_arg_f(jit_state_t*);
+extern void _jit_getarg_f(jit_state_t*, jit_fpr_t, jit_node_t*);
+extern void _jit_putargr_f(jit_state_t*, jit_fpr_t, jit_node_t*);
+extern void _jit_putargi_f(jit_state_t*, jit_float32_t, jit_node_t*);
+extern void _jit_pushargr_f(jit_state_t*, jit_fpr_t);
+extern void _jit_pushargi_f(jit_state_t*, jit_float32_t);
+extern void _jit_retr_f(jit_state_t*, jit_fpr_t);
+extern void _jit_reti_f(jit_state_t*, jit_float32_t);
+extern void _jit_retval_f(jit_state_t*, jit_fpr_t);
+
+extern jit_node_t *_jit_arg_d(jit_state_t*);
+extern void _jit_getarg_d(jit_state_t*, jit_fpr_t, jit_node_t*);
+extern void _jit_putargr_d(jit_state_t*, jit_fpr_t, jit_node_t*);
+extern void _jit_putargi_d(jit_state_t*, jit_float64_t, jit_node_t*);
+extern void _jit_pushargr_d(jit_state_t*, jit_fpr_t);
+extern void _jit_pushargi_d(jit_state_t*, jit_float64_t);
+extern void _jit_retr_d(jit_state_t*, jit_fpr_t);
+extern void _jit_reti_d(jit_state_t*, jit_float64_t);
+extern void _jit_retval_d(jit_state_t*, jit_fpr_t);
+
+#define jit_new_node(c)                _jit_new_node(_jit,c)
+extern jit_node_t *_jit_new_node(jit_state_t*, jit_code_t);
+#define jit_new_node_w(c,u)    _jit_new_node_w(_jit,c,u)
+extern jit_node_t *_jit_new_node_w(jit_state_t*, jit_code_t,
+                                  jit_word_t);
+#define jit_new_node_f(c,u)    _jit_new_node_f(_jit,c,u)
+extern jit_node_t *_jit_new_node_f(jit_state_t*, jit_code_t,
+                                  jit_float32_t);
+#define jit_new_node_d(c,u)    _jit_new_node_d(_jit,c,u)
+extern jit_node_t *_jit_new_node_d(jit_state_t*, jit_code_t,
+                                  jit_float64_t);
+#define jit_new_node_p(c,u)    _jit_new_node_p(_jit,c,u)
+extern jit_node_t *_jit_new_node_p(jit_state_t*, jit_code_t,
+                                  jit_pointer_t);
+#define jit_new_node_ww(c,u,v) _jit_new_node_ww(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_ww(jit_state_t*,jit_code_t,
+                                   jit_word_t, jit_word_t);
+#define jit_new_node_wp(c,u,v) _jit_new_node_wp(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_wp(jit_state_t*,jit_code_t,
+                                   jit_word_t, jit_pointer_t);
+#define jit_new_node_fp(c,u,v) _jit_new_node_fp(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_fp(jit_state_t*,jit_code_t,
+                                   jit_float32_t, jit_pointer_t);
+#define jit_new_node_dp(c,u,v) _jit_new_node_dp(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_dp(jit_state_t*,jit_code_t,
+                                   jit_float64_t, jit_pointer_t);
+#define jit_new_node_pw(c,u,v) _jit_new_node_pw(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_pw(jit_state_t*,jit_code_t,
+                                   jit_pointer_t, jit_word_t);
+#define jit_new_node_wf(c,u,v) _jit_new_node_wf(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_wf(jit_state_t*, jit_code_t,
+                                   jit_word_t, jit_float32_t);
+#define jit_new_node_wd(c,u,v) _jit_new_node_wd(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_wd(jit_state_t*, jit_code_t,
+                                   jit_word_t, jit_float64_t);
+#define jit_new_node_www(c,u,v,w) _jit_new_node_www(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_www(jit_state_t*, jit_code_t,
+                                    jit_word_t, jit_word_t, jit_word_t);
+#define jit_new_node_qww(c,l,h,v,w) _jit_new_node_qww(_jit,c,l,h,v,w)
+extern jit_node_t *_jit_new_node_qww(jit_state_t*, jit_code_t,
+                                    jit_int32_t, jit_int32_t,
+                                    jit_word_t, jit_word_t);
+#define jit_new_node_wwf(c,u,v,w) _jit_new_node_wwf(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_wwf(jit_state_t*, jit_code_t,
+                                    jit_word_t, jit_word_t, jit_float32_t);
+#define jit_new_node_wwd(c,u,v,w) _jit_new_node_wwd(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_wwd(jit_state_t*, jit_code_t,
+                                    jit_word_t, jit_word_t, jit_float64_t);
+#define jit_new_node_pww(c,u,v,w) _jit_new_node_pww(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_pww(jit_state_t*, jit_code_t,
+                                    jit_pointer_t, jit_word_t, jit_word_t);
+#define jit_new_node_pwf(c,u,v,w) _jit_new_node_pwf(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_pwf(jit_state_t*, jit_code_t,
+                                    jit_pointer_t, jit_word_t, jit_float32_t);
+#define jit_new_node_pwd(c,u,v,w) _jit_new_node_pwd(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_pwd(jit_state_t*, jit_code_t,
+                                    jit_pointer_t, jit_word_t, jit_float64_t);
+
+#define jit_arg_register_p(u)          _jit_arg_register_p(_jit,u)
+extern jit_bool_t _jit_arg_register_p(jit_state_t*, jit_node_t*);
+#define jit_callee_save_p(u)           _jit_callee_save_p(_jit,u)
+extern jit_bool_t _jit_callee_save_p(jit_state_t*, jit_int32_t);
+#define jit_pointer_p(u)               _jit_pointer_p(_jit,u)
+extern jit_bool_t _jit_pointer_p(jit_state_t*,jit_pointer_t);
+
+#define jit_get_note(n,u,v,w)  _jit_get_note(_jit,n,u,v,w)
+extern jit_bool_t _jit_get_note(jit_state_t*,jit_pointer_t,char**,char**,int*);
+
+#define jit_disassemble()              _jit_disassemble(_jit)
+extern void _jit_disassemble(jit_state_t*);
+
+extern void jit_set_memory_functions(jit_alloc_func_ptr,
+                                    jit_realloc_func_ptr,
+                                    jit_free_func_ptr);
+extern void jit_get_memory_functions(jit_alloc_func_ptr*,
+                                    jit_realloc_func_ptr*,
+                                    jit_free_func_ptr*);
+
+#endif /* _lightning_h */
diff --git a/deps/lightning/include/lightning.h.in b/deps/lightning/include/lightning.h.in
new file mode 100644 (file)
index 0000000..70560c9
--- /dev/null
@@ -0,0 +1,1092 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _lightning_h
+#define _lightning_h
+
+#include <unistd.h>
+#include <stdlib.h>
+@MAYBE_INCLUDE_STDINT_H@
+#include <string.h>
+
+#if defined(__hpux) && defined(__hppa__)
+#  include <machine/param.h>
+#endif
+#if defined(__alpha__) && defined(__osf__)
+#  include <machine/endian.h>
+#endif
+
+#ifndef __WORDSIZE
+#  if defined(WORDSIZE)                                /* ppc darwin */
+#    define __WORDSIZE         WORDSIZE
+#  elif defined(__SIZEOF_POINTER__)            /* ppc aix */
+#    define __WORDSIZE         (__SIZEOF_POINTER__ << 3)
+#  elif defined(_ILP32)                                /* hppa hp-ux */
+#    define __WORDSIZE         32
+#  elif defined(_LP64)                         /* ia64 hp-ux (with cc +DD64) */
+#    define __WORDSIZE         64
+#  elif defined(_MIPS_SZPTR)                   /* mips irix */
+#    if _MIPS_SZPTR == 32
+#      define __WORDSIZE       32
+#    else
+#      define __WORDSIZE       64
+#    endif
+#  else                                                /* From FreeBSD 9.1 stdint.h */
+#    if defined(UINTPTR_MAX) && defined(UINT64_MAX) && \
+       (UINTPTR_MAX == UINT64_MAX)
+#      define __WORDSIZE       64
+#    else
+#      define __WORDSIZE       32
+#    endif
+#  endif
+#endif
+#ifndef __LITTLE_ENDIAN
+#  if defined(LITTLE_ENDIAN)                   /* ppc darwin */
+#    define __LITTLE_ENDIAN    LITTLE_ENDIAN
+#  elif defined(__ORDER_LITTLE_ENDIAN__)       /* ppc aix */
+#    define __LITTLE_ENDIAN    __ORDER_LITTLE_ENDIAN__
+#  else
+#    define __LITTLE_ENDIAN    1234
+#  endif
+#endif
+#ifndef __BIG_ENDIAN
+#  if defined(BIG_ENDIAN)                      /* ppc darwin */
+#    define __BIG_ENDIAN       BIG_ENDIAN
+#  elif defined(__ORDER_BIG_ENDIAN__)          /* ppc aix */
+#    define __BIG_ENDIAN       __ORDER_BIG_ENDIAN__
+#  else
+#    define __BIG_ENDIAN       4321
+#  endif
+#endif
+#ifndef __BYTE_ORDER
+#  if defined(BYTE_ORDER)                      /* ppc darwin */
+#    define __BYTE_ORDER       BYTE_ORDER
+#  elif defined(__BYTE_ORDER__)                        /* ppc aix */
+#    define __BYTE_ORDER       __BYTE_ORDER__
+#  elif defined(_BIG_ENDIAN)                   /* hppa hp-ux */
+#    define __BYTE_ORDER       __BIG_ENDIAN
+#  elif defined(__BIG_ENDIAN__)                        /* ia64 hp-ux */
+#    define __BYTE_ORDER       __BIG_ENDIAN
+#  elif defined(__i386__)                      /* 32 bit x86 solaris */
+#    define __BYTE_ORDER       __LITTLE_ENDIAN
+#  elif defined(__x86_64__)                    /* 64 bit x86 solaris */
+#    define __BYTE_ORDER       __LITTLE_ENDIAN
+#  elif defined(__MIPSEB)                      /* mips irix */
+#    define __BYTE_ORDER       __BIG_ENDIAN
+#  else
+#    error cannot figure __BYTE_ORDER
+#  endif
+#endif
+
+typedef signed char            jit_int8_t;
+typedef unsigned char          jit_uint8_t;
+typedef signed short           jit_int16_t;
+typedef unsigned short         jit_uint16_t;
+typedef signed int             jit_int32_t;
+typedef unsigned int           jit_uint32_t;
+#if __WORDSIZE == 32
+typedef signed long long       jit_int64_t;
+typedef unsigned long long     jit_uint64_t;
+typedef jit_int32_t            jit_word_t;
+typedef jit_uint32_t           jit_uword_t;
+#elif (_WIN32 && !__CYGWIN__)
+typedef signed long long       jit_int64_t;
+typedef unsigned long long     jit_uint64_t;
+typedef jit_int64_t            jit_word_t;
+typedef jit_uint64_t           jit_uword_t;
+#else
+typedef signed long            jit_int64_t;
+typedef unsigned long          jit_uint64_t;
+typedef jit_int64_t            jit_word_t;
+typedef jit_uint64_t           jit_uword_t;
+#endif
+typedef float                  jit_float32_t;
+typedef double                 jit_float64_t;
+typedef void*                  jit_pointer_t;
+typedef jit_int32_t            jit_bool_t;
+typedef jit_int32_t            jit_gpr_t;
+typedef jit_int32_t            jit_fpr_t;
+
+#if defined(__i386__) || defined(__x86_64__)
+#  include <lightning/jit_x86.h>
+#elif defined(__mips__)
+#  include <lightning/jit_mips.h>
+#elif defined(__arm__)
+#  include <lightning/jit_arm.h>
+#elif defined(__powerpc__)
+#  include <lightning/jit_ppc.h>
+#elif defined(__sparc__)
+#  include <lightning/jit_sparc.h>
+#elif defined(__ia64__)
+#  include <lightning/jit_ia64.h>
+#elif defined(__hppa__)
+#  include <lightning/jit_hppa.h>
+#elif defined(__aarch64__)
+#  include <lightning/jit_aarch64.h>
+#elif defined(__s390__) || defined(__s390x__)
+#  include <lightning/jit_s390.h>
+#elif defined(__alpha__)
+#  include <lightning/jit_alpha.h>
+#elif defined(__riscv)
+#  include <lightning/jit_riscv.h>
+#endif
+
+#define jit_flag_node          0x0001  /* patch node not absolute */
+#define jit_flag_patch         0x0002  /* jump already patched */
+#define jit_flag_data          0x0004  /* data in the constant pool */
+#define jit_flag_use           0x0008  /* do not remove marker label */
+#define jit_flag_synth         0x0010  /* synthesized instruction */
+#define jit_flag_head          0x1000  /* label reached by normal flow */
+#define jit_flag_varargs       0x2000  /* call{r,i} to varargs function */
+
+#define JIT_R(index)           jit_r(index)
+#define JIT_V(index)           jit_v(index)
+#define JIT_F(index)           jit_f(index)
+#define JIT_R_NUM              jit_r_num()
+#define JIT_V_NUM              jit_v_num()
+#define JIT_F_NUM              jit_f_num()
+
+#define JIT_DISABLE_DATA       1       /* force synthesize of constants */
+#define JIT_DISABLE_NOTE       2       /* disable debug info generation */
+
+#define jit_class_chk          0x02000000      /* just checking */
+#define jit_class_arg          0x08000000      /* argument register */
+#define jit_class_sav          0x10000000      /* callee save */
+#define jit_class_gpr          0x20000000      /* general purpose */
+#define jit_class_fpr          0x40000000      /* float */
+#define jit_class(reg)         ((reg) & 0xffff0000)
+#define jit_regno(reg)         ((reg) & 0x00007fff)
+
+typedef struct jit_node                jit_node_t;
+typedef struct jit_state       jit_state_t;
+
+typedef enum {
+    jit_code_data,
+#define jit_live(u)            jit_new_node_w(jit_code_live, u)
+#define jit_align(u)           jit_new_node_w(jit_code_align, u)
+    jit_code_live,             jit_code_align,
+    jit_code_save,             jit_code_load,
+#define jit_name(u)            _jit_name(_jit,u)
+    jit_code_name,
+#define jit_note(u, v)         _jit_note(_jit, u, v)
+#define jit_label()            _jit_label(_jit)
+#define jit_forward()          _jit_forward(_jit)
+#define jit_indirect()         _jit_indirect(_jit)
+#define jit_link(u)            _jit_link(_jit,u)
+    jit_code_note,             jit_code_label,
+
+#define jit_prolog()           _jit_prolog(_jit)
+    jit_code_prolog,
+
+#define jit_ellipsis()         _jit_ellipsis(_jit)
+    jit_code_ellipsis,
+#define jit_va_push(u)         _jit_va_push(_jit,u)
+    jit_code_va_push,
+#define jit_allocai(u)         _jit_allocai(_jit,u)
+#define jit_allocar(u, v)      _jit_allocar(_jit,u,v)
+    jit_code_allocai,          jit_code_allocar,
+
+#define jit_arg()              _jit_arg(_jit)
+    jit_code_arg,
+#define jit_getarg_c(u,v)      _jit_getarg_c(_jit,u,v)
+#define jit_getarg_uc(u,v)     _jit_getarg_uc(_jit,u,v)
+    jit_code_getarg_c,         jit_code_getarg_uc,
+#define jit_getarg_s(u,v)      _jit_getarg_s(_jit,u,v)
+#define jit_getarg_us(u,v)     _jit_getarg_us(_jit,u,v)
+    jit_code_getarg_s,         jit_code_getarg_us,
+#define jit_getarg_i(u,v)      _jit_getarg_i(_jit,u,v)
+#if __WORDSIZE == 32
+#  define jit_getarg(u,v)      jit_getarg_i(u,v)
+#else
+#  define jit_getarg(u,v)      jit_getarg_l(u,v)
+#  define jit_getarg_ui(u,v)   _jit_getarg_ui(_jit,u,v)
+#  define jit_getarg_l(u,v)    _jit_getarg_l(_jit,u,v)
+#endif
+    jit_code_getarg_i,         jit_code_getarg_ui,
+    jit_code_getarg_l,
+#  define jit_putargr(u,v)     _jit_putargr(_jit,u,v)
+#  define jit_putargi(u,v)     _jit_putargi(_jit,u,v)
+    jit_code_putargr,          jit_code_putargi,
+
+#define jit_va_start(u)                jit_new_node_w(jit_code_va_start, u)
+    jit_code_va_start,
+#define jit_va_arg(u, v)       jit_new_node_ww(jit_code_va_arg, u, v)
+#define jit_va_arg_d(u, v)     jit_new_node_ww(jit_code_va_arg_d, u, v)
+    jit_code_va_arg,           jit_code_va_arg_d,
+#define jit_va_end(u)          jit_new_node_w(jit_code_va_end, u)
+    jit_code_va_end,
+
+#define jit_addr(u,v,w)                jit_new_node_www(jit_code_addr,u,v,w)
+#define jit_addi(u,v,w)                jit_new_node_www(jit_code_addi,u,v,w)
+    jit_code_addr,             jit_code_addi,
+#define jit_addcr(u,v,w)       jit_new_node_www(jit_code_addcr,u,v,w)
+#define jit_addci(u,v,w)       jit_new_node_www(jit_code_addci,u,v,w)
+    jit_code_addcr,            jit_code_addci,
+#define jit_addxr(u,v,w)       jit_new_node_www(jit_code_addxr,u,v,w)
+#define jit_addxi(u,v,w)       jit_new_node_www(jit_code_addxi,u,v,w)
+    jit_code_addxr,            jit_code_addxi,
+#define jit_subr(u,v,w)                jit_new_node_www(jit_code_subr,u,v,w)
+#define jit_subi(u,v,w)                jit_new_node_www(jit_code_subi,u,v,w)
+    jit_code_subr,             jit_code_subi,
+#define jit_subcr(u,v,w)       jit_new_node_www(jit_code_subcr,u,v,w)
+#define jit_subci(u,v,w)       jit_new_node_www(jit_code_subci,u,v,w)
+    jit_code_subcr,            jit_code_subci,
+#define jit_subxr(u,v,w)       jit_new_node_www(jit_code_subxr,u,v,w)
+#define jit_subxi(u,v,w)       jit_new_node_www(jit_code_subxi,u,v,w)
+    jit_code_subxr,            jit_code_subxi,
+#define jit_rsbr(u,v,w)                jit_subr(u,w,v)
+#define jit_rsbi(u,v,w)                jit_new_node_www(jit_code_rsbi,u,v,w)
+    jit_code_rsbi,
+#define jit_mulr(u,v,w)                jit_new_node_www(jit_code_mulr,u,v,w)
+#define jit_muli(u,v,w)                jit_new_node_www(jit_code_muli,u,v,w)
+    jit_code_mulr,             jit_code_muli,
+#define jit_qmulr(l,h,v,w)     jit_new_node_qww(jit_code_qmulr,l,h,v,w)
+#define jit_qmuli(l,h,v,w)     jit_new_node_qww(jit_code_qmuli,l,h,v,w)
+    jit_code_qmulr,            jit_code_qmuli,
+#define jit_qmulr_u(l,h,v,w)   jit_new_node_qww(jit_code_qmulr_u,l,h,v,w)
+#define jit_qmuli_u(l,h,v,w)   jit_new_node_qww(jit_code_qmuli_u,l,h,v,w)
+    jit_code_qmulr_u,          jit_code_qmuli_u,
+#define jit_divr(u,v,w)                jit_new_node_www(jit_code_divr,u,v,w)
+#define jit_divi(u,v,w)                jit_new_node_www(jit_code_divi,u,v,w)
+    jit_code_divr,             jit_code_divi,
+#define jit_divr_u(u,v,w)      jit_new_node_www(jit_code_divr_u,u,v,w)
+#define jit_divi_u(u,v,w)      jit_new_node_www(jit_code_divi_u,u,v,w)
+    jit_code_divr_u,           jit_code_divi_u,
+#define jit_qdivr(l,h,v,w)     jit_new_node_qww(jit_code_qdivr,l,h,v,w)
+#define jit_qdivi(l,h,v,w)     jit_new_node_qww(jit_code_qdivi,l,h,v,w)
+    jit_code_qdivr,            jit_code_qdivi,
+#define jit_qdivr_u(l,h,v,w)   jit_new_node_qww(jit_code_qdivr_u,l,h,v,w)
+#define jit_qdivi_u(l,h,v,w)   jit_new_node_qww(jit_code_qdivi_u,l,h,v,w)
+    jit_code_qdivr_u,          jit_code_qdivi_u,
+#define jit_remr(u,v,w)                jit_new_node_www(jit_code_remr,u,v,w)
+#define jit_remi(u,v,w)                jit_new_node_www(jit_code_remi,u,v,w)
+    jit_code_remr,             jit_code_remi,
+#define jit_remr_u(u,v,w)      jit_new_node_www(jit_code_remr_u,u,v,w)
+#define jit_remi_u(u,v,w)      jit_new_node_www(jit_code_remi_u,u,v,w)
+    jit_code_remr_u,           jit_code_remi_u,
+
+#define jit_andr(u,v,w)                jit_new_node_www(jit_code_andr,u,v,w)
+#define jit_andi(u,v,w)                jit_new_node_www(jit_code_andi,u,v,w)
+    jit_code_andr,             jit_code_andi,
+#define jit_orr(u,v,w)         jit_new_node_www(jit_code_orr,u,v,w)
+#define jit_ori(u,v,w)         jit_new_node_www(jit_code_ori,u,v,w)
+    jit_code_orr,              jit_code_ori,
+#define jit_xorr(u,v,w)                jit_new_node_www(jit_code_xorr,u,v,w)
+#define jit_xori(u,v,w)                jit_new_node_www(jit_code_xori,u,v,w)
+    jit_code_xorr,             jit_code_xori,
+
+#define jit_lshr(u,v,w)                jit_new_node_www(jit_code_lshr,u,v,w)
+#define jit_lshi(u,v,w)                jit_new_node_www(jit_code_lshi,u,v,w)
+    jit_code_lshr,             jit_code_lshi,
+#define jit_rshr(u,v,w)                jit_new_node_www(jit_code_rshr,u,v,w)
+#define jit_rshi(u,v,w)                jit_new_node_www(jit_code_rshi,u,v,w)
+    jit_code_rshr,             jit_code_rshi,
+#define jit_rshr_u(u,v,w)      jit_new_node_www(jit_code_rshr_u,u,v,w)
+#define jit_rshi_u(u,v,w)      jit_new_node_www(jit_code_rshi_u,u,v,w)
+    jit_code_rshr_u,           jit_code_rshi_u,
+
+#define jit_negr(u,v)          jit_new_node_ww(jit_code_negr,u,v)
+#define jit_comr(u,v)          jit_new_node_ww(jit_code_comr,u,v)
+    jit_code_negr,             jit_code_comr,
+
+#define jit_ltr(u,v,w)         jit_new_node_www(jit_code_ltr,u,v,w)
+#define jit_lti(u,v,w)         jit_new_node_www(jit_code_lti,u,v,w)
+    jit_code_ltr,              jit_code_lti,
+#define jit_ltr_u(u,v,w)       jit_new_node_www(jit_code_ltr_u,u,v,w)
+#define jit_lti_u(u,v,w)       jit_new_node_www(jit_code_lti_u,u,v,w)
+    jit_code_ltr_u,            jit_code_lti_u,
+#define jit_ler(u,v,w)         jit_new_node_www(jit_code_ler,u,v,w)
+#define jit_lei(u,v,w)         jit_new_node_www(jit_code_lei,u,v,w)
+    jit_code_ler,              jit_code_lei,
+#define jit_ler_u(u,v,w)       jit_new_node_www(jit_code_ler_u,u,v,w)
+#define jit_lei_u(u,v,w)       jit_new_node_www(jit_code_lei_u,u,v,w)
+    jit_code_ler_u,            jit_code_lei_u,
+#define jit_eqr(u,v,w)         jit_new_node_www(jit_code_eqr,u,v,w)
+#define jit_eqi(u,v,w)         jit_new_node_www(jit_code_eqi,u,v,w)
+    jit_code_eqr,              jit_code_eqi,
+#define jit_ger(u,v,w)         jit_new_node_www(jit_code_ger,u,v,w)
+#define jit_gei(u,v,w)         jit_new_node_www(jit_code_gei,u,v,w)
+    jit_code_ger,              jit_code_gei,
+#define jit_ger_u(u,v,w)       jit_new_node_www(jit_code_ger_u,u,v,w)
+#define jit_gei_u(u,v,w)       jit_new_node_www(jit_code_gei_u,u,v,w)
+    jit_code_ger_u,            jit_code_gei_u,
+#define jit_gtr(u,v,w)         jit_new_node_www(jit_code_gtr,u,v,w)
+#define jit_gti(u,v,w)         jit_new_node_www(jit_code_gti,u,v,w)
+    jit_code_gtr,              jit_code_gti,
+#define jit_gtr_u(u,v,w)       jit_new_node_www(jit_code_gtr_u,u,v,w)
+#define jit_gti_u(u,v,w)       jit_new_node_www(jit_code_gti_u,u,v,w)
+    jit_code_gtr_u,            jit_code_gti_u,
+#define jit_ner(u,v,w)         jit_new_node_www(jit_code_ner,u,v,w)
+#define jit_nei(u,v,w)         jit_new_node_www(jit_code_nei,u,v,w)
+    jit_code_ner,              jit_code_nei,
+
+#define jit_movr(u,v)          jit_new_node_ww(jit_code_movr,u,v)
+#define jit_movi(u,v)          jit_new_node_ww(jit_code_movi,u,v)
+    jit_code_movr,             jit_code_movi,
+#define jit_extr_c(u,v)                jit_new_node_ww(jit_code_extr_c,u,v)
+#define jit_extr_uc(u,v)       jit_new_node_ww(jit_code_extr_uc,u,v)
+    jit_code_extr_c,           jit_code_extr_uc,
+#define jit_extr_s(u,v)                jit_new_node_ww(jit_code_extr_s,u,v)
+#define jit_extr_us(u,v)       jit_new_node_ww(jit_code_extr_us,u,v)
+    jit_code_extr_s,           jit_code_extr_us,
+#if __WORDSIZE == 64
+#  define jit_extr_i(u,v)      jit_new_node_ww(jit_code_extr_i,u,v)
+#  define jit_extr_ui(u,v)     jit_new_node_ww(jit_code_extr_ui,u,v)
+#endif
+    jit_code_extr_i,           jit_code_extr_ui,
+
+#define jit_htonr_us(u,v)      jit_new_node_ww(jit_code_htonr_us,u,v)
+#define jit_ntohr_us(u,v)      jit_new_node_ww(jit_code_htonr_us,u,v)
+    jit_code_htonr_us,
+#define jit_htonr_ui(u,v)      jit_new_node_ww(jit_code_htonr_ui,u,v)
+#define jit_ntohr_ui(u,v)      jit_new_node_ww(jit_code_htonr_ui,u,v)
+#if __WORDSIZE == 32
+#  define jit_htonr(u,v)       jit_new_node_ww(jit_code_htonr_ui,u,v)
+#  define jit_ntohr(u,v)       jit_new_node_ww(jit_code_htonr_ui,u,v)
+#else
+#define jit_htonr_ul(u,v)      jit_new_node_ww(jit_code_htonr_ul,u,v)
+#define jit_ntohr_ul(u,v)      jit_new_node_ww(jit_code_htonr_ul,u,v)
+#  define jit_htonr(u,v)       jit_new_node_ww(jit_code_htonr_ul,u,v)
+#  define jit_ntohr(u,v)       jit_new_node_ww(jit_code_htonr_ul,u,v)
+#endif
+    jit_code_htonr_ui,         jit_code_htonr_ul,
+
+#define jit_ldr_c(u,v)         jit_new_node_ww(jit_code_ldr_c,u,v)
+#define jit_ldi_c(u,v)         jit_new_node_wp(jit_code_ldi_c,u,v)
+    jit_code_ldr_c,            jit_code_ldi_c,
+#define jit_ldr_uc(u,v)                jit_new_node_ww(jit_code_ldr_uc,u,v)
+#define jit_ldi_uc(u,v)                jit_new_node_wp(jit_code_ldi_uc,u,v)
+    jit_code_ldr_uc,           jit_code_ldi_uc,
+#define jit_ldr_s(u,v)         jit_new_node_ww(jit_code_ldr_s,u,v)
+#define jit_ldi_s(u,v)         jit_new_node_wp(jit_code_ldi_s,u,v)
+    jit_code_ldr_s,            jit_code_ldi_s,
+#define jit_ldr_us(u,v)                jit_new_node_ww(jit_code_ldr_us,u,v)
+#define jit_ldi_us(u,v)                jit_new_node_wp(jit_code_ldi_us,u,v)
+    jit_code_ldr_us,           jit_code_ldi_us,
+#define jit_ldr_i(u,v)         jit_new_node_ww(jit_code_ldr_i,u,v)
+#define jit_ldi_i(u,v)         jit_new_node_wp(jit_code_ldi_i,u,v)
+    jit_code_ldr_i,            jit_code_ldi_i,
+#if __WORDSIZE == 32
+#  define jit_ldr(u,v)         jit_ldr_i(u,v)
+#  define jit_ldi(u,v)         jit_ldi_i(u,v)
+#else
+#  define jit_ldr(u,v)         jit_ldr_l(u,v)
+#  define jit_ldi(u,v)         jit_ldi_l(u,v)
+#  define jit_ldr_ui(u,v)      jit_new_node_ww(jit_code_ldr_ui,u,v)
+#  define jit_ldi_ui(u,v)      jit_new_node_wp(jit_code_ldi_ui,u,v)
+#define jit_ldr_l(u,v)         jit_new_node_ww(jit_code_ldr_l,u,v)
+#define jit_ldi_l(u,v)         jit_new_node_wp(jit_code_ldi_l,u,v)
+#endif
+    jit_code_ldr_ui,           jit_code_ldi_ui,
+    jit_code_ldr_l,            jit_code_ldi_l,
+
+#define jit_ldxr_c(u,v,w)      jit_new_node_www(jit_code_ldxr_c,u,v,w)
+#define jit_ldxi_c(u,v,w)      jit_new_node_www(jit_code_ldxi_c,u,v,w)
+    jit_code_ldxr_c,           jit_code_ldxi_c,
+#define jit_ldxr_uc(u,v,w)     jit_new_node_www(jit_code_ldxr_uc,u,v,w)
+#define jit_ldxi_uc(u,v,w)     jit_new_node_www(jit_code_ldxi_uc,u,v,w)
+    jit_code_ldxr_uc,          jit_code_ldxi_uc,
+#define jit_ldxr_s(u,v,w)      jit_new_node_www(jit_code_ldxr_s,u,v,w)
+#define jit_ldxi_s(u,v,w)      jit_new_node_www(jit_code_ldxi_s,u,v,w)
+    jit_code_ldxr_s,           jit_code_ldxi_s,
+#define jit_ldxr_us(u,v,w)     jit_new_node_www(jit_code_ldxr_us,u,v,w)
+#define jit_ldxi_us(u,v,w)     jit_new_node_www(jit_code_ldxi_us,u,v,w)
+    jit_code_ldxr_us,          jit_code_ldxi_us,
+#define jit_ldxr_i(u,v,w)      jit_new_node_www(jit_code_ldxr_i,u,v,w)
+#define jit_ldxi_i(u,v,w)      jit_new_node_www(jit_code_ldxi_i,u,v,w)
+    jit_code_ldxr_i,           jit_code_ldxi_i,
+#if __WORDSIZE == 32
+#  define jit_ldxr(u,v,w)      jit_ldxr_i(u,v,w)
+#  define jit_ldxi(u,v,w)      jit_ldxi_i(u,v,w)
+#else
+#  define jit_ldxr_ui(u,v,w)   jit_new_node_www(jit_code_ldxr_ui,u,v,w)
+#  define jit_ldxi_ui(u,v,w)   jit_new_node_www(jit_code_ldxi_ui,u,v,w)
+#  define jit_ldxr_l(u,v,w)    jit_new_node_www(jit_code_ldxr_l,u,v,w)
+#  define jit_ldxi_l(u,v,w)    jit_new_node_www(jit_code_ldxi_l,u,v,w)
+#  define jit_ldxr(u,v,w)      jit_ldxr_l(u,v,w)
+#  define jit_ldxi(u,v,w)      jit_ldxi_l(u,v,w)
+#endif
+    jit_code_ldxr_ui,          jit_code_ldxi_ui,
+    jit_code_ldxr_l,           jit_code_ldxi_l,
+
+#define jit_str_c(u,v)         jit_new_node_ww(jit_code_str_c,u,v)
+#define jit_sti_c(u,v)         jit_new_node_pw(jit_code_sti_c,u,v)
+    jit_code_str_c,            jit_code_sti_c,
+#define jit_str_s(u,v)         jit_new_node_ww(jit_code_str_s,u,v)
+#define jit_sti_s(u,v)         jit_new_node_pw(jit_code_sti_s,u,v)
+    jit_code_str_s,            jit_code_sti_s,
+#define jit_str_i(u,v)         jit_new_node_ww(jit_code_str_i,u,v)
+#define jit_sti_i(u,v)         jit_new_node_pw(jit_code_sti_i,u,v)
+    jit_code_str_i,            jit_code_sti_i,
+#if __WORDSIZE == 32
+#  define jit_str(u,v)         jit_str_i(u,v)
+#  define jit_sti(u,v)         jit_sti_i(u,v)
+#else
+#  define jit_str(u,v)         jit_str_l(u,v)
+#  define jit_sti(u,v)         jit_sti_l(u,v)
+#  define jit_str_l(u,v)       jit_new_node_ww(jit_code_str_l,u,v)
+#  define jit_sti_l(u,v)       jit_new_node_pw(jit_code_sti_l,u,v)
+#endif
+    jit_code_str_l,            jit_code_sti_l,
+
+#define jit_stxr_c(u,v,w)      jit_new_node_www(jit_code_stxr_c,u,v,w)
+#define jit_stxi_c(u,v,w)      jit_new_node_www(jit_code_stxi_c,u,v,w)
+    jit_code_stxr_c,           jit_code_stxi_c,
+#define jit_stxr_s(u,v,w)      jit_new_node_www(jit_code_stxr_s,u,v,w)
+#define jit_stxi_s(u,v,w)      jit_new_node_www(jit_code_stxi_s,u,v,w)
+    jit_code_stxr_s,           jit_code_stxi_s,
+#define jit_stxr_i(u,v,w)      jit_new_node_www(jit_code_stxr_i,u,v,w)
+#define jit_stxi_i(u,v,w)      jit_new_node_www(jit_code_stxi_i,u,v,w)
+    jit_code_stxr_i,           jit_code_stxi_i,
+#if __WORDSIZE == 32
+#  define jit_stxr(u,v,w)      jit_stxr_i(u,v,w)
+#  define jit_stxi(u,v,w)      jit_stxi_i(u,v,w)
+#else
+#  define jit_stxr(u,v,w)      jit_stxr_l(u,v,w)
+#  define jit_stxi(u,v,w)      jit_stxi_l(u,v,w)
+#  define jit_stxr_l(u,v,w)    jit_new_node_www(jit_code_stxr_l,u,v,w)
+#  define jit_stxi_l(u,v,w)    jit_new_node_www(jit_code_stxi_l,u,v,w)
+#endif
+    jit_code_stxr_l,           jit_code_stxi_l,
+
+#define jit_bltr(v,w)          jit_new_node_pww(jit_code_bltr,NULL,v,w)
+#define jit_blti(v,w)          jit_new_node_pww(jit_code_blti,NULL,v,w)
+    jit_code_bltr,             jit_code_blti,
+#define jit_bltr_u(v,w)                jit_new_node_pww(jit_code_bltr_u,NULL,v,w)
+#define jit_blti_u(v,w)                jit_new_node_pww(jit_code_blti_u,NULL,v,w)
+    jit_code_bltr_u,           jit_code_blti_u,
+#define jit_bler(v,w)          jit_new_node_pww(jit_code_bler,NULL,v,w)
+#define jit_blei(v,w)          jit_new_node_pww(jit_code_blei,NULL,v,w)
+    jit_code_bler,             jit_code_blei,
+#define jit_bler_u(v,w)                jit_new_node_pww(jit_code_bler_u,NULL,v,w)
+#define jit_blei_u(v,w)                jit_new_node_pww(jit_code_blei_u,NULL,v,w)
+    jit_code_bler_u,           jit_code_blei_u,
+#define jit_beqr(v,w)          jit_new_node_pww(jit_code_beqr,NULL,v,w)
+#define jit_beqi(v,w)          jit_new_node_pww(jit_code_beqi,NULL,v,w)
+    jit_code_beqr,             jit_code_beqi,
+#define jit_bger(v,w)          jit_new_node_pww(jit_code_bger,NULL,v,w)
+#define jit_bgei(v,w)          jit_new_node_pww(jit_code_bgei,NULL,v,w)
+    jit_code_bger,             jit_code_bgei,
+#define jit_bger_u(v,w)                jit_new_node_pww(jit_code_bger_u,NULL,v,w)
+#define jit_bgei_u(v,w)                jit_new_node_pww(jit_code_bgei_u,NULL,v,w)
+    jit_code_bger_u,           jit_code_bgei_u,
+#define jit_bgtr(v,w)          jit_new_node_pww(jit_code_bgtr,NULL,v,w)
+#define jit_bgti(v,w)          jit_new_node_pww(jit_code_bgti,NULL,v,w)
+    jit_code_bgtr,             jit_code_bgti,
+#define jit_bgtr_u(v,w)                jit_new_node_pww(jit_code_bgtr_u,NULL,v,w)
+#define jit_bgti_u(v,w)                jit_new_node_pww(jit_code_bgti_u,NULL,v,w)
+    jit_code_bgtr_u,           jit_code_bgti_u,
+#define jit_bner(v,w)          jit_new_node_pww(jit_code_bner,NULL,v,w)
+#define jit_bnei(v,w)          jit_new_node_pww(jit_code_bnei,NULL,v,w)
+    jit_code_bner,             jit_code_bnei,
+
+#define jit_bmsr(v,w)          jit_new_node_pww(jit_code_bmsr,NULL,v,w)
+#define jit_bmsi(v,w)          jit_new_node_pww(jit_code_bmsi,NULL,v,w)
+    jit_code_bmsr,             jit_code_bmsi,
+#define jit_bmcr(v,w)          jit_new_node_pww(jit_code_bmcr,NULL,v,w)
+#define jit_bmci(v,w)          jit_new_node_pww(jit_code_bmci,NULL,v,w)
+    jit_code_bmcr,             jit_code_bmci,
+
+#define jit_boaddr(v,w)                jit_new_node_pww(jit_code_boaddr,NULL,v,w)
+#define jit_boaddi(v,w)                jit_new_node_pww(jit_code_boaddi,NULL,v,w)
+    jit_code_boaddr,           jit_code_boaddi,
+#define jit_boaddr_u(v,w)      jit_new_node_pww(jit_code_boaddr_u,NULL,v,w)
+#define jit_boaddi_u(v,w)      jit_new_node_pww(jit_code_boaddi_u,NULL,v,w)
+    jit_code_boaddr_u,         jit_code_boaddi_u,
+#define jit_bxaddr(v,w)                jit_new_node_pww(jit_code_bxaddr,NULL,v,w)
+#define jit_bxaddi(v,w)                jit_new_node_pww(jit_code_bxaddi,NULL,v,w)
+    jit_code_bxaddr,           jit_code_bxaddi,
+#define jit_bxaddr_u(v,w)      jit_new_node_pww(jit_code_bxaddr_u,NULL,v,w)
+#define jit_bxaddi_u(v,w)      jit_new_node_pww(jit_code_bxaddi_u,NULL,v,w)
+    jit_code_bxaddr_u,         jit_code_bxaddi_u,
+#define jit_bosubr(v,w)                jit_new_node_pww(jit_code_bosubr,NULL,v,w)
+#define jit_bosubi(v,w)                jit_new_node_pww(jit_code_bosubi,NULL,v,w)
+    jit_code_bosubr,           jit_code_bosubi,
+#define jit_bosubr_u(v,w)      jit_new_node_pww(jit_code_bosubr_u,NULL,v,w)
+#define jit_bosubi_u(v,w)      jit_new_node_pww(jit_code_bosubi_u,NULL,v,w)
+    jit_code_bosubr_u,         jit_code_bosubi_u,
+#define jit_bxsubr(v,w)                jit_new_node_pww(jit_code_bxsubr,NULL,v,w)
+#define jit_bxsubi(v,w)                jit_new_node_pww(jit_code_bxsubi,NULL,v,w)
+    jit_code_bxsubr,           jit_code_bxsubi,
+#define jit_bxsubr_u(v,w)      jit_new_node_pww(jit_code_bxsubr_u,NULL,v,w)
+#define jit_bxsubi_u(v,w)      jit_new_node_pww(jit_code_bxsubi_u,NULL,v,w)
+    jit_code_bxsubr_u,         jit_code_bxsubi_u,
+
+#define jit_jmpr(u)            jit_new_node_w(jit_code_jmpr,u)
+#define jit_jmpi()             jit_new_node_p(jit_code_jmpi,NULL)
+    jit_code_jmpr,             jit_code_jmpi,
+#define jit_callr(u)           jit_new_node_w(jit_code_callr,u)
+#define jit_calli(u)           jit_new_node_p(jit_code_calli,u)
+    jit_code_callr,            jit_code_calli,
+
+#define jit_prepare()          _jit_prepare(_jit)
+    jit_code_prepare,
+#define jit_pushargr(u)                _jit_pushargr(_jit,u)
+#define jit_pushargi(u)                _jit_pushargi(_jit,u)
+    jit_code_pushargr,         jit_code_pushargi,
+#define jit_finishr(u)         _jit_finishr(_jit,u)
+#define jit_finishi(u)         _jit_finishi(_jit,u)
+    jit_code_finishr,          jit_code_finishi,
+#define jit_ret()              _jit_ret(_jit)
+    jit_code_ret,
+#define jit_retr(u)            _jit_retr(_jit,u)
+#define jit_reti(u)            _jit_reti(_jit,u)
+    jit_code_retr,             jit_code_reti,
+#define jit_retval_c(u)                _jit_retval_c(_jit,u)
+#define jit_retval_uc(u)       _jit_retval_uc(_jit,u)
+    jit_code_retval_c,         jit_code_retval_uc,
+#define jit_retval_s(u)                _jit_retval_s(_jit,u)
+#define jit_retval_us(u)       _jit_retval_us(_jit,u)
+    jit_code_retval_s,         jit_code_retval_us,
+#define jit_retval_i(u)                _jit_retval_i(_jit,u)
+#if __WORDSIZE == 32
+#  define jit_retval(u)                jit_retval_i(u)
+#else
+#  define jit_retval(u)                jit_retval_l(u)
+#  define jit_retval_ui(u)     _jit_retval_ui(_jit,u)
+#  define jit_retval_l(u)      _jit_retval_l(_jit,u)
+#endif
+    jit_code_retval_i,         jit_code_retval_ui,
+    jit_code_retval_l,
+
+#define jit_epilog()           _jit_epilog(_jit)
+    jit_code_epilog,
+
+#define jit_arg_f()            _jit_arg_f(_jit)
+    jit_code_arg_f,
+#define jit_getarg_f(u,v)      _jit_getarg_f(_jit,u,v)
+    jit_code_getarg_f,
+#define jit_putargr_f(u,v)     _jit_putargr_f(_jit,u,v)
+#define jit_putargi_f(u,v)     _jit_putargi_f(_jit,u,v)
+    jit_code_putargr_f,                jit_code_putargi_f,
+
+#define jit_addr_f(u,v,w)      jit_new_node_www(jit_code_addr_f,u,v,w)
+#define jit_addi_f(u,v,w)      jit_new_node_wwf(jit_code_addi_f,u,v,w)
+    jit_code_addr_f,           jit_code_addi_f,
+#define jit_subr_f(u,v,w)      jit_new_node_www(jit_code_subr_f,u,v,w)
+#define jit_subi_f(u,v,w)      jit_new_node_wwf(jit_code_subi_f,u,v,w)
+    jit_code_subr_f,           jit_code_subi_f,
+#define jit_rsbr_f(u,v,w)      jit_subr_f(u,w,v)
+#define jit_rsbi_f(u,v,w)      jit_new_node_wwf(jit_code_rsbi_f,u,v,w)
+    jit_code_rsbi_f,
+#define jit_mulr_f(u,v,w)      jit_new_node_www(jit_code_mulr_f,u,v,w)
+#define jit_muli_f(u,v,w)      jit_new_node_wwf(jit_code_muli_f,u,v,w)
+    jit_code_mulr_f,           jit_code_muli_f,
+#define jit_divr_f(u,v,w)      jit_new_node_www(jit_code_divr_f,u,v,w)
+#define jit_divi_f(u,v,w)      jit_new_node_wwf(jit_code_divi_f,u,v,w)
+    jit_code_divr_f,           jit_code_divi_f,
+#define jit_negr_f(u,v)                jit_new_node_ww(jit_code_negr_f,u,v)
+#define jit_absr_f(u,v)                jit_new_node_ww(jit_code_absr_f,u,v)
+#define jit_sqrtr_f(u,v)       jit_new_node_ww(jit_code_sqrtr_f,u,v)
+    jit_code_negr_f,           jit_code_absr_f,        jit_code_sqrtr_f,
+
+#define jit_ltr_f(u,v,w)       jit_new_node_www(jit_code_ltr_f,u,v,w)
+#define jit_lti_f(u,v,w)       jit_new_node_wwf(jit_code_lti_f,u,v,w)
+    jit_code_ltr_f,            jit_code_lti_f,
+#define jit_ler_f(u,v,w)       jit_new_node_www(jit_code_ler_f,u,v,w)
+#define jit_lei_f(u,v,w)       jit_new_node_wwf(jit_code_lei_f,u,v,w)
+    jit_code_ler_f,            jit_code_lei_f,
+#define jit_eqr_f(u,v,w)       jit_new_node_www(jit_code_eqr_f,u,v,w)
+#define jit_eqi_f(u,v,w)       jit_new_node_wwf(jit_code_eqi_f,u,v,w)
+    jit_code_eqr_f,            jit_code_eqi_f,
+#define jit_ger_f(u,v,w)       jit_new_node_www(jit_code_ger_f,u,v,w)
+#define jit_gei_f(u,v,w)       jit_new_node_wwf(jit_code_gei_f,u,v,w)
+    jit_code_ger_f,            jit_code_gei_f,
+#define jit_gtr_f(u,v,w)       jit_new_node_www(jit_code_gtr_f,u,v,w)
+#define jit_gti_f(u,v,w)       jit_new_node_wwf(jit_code_gti_f,u,v,w)
+    jit_code_gtr_f,            jit_code_gti_f,
+#define jit_ner_f(u,v,w)       jit_new_node_www(jit_code_ner_f,u,v,w)
+#define jit_nei_f(u,v,w)       jit_new_node_wwf(jit_code_nei_f,u,v,w)
+    jit_code_ner_f,            jit_code_nei_f,
+#define jit_unltr_f(u,v,w)     jit_new_node_www(jit_code_unltr_f,u,v,w)
+#define jit_unlti_f(u,v,w)     jit_new_node_wwf(jit_code_unlti_f,u,v,w)
+    jit_code_unltr_f,          jit_code_unlti_f,
+#define jit_unler_f(u,v,w)     jit_new_node_www(jit_code_unler_f,u,v,w)
+#define jit_unlei_f(u,v,w)     jit_new_node_wwf(jit_code_unlei_f,u,v,w)
+    jit_code_unler_f,          jit_code_unlei_f,
+#define jit_uneqr_f(u,v,w)     jit_new_node_www(jit_code_uneqr_f,u,v,w)
+#define jit_uneqi_f(u,v,w)     jit_new_node_wwf(jit_code_uneqi_f,u,v,w)
+    jit_code_uneqr_f,          jit_code_uneqi_f,
+#define jit_unger_f(u,v,w)     jit_new_node_www(jit_code_unger_f,u,v,w)
+#define jit_ungei_f(u,v,w)     jit_new_node_wwf(jit_code_ungei_f,u,v,w)
+    jit_code_unger_f,          jit_code_ungei_f,
+#define jit_ungtr_f(u,v,w)     jit_new_node_www(jit_code_ungtr_f,u,v,w)
+#define jit_ungti_f(u,v,w)     jit_new_node_wwf(jit_code_ungti_f,u,v,w)
+    jit_code_ungtr_f,          jit_code_ungti_f,
+#define jit_ltgtr_f(u,v,w)     jit_new_node_www(jit_code_ltgtr_f,u,v,w)
+#define jit_ltgti_f(u,v,w)     jit_new_node_wwf(jit_code_ltgti_f,u,v,w)
+    jit_code_ltgtr_f,          jit_code_ltgti_f,
+#define jit_ordr_f(u,v,w)      jit_new_node_www(jit_code_ordr_f,u,v,w)
+#define jit_ordi_f(u,v,w)      jit_new_node_wwf(jit_code_ordi_f,u,v,w)
+    jit_code_ordr_f,           jit_code_ordi_f,
+#define jit_unordr_f(u,v,w)    jit_new_node_www(jit_code_unordr_f,u,v,w)
+#define jit_unordi_f(u,v,w)    jit_new_node_wwf(jit_code_unordi_f,u,v,w)
+    jit_code_unordr_f,         jit_code_unordi_f,
+
+#define jit_truncr_f_i(u,v)    jit_new_node_ww(jit_code_truncr_f_i,u,v)
+    jit_code_truncr_f_i,
+#if __WORDSIZE == 32
+#  define jit_truncr_f(u,v)    jit_truncr_f_i(u,v)
+#else
+#  define jit_truncr_f(u,v)    jit_truncr_f_l(u,v)
+#  define jit_truncr_f_l(u,v)  jit_new_node_ww(jit_code_truncr_f_l,u,v)
+#endif
+    jit_code_truncr_f_l,
+#define jit_extr_f(u,v)                jit_new_node_ww(jit_code_extr_f,u,v)
+#define jit_extr_d_f(u,v)      jit_new_node_ww(jit_code_extr_d_f,u,v)
+    jit_code_extr_f,           jit_code_extr_d_f,
+#define jit_movr_f(u,v)                jit_new_node_ww(jit_code_movr_f,u,v)
+#define jit_movi_f(u,v)                jit_new_node_wf(jit_code_movi_f,u,v)
+    jit_code_movr_f,           jit_code_movi_f,
+
+#define jit_ldr_f(u,v)         jit_new_node_ww(jit_code_ldr_f,u,v)
+#define jit_ldi_f(u,v)         jit_new_node_wp(jit_code_ldi_f,u,v)
+    jit_code_ldr_f,            jit_code_ldi_f,
+#define jit_ldxr_f(u,v,w)      jit_new_node_www(jit_code_ldxr_f,u,v,w)
+#define jit_ldxi_f(u,v,w)      jit_new_node_www(jit_code_ldxi_f,u,v,w)
+    jit_code_ldxr_f,           jit_code_ldxi_f,
+#define jit_str_f(u,v)         jit_new_node_ww(jit_code_str_f,u,v)
+#define jit_sti_f(u,v)         jit_new_node_pw(jit_code_sti_f,u,v)
+    jit_code_str_f,            jit_code_sti_f,
+#define jit_stxr_f(u,v,w)      jit_new_node_www(jit_code_stxr_f,u,v,w)
+#define jit_stxi_f(u,v,w)      jit_new_node_www(jit_code_stxi_f,u,v,w)
+    jit_code_stxr_f,           jit_code_stxi_f,
+
+#define jit_bltr_f(v,w)                jit_new_node_pww(jit_code_bltr_f,NULL,v,w)
+#define jit_blti_f(v,w)                jit_new_node_pwf(jit_code_blti_f,NULL,v,w)
+    jit_code_bltr_f,           jit_code_blti_f,
+#define jit_bler_f(v,w)                jit_new_node_pww(jit_code_bler_f,NULL,v,w)
+#define jit_blei_f(v,w)                jit_new_node_pwf(jit_code_blei_f,NULL,v,w)
+    jit_code_bler_f,           jit_code_blei_f,
+#define jit_beqr_f(v,w)                jit_new_node_pww(jit_code_beqr_f,NULL,v,w)
+#define jit_beqi_f(v,w)                jit_new_node_pwf(jit_code_beqi_f,NULL,v,w)
+    jit_code_beqr_f,           jit_code_beqi_f,
+#define jit_bger_f(v,w)                jit_new_node_pww(jit_code_bger_f,NULL,v,w)
+#define jit_bgei_f(v,w)                jit_new_node_pwf(jit_code_bgei_f,NULL,v,w)
+    jit_code_bger_f,           jit_code_bgei_f,
+#define jit_bgtr_f(v,w)                jit_new_node_pww(jit_code_bgtr_f,NULL,v,w)
+#define jit_bgti_f(v,w)                jit_new_node_pwf(jit_code_bgti_f,NULL,v,w)
+    jit_code_bgtr_f,           jit_code_bgti_f,
+#define jit_bner_f(v,w)                jit_new_node_pww(jit_code_bner_f,NULL,v,w)
+#define jit_bnei_f(v,w)                jit_new_node_pwf(jit_code_bnei_f,NULL,v,w)
+    jit_code_bner_f,           jit_code_bnei_f,
+#define jit_bunltr_f(v,w)      jit_new_node_pww(jit_code_bunltr_f,NULL,v,w)
+#define jit_bunlti_f(v,w)      jit_new_node_pwf(jit_code_bunlti_f,NULL,v,w)
+    jit_code_bunltr_f,         jit_code_bunlti_f,
+#define jit_bunler_f(v,w)      jit_new_node_pww(jit_code_bunler_f,NULL,v,w)
+#define jit_bunlei_f(v,w)      jit_new_node_pwf(jit_code_bunlei_f,NULL,v,w)
+    jit_code_bunler_f,         jit_code_bunlei_f,
+#define jit_buneqr_f(v,w)      jit_new_node_pww(jit_code_buneqr_f,NULL,v,w)
+#define jit_buneqi_f(v,w)      jit_new_node_pwf(jit_code_buneqi_f,NULL,v,w)
+    jit_code_buneqr_f,         jit_code_buneqi_f,
+#define jit_bunger_f(v,w)      jit_new_node_pww(jit_code_bunger_f,NULL,v,w)
+#define jit_bungei_f(v,w)      jit_new_node_pwf(jit_code_bungei_f,NULL,v,w)
+    jit_code_bunger_f,         jit_code_bungei_f,
+#define jit_bungtr_f(v,w)      jit_new_node_pww(jit_code_bungtr_f,NULL,v,w)
+#define jit_bungti_f(v,w)      jit_new_node_pwf(jit_code_bungti_f,NULL,v,w)
+    jit_code_bungtr_f,         jit_code_bungti_f,
+#define jit_bltgtr_f(v,w)      jit_new_node_pww(jit_code_bltgtr_f,NULL,v,w)
+#define jit_bltgti_f(v,w)      jit_new_node_pwf(jit_code_bltgti_f,NULL,v,w)
+    jit_code_bltgtr_f,         jit_code_bltgti_f,
+#define jit_bordr_f(v,w)       jit_new_node_pww(jit_code_bordr_f,NULL,v,w)
+#define jit_bordi_f(v,w)       jit_new_node_pwf(jit_code_bordi_f,NULL,v,w)
+    jit_code_bordr_f,          jit_code_bordi_f,
+#define jit_bunordr_f(v,w)     jit_new_node_pww(jit_code_bunordr_f,NULL,v,w)
+#define jit_bunordi_f(v,w)     jit_new_node_pwf(jit_code_bunordi_f,NULL,v,w)
+    jit_code_bunordr_f,                jit_code_bunordi_f,
+
+#define jit_pushargr_f(u)      _jit_pushargr_f(_jit,u)
+#define jit_pushargi_f(u)      _jit_pushargi_f(_jit,u)
+    jit_code_pushargr_f,       jit_code_pushargi_f,
+#define jit_retr_f(u)          _jit_retr_f(_jit,u)
+#define jit_reti_f(u)          _jit_reti_f(_jit,u)
+    jit_code_retr_f,           jit_code_reti_f,
+#define jit_retval_f(u)                _jit_retval_f(_jit,u)
+    jit_code_retval_f,
+
+#define jit_arg_d()            _jit_arg_d(_jit)
+    jit_code_arg_d,
+#define jit_getarg_d(u,v)      _jit_getarg_d(_jit,u,v)
+    jit_code_getarg_d,
+#define jit_putargr_d(u,v)     _jit_putargr_d(_jit,u,v)
+#define jit_putargi_d(u,v)     _jit_putargi_d(_jit,u,v)
+    jit_code_putargr_d,                jit_code_putargi_d,
+
+#define jit_addr_d(u,v,w)      jit_new_node_www(jit_code_addr_d,u,v,w)
+#define jit_addi_d(u,v,w)      jit_new_node_wwd(jit_code_addi_d,u,v,w)
+    jit_code_addr_d,           jit_code_addi_d,
+#define jit_subr_d(u,v,w)      jit_new_node_www(jit_code_subr_d,u,v,w)
+#define jit_subi_d(u,v,w)      jit_new_node_wwd(jit_code_subi_d,u,v,w)
+    jit_code_subr_d,           jit_code_subi_d,
+#define jit_rsbr_d(u,v,w)      jit_subr_d(u,w,v)
+#define jit_rsbi_d(u,v,w)      jit_new_node_wwd(jit_code_rsbi_d,u,v,w)
+    jit_code_rsbi_d,
+#define jit_mulr_d(u,v,w)      jit_new_node_www(jit_code_mulr_d,u,v,w)
+#define jit_muli_d(u,v,w)      jit_new_node_wwd(jit_code_muli_d,u,v,w)
+    jit_code_mulr_d,           jit_code_muli_d,
+#define jit_divr_d(u,v,w)      jit_new_node_www(jit_code_divr_d,u,v,w)
+#define jit_divi_d(u,v,w)      jit_new_node_wwd(jit_code_divi_d,u,v,w)
+    jit_code_divr_d,           jit_code_divi_d,
+
+#define jit_negr_d(u,v)                jit_new_node_ww(jit_code_negr_d,u,v)
+#define jit_absr_d(u,v)                jit_new_node_ww(jit_code_absr_d,u,v)
+#define jit_sqrtr_d(u,v)       jit_new_node_ww(jit_code_sqrtr_d,u,v)
+    jit_code_negr_d,           jit_code_absr_d,        jit_code_sqrtr_d,
+
+#define jit_ltr_d(u,v,w)       jit_new_node_www(jit_code_ltr_d,u,v,w)
+#define jit_lti_d(u,v,w)       jit_new_node_wwd(jit_code_lti_d,u,v,w)
+    jit_code_ltr_d,            jit_code_lti_d,
+#define jit_ler_d(u,v,w)       jit_new_node_www(jit_code_ler_d,u,v,w)
+#define jit_lei_d(u,v,w)       jit_new_node_wwd(jit_code_lei_d,u,v,w)
+    jit_code_ler_d,            jit_code_lei_d,
+#define jit_eqr_d(u,v,w)       jit_new_node_www(jit_code_eqr_d,u,v,w)
+#define jit_eqi_d(u,v,w)       jit_new_node_wwd(jit_code_eqi_d,u,v,w)
+    jit_code_eqr_d,            jit_code_eqi_d,
+#define jit_ger_d(u,v,w)       jit_new_node_www(jit_code_ger_d,u,v,w)
+#define jit_gei_d(u,v,w)       jit_new_node_wwd(jit_code_gei_d,u,v,w)
+    jit_code_ger_d,            jit_code_gei_d,
+#define jit_gtr_d(u,v,w)       jit_new_node_www(jit_code_gtr_d,u,v,w)
+#define jit_gti_d(u,v,w)       jit_new_node_wwd(jit_code_gti_d,u,v,w)
+    jit_code_gtr_d,            jit_code_gti_d,
+#define jit_ner_d(u,v,w)       jit_new_node_www(jit_code_ner_d,u,v,w)
+#define jit_nei_d(u,v,w)       jit_new_node_wwd(jit_code_nei_d,u,v,w)
+    jit_code_ner_d,            jit_code_nei_d,
+#define jit_unltr_d(u,v,w)     jit_new_node_www(jit_code_unltr_d,u,v,w)
+#define jit_unlti_d(u,v,w)     jit_new_node_wwd(jit_code_unlti_d,u,v,w)
+    jit_code_unltr_d,          jit_code_unlti_d,
+#define jit_unler_d(u,v,w)     jit_new_node_www(jit_code_unler_d,u,v,w)
+#define jit_unlei_d(u,v,w)     jit_new_node_wwd(jit_code_unlei_d,u,v,w)
+    jit_code_unler_d,          jit_code_unlei_d,
+#define jit_uneqr_d(u,v,w)     jit_new_node_www(jit_code_uneqr_d,u,v,w)
+#define jit_uneqi_d(u,v,w)     jit_new_node_wwd(jit_code_uneqi_d,u,v,w)
+    jit_code_uneqr_d,          jit_code_uneqi_d,
+#define jit_unger_d(u,v,w)     jit_new_node_www(jit_code_unger_d,u,v,w)
+#define jit_ungei_d(u,v,w)     jit_new_node_wwd(jit_code_ungei_d,u,v,w)
+    jit_code_unger_d,          jit_code_ungei_d,
+#define jit_ungtr_d(u,v,w)     jit_new_node_www(jit_code_ungtr_d,u,v,w)
+#define jit_ungti_d(u,v,w)     jit_new_node_wwd(jit_code_ungti_d,u,v,w)
+    jit_code_ungtr_d,          jit_code_ungti_d,
+#define jit_ltgtr_d(u,v,w)     jit_new_node_www(jit_code_ltgtr_d,u,v,w)
+#define jit_ltgti_d(u,v,w)     jit_new_node_wwd(jit_code_ltgti_d,u,v,w)
+    jit_code_ltgtr_d,          jit_code_ltgti_d,
+#define jit_ordr_d(u,v,w)      jit_new_node_www(jit_code_ordr_d,u,v,w)
+#define jit_ordi_d(u,v,w)      jit_new_node_wwd(jit_code_ordi_d,u,v,w)
+    jit_code_ordr_d,           jit_code_ordi_d,
+#define jit_unordr_d(u,v,w)    jit_new_node_www(jit_code_unordr_d,u,v,w)
+#define jit_unordi_d(u,v,w)    jit_new_node_wwd(jit_code_unordi_d,u,v,w)
+    jit_code_unordr_d,         jit_code_unordi_d,
+
+#define jit_truncr_d_i(u,v)    jit_new_node_ww(jit_code_truncr_d_i,u,v)
+    jit_code_truncr_d_i,
+#if __WORDSIZE == 32
+#  define jit_truncr_d(u,v)    jit_truncr_d_i(u,v)
+#else
+#  define jit_truncr_d(u,v)    jit_truncr_d_l(u,v)
+#  define jit_truncr_d_l(u,v)  jit_new_node_ww(jit_code_truncr_d_l,u,v)
+#endif
+    jit_code_truncr_d_l,
+#define jit_extr_d(u,v)                jit_new_node_ww(jit_code_extr_d,u,v)
+#define jit_extr_f_d(u,v)      jit_new_node_ww(jit_code_extr_f_d,u,v)
+    jit_code_extr_d,           jit_code_extr_f_d,
+#define jit_movr_d(u,v)                jit_new_node_ww(jit_code_movr_d,u,v)
+#define jit_movi_d(u,v)                jit_new_node_wd(jit_code_movi_d,u,v)
+    jit_code_movr_d,           jit_code_movi_d,
+
+#define jit_ldr_d(u,v)         jit_new_node_ww(jit_code_ldr_d,u,v)
+#define jit_ldi_d(u,v)         jit_new_node_wp(jit_code_ldi_d,u,v)
+    jit_code_ldr_d,            jit_code_ldi_d,
+#define jit_ldxr_d(u,v,w)      jit_new_node_www(jit_code_ldxr_d,u,v,w)
+#define jit_ldxi_d(u,v,w)      jit_new_node_www(jit_code_ldxi_d,u,v,w)
+    jit_code_ldxr_d,           jit_code_ldxi_d,
+#define jit_str_d(u,v)         jit_new_node_ww(jit_code_str_d,u,v)
+#define jit_sti_d(u,v)         jit_new_node_pw(jit_code_sti_d,u,v)
+    jit_code_str_d,            jit_code_sti_d,
+#define jit_stxr_d(u,v,w)      jit_new_node_www(jit_code_stxr_d,u,v,w)
+#define jit_stxi_d(u,v,w)      jit_new_node_www(jit_code_stxi_d,u,v,w)
+    jit_code_stxr_d,           jit_code_stxi_d,
+
+#define jit_bltr_d(v,w)                jit_new_node_pww(jit_code_bltr_d,NULL,v,w)
+#define jit_blti_d(v,w)                jit_new_node_pwd(jit_code_blti_d,NULL,v,w)
+    jit_code_bltr_d,           jit_code_blti_d,
+#define jit_bler_d(v,w)                jit_new_node_pww(jit_code_bler_d,NULL,v,w)
+#define jit_blei_d(v,w)                jit_new_node_pwd(jit_code_blei_d,NULL,v,w)
+    jit_code_bler_d,           jit_code_blei_d,
+#define jit_beqr_d(v,w)                jit_new_node_pww(jit_code_beqr_d,NULL,v,w)
+#define jit_beqi_d(v,w)                jit_new_node_pwd(jit_code_beqi_d,NULL,v,w)
+    jit_code_beqr_d,           jit_code_beqi_d,
+#define jit_bger_d(v,w)                jit_new_node_pww(jit_code_bger_d,NULL,v,w)
+#define jit_bgei_d(v,w)                jit_new_node_pwd(jit_code_bgei_d,NULL,v,w)
+    jit_code_bger_d,           jit_code_bgei_d,
+#define jit_bgtr_d(v,w)                jit_new_node_pww(jit_code_bgtr_d,NULL,v,w)
+#define jit_bgti_d(v,w)                jit_new_node_pwd(jit_code_bgti_d,NULL,v,w)
+    jit_code_bgtr_d,           jit_code_bgti_d,
+#define jit_bner_d(v,w)                jit_new_node_pww(jit_code_bner_d,NULL,v,w)
+#define jit_bnei_d(v,w)                jit_new_node_pwd(jit_code_bnei_d,NULL,v,w)
+    jit_code_bner_d,           jit_code_bnei_d,
+#define jit_bunltr_d(v,w)      jit_new_node_pww(jit_code_bunltr_d,NULL,v,w)
+#define jit_bunlti_d(v,w)      jit_new_node_pwd(jit_code_bunlti_d,NULL,v,w)
+    jit_code_bunltr_d,         jit_code_bunlti_d,
+#define jit_bunler_d(v,w)      jit_new_node_pww(jit_code_bunler_d,NULL,v,w)
+#define jit_bunlei_d(v,w)      jit_new_node_pwd(jit_code_bunlei_d,NULL,v,w)
+    jit_code_bunler_d,         jit_code_bunlei_d,
+#define jit_buneqr_d(v,w)      jit_new_node_pww(jit_code_buneqr_d,NULL,v,w)
+#define jit_buneqi_d(v,w)      jit_new_node_pwd(jit_code_buneqi_d,NULL,v,w)
+    jit_code_buneqr_d,         jit_code_buneqi_d,
+#define jit_bunger_d(v,w)      jit_new_node_pww(jit_code_bunger_d,NULL,v,w)
+#define jit_bungei_d(v,w)      jit_new_node_pwd(jit_code_bungei_d,NULL,v,w)
+    jit_code_bunger_d,         jit_code_bungei_d,
+#define jit_bungtr_d(v,w)      jit_new_node_pww(jit_code_bungtr_d,NULL,v,w)
+#define jit_bungti_d(v,w)      jit_new_node_pwd(jit_code_bungti_d,NULL,v,w)
+    jit_code_bungtr_d,         jit_code_bungti_d,
+#define jit_bltgtr_d(v,w)      jit_new_node_pww(jit_code_bltgtr_d,NULL,v,w)
+#define jit_bltgti_d(v,w)      jit_new_node_pwd(jit_code_bltgti_d,NULL,v,w)
+    jit_code_bltgtr_d,         jit_code_bltgti_d,
+#define jit_bordr_d(v,w)       jit_new_node_pww(jit_code_bordr_d,NULL,v,w)
+#define jit_bordi_d(v,w)       jit_new_node_pwd(jit_code_bordi_d,NULL,v,w)
+    jit_code_bordr_d,          jit_code_bordi_d,
+#define jit_bunordr_d(v,w)     jit_new_node_pww(jit_code_bunordr_d,NULL,v,w)
+#define jit_bunordi_d(v,w)     jit_new_node_pwd(jit_code_bunordi_d,NULL,v,w)
+    jit_code_bunordr_d,                jit_code_bunordi_d,
+
+#define jit_pushargr_d(u)      _jit_pushargr_d(_jit,u)
+#define jit_pushargi_d(u)      _jit_pushargi_d(_jit,u)
+    jit_code_pushargr_d,       jit_code_pushargi_d,
+#define jit_retr_d(u)          _jit_retr_d(_jit,u)
+#define jit_reti_d(u)          _jit_reti_d(_jit,u)
+    jit_code_retr_d,           jit_code_reti_d,
+#define jit_retval_d(u)                _jit_retval_d(_jit,u)
+    jit_code_retval_d,
+
+    /* Special internal backend specific codes */
+    jit_code_movr_w_f,         jit_code_movr_ww_d,     /* w* -> f|d */
+#define jit_movr_w_f(u, v)     jit_new_node_ww(jit_code_movr_w_f, u, v)
+#define jit_movr_ww_d(u, v, w) jit_new_node_www(jit_code_movr_ww_d, u, v, w)
+    jit_code_movr_w_d,                                 /* w -> d */
+#define jit_movr_w_d(u, v)     jit_new_node_ww(jit_code_movr_w_d, u, v)
+
+    jit_code_movr_f_w,         jit_code_movi_f_w,      /* f|d -> w* */
+#define jit_movr_f_w(u, v)     jit_new_node_ww(jit_code_movr_f_w, u, v)
+#define jit_movi_f_w(u, v)     jit_new_node_wf(jit_code_movi_f_w, u, v)
+    jit_code_movr_d_ww,                jit_code_movi_d_ww,
+#define jit_movr_d_ww(u, v, w) jit_new_node_www(jit_code_movr_d_ww, u, v, w)
+#define jit_movi_d_ww(u, v, w) jit_new_node_wwd(jit_code_movi_d_ww, u, v, w)
+
+    jit_code_movr_d_w,         jit_code_movi_d_w,      /* d -> w */
+#define jit_movr_d_w(u, v)     jit_new_node_ww(jit_code_movr_d_w, u, v)
+#define jit_movi_d_w(u, v)     jit_new_node_wd(jit_code_movi_d_w, u, v)
+
+    jit_code_last_code
+} jit_code_t;
+
+typedef void* (*jit_alloc_func_ptr)    (size_t);
+typedef void* (*jit_realloc_func_ptr)  (void*, size_t);
+typedef void  (*jit_free_func_ptr)     (void*);
+
+/*
+ * Prototypes
+ */
+extern void init_jit(const char*);
+extern void finish_jit(void);
+
+extern jit_state_t *jit_new_state(void);
+#define jit_clear_state()      _jit_clear_state(_jit)
+extern void _jit_clear_state(jit_state_t*);
+#define jit_destroy_state()    _jit_destroy_state(_jit)
+extern void _jit_destroy_state(jit_state_t*);
+
+#define jit_address(node)      _jit_address(_jit, node)
+extern jit_pointer_t _jit_address(jit_state_t*, jit_node_t*);
+extern jit_node_t *_jit_name(jit_state_t*, const char*);
+extern jit_node_t *_jit_note(jit_state_t*, const char*, int);
+extern jit_node_t *_jit_label(jit_state_t*);
+extern jit_node_t *_jit_forward(jit_state_t*);
+extern jit_node_t *_jit_indirect(jit_state_t*);
+extern void _jit_link(jit_state_t*, jit_node_t*);
+#define jit_forward_p(u)       _jit_forward_p(_jit,u)
+extern jit_bool_t _jit_forward_p(jit_state_t*,jit_node_t*);
+#define jit_indirect_p(u)      _jit_indirect_p(_jit,u)
+extern jit_bool_t _jit_indirect_p(jit_state_t*,jit_node_t*);
+#define jit_target_p(u)                _jit_target_p(_jit,u)
+extern jit_bool_t _jit_target_p(jit_state_t*,jit_node_t*);
+
+extern void _jit_prolog(jit_state_t*);
+
+extern jit_int32_t _jit_allocai(jit_state_t*, jit_int32_t);
+extern void _jit_allocar(jit_state_t*, jit_int32_t, jit_int32_t);
+extern void _jit_ellipsis(jit_state_t*);
+
+extern jit_node_t *_jit_arg(jit_state_t*);
+extern void _jit_getarg_c(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_uc(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_s(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_us(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_i(jit_state_t*, jit_gpr_t, jit_node_t*);
+#if __WORDSIZE == 64
+extern void _jit_getarg_ui(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_getarg_l(jit_state_t*, jit_gpr_t, jit_node_t*);
+#endif
+extern void _jit_putargr(jit_state_t*, jit_gpr_t, jit_node_t*);
+extern void _jit_putargi(jit_state_t*, jit_word_t, jit_node_t*);
+
+extern void _jit_prepare(jit_state_t*);
+extern void _jit_ellipsis(jit_state_t*);
+extern void _jit_va_push(jit_state_t*, jit_gpr_t);
+extern void _jit_pushargr(jit_state_t*, jit_gpr_t);
+extern void _jit_pushargi(jit_state_t*, jit_word_t);
+extern void _jit_finishr(jit_state_t*, jit_gpr_t);
+extern jit_node_t *_jit_finishi(jit_state_t*, jit_pointer_t);
+extern void _jit_ret(jit_state_t*);
+extern void _jit_retr(jit_state_t*, jit_gpr_t);
+extern void _jit_reti(jit_state_t*, jit_word_t);
+extern void _jit_retval_c(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_uc(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_s(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_us(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_i(jit_state_t*, jit_gpr_t);
+#if __WORDSIZE == 64
+extern void _jit_retval_ui(jit_state_t*, jit_gpr_t);
+extern void _jit_retval_l(jit_state_t*, jit_gpr_t);
+#endif
+extern void _jit_epilog(jit_state_t*);
+
+#define jit_patch(u)           _jit_patch(_jit,u)
+extern void _jit_patch(jit_state_t*, jit_node_t*);
+#define jit_patch_at(u,v)      _jit_patch_at(_jit,u,v)
+extern void _jit_patch_at(jit_state_t*, jit_node_t*, jit_node_t*);
+#define jit_patch_abs(u,v)     _jit_patch_abs(_jit,u,v)
+extern void _jit_patch_abs(jit_state_t*, jit_node_t*, jit_pointer_t);
+#define jit_realize()          _jit_realize(_jit)
+extern void _jit_realize(jit_state_t*);
+#define jit_get_code(u)                _jit_get_code(_jit,u)
+extern jit_pointer_t _jit_get_code(jit_state_t*, jit_word_t*);
+#define jit_set_code(u,v)      _jit_set_code(_jit,u,v)
+extern void _jit_set_code(jit_state_t*, jit_pointer_t, jit_word_t);
+#define jit_get_data(u,v)      _jit_get_data(_jit,u,v)
+extern jit_pointer_t _jit_get_data(jit_state_t*, jit_word_t*, jit_word_t*);
+#define jit_set_data(u,v,w)    _jit_set_data(_jit,u,v,w)
+extern void _jit_set_data(jit_state_t*, jit_pointer_t, jit_word_t, jit_word_t);
+#define jit_frame(u)           _jit_frame(_jit,u)
+extern void _jit_frame(jit_state_t*, jit_int32_t);
+#define jit_tramp(u)           _jit_tramp(_jit,u)
+extern void _jit_tramp(jit_state_t*, jit_int32_t);
+#define jit_emit()             _jit_emit(_jit)
+extern jit_pointer_t _jit_emit(jit_state_t*);
+
+#define jit_print()            _jit_print(_jit)
+extern void _jit_print(jit_state_t*);
+
+extern jit_node_t *_jit_arg_f(jit_state_t*);
+extern void _jit_getarg_f(jit_state_t*, jit_fpr_t, jit_node_t*);
+extern void _jit_putargr_f(jit_state_t*, jit_fpr_t, jit_node_t*);
+extern void _jit_putargi_f(jit_state_t*, jit_float32_t, jit_node_t*);
+extern void _jit_pushargr_f(jit_state_t*, jit_fpr_t);
+extern void _jit_pushargi_f(jit_state_t*, jit_float32_t);
+extern void _jit_retr_f(jit_state_t*, jit_fpr_t);
+extern void _jit_reti_f(jit_state_t*, jit_float32_t);
+extern void _jit_retval_f(jit_state_t*, jit_fpr_t);
+
+extern jit_node_t *_jit_arg_d(jit_state_t*);
+extern void _jit_getarg_d(jit_state_t*, jit_fpr_t, jit_node_t*);
+extern void _jit_putargr_d(jit_state_t*, jit_fpr_t, jit_node_t*);
+extern void _jit_putargi_d(jit_state_t*, jit_float64_t, jit_node_t*);
+extern void _jit_pushargr_d(jit_state_t*, jit_fpr_t);
+extern void _jit_pushargi_d(jit_state_t*, jit_float64_t);
+extern void _jit_retr_d(jit_state_t*, jit_fpr_t);
+extern void _jit_reti_d(jit_state_t*, jit_float64_t);
+extern void _jit_retval_d(jit_state_t*, jit_fpr_t);
+
+#define jit_new_node(c)                _jit_new_node(_jit,c)
+extern jit_node_t *_jit_new_node(jit_state_t*, jit_code_t);
+#define jit_new_node_w(c,u)    _jit_new_node_w(_jit,c,u)
+extern jit_node_t *_jit_new_node_w(jit_state_t*, jit_code_t,
+                                  jit_word_t);
+#define jit_new_node_f(c,u)    _jit_new_node_f(_jit,c,u)
+extern jit_node_t *_jit_new_node_f(jit_state_t*, jit_code_t,
+                                  jit_float32_t);
+#define jit_new_node_d(c,u)    _jit_new_node_d(_jit,c,u)
+extern jit_node_t *_jit_new_node_d(jit_state_t*, jit_code_t,
+                                  jit_float64_t);
+#define jit_new_node_p(c,u)    _jit_new_node_p(_jit,c,u)
+extern jit_node_t *_jit_new_node_p(jit_state_t*, jit_code_t,
+                                  jit_pointer_t);
+#define jit_new_node_ww(c,u,v) _jit_new_node_ww(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_ww(jit_state_t*,jit_code_t,
+                                   jit_word_t, jit_word_t);
+#define jit_new_node_wp(c,u,v) _jit_new_node_wp(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_wp(jit_state_t*,jit_code_t,
+                                   jit_word_t, jit_pointer_t);
+#define jit_new_node_fp(c,u,v) _jit_new_node_fp(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_fp(jit_state_t*,jit_code_t,
+                                   jit_float32_t, jit_pointer_t);
+#define jit_new_node_dp(c,u,v) _jit_new_node_dp(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_dp(jit_state_t*,jit_code_t,
+                                   jit_float64_t, jit_pointer_t);
+#define jit_new_node_pw(c,u,v) _jit_new_node_pw(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_pw(jit_state_t*,jit_code_t,
+                                   jit_pointer_t, jit_word_t);
+#define jit_new_node_wf(c,u,v) _jit_new_node_wf(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_wf(jit_state_t*, jit_code_t,
+                                   jit_word_t, jit_float32_t);
+#define jit_new_node_wd(c,u,v) _jit_new_node_wd(_jit,c,u,v)
+extern jit_node_t *_jit_new_node_wd(jit_state_t*, jit_code_t,
+                                   jit_word_t, jit_float64_t);
+#define jit_new_node_www(c,u,v,w) _jit_new_node_www(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_www(jit_state_t*, jit_code_t,
+                                    jit_word_t, jit_word_t, jit_word_t);
+#define jit_new_node_qww(c,l,h,v,w) _jit_new_node_qww(_jit,c,l,h,v,w)
+extern jit_node_t *_jit_new_node_qww(jit_state_t*, jit_code_t,
+                                    jit_int32_t, jit_int32_t,
+                                    jit_word_t, jit_word_t);
+#define jit_new_node_wwf(c,u,v,w) _jit_new_node_wwf(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_wwf(jit_state_t*, jit_code_t,
+                                    jit_word_t, jit_word_t, jit_float32_t);
+#define jit_new_node_wwd(c,u,v,w) _jit_new_node_wwd(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_wwd(jit_state_t*, jit_code_t,
+                                    jit_word_t, jit_word_t, jit_float64_t);
+#define jit_new_node_pww(c,u,v,w) _jit_new_node_pww(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_pww(jit_state_t*, jit_code_t,
+                                    jit_pointer_t, jit_word_t, jit_word_t);
+#define jit_new_node_pwf(c,u,v,w) _jit_new_node_pwf(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_pwf(jit_state_t*, jit_code_t,
+                                    jit_pointer_t, jit_word_t, jit_float32_t);
+#define jit_new_node_pwd(c,u,v,w) _jit_new_node_pwd(_jit,c,u,v,w)
+extern jit_node_t *_jit_new_node_pwd(jit_state_t*, jit_code_t,
+                                    jit_pointer_t, jit_word_t, jit_float64_t);
+
+#define jit_arg_register_p(u)          _jit_arg_register_p(_jit,u)
+extern jit_bool_t _jit_arg_register_p(jit_state_t*, jit_node_t*);
+#define jit_callee_save_p(u)           _jit_callee_save_p(_jit,u)
+extern jit_bool_t _jit_callee_save_p(jit_state_t*, jit_int32_t);
+#define jit_pointer_p(u)               _jit_pointer_p(_jit,u)
+extern jit_bool_t _jit_pointer_p(jit_state_t*,jit_pointer_t);
+
+#define jit_get_note(n,u,v,w)  _jit_get_note(_jit,n,u,v,w)
+extern jit_bool_t _jit_get_note(jit_state_t*,jit_pointer_t,char**,char**,int*);
+
+#define jit_disassemble()              _jit_disassemble(_jit)
+extern void _jit_disassemble(jit_state_t*);
+
+extern void jit_set_memory_functions(jit_alloc_func_ptr,
+                                    jit_realloc_func_ptr,
+                                    jit_free_func_ptr);
+extern void jit_get_memory_functions(jit_alloc_func_ptr*,
+                                    jit_realloc_func_ptr*,
+                                    jit_free_func_ptr*);
+
+#endif /* _lightning_h */
diff --git a/deps/lightning/include/lightning/Makefile.am b/deps/lightning/include/lightning/Makefile.am
new file mode 100644 (file)
index 0000000..9b1b3e6
--- /dev/null
@@ -0,0 +1,65 @@
+#
+# Copyright 2000, 2001, 2002, 2012-2019 Free Software Foundation, Inc.
+#
+# This file is part of GNU lightning.
+#
+# GNU lightning is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU lightning is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+#
+
+lightning_includedir = $(includedir)/lightning
+
+EXTRA_DIST =           \
+       jit_private.h
+
+if cpu_arm
+lightning_include_HEADERS =    \
+       jit_arm.h
+endif
+if cpu_mips
+lightning_include_HEADERS =    \
+       jit_mips.h
+endif
+if cpu_ppc
+lightning_include_HEADERS =    \
+       jit_ppc.h
+endif
+if cpu_sparc
+lightning_include_HEADERS =    \
+       jit_sparc.h
+endif
+if cpu_x86
+lightning_include_HEADERS =    \
+       jit_x86.h
+endif
+if cpu_ia64
+lightning_include_HEADERS =    \
+       jit_ia64.h
+endif
+if cpu_hppa
+lightning_include_HEADERS =    \
+       jit_hppa.h
+endif
+if cpu_aarch64
+lightning_include_HEADERS =    \
+       jit_aarch64.h
+endif
+if cpu_s390
+lightning_include_HEADERS =    \
+       jit_s390.h
+endif
+if cpu_alpha
+lightning_include_HEADERS =    \
+       jit_alpha.h
+endif
+if cpu_riscv
+lightning_include_HEADERS =    \
+       jit_riscv.h
+endif
diff --git a/deps/lightning/include/lightning/jit_aarch64.h b/deps/lightning/include/lightning/jit_aarch64.h
new file mode 100644 (file)
index 0000000..6e7d8be
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_aarch64_h
+#define _jit_aarch64_h
+
+#define JIT_HASH_CONSTS                0
+#define JIT_NUM_OPERANDS       3
+
+/*
+ * Types
+ */
+#define JIT_FP                 _R29
+typedef enum {
+#define jit_r(i)               (_R9 + (i))
+#define jit_r_num()            7
+#define jit_v(i)               (_R19 + (i))
+#define jit_v_num()            10
+#define jit_f(i)               (_V8 + (i))
+#define jit_f_num()            8
+#define JIT_R0                 _R9
+#define JIT_R1                 _R10
+#define JIT_R2                 _R11
+#define JIT_R3                 _R12
+#define JIT_R4                 _R13
+#define JIT_R5                 _R14
+#define JIT_R6                 _R15
+    _R8,                               /* indirect result */
+    _R18,                              /* platform register */
+    _R17,                              /* IP1 */
+    _R16,                              /* IP0 */
+    _R9,       _R10,   _R11,   _R12,   /* temporaries */
+    _R13,      _R14,   _R15,
+#define JIT_V0                 _R19
+#define JIT_V1                 _R20
+#define JIT_V2                 _R21
+#define JIT_V3                 _R22
+#define JIT_V4                 _R23
+#define JIT_V5                 _R24
+#define JIT_V6                 _R25
+#define JIT_V7                 _R26
+#define JIT_V8                 _R27
+#define JIT_V9                 _R28
+    _R19,      _R20,   _R21,   _R22,   /* callee save */
+    _R23,      _R24,   _R25,   _R26,
+    _R27,      _R28,
+    _SP,                               /* stack pointer */
+    _R30,                              /* link register */
+    _R29,                              /* frame pointer */
+    _R7,       _R6,    _R5,    _R4,
+    _R3,       _R2,    _R1,    _R0,
+#define JIT_F0                 _V8
+#define JIT_F1                 _V9
+#define JIT_F2                 _V10
+#define JIT_F3                 _V11
+#define JIT_F4                 _V12
+#define JIT_F5                 _V13
+#define JIT_F6                 _V14
+#define JIT_F7                 _V15
+    _V31,      _V30,   _V29,   _V28,   /* temporaries */
+    _V27,      _V26,   _V25,   _V24,
+    _V23,      _V22,   _V21,   _V20,
+    _V19,      _V18,   _V17,   _V16,
+    /* callee save */
+    _V8,       _V9,    _V10,   _V11,
+    _V12,      _V13,   _V14,   _V15,
+    _V7,       _V6,    _V5,    _V4,    /* arguments */
+    _V3,       _V2,    _V1,    _V0,
+    _NOREG,
+#define JIT_NOREG              _NOREG
+} jit_reg_t;
+
+#endif /* _jit_aarch64_h */
diff --git a/deps/lightning/include/lightning/jit_alpha.h b/deps/lightning/include/lightning/jit_alpha.h
new file mode 100644 (file)
index 0000000..9bae343
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2014-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_alpha_h
+#define _jit_alpha_h
+
+#define JIT_HASH_CONSTS                1
+#define JIT_NUM_OPERANDS       3
+
+/*
+ * Types
+ */
+#define JIT_FP                 _FP
+typedef enum {
+#define jit_r(i)               (_S0 + (i))
+#define jit_r_num()            3
+#define jit_v(i)               (_S3 + (i))
+#define jit_v_num()            3
+#define jit_f(i)               (_F2 + (i))
+#define jit_f_num()            8
+    /* Volatile - Assembly temporary register */
+    _AT,
+    /* Volatile - Return value register */
+    _V0,
+    /* Volatile - Temporary registers */
+    _T0,               _T1,            _T2,            _T3,
+    _T4,               _T5,            _T6,            _T7,
+    _T8,               _T9,            _T10,           _T11,
+    /* FIXME Use callee save register for r0-r2 (instead of 12+ JIT_RN
+     * and 6 JIT_VN because division must call a function)
+     * FIX would be to create proper functions that do not clobber
+     * registers and inject/inline them in the jit */
+#define JIT_R0                 _S0
+#define JIT_R1                 _S1
+#define JIT_R2                 _S2
+#define JIT_V0                 _S3
+#define JIT_V1                 _S4
+#define JIT_V2                 _S5
+    /* Nonvolatile - Saved registers */
+    _S0,               _S1,            _S2,            _S3,
+    _S4,               _S5,
+    /* Nonvolatile - Frame pointer */
+    _FP,
+    /* Volatile - Argument registers */
+    _A5,               _A4,            _A3,            _A2,
+    _A1,               _A0,
+    /* Volatile - Return address register */
+    _RA,
+    /* Volatile - Temporary register */
+    _PV,
+    /* Nonvolatile - Global pointer */
+    _GP,
+    /* Nonvolatile - Stack pointer */
+    _SP,
+    /* Constant  RAZ / writes ignored */
+    _ZERO,
+#define JIT_F0                 _F2
+#define JIT_F1                 _F3
+#define JIT_F2                 _F4
+#define JIT_F3                 _F5
+#define JIT_F4                 _F6
+#define JIT_F5                 _F7
+#define JIT_F6                 _F8
+#define JIT_F7                 _F9
+    /* Volatile - Return value register (real part) */
+    _F0,
+    /* Volatile - Return value register (imaginary part) */
+    _F1,
+    /* Nonvolatile - Saved registers */
+    _F2,               _F3,            _F4,            _F5,
+    _F6,               _F7,            _F8,            _F9,
+    /* Volatile - Temporary registers */
+    _F10,              _F11,           _F12,           _F13,
+    _F14,              _F15,
+    /* Volatile - Argument registers */
+    _F21,              _F20,           _F19,           _F18,
+    _F17,              _F16,
+    /* Volatile - Temporary registers */
+    _F22,              _F23,           _R24,           _F25,
+    _F26,              _F27,           _F28,           _F29,
+    _F30,
+    /* Constant - RAZ / writes ignored */
+    _F31,
+    /* Lightning internal invalid register identifier */
+    _NOREG,
+#define JIT_NOREG              _NOREG
+} jit_reg_t;
+
+#endif /* _jit_alpha_h */
diff --git a/deps/lightning/include/lightning/jit_arm.h b/deps/lightning/include/lightning/jit_arm.h
new file mode 100644 (file)
index 0000000..81451f1
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_arm_h
+#define _jit_arm_h
+
+#define JIT_HASH_CONSTS                0
+#define JIT_NUM_OPERANDS       3
+
+/*
+ * Types
+ */
+#define jit_swf_p()            (jit_cpu.vfp == 0)
+#define jit_hardfp_p()         jit_cpu.abi
+#define jit_ldrt_strt_p()      jit_cpu.ldrt_strt
+
+#define JIT_FP                 _R11
+typedef enum {
+#define jit_r(i)               (_R4 + (i))
+#define jit_r_num()            3
+#define jit_v(i)               (_R7 + (i))
+#define jit_v_num()            3
+#define jit_f(i)               (jit_cpu.abi ? _D8 + ((i)<<1) : _D0 - ((i)<<1))
+#define jit_f_num()            8
+    _R12,                      /* ip - temporary */
+#define JIT_R0                 _R4
+#define JIT_R1                 _R5
+#define JIT_R2                 _R6
+    _R4,                       /* r4 - variable */
+    _R5,                       /* r5 - variable */
+    _R6,                       /* r6 - variable */
+#define JIT_V0                 _R7
+#define JIT_V1                 _R8
+#define JIT_V2                 _R9
+    _R7,                       /* r7 - variable */
+    _R8,                       /* r8 - variable */
+    _R9,                       /* r9 - variable */
+    _R10,                      /* sl - stack limit */
+    _R11,                      /* fp - frame pointer */
+    _R13,                      /* sp - stack pointer */
+    _R14,                      /* lr - link register */
+    _R15,                      /* pc - program counter */
+    _R3,                       /* r3 - argument/result */
+    _R2,                       /* r2 - argument/result */
+    _R1,                       /* r1 - argument/result */
+    _R0,                       /* r0 - argument/result */
+#define JIT_F0                 (jit_hardfp_p() ? _D8 : _D0)
+#define JIT_F1                 (jit_hardfp_p() ? _D9 : _D1)
+#define JIT_F2                 (jit_hardfp_p() ? _D10 : _D2)
+#define JIT_F3                 (jit_hardfp_p() ? _D11 : _D3)
+#define JIT_F4                 (jit_hardfp_p() ? _D12 : _D4)
+#define JIT_F5                 (jit_hardfp_p() ? _D13 : _D5)
+#define JIT_F6                 (jit_hardfp_p() ? _D14 : _D6)
+#define JIT_F7                 (jit_hardfp_p() ? _D15 : _D7)
+    _S16,      _D8 = _S16,     _Q4 = _D8,
+    _S17,
+    _S18,      _D9 = _S18,
+    _S19,
+    _S20,      _D10 = _S20,    _Q5 = _D10,
+    _S21,
+    _S22,      _D11 = _S22,
+    _S23,
+    _S24,      _D12 = _S24,    _Q6 = _D12,
+    _S25,
+    _S26,      _D13 = _S26,
+    _S27,
+    _S28,      _D14 = _S28,    _Q7 = _D14,
+    _S29,
+    _S30,      _D15 = _S30,
+    _S31,
+    _S15,
+    _S14,      _D7 = _S14,
+    _S13,
+    _S12,      _D6 = _S12,     _Q3 = _D6,
+    _S11,
+    _S10,      _D5 = _S10,
+    _S9,
+    _S8,       _D4 = _S8,      _Q2 = _D4,
+    _S7,
+    _S6,       _D3 = _S6,
+    _S5,
+    _S4,       _D2 = _S4,      _Q1 = _D2,
+    _S3,
+    _S2,       _D1 = _S2,
+    _S1,
+    _S0,       _D0 = _S0,      _Q0 = _D0,
+    _NOREG,
+#define JIT_NOREG              _NOREG
+} jit_reg_t;
+
+typedef struct {
+    jit_uint32_t version       : 4;
+    jit_uint32_t extend                : 1;
+    /* only generate thumb instructions for thumb2 */
+    jit_uint32_t thumb         : 1;
+    jit_uint32_t vfp           : 3;
+    jit_uint32_t neon          : 1;
+    jit_uint32_t abi           : 2;
+    /* use strt+offset instead of str.w?
+     * on special cases it causes a SIGILL at least on qemu, probably
+     * due to some memory ordering constraint not being respected, so,
+     * disable by default */
+    jit_uint32_t ldrt_strt     : 1;
+} jit_cpu_t;
+
+/*
+ * Initialization
+ */
+extern jit_cpu_t               jit_cpu;
+
+#endif /* _jit_arm_h */
diff --git a/deps/lightning/include/lightning/jit_hppa.h b/deps/lightning/include/lightning/jit_hppa.h
new file mode 100644 (file)
index 0000000..ddc3950
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_hppa_h
+#define _jit_hppa_h
+
+#define JIT_HASH_CONSTS                1
+#define JIT_NUM_OPERANDS       3
+
+/*
+ * Types
+ */
+typedef enum {
+    _R0,                       /* Always zero */
+    _R1,                       /* ADDIL implicit target */
+    _R2,                       /* B,L implicit target */
+#define jit_r_num()            4
+#define jit_r(n)               ((n) < 3 ? _R4 + (n) : _R10 + (n) - 3)
+#define jit_v_num()            11
+#define jit_v(n)               ((n) < 3 ? _R7 + (n) : _R11 + (n) - 3)
+#define jit_f_num()            8
+#define jit_f(n)               (_F12 - (n))
+#define JIT_FP                 _R3
+#define JIT_R0                 _R4
+#define JIT_R1                 _R5
+#define JIT_R2                 _R6
+#define JIT_R3                 _R10
+#define JIT_V0                 _R7
+#define JIT_V1                 _R8
+#define JIT_V2                 _R9
+#define JIT_V3                 _R11
+#define JIT_V4                 _R12
+#define JIT_V5                 _R13
+#define JIT_V6                 _R14
+#define JIT_V7                 _R15
+#define JIT_V8                 _R16
+#define JIT_V9                 _R17
+#define JIT_V10                        _R18
+    _R3,
+    _R19,
+    _R20,
+    _R21,
+    _R22,
+    _R29,                      /* ret1 */
+    _R28,                      /* ret0 */
+    _R4,
+    _R5,
+    _R6,
+    _R7,
+    _R8,
+    _R9,
+    _R10,
+    _R11,
+    _R12,
+    _R13,
+    _R14,
+    _R15,
+    _R16,
+    _R17,
+    _R18,
+    _R23,                      /* arg3 */
+    _R24,                      /* arg2 */
+    _R25,                      /* arg1 */
+    _R26,                      /* arg0 */
+    _R27,                      /* Data Pointer */
+    _R30,                      /* Stack Pointer */
+    _R31,                      /* Link register */
+#define JIT_F0                 _F12
+#define JIT_F1                 _F13
+#define JIT_F2                 _F14
+#define JIT_F3                 _F15
+#define JIT_F4                 _F16
+#define JIT_F5                 _F17
+#define JIT_F6                 _F18
+#define JIT_F7                 _F19
+#define JIT_F8                 _F20
+#define JIT_F9                 _F21
+    /* Caller Saves */
+    _F31,
+    _F30,
+    _F29,
+    _F28,
+    _F27,
+    _F26,
+    _F25,
+    _F24,
+    _F23,
+    _F22,
+    _F11,
+    _F10,
+    _F9,
+    _F8,
+    /* Arguments */
+    _F7,                       /* farg3 */
+    _F6,                       /* farg2 */
+    _F5,                       /* farg1 */
+    _F4,                       /* farg0 */
+    /* Callee Saves */
+    _F21,
+    _F20,
+    _F19,
+    _F18,
+    _F17,
+    _F16,
+    _F15,
+    _F14,
+    _F13,
+    _F12,
+    /* Floating-Pointer Status and Exception */
+    _F0,
+    _F1,
+    _F2,
+    _F3,
+#define JIT_NOREG              _NOREG
+    _NOREG,
+} jit_reg_t;
+
+#endif /* _jit_hppa */
diff --git a/deps/lightning/include/lightning/jit_ia64.h b/deps/lightning/include/lightning/jit_ia64.h
new file mode 100644 (file)
index 0000000..718f191
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_ia64_h
+#define _jit_ia64_h
+
+#define JIT_HASH_CONSTS                1
+#define JIT_NUM_OPERANDS       3
+
+/*
+ * Types
+ */
+#define JIT_FP                 _R4     /* Not abi specific */
+typedef enum {
+#define JIT_R0         _R40
+#define JIT_R1         _R41
+#define JIT_R2         _R42
+#define JIT_R3         _R43
+#define JIT_V0         _R44
+#define JIT_V1         _R45
+#define JIT_V2         _R46
+#define JIT_V3         _R47
+#define jit_r_num()    4
+#define jit_r(n)       (_R40 + (n))
+#define jit_v_num()    4
+#define jit_v(n)       (_R44 + (n))
+    _R0,       /* constant - Always 0 */
+    _R1,       /* special - Global Data pointer (gp) */
+    /* r2-r3    - scratch - Use with 22-bit immediate add - scratch */
+    _R2,       _R3,
+    /* r4-r7 - preserved */
+    _R4,       _R5,    _R6,    _R7,
+    _R8,       /* scratch - Return value; structure/union return pointer */
+    /* r9-r11   - scratch - Return values */
+    _R9,       _R10,   _R11,
+    _R12,      /* special - Memory stack pointer (sp) */
+    _R13,      /* special - Reserved as a thread pointer (tp)*/
+    /* r14-r31  - scratch */
+    _R31,      _R30,
+    _R29,      _R28,   _R27,   _R26,   _R25,   _R24,   _R23,   _R22,
+    _R21,      _R20,   _R19,   _R18,   _R17,   _R16,   _R15,   _R14,
+    /* r32-r39  - aka in0-in7 - Incoming register arguments */
+    _R32,      _R33,   _R34,   _R35,   _R36,   _R37,   _R38,   _R39,
+    /* r40-r127         - loc0...locn,out0...outn */
+    _R40,      _R41,   _R42,   _R43,   _R44,   _R45,   _R46,   _R47,
+    _R48,      _R49,   _R50,   _R51,   _R52,   _R53,   _R54,   _R55,
+    _R56,      _R57,   _R58,   _R59,   _R60,   _R61,   _R62,   _R63,
+    _R64,      _R65,   _R66,   _R67,   _R68,   _R69,   _R70,   _R71,
+    _R72,      _R73,   _R74,   _R75,   _R76,   _R77,   _R78,   _R79,
+    _R80,      _R81,   _R82,   _R83,   _R84,   _R85,   _R86,   _R87,
+    _R88,      _R89,   _R90,   _R91,   _R92,   _R93,   _R94,   _R95,
+    _R96,      _R97,   _R98,   _R99,   _R100,  _R101,  _R102,  _R103,
+    _R104,     _R105,  _R106,  _R107,  _R108,  _R109,  _R110,  _R111,
+    _R112,     _R113,  _R114,  _R115,  _R116,  _R117,  _R118,  _R119,
+    _R120,     _R121,  _R122,  _R123,  _R124,  _R125,  _R126,  _R127,
+#define JIT_F0         _F16
+#define JIT_F1         _F17
+#define JIT_F2         _F18
+#define JIT_F3         _F19
+#define JIT_F4         _F20
+#define JIT_F5         _F21
+#define jit_f_num()    6
+#define jit_f(n)       (_F16 + (n))
+    _F0,       /* constant - Always 0.0 */
+    _F1,       /* constant - Always 1.0 */
+    /* f2-f5    - preserved */
+    _F2,       _F3,    _F4,    _F5,
+    /* f6-f7    - scratch */
+    _F6,       _F7,
+    /* f8-f15   - scratch - Argument/return registers */
+    _F8,       _F9,    _F10,   _F11,   _F12,   _F13,   _F14,   _F15,
+    /* f16-f31  - preserved */
+    _F16,      _F17,   _F18,   _F19,   _F20,   _F21,   _F22,   _F23,
+    _F24,      _F25,   _F26,   _F27,   _F28,   _F29,   _F30,   _F31,
+    /* f32-f127         - scratch - Rotating registers or scratch */
+    _F32,      _F33,   _F34,   _F35,   _F36,   _F37,   _F38,   _F39,
+    _F40,      _F41,   _F42,   _F43,   _F44,   _F45,   _F46,   _F47,
+    _F48,      _F49,   _F50,   _F51,   _F52,   _F53,   _F54,   _F55,
+    _F56,      _F57,   _F58,   _F59,   _F60,   _F61,   _F62,   _F63,
+    _F64,      _F65,   _F66,   _F67,   _F68,   _F69,   _F70,   _F71,
+    _F72,      _F73,   _F74,   _F75,   _F76,   _F77,   _F78,   _F79,
+    _F80,      _F81,   _F82,   _F83,   _F84,   _F85,   _F86,   _F87,
+    _F88,      _F89,   _F90,   _F91,   _F92,   _F93,   _F94,   _F95,
+    _F96,      _F97,   _F98,   _F99,   _F100,  _F101,  _F102,  _F103,
+    _F104,     _F105,  _F106,  _F107,  _F108,  _F109,  _F110,  _F111,
+    _F112,     _F113,  _F114,  _F115,  _F116,  _F117,  _F118,  _F119,
+
+#if 0
+    /* Do not list these to not need an unique identifier larger
+     * than 255 for jit_regset_t */
+    _F120,     _F121,  _F122,  _F123,  _F124,  _F125,  _F126,  _F127,
+#endif
+
+    /* Fake registers. Required because while "in" parameters start at r32,
+     * "out" parameters start *after* registers allocated for temporaries,
+     * and that are supposed to kept alive (what is desirable, that is, to
+      * not spill/reload them in memory) */
+    _OUT0,     _OUT1,  _OUT2,  _OUT3,  _OUT4,  _OUT5,  _OUT6,  _OUT7,
+
+#define JIT_NOREG              _NOREG
+    _NOREG,
+} jit_reg_t;
+
+#endif /* _jit_ia64_h */
diff --git a/deps/lightning/include/lightning/jit_mips.h b/deps/lightning/include/lightning/jit_mips.h
new file mode 100644 (file)
index 0000000..eb7d783
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_mips_h
+#define _jit_mips_h
+
+#define JIT_HASH_CONSTS                1
+#define JIT_NUM_OPERANDS       3
+
+#if _MIPS_SIM != _ABIO32
+#    define NEW_ABI            1
+#endif
+
+/*
+ * Types
+ */
+#define JIT_FP                 _FP
+typedef enum {
+#define jit_r(i)               (_V0 + (i))
+#if NEW_ABI
+#  define jit_r_num()          7
+#else
+#  define jit_r_num()          11
+#endif
+#define jit_v(i)               (_S0 + (i))
+#define jit_v_num()            8
+#define jit_f(i)               (_F0 + (i))
+#if NEW_ABI
+#  define jit_f_num()          6
+#else
+#  define jit_f_num()          8
+#endif
+    _AT,
+#define JIT_R0                 _V0
+#define JIT_R1                 _V1
+#if NEW_ABI
+#  define JIT_R2               _T4
+#  define JIT_R3               _T5
+#  define JIT_R4               _T6
+#  define JIT_R5               _T7
+#  define JIT_R6               _T8
+#else
+#  define JIT_R2               _T0
+#  define JIT_R3               _T1
+#  define JIT_R4               _T2
+#  define JIT_R5               _T3
+#  define JIT_R6               _T4
+#  define JIT_R7               _T5
+#  define JIT_R8               _T6
+#  define JIT_R9               _T7
+#  define JIT_R10              _T8
+#endif
+    _V0, _V1,
+#if !NEW_ABI
+    _T0, _T1, _T2, _T3,
+#endif
+    _T4, _T5, _T6, _T7, _T8, _T9,
+#define JIT_V0                 _S0
+#define JIT_V1                 _S1
+#define JIT_V2                 _S2
+#define JIT_V3                 _S3
+#define JIT_V4                 _S4
+#define JIT_V5                 _S5
+#define JIT_V6                 _S6
+#define JIT_V7                 _S7
+    _S0, _S1, _S2, _S3, _S4, _S5, _S6, _S7,
+    _ZERO, _K0, _K1, _RA,
+    _GP,
+    _SP, _FP,
+#if NEW_ABI
+    _A7, _A6, _A5, _A4,
+#endif
+    _A3, _A2, _A1, _A0,
+#define JIT_F0                 _F0
+#define JIT_F1                 _F2
+#define JIT_F2                 _F4
+#define JIT_F3                 _F6
+#define JIT_F4                 _F8
+#define JIT_F5                 _F10
+#if !NEW_ABI
+#  define JIT_F6               _F16
+#  define JIT_F7               _F18
+#endif
+    _F0, _F2, _F4, _F6, _F8, _F10,
+    /* callee save float registers */
+#if !NEW_ABI
+    _F16, _F18,
+#endif
+    _F20, _F22, _F24, _F26, _F28, _F30,
+#if NEW_ABI
+    _F19, _F18, _F17, _F16, _F15, _F14, _F13, _F12,
+#else
+    _F14, _F12,
+#endif
+#define JIT_NOREG              _NOREG
+    _NOREG,
+} jit_reg_t;
+
+#endif /* _jit_mips_h */
diff --git a/deps/lightning/include/lightning/jit_ppc.h b/deps/lightning/include/lightning/jit_ppc.h
new file mode 100644 (file)
index 0000000..f1bdbcb
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_ppc_h
+#define _jit_ppc_h
+
+#define JIT_HASH_CONSTS                1
+#define JIT_NUM_OPERANDS       3
+
+/*
+ * Types
+ */
+typedef enum {
+#define jit_r(i)               (_R28 + (i))
+#define jit_r_num()            3
+#define jit_v(i)               (_R27 - (i))
+#define jit_v_num()            14
+#define jit_f(i)               (_F14 + (i))
+#define jit_f_num()            8
+    _R0,
+#define JIT_R0                 _R28
+#define JIT_R1                 _R29
+#define JIT_R2                 _R30
+    _R11,      _R12,   _R13,   _R2,
+#define JIT_V0                 jit_v(0)
+#define JIT_V1                 jit_v(1)
+#define JIT_V2                 jit_v(2)
+#define JIT_V3                 jit_v(3)
+#define JIT_V4                 jit_v(4)
+#define JIT_V5                 jit_v(5)
+#define JIT_V6                 jit_v(6)
+#define JIT_V7                 jit_v(7)
+#define JIT_V8                 jit_v(8)
+#define JIT_V9                 jit_v(9)
+#define JIT_V10                        jit_v(10)
+#define JIT_V11                        jit_v(11)
+#define JIT_V12                        jit_v(12)
+#define JIT_V13                        jit_v(13)
+    _R14,      _R15,   _R16,   _R17,   _R18,   _R19,   _R20,   _R21,
+    _R22,      _R23,   _R24,   _R25,   _R26,   _R27,   _R28,   _R29,
+    _R30,
+    _R1,
+#define JIT_FP                 _R31
+    _R31,
+    _R10,      _R9,    _R8,    _R7,    _R6,    _R5,    _R4,    _R3,
+    _F0,
+    _F14,      _F15,   _F16,   _F17,   _F18,   _F19,   _F20,   _F21,
+#define JIT_F0                 _F14
+#define JIT_F1                 _F15
+#define JIT_F2                 _F16
+#define JIT_F3                 _F17
+#define JIT_F4                 _F18
+#define JIT_F5                 _F19
+#define JIT_F6                 _F20
+#define JIT_F7                 _F21
+    /* FIXME _F20-_F31 not (easily) accessible and only _F14-_F21
+     * saved/restored (if used) */
+    _F22,      _F23,   _F24,   _F25,   _F26,   _F27,   _F28,   _F29,
+    _F30,      _F31,
+    _F13,      _F12,   _F11,   _F10,   _F9,    _F8,    _F7,    _F6,
+    _F5,       _F4,    _F3,    _F2,    _F1,
+    _NOREG,
+#define JIT_NOREG              _NOREG
+} jit_reg_t;
+
+#endif /* _jit_ppc_h */
diff --git a/deps/lightning/include/lightning/jit_private.h b/deps/lightning/include/lightning/jit_private.h
new file mode 100644 (file)
index 0000000..8c05853
--- /dev/null
@@ -0,0 +1,773 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_private_h
+#define _jit_private_h
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+
+#ifdef STDC_HEADERS
+#  include <stddef.h>
+#else
+#  if !defined(offsetof)
+#    define offsetof(type, field) ((char *)&((type *)0)->field - (char *)0)
+#  endif
+#endif
+
+#if defined(__GNUC__)
+#  define maybe_unused         __attribute__ ((unused))
+#  define unlikely(exprn)      __builtin_expect(!!(exprn), 0)
+#  define likely(exprn)                __builtin_expect(!!(exprn), 1)
+#  if (__GNUC__ >= 4)
+#    define PUBLIC             __attribute__ ((visibility("default")))
+#    define HIDDEN             __attribute__ ((visibility("hidden")))
+#  else
+#    define PUBLIC             /**/
+#    define HIDDEN             /**/
+#  endif
+#else
+#  define maybe_unused         /**/
+#  define unlikely(exprn)      exprn
+#  define likely(exprn)                exprn
+#  define PUBLIC               /**/
+#  define HIDDEN               /**/
+#endif
+
+#define rc(value)              jit_class_##value
+#define rn(reg)                        (jit_regno(_rvs[jit_regno(reg)].spec))
+
+#if defined(__i386__) || defined(__x86_64__)
+#  define JIT_SP               _RSP
+#  define JIT_RET              _RAX
+#  if __X32
+#    define JIT_FRET           _ST0
+typedef jit_uint32_t           jit_regset_t;
+#  else
+#    if __CYGWIN__ || _WIN32
+#      define JIT_RA0          _RCX
+#    else
+#      define JIT_RA0          _RDI
+#    endif
+#    define JIT_FA0            _XMM0
+#    define JIT_FRET           _XMM0
+typedef jit_uint64_t           jit_regset_t;
+#  endif
+#elif defined(__mips__)
+#  define JIT_RA0              _A0
+#  define JIT_FA0              _F12
+#  define JIT_SP               _SP
+#  define JIT_RET              _V0
+#  define JIT_FRET             _F0
+typedef jit_uint64_t           jit_regset_t;
+#elif defined(__arm__)
+#  define JIT_RA0              _R0
+#  define JIT_FA0              _D0
+#  define JIT_SP               _R13
+#  define JIT_RET              _R0
+#  if defined(__ARM_PCS_VFP)
+#    define JIT_FRET           _D0
+#  else
+#    define JIT_FRET           _R0
+#  endif
+typedef jit_uint64_t           jit_regset_t;
+#elif defined(__powerpc__)
+#  define JIT_RA0              _R3
+#  define JIT_FA0              _F1
+#  define JIT_SP               _R1
+#  define JIT_RET              _R3
+#  define JIT_FRET             _F1
+typedef jit_uint64_t           jit_regset_t;
+#elif defined(__sparc__)
+#  define JIT_SP               _SP
+#  define JIT_RET              _I0
+#  define JIT_FRET             _F0
+#  if __WORDSIZE == 32
+typedef jit_uint64_t           jit_regset_t;
+#  else
+typedef struct {
+    jit_uint64_t       rl;
+    jit_uint64_t       rh;
+} jit_regset_t;
+#  endif
+#elif defined(__ia64__)
+#  define JIT_SP               _R12
+#  define JIT_RET              _R8
+#  define JIT_FRET             _F8
+typedef struct {
+    jit_uint64_t       rl;
+    jit_uint64_t       rh;
+    jit_uint64_t       fl;
+    jit_uint64_t       fh;
+} jit_regset_t;
+#elif defined(__hppa__)
+#  define JIT_SP               _R30
+#  define JIT_RET              _R28
+#  define JIT_FRET             _F4
+typedef jit_uint64_t           jit_regset_t;
+#elif defined(__aarch64__)
+#  define JIT_RA0              _R0
+#  define JIT_FA0              _V0
+#  define JIT_SP               _SP
+#  define JIT_RET              _R0
+#  define JIT_FRET             _V0
+typedef jit_uint64_t           jit_regset_t;
+#elif defined(__s390__) || defined(__s390x__)
+#  define JIT_SP               _R15
+#  define JIT_RET              _R2
+#  define JIT_FRET             _F0
+typedef jit_uint32_t           jit_regset_t;
+#elif defined(__alpha__)
+#  define JIT_SP               _SP
+#  define JIT_RET              _V0
+#  define JIT_FRET             _F0
+typedef jit_uint64_t           jit_regset_t;
+#elif defined(__riscv)
+#  define JIT_RA0              _A0
+#  define JIT_FA0              _FA0
+#  define JIT_SP               _SP
+#  define JIT_RET              _A0
+#  define JIT_FRET             _FA0
+typedef jit_uint64_t           jit_regset_t;
+#endif
+
+#define jit_data(u,v,w)                _jit_data(_jit,u,v,w)
+extern jit_node_t *_jit_data(jit_state_t*, const void*,
+                            jit_word_t, jit_int32_t);
+
+#define jit_size(vector)       (sizeof(vector) / sizeof((vector)[0]))
+
+#define jit_reg_free_p(regno)                                          \
+    (!jit_regset_tstbit(&_jitc->reglive, regno) &&                     \
+     !jit_regset_tstbit(&_jitc->regarg, regno) &&                      \
+     !jit_regset_tstbit(&_jitc->regsav, regno))
+
+#define jit_reg_free_if_spill_p(regno)                                 \
+    (!jit_regset_tstbit(&_jitc->regarg, regno) &&                      \
+     !jit_regset_tstbit(&_jitc->regsav, regno))
+
+#define jit_inc_synth(code)                                            \
+    do {                                                               \
+       (void)jit_new_node(jit_code_##code);                            \
+       jit_synth_inc();                                                \
+    } while (0)
+#define jit_inc_synth_w(code, u)                                       \
+    do {                                                               \
+       (void)jit_new_node_w(jit_code_##code, u);                       \
+       jit_synth_inc();                                                \
+    } while (0)
+#define jit_inc_synth_f(code, u)                                       \
+    do {                                                               \
+       (void)jit_new_node_f(jit_code_##code, u);                       \
+       jit_synth_inc();                                                \
+    } while (0)
+#define jit_inc_synth_d(code, u)                                       \
+    do {                                                               \
+       (void)jit_new_node_d(jit_code_##code, u);                       \
+       jit_synth_inc();                                                \
+    } while (0)
+#define jit_inc_synth_ww(code, u, v)                                   \
+    do {                                                               \
+       (void)jit_new_node_ww(jit_code_##code, u, v);                   \
+       jit_synth_inc();                                                \
+    } while (0)
+#define jit_inc_synth_wp(code, u, v)                                   \
+    do {                                                               \
+       (void)jit_new_node_wp(jit_code_##code, u, v);                   \
+       jit_synth_inc();                                                \
+    } while (0)
+#define jit_inc_synth_fp(code, u, v)                                   \
+    do {                                                               \
+       (void)jit_new_node_fp(jit_code_##code, u, v);                   \
+       jit_synth_inc();                                                \
+    } while (0)
+#define jit_inc_synth_dp(code, u, v)                                   \
+    do {                                                               \
+       (void)jit_new_node_dp(jit_code_##code, u, v);                   \
+       jit_synth_inc();                                                \
+    } while (0)
+#define jit_dec_synth()                jit_synth_dec()
+
+#define jit_link_prolog()                                              \
+    do {                                                               \
+       _jitc->tail->link = _jitc->function->prolog->link;              \
+       _jitc->function->prolog->link = _jitc->tail;                    \
+    } while (0)
+#define jit_link_prepare()                                             \
+    do {                                                               \
+       _jitc->tail->link = _jitc->prepare->link;                       \
+       _jitc->prepare->link = _jitc->tail;                             \
+    } while (0)
+#define jit_link_reverse(where)                                                \
+    do {                                                               \
+       jit_node_t      *tmp, *tail = 0;                                \
+       while (where) {                                                 \
+           tmp = (where)->link;                                        \
+           (where)->link = tail;                                       \
+           tail = where;                                               \
+           where = tmp;                                                \
+       }                                                               \
+       where = tail;                                                   \
+    } while (0);
+
+/*
+ * Private jit_class bitmasks
+ */
+#define jit_class_named                0x00400000      /* hit must be the named reg */
+#define jit_class_nospill      0x00800000      /* hint to fail if need spill */
+#define jit_class_sft          0x01000000      /* not a hardware register */
+#define jit_class_rg8          0x04000000      /* x86 8 bits */
+#define jit_class_xpr          0x80000000      /* float / vector */
+/* Used on sparc64 where %f0-%f31 can be encode for single float
+ * but %f32 to %f62 only as double precision */
+#define jit_class_sng          0x10000000      /* Single precision float */
+#define jit_class_dbl          0x20000000      /* Only double precision float */
+#define jit_regno_patch                0x00008000      /* this is a register
+                                                * returned by a "user" call
+                                                * to jit_get_reg() */
+
+#define jit_call_default       0
+#define jit_call_varargs       1
+
+#define jit_kind_register      1
+#define jit_kind_code          2
+#define jit_kind_word          3
+#define jit_kind_float32       4
+#define jit_kind_float64       5
+
+#define jit_cc_a0_reg          0x00000001      /* arg0 is a register */
+#define jit_cc_a0_chg          0x00000002      /* arg0 is modified */
+#define jit_cc_a0_jmp          0x00000004      /* arg0 is a jump target */
+#define jit_cc_a0_rlh          0x00000008      /* arg0 is a register pair */
+#define jit_cc_a0_int          0x00000010      /* arg0 is immediate word */
+#define jit_cc_a0_flt          0x00000020      /* arg0 is immediate float */
+#define jit_cc_a0_dbl          0x00000040      /* arg0 is immediate double */
+#define jit_cc_a0_arg          0x00000080      /* arg1 is an argument int id */
+#define jit_cc_a1_reg          0x00000100      /* arg1 is a register */
+#define jit_cc_a1_chg          0x00000200      /* arg1 is modified */
+#define jit_cc_a1_int          0x00001000      /* arg1 is immediate word */
+#define jit_cc_a1_flt          0x00002000      /* arg1 is immediate float */
+#define jit_cc_a1_dbl          0x00004000      /* arg1 is immediate double */
+#define jit_cc_a1_arg          0x00008000      /* arg1 is an argument node */
+#define jit_cc_a2_reg          0x00010000      /* arg2 is a register */
+#define jit_cc_a2_chg          0x00020000      /* arg2 is modified */
+#define jit_cc_a2_int          0x00100000      /* arg2 is immediate word */
+#define jit_cc_a2_flt          0x00200000      /* arg2 is immediate float */
+#define jit_cc_a2_dbl          0x00400000      /* arg2 is immediate double */
+
+#if __ia64__ || (__sparc__ && __WORDSIZE == 64)
+extern void
+jit_regset_com(jit_regset_t*, jit_regset_t*);
+
+extern void
+jit_regset_and(jit_regset_t*, jit_regset_t*, jit_regset_t*);
+
+extern void
+jit_regset_ior(jit_regset_t*, jit_regset_t*, jit_regset_t*);
+
+extern void
+jit_regset_xor(jit_regset_t*, jit_regset_t*, jit_regset_t*);
+
+extern void
+jit_regset_set(jit_regset_t*, jit_regset_t*);
+
+extern void
+jit_regset_set_mask(jit_regset_t*, jit_int32_t);
+
+extern jit_bool_t
+jit_regset_cmp_ui(jit_regset_t*, jit_word_t);
+
+extern void
+jit_regset_set_ui(jit_regset_t*, jit_word_t);
+
+extern jit_bool_t
+jit_regset_set_p(jit_regset_t*);
+
+extern void
+jit_regset_clrbit(jit_regset_t*, jit_int32_t);
+
+extern void
+jit_regset_setbit(jit_regset_t*, jit_int32_t);
+
+extern jit_bool_t
+jit_regset_tstbit(jit_regset_t*, jit_int32_t);
+#  if __sparc__ && __WORDSIZE == 64
+#    define jit_regset_new(set)                                                \
+    do { (set)->rl = (set)->rh = 0; } while (0)
+#    define jit_regset_del(set)                                                \
+    do { (set)->rl = (set)->rh = 0; } while (0)
+#  else
+#    define jit_regset_new(set)                                                \
+    do { (set)->rl = (set)->rh = (set)->fl = (set)->fh = 0; } while (0)
+#    define jit_regset_del(set)                                                \
+    do { (set)->rl = (set)->rh = (set)->fl = (set)->fh = 0; } while (0)
+#  endif
+#else
+#  define jit_regset_com(u, v)         (*(u) = ~*(v))
+#  define jit_regset_and(u, v, w)      (*(u) = *(v) & *(w))
+#  define jit_regset_ior(u, v, w)      (*(u) = *(v) | *(w))
+#  define jit_regset_xor(u, v, w)      (*(u) = *(v) ^ *(w))
+#  define jit_regset_set(u, v)         (*(u) = *(v))
+#  define jit_regset_set_mask(u, v)    (*(u) = (1LL << (v)) - 1)
+#  define jit_regset_cmp_ui(u, v)      (*(u) != (v))
+#  define jit_regset_set_ui(u, v)      (*(u) = (v))
+#  define jit_regset_set_p(set)                (*set)
+#  define jit_regset_clrbit(set, bit)  (*(set) &= ~(1LL << (bit)))
+#  define jit_regset_setbit(set, bit)  (*(set) |= 1LL << (bit))
+#  define jit_regset_tstbit(set, bit)  (*(set) & (1LL << (bit)))
+#  define jit_regset_new(set)          (*(set) = 0)
+#  define jit_regset_del(set)          (*(set) = 0)
+#endif
+extern unsigned long
+jit_regset_scan1(jit_regset_t*, jit_int32_t);
+
+#define jit_reglive_setup()                                            \
+    do {                                                               \
+       jit_regset_set_ui(&_jitc->reglive, 0);                          \
+       jit_regset_set_ui(&_jitc->regmask, 0);                          \
+    } while (0)
+
+/*
+ * Types
+ */
+typedef union jit_data         jit_data_t;
+typedef struct jit_note                jit_note_t;
+typedef struct jit_line                jit_line_t;
+typedef struct jit_block       jit_block_t;
+typedef struct jit_value       jit_value_t;
+typedef struct jit_compiler    jit_compiler_t;
+typedef struct jit_function    jit_function_t;
+typedef struct jit_register    jit_register_t;
+#if __arm__
+#  if DISASSEMBLER
+typedef struct jit_data_info   jit_data_info_t;
+#  endif
+#endif
+
+union jit_data {
+    struct {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+       jit_int32_t      l;
+       jit_int32_t      h;
+#else
+       jit_int32_t      h;
+       jit_int32_t      l;
+#endif
+    } q;
+    jit_word_t          w;
+    jit_float32_t       f;
+    jit_float64_t       d;
+    jit_pointer_t       p;
+    jit_node_t         *n;
+};
+
+struct jit_note {
+    jit_uint8_t                *code;
+    char               *name;
+    jit_line_t         *lines;
+    jit_word_t          length;
+    jit_word_t          size;          /* of code */
+};
+
+struct jit_line {
+    char               *file;
+    jit_int32_t                *linenos;
+    jit_int32_t                *offsets;
+    jit_word_t          length;
+};
+
+struct jit_node {
+    jit_node_t         *next;
+    jit_code_t          code;
+    jit_uint16_t        flag;
+    jit_uint16_t        offset;        /* Used if DEVEL_DISASSEMBLER */
+    jit_data_t          u;
+    jit_data_t          v;
+    jit_data_t          w;
+    jit_node_t         *link;
+};
+
+struct jit_block {
+    jit_node_t         *label;
+    jit_regset_t        reglive;
+    jit_regset_t        regmask;
+};
+
+struct jit_value {
+    jit_int32_t                kind;
+    jit_code_t         code;
+    jit_data_t         base;
+    jit_data_t         disp;
+};
+
+typedef struct {
+#if __arm__
+    jit_word_t          kind;
+#endif
+    jit_word_t          inst;
+    jit_node_t         *node;
+} jit_patch_t;
+
+#if __arm__ && DISASSEMBLER
+struct jit_data_info {
+    jit_uword_t                  code;         /* pointer in code buffer */
+    jit_word_t           length;       /* length of constant vector */
+};
+#endif
+
+struct jit_function {
+    struct {
+       jit_int32_t      argi;
+       jit_int32_t      argf;
+       jit_int32_t      size;
+       jit_int32_t      aoff;
+       jit_int32_t      alen;
+       jit_int32_t      call;
+       jit_int32_t      argn;          /* for debug output */
+    } self;
+    struct {
+       jit_int32_t      argi;
+       jit_int32_t      argf;
+       jit_int32_t      size;
+       jit_int32_t      call;
+    } call;
+    jit_node_t         *prolog;
+    jit_node_t         *epilog;
+    jit_int32_t                *regoff;
+    jit_regset_t        regset;
+    jit_int32_t                 stack;
+
+    /* Helper for common jit generation pattern, used in GNU Smalltalk
+     * and possibly others, where a static frame layout is required or
+     * assumed. */
+    jit_int32_t                 frame;
+    jit_uint32_t        define_frame : 1;
+    jit_uint32_t        assume_frame : 1;
+
+    /* alloca offset offset */
+    jit_int32_t                 aoffoff;
+    /* uses allocar flag */
+    jit_uint32_t        allocar : 1;
+
+    /* varargs state offsets */
+    jit_int32_t                 vaoff;         /* offset of jit_va_list */
+    jit_int32_t                 vagp;          /* first gp va argument */
+    jit_int32_t                 vafp;          /* first fp va argument */
+};
+
+/* data used only during jit generation */
+struct jit_compiler {
+#if __ia64__
+    struct {
+       jit_uint64_t      i : 41;
+       jit_uint64_t      t :  4;
+    } inst[3];
+    jit_regset_t         regs;         /* changed regs since last stop */
+    jit_int32_t                  pred;         /* changed preds last stop */
+    jit_int32_t                  ioff;         /* offset in inst vector */
+    jit_int32_t                  rout;         /* first output register */
+    jit_int32_t                  breg;         /* base register for prolog/epilog */
+#endif
+#if __mips__ || __ia64__ || __alpha__ || \
+       (__sparc__ && __WORDSIZE == 64) || __riscv
+    jit_int32_t                  carry;
+#define jit_carry        _jitc->carry
+#endif
+    jit_node_t          *head;
+    jit_node_t          *tail;
+    jit_node_t          *prepare;      /* inside prepare/finish* block */
+    jit_uint32_t         realize : 1;  /* jit_realize() called? */
+    jit_uint32_t         dataset : 1;  /* jit_dataset() called? */
+    jit_uint32_t         done  : 1;    /* emit state finished */
+    jit_uint32_t         emit  : 1;    /* emit state entered */
+    jit_uint32_t         again : 1;    /* start over emiting function */
+    jit_uint32_t         synth : 8;    /* emiting synthesized instructions */
+#if DEBUG
+    jit_uint32_t         getreg : 1;
+#endif
+    jit_uint32_t         no_data : 1;
+    jit_uint32_t         no_note : 1;
+    jit_int32_t                  reglen;       /* number of registers */
+    jit_regset_t         regarg;       /* cannot allocate */
+    jit_regset_t         regsav;       /* automatic spill only once */
+    jit_regset_t         reglive;      /* known live registers at some point */
+    jit_regset_t         regmask;      /* register mask to update reglive */
+    struct {
+       jit_uint8_t      *end;
+    } code;
+    struct {
+       jit_uint8_t      *ptr;
+       jit_node_t      **table;        /* very simple hash table */
+       jit_word_t        size;         /* number of vectors in table */
+       jit_word_t        count;        /* number of hash table entries */
+       jit_word_t        offset;       /* offset in bytes in ptr */
+    } data;
+    jit_node_t         **spill;
+    jit_int32_t                 *gen;          /* ssa like "register version" */
+    jit_value_t                 *values;       /* temporary jit_value_t vector */
+    struct {
+       jit_block_t      *ptr;
+       jit_word_t        offset;
+       jit_word_t        length;
+    } blocks;                          /* basic blocks */
+    struct {
+       jit_patch_t      *ptr;
+       jit_word_t        offset;
+       jit_word_t        length;
+    } patches;                         /* forward patch information */
+    jit_function_t      *function;     /* current function */
+    struct {
+       jit_function_t   *ptr;
+       jit_word_t        offset;
+       jit_word_t        length;
+    } functions;                       /* prolog/epilogue offsets in code */
+    struct {
+       jit_node_t      **ptr;
+       jit_word_t        offset;
+       jit_word_t        length;
+    } pool;
+    jit_node_t          *list;
+    struct {
+       jit_node_t       *head;         /* first note node */
+       jit_node_t       *tail;         /* linked list insertion */
+       /* fields to store temporary state information */
+       jit_word_t        size;
+       jit_node_t       *name;
+       jit_node_t       *note;
+       jit_uint8_t      *base;
+    } note;
+#if __arm__
+    /* prevent using thumb instructions that set flags? */
+    jit_uint32_t         no_set_flags : 1;
+#  if DISASSEMBLER
+    struct {
+       jit_data_info_t  *ptr;
+       jit_word_t        offset;
+       jit_word_t        length;
+    } data_info;                       /* constant pools information */
+#  endif
+    /* Note that this field is somewhat hackish, but required by most
+     * ways to implement jit, unless implementing a pure one function
+     * per jit, as most times it needs to start the jit buffer with a
+     * jump where the "main" prolog starts, and because the initial
+     * code is in "arm mode", need to make an "arm mode" patch on that
+     * jump. A good example is the test suite assembler, where most
+     * test cases start with a "jmpi main" call. */
+    jit_uword_t                  thumb;
+    struct {
+       jit_uint8_t      *data;         /* pointer to code */
+       jit_word_t        size;         /* size data */
+       jit_word_t        offset;       /* pending patches */
+       jit_word_t        length;       /* number of pending constants */
+       jit_int32_t       values[1024]; /* pending constants */
+       jit_word_t        patches[2048];
+    } consts;
+#elif (__powerpc__ && _CALL_AIXDESC) || __ia64__
+    /* Keep track of prolog addresses, just for the sake of making
+     * jit that starts with a jump to a "main" label work like other
+     * backends. */
+    struct {
+       jit_word_t       *ptr;
+       jit_word_t        offset;
+       jit_word_t        length;
+    } prolog;
+    jit_bool_t           jump;
+#endif
+#if GET_JIT_SIZE
+    /* Temporary storage to calculate instructions length */
+    jit_word_t           size;
+    /* Global flag for code buffer heuristic size computation */
+    jit_word_t           mult;
+    /* Pointer to code to prevent miscalculation if reallocating buffer */
+    jit_uint8_t                 *cptr;
+#endif
+};
+
+#define _jitc                          _jit->comp
+struct jit_state {
+    union {
+       jit_uint8_t      *uc;
+       jit_uint16_t     *us;
+       jit_uint32_t     *ui;
+       jit_uint64_t     *ul;
+       jit_word_t        w;
+    } pc;
+    struct {
+       jit_uint8_t     *ptr;
+       jit_word_t       length;
+    } code;
+    struct {
+       jit_uint8_t     *ptr;
+       jit_word_t       length;
+    } data;
+    struct {
+       jit_note_t      *ptr;
+       jit_word_t       length;
+    } note;
+    jit_compiler_t     *comp;
+    /* Flags to know if user did set the code and data buffers */
+    jit_uint32_t        user_code      : 1;
+    jit_uint32_t        user_data      : 1;
+};
+
+struct jit_register {
+    jit_reg_t           spec;
+    char               *name;
+};
+
+/*
+ * Prototypes
+ */
+extern void jit_get_cpu(void);
+
+#define jit_init()                     _jit_init(_jit)
+extern void _jit_init(jit_state_t*);
+
+#define jit_synth_inc()                        _jit_synth_inc(_jit)
+extern void _jit_synth_inc(jit_state_t*);
+
+#define jit_new_node_no_link(u)                _jit_new_node_no_link(_jit, u)
+extern jit_node_t *_jit_new_node_no_link(jit_state_t*, jit_code_t);
+
+#define jit_link_node(u)               _jit_link_node(_jit, u)
+extern void _jit_link_node(jit_state_t*, jit_node_t*);
+
+#define jit_link_label(l)      _jit_link_label(_jit,l)
+extern void
+_jit_link_label(jit_state_t*,jit_node_t*);
+
+#define jit_synth_dec()                        _jit_synth_dec(_jit)
+extern void _jit_synth_dec(jit_state_t*);
+
+#define jit_reglive(node)      _jit_reglive(_jit, node)
+extern void
+_jit_reglive(jit_state_t*, jit_node_t*);
+
+#define jit_regarg_set(n,v)    _jit_regarg_set(_jit,n,v)
+extern void
+_jit_regarg_set(jit_state_t*, jit_node_t*, jit_int32_t);
+
+#define jit_regarg_clr(n,v)    _jit_regarg_clr(_jit,n,v)
+extern void
+_jit_regarg_clr(jit_state_t*, jit_node_t*, jit_int32_t);
+
+#define jit_get_reg(s)         _jit_get_reg(_jit,s)
+extern jit_int32_t
+_jit_get_reg(jit_state_t*, jit_int32_t);
+
+#define jit_unget_reg(r)       _jit_unget_reg(_jit,r)
+extern void
+_jit_unget_reg(jit_state_t*, jit_int32_t);
+
+#define jit_save(reg)          _jit_save(_jit, reg)
+extern void
+_jit_save(jit_state_t*, jit_int32_t);
+
+#define jit_load(reg)          _jit_load(_jit, reg)
+extern void
+_jit_load(jit_state_t*, jit_int32_t);
+
+#define jit_trampoline(u,v)    _jit_trampoline(_jit, u, v)
+extern void _jit_trampoline(jit_state_t*, jit_int32_t, jit_bool_t);
+
+#define jit_optimize()         _jit_optimize(_jit)
+extern void
+_jit_optimize(jit_state_t*);
+
+#define jit_classify(code)     _jit_classify(_jit, code)
+extern jit_int32_t
+_jit_classify(jit_state_t*, jit_code_t);
+
+#define jit_regarg_p(n, r)     _jit_regarg_p(_jit, n, r)
+extern jit_bool_t
+_jit_regarg_p(jit_state_t*, jit_node_t*, jit_int32_t);
+
+#define emit_code()            _emit_code(_jit)
+extern jit_pointer_t
+_emit_code(jit_state_t*);
+
+extern void
+jit_flush(void *fptr, void *tptr);
+
+#define emit_ldxi(r0, r1, i0)  _emit_ldxi(_jit, r0, r1, i0)
+extern void
+_emit_ldxi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+
+#define emit_stxi(i0, r0, r1)  _emit_stxi(_jit, i0, r0, r1)
+extern void
+_emit_stxi(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+
+#define emit_ldxi_d(r0, r1, i0)        _emit_ldxi_d(_jit, r0, r1, i0)
+extern void
+_emit_ldxi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+
+#define emit_stxi_d(i0, r0, r1)        _emit_stxi_d(_jit, i0, r0, r1)
+extern void
+_emit_stxi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+
+extern void jit_init_debug(const char*);
+extern void jit_finish_debug(void);
+
+extern void jit_init_note(void);
+extern void jit_finish_note(void);
+#define jit_set_note(n,u,v,w)  _jit_set_note(_jit, n, u, v, w)
+extern void _jit_set_note(jit_state_t*, jit_note_t*, char*, int, jit_int32_t);
+#define jit_annotate()         _jit_annotate(_jit)
+extern void _jit_annotate(jit_state_t*);
+
+#define jit_print_node(u)      _jit_print_node(_jit,u)
+extern void _jit_print_node(jit_state_t*,jit_node_t*);
+
+extern jit_pointer_t jit_memcpy(jit_pointer_t,const void*,jit_word_t);
+extern jit_pointer_t jit_memmove(jit_pointer_t,const void*,jit_word_t);
+extern void jit_alloc(jit_pointer_t*, jit_word_t);
+extern void jit_realloc(jit_pointer_t*, jit_word_t, jit_word_t);
+void jit_free(jit_pointer_t*);
+
+extern void jit_init_size(void);
+extern void jit_finish_size(void);
+
+#if GET_JIT_SIZE
+#  define jit_size_prepare()           _jit_size_prepare(_jit)
+extern void
+_jit_size_prepare(jit_state_t*);
+
+#  define jit_size_collect(node)       _jit_size_collect(_jit, node)
+extern void
+_jit_size_collect(jit_state_t*, jit_node_t*);
+#else
+#  define jit_get_size()               _jit_get_size(_jit)
+extern jit_word_t
+_jit_get_size(jit_state_t*);
+#endif
+
+extern jit_word_t
+jit_get_max_instr(void);
+
+/*
+ * Externs
+ */
+extern jit_register_t   _rvs[];
+
+#endif /* _jit_private_h */
diff --git a/deps/lightning/include/lightning/jit_riscv.h b/deps/lightning/include/lightning/jit_riscv.h
new file mode 100644 (file)
index 0000000..1b4f93d
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_riscv_h
+#define _jit_riscv_h
+
+#define JIT_HASH_CONSTS                0
+#define JIT_NUM_OPERANDS       3
+
+/*
+ * Types
+ */
+#define JIT_FP                 _FP
+typedef enum {
+#define jit_r(i)               (JIT_R0 + (i))
+#define jit_r_num()            7
+#define jit_v(i)               (JIT_V0 + (i))
+#define jit_v_num()            11
+#define jit_f(i)               (JIT_F0 + (i))
+#define jit_f_num()            12
+    _ZERO,     /*  x0 - Hard-wired zero        ---             */
+    _RA,       /*  x1 - Return address         (CalleR save)   */
+    _SP,       /*  x2 - Stack pointer          (CalleE save)   */
+    _GP,       /*  x3 - Global pointer         ---             */
+
+#if 0          /* Pretend it does not exist, so _NOREG can be used in
+                * a 64 bit bitmask */
+    _TP,       /*  x4 - Thread pointer         ---             */
+#endif
+    
+#define JIT_R0         _T0
+#define JIT_R1         _T1
+#define JIT_R2         _T2
+#define JIT_R3         _T3
+#define JIT_R4         _T4
+#define JIT_R5         _T5
+#define JIT_R6         _T6
+    _T0,       /*  x5 - Temporary/alternate
+                        link register          (CalleR save)   */
+    _T1,       /*  x6 - Temporary              (CalleR save)   */
+    _T2,       /*  x7 - Temporary              (CalleR save)   */
+    _T3,       /* x28 - Temporary              (CalleR save)   */
+    _T4,       /* x28 - Temporary              (CalleR save)   */
+    _T5,       /* x30 - Temporary              (CalleR save)   */
+    _T6,       /* x31 - Temporary              (CalleR save)   */
+    _FP,       /*  x8 - Saved register/frame
+                        pointer                (CalleE save)   */
+    _S0 = _FP,
+#define JIT_V0         _S1
+#define JIT_V1         _S2
+#define JIT_V2         _S3
+#define JIT_V3         _S4
+#define JIT_V4         _S5
+#define JIT_V5         _S6
+#define JIT_V6         _S7
+#define JIT_V7         _S8
+#define JIT_V8         _S9
+#define JIT_V9         _S10
+#define JIT_V10                _S11
+    _S1,       /*  x9 - Saved register         (CalleE save)   */
+    _S2,       /* x18 - Saved register         (CalleE save)   */
+    _S3,       /* x19 - Saved register         (CalleE save)   */
+    _S4,       /* x20 - Saved register         (CalleE save)   */
+    _S5,       /* x21 - Saved register         (CalleE save)   */
+    _S6,       /* x22 - Saved register         (CalleE save)   */
+    _S7,       /* x23 - Saved register         (CalleE save)   */
+    _S8,       /* x24 - Saved register         (CalleE save)   */
+    _S9,       /* x25 - Saved register         (CalleE save)   */
+    _S10,      /* x26 - Saved register         (CalleE save)   */
+    _S11,      /* x27 - Saved register         (CalleE save)   */
+    _A7,       /* x17 - Function argument      (CalleR save)   */
+    _A6,       /* x16 - Function argument      (CalleR save)   */
+    _A5,       /* x15 - Function argument      (CalleR save)   */
+    _A4,       /* x14 - Function argument      (CalleR save)   */
+    _A3,       /* x13 - Function argument      (CalleR save)   */
+    _A2,       /* x12 - Function argument      (CalleR save)   */
+    _A1,       /* x11 - Function argument/
+                        return value           (CalleR save)   */
+    _A0,       /* x10 - Function argument/
+                        return value           (CalleR save)   */
+    _FT0,      /*  f0 - FP temporary           (CalleR save)   */
+    _FT1,      /*  f1 - FP temporary           (CalleR save)   */
+    _FT2,      /*  f2 - FP temporary           (CalleR save)   */
+    _FT3,      /*  f3 - FP temporary           (CalleR save)   */
+    _FT4,      /*  f4 - FP temporary           (CalleR save)   */
+    _FT5,      /*  f5 - FP temporary           (CalleR save)   */
+    _FT6,      /*  f6 - FP temporary           (CalleR save)   */
+    _FT7,      /*  f7 - FP temporary           (CalleR save)   */
+    _FT8,      /* f28 - FP temporary           (CalleR save)   */
+    _FT9,      /* f29 - FP temporary           (CalleR save)   */
+    _FT10,     /* f30 - FP temporary           (CalleR save)   */
+    _FT11,     /* f31 - FP temporary           (CalleR save)   */
+#define JIT_F0         _FS0
+#define JIT_F1         _FS1
+#define JIT_F2         _FS2
+#define JIT_F3         _FS3
+#define JIT_F4         _FS4
+#define JIT_F5         _FS5
+#define JIT_F6         _FS6
+#define JIT_F7         _FS7
+#define JIT_F8         _FS8
+#define JIT_F9         _FS9
+#define JIT_F10                _FS10
+#define JIT_F11                _FS11
+    _FS0,      /*  f8 - FP saved register      (CalleE save)   */
+    _FS1,      /*  f9 - FP saved register      (CalleE save)   */
+    _FS2,      /* f18 - FP saved register      (CalleE save)   */
+    _FS3,      /* f19 - FP saved register      (CalleE save)   */
+    _FS4,      /* f20 - FP saved register      (CalleE save)   */
+    _FS5,      /* f21 - FP saved register      (CalleE save)   */
+    _FS6,      /* f22 - FP saved register      (CalleE save)   */
+    _FS7,      /* f23 - FP saved register      (CalleE save)   */
+    _FS8,      /* f24 - FP saved register      (CalleE save)   */
+    _FS9,      /* f25 - FP saved register      (CalleE save)   */
+    _FS10,     /* f26 - FP saved register      (CalleE save)   */
+    _FS11,     /* f27 - FP saved register      (CalleE save)   */
+    _FA7,      /* f17 - FP Function argument   (CalleR save)   */
+    _FA6,      /* f16 - FP Function argument   (CalleR save)   */
+    _FA5,      /* f15 - FP Function argument   (CalleR save)   */
+    _FA4,      /* f14 - FP Function argument   (CalleR save)   */
+    _FA3,      /* f13 - FP Function argument   (CalleR save)   */
+    _FA2,      /* f12 - FP Function argument   (CalleR save)   */
+    _FA1,      /* f11 - FP function argument/
+                        return value           (CalleR save)   */
+    _FA0,      /* f10 - FP function argument/
+                        return value           (CalleR save)   */
+    _NOREG,
+#define JIT_NOREG              _NOREG
+} jit_reg_t;
+
+#endif /* _jit_riscv_h */
diff --git a/deps/lightning/include/lightning/jit_s390.h b/deps/lightning/include/lightning/jit_s390.h
new file mode 100644 (file)
index 0000000..6ab196b
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_s390_h
+#define _jit_s390_h
+
+#define JIT_HASH_CONSTS                1
+#define JIT_NUM_OPERANDS       2
+
+/*
+ * Types
+ */
+#define JIT_FP                 _R13
+typedef enum {
+#define jit_r(i)               (_R12 + ((i) << 1))
+#define jit_r_num()            3
+#define jit_v(i)               (_R11 + ((i) << 1))
+#define jit_v_num()            3
+#define jit_f(i)               (_F8 + (i))
+#define jit_f_num()            6
+#define JIT_R0                 _R12
+#define JIT_R1                 _R10
+#define JIT_R2                 _R8
+#define JIT_V0                 _R11
+#define JIT_V1                 _R9
+#define JIT_V2                 _R7
+     _R0,  _R1,                        /* Volatile */
+    _R12,                      /* Saved, GOT */
+    _R11,  _R10,  _R9,  _R8,   /* Saved */
+     _R7,                      /* Saved */
+     _R6,                      /* Saved, parameter */
+     _R5,  _R4,  _R3,          /* Parameter passing */
+     _R2,                      /* Volatile, parameter and return value */
+    _R13,                      /* Saved, literal pool pointer */
+    _R14,                      /* Volatile, return address */
+    _R15,                      /* Saved, stack pointer */
+#define JIT_F0                 _F8
+#define JIT_F1                 _F9
+#define JIT_F2                 _F10
+#define JIT_F3                 _F11
+#define JIT_F4                 _F12
+#define JIT_F5                 _F13
+     _F1,  _F3,  _F5,  _F7,    /* Volatile */
+    _F14, _F15,         _F8,  _F9,     /* Saved */
+    _F10, _F11, _F12, _F13,    /* Saved */
+     _F6,  _F4,  _F2,          /* Volatile, parameter */
+     _F0,                      /* Volatile, parameter and return value */
+    _NOREG,
+#define JIT_NOREG              _NOREG
+} jit_reg_t;
+
+#endif /* _jit_s390_h */
diff --git a/deps/lightning/include/lightning/jit_sparc.h b/deps/lightning/include/lightning/jit_sparc.h
new file mode 100644 (file)
index 0000000..bee440b
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_sparc_h
+#define _jit_sparc_h
+
+#define JIT_HASH_CONSTS                1
+#define JIT_NUM_OPERANDS       3
+
+/*
+ * Types
+ */
+#define JIT_FP                 _FP
+typedef enum {
+#define jit_r(i)               (_G2 + (i))
+#define jit_r_num()            3
+#define jit_v(i)               (_L0 + (i))
+#define jit_v_num()            8
+#if __WORDSIZE == 32
+#  define jit_f(i)             (_F0 + ((i) << 1))
+#  define jit_f_num()          8
+#else
+#  define jit_f(i)             (_F32 - (i))
+#  define jit_f_num()          16
+#endif
+#define JIT_R0                 _G2
+#define JIT_R1                 _G3
+#define JIT_R2                 _G4
+#define JIT_V0                 _L0
+#define JIT_V1                 _L1
+#define JIT_V2                 _L2
+#define JIT_V3                 _L3
+#define JIT_V4                 _L4
+#define JIT_V5                 _L5
+#define JIT_V6                 _L6
+#define JIT_V7                 _L7
+    _G0, _G1, _G2, _G3, _G4, _G5, _G6, _G7,
+    _O0, _O1, _O2, _O3, _O4, _O5, _SP, _O7,
+    _L0, _L1, _L2, _L3, _L4, _L5, _L6, _L7,
+    _I0, _I1, _I2, _I3, _I4, _I5, _FP, _I7,
+#if __WORDSIZE == 32
+#  define JIT_F0               _F0
+#  define JIT_F1               _F2
+#  define JIT_F2               _F4
+#  define JIT_F3               _F6
+#  define JIT_F4               _F8
+#  define JIT_F5               _F10
+#  define JIT_F6               _F12
+#  define JIT_F7               _F14
+    _F0, _F1,  _F2,  _F3,  _F4,  _F5,  _F6,  _F7,
+    _F8, _F9, _F10, _F11, _F12, _F13, _F14, _F15,
+#else
+    /* All single precision operations have a high cost due to being
+     * stored on registers only encodable as double precision.
+     * The cost is due to needing to move values to a register with
+     * value <= 31.
+     * This is a limitation due to using fixed named registers in
+     * lightning. */
+#  define JIT_F0               _F32
+#  define JIT_F1               _F34
+#  define JIT_F2               _F36
+#  define JIT_F3               _F38
+#  define JIT_F4               _F40
+#  define JIT_F5               _F42
+#  define JIT_F6               _F44
+#  define JIT_F7               _F46
+#  define JIT_F8               _F48
+#  define JIT_F9               _F50
+#  define JIT_F10              _F52
+#  define JIT_F11              _F54
+#  define JIT_F12              _F56
+#  define JIT_F13              _F58
+#  define JIT_F14              _F60
+#  define JIT_F15              _F62
+    _F62, _F60, _F58, _F56, _F54, _F52, _F50, _F48,
+    _F46, _F44, _F42, _F40, _F38, _F36, _F34, _F32,
+    _F31, _F30, _F29, _F28, _F27, _F26, _F25, _F24,
+    _F23, _F22, _F21, _F20, _F19, _F18, _F17, _F16,
+    _F15, _F14, _F13, _F12, _F11, _F10,  _F9,  _F8,
+     _F7,  _F6,  _F5,  _F4,  _F3,  _F2,  _F1,  _F0,
+#endif
+#define JIT_NOREG              _NOREG
+    _NOREG,
+} jit_reg_t;
+
+#endif /* _jit_sparc_h */
diff --git a/deps/lightning/include/lightning/jit_x86.h b/deps/lightning/include/lightning/jit_x86.h
new file mode 100644 (file)
index 0000000..a278d06
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#ifndef _jit_x86_h
+#define _jit_x86_h
+
+#define JIT_HASH_CONSTS                1
+#define JIT_NUM_OPERANDS       2
+
+/*
+ * Types
+ */
+#define jit_sse2_p()           jit_cpu.sse2
+#define jit_x87_reg_p(reg)     ((reg) >= _ST0 && (reg) <= _ST6)
+#if __WORDSIZE == 32
+#  if defined(__x86_64__)
+#    define __X64_32           1
+#    define __X64              1
+#  else
+#    define __X32              1
+#  endif
+#else
+#  define __X64                        1
+#endif
+
+#define JIT_FP                 _RBP
+typedef enum {
+#if __X32
+#  define jit_r(i)             (_RAX + (i))
+#  define jit_r_num()          3
+#  define jit_v(i)             (_RBX + (i))
+#  define jit_v_num()          3
+#  define jit_f(i)             (jit_cpu.sse2 ? _XMM0 + (i) : _ST0 + (i))
+#  define jit_f_num()          (jit_cpu.sse2 ? 8 : 6)
+#  define JIT_R0               _RAX
+#  define JIT_R1               _RCX
+#  define JIT_R2               _RDX
+    _RAX,      _RCX,   _RDX,
+#  define JIT_V0               _RBX
+#  define JIT_V1               _RSI
+#  define JIT_V2               _RDI
+    _RBX,      _RSI,   _RDI,
+    _RSP,      _RBP,
+#  define JIT_F0               (jit_sse2_p() ? _XMM0 : _ST0)
+#  define JIT_F1               (jit_sse2_p() ? _XMM1 : _ST1)
+#  define JIT_F2               (jit_sse2_p() ? _XMM2 : _ST2)
+#  define JIT_F3               (jit_sse2_p() ? _XMM3 : _ST3)
+#  define JIT_F4               (jit_sse2_p() ? _XMM4 : _ST4)
+#  define JIT_F5               (jit_sse2_p() ? _XMM5 : _ST5)
+#  define JIT_F6               (jit_sse2_p() ? _XMM6 : _ST6)
+    _XMM0,     _XMM1,  _XMM2,  _XMM3,  _XMM4,  _XMM5,  _XMM6,   _XMM7,
+#  define jit_sse_reg_p(reg)   ((reg) >= _XMM0 && (reg) <= _XMM7)
+#else
+#  if __CYGWIN__ || _WIN32
+#    define jit_r(i)           (_RAX + (i))
+#    define jit_r_num()                3
+#    define jit_v(i)           (_RBX + (i))
+#    define jit_v_num()                7
+#    define jit_f(index)       (_XMM4 + (index))
+#    define jit_f_num()                12
+#    define JIT_R0             _RAX
+#    define JIT_R1             _R10
+#    define JIT_R2             _R11
+#    define JIT_V0             _RBX
+#    define JIT_V1             _RDI
+#    define JIT_V2             _RSI
+#    define JIT_V3             _R12
+#    define JIT_V4             _R13
+#    define JIT_V5             _R14
+#    define JIT_V6             _R15
+    /* Volatile - Return value register */
+    _RAX,
+    /* Volatile */
+    _R10,      _R11,
+    /* Nonvolatile */
+    _RBX,      _RDI,   _RSI,
+    _R12,      _R13,   _R14,   _R15,
+    /* Volatile - Integer arguments (4 to 1) */
+    _R9,       _R8,    _RDX,   _RCX,
+    /* Nonvolatile */
+    _RSP,      _RBP,
+#    define JIT_F0             _XMM4
+#    define JIT_F1             _XMM5
+#    define JIT_F2             _XMM6
+#    define JIT_F3             _XMM7
+#    define JIT_F4             _XMM8
+#    define JIT_F5             _XMM9
+#    define JIT_F6             _XMM10
+#    define JIT_F7             _XMM11
+#    define JIT_F8             _XMM12
+#    define JIT_F9             _XMM13
+#    define JIT_F10            _XMM14
+#    define JIT_F11            _XMM15
+    /* Volatile */
+    _XMM4,     _XMM5,
+    /* Nonvolatile */
+    _XMM6,     _XMM7,  _XMM8,  _XMM9,  _XMM10,
+    _XMM11,    _XMM12, _XMM13, _XMM14, _XMM15,
+    /* Volatile - FP arguments (4 to 1) */
+    _XMM3,     _XMM2,  _XMM1,  _XMM0,
+#    define jit_sse_reg_p(reg) ((reg) >= _XMM4 && (reg) <= _XMM0)
+#  else
+#    define jit_r(i)           (_RAX + (i))
+#    define jit_r_num()                3
+#    define jit_v(i)           (_RBX + (i))
+#    define jit_v_num()                5
+#    define jit_f(index)       (_XMM8 + (index))
+#    define jit_f_num()                8
+#    define JIT_R0             _RAX
+#    define JIT_R1             _R10
+#    define JIT_R2             _R11
+    _RAX,      _R10,   _R11,
+#    define JIT_V0             _RBX
+#    define JIT_V1             _R13
+#    define JIT_V2             _R14
+#    define JIT_V3             _R15
+#    define JIT_V4             _R12
+    _RBX,      _R13,   _R14,   _R15,   _R12,
+    _R9,       _R8,    _RCX,   _RDX,   _RSI,   _RDI,
+    _RSP,      _RBP,
+#    define JIT_F0             _XMM8
+#    define JIT_F1             _XMM9
+#    define JIT_F2             _XMM10
+#    define JIT_F3             _XMM11
+#    define JIT_F4             _XMM12
+#    define JIT_F5             _XMM13
+#    define JIT_F6             _XMM14
+#    define JIT_F7             _XMM15
+    _XMM8,     _XMM9,  _XMM10, _XMM11, _XMM12, _XMM13, _XMM14, _XMM15,
+    _XMM7,     _XMM6,  _XMM5,  _XMM4,  _XMM3,  _XMM2,  _XMM1,  _XMM0,
+#    define jit_sse_reg_p(reg) ((reg) >= _XMM8 && (reg) <= _XMM0)
+#  endif
+#endif
+    _ST0,      _ST1,   _ST2,   _ST3,   _ST4,   _ST5,   _ST6,
+#  define JIT_NOREG            _NOREG
+    _NOREG,
+} jit_reg_t;
+
+typedef struct {
+    /* x87 present */
+    jit_uint32_t fpu           : 1;
+    /* cmpxchg8b instruction */
+    jit_uint32_t cmpxchg8b     : 1;
+    /* cmov and fcmov branchless conditional mov */
+    jit_uint32_t cmov          : 1;
+    /* mmx registers/instructions available */
+    jit_uint32_t mmx           : 1;
+    /* sse registers/instructions available */
+    jit_uint32_t sse           : 1;
+    /* sse2 registers/instructions available */
+    jit_uint32_t sse2          : 1;
+    /* sse3 instructions available */
+    jit_uint32_t sse3          : 1;
+    /* pcmulqdq instruction */
+    jit_uint32_t pclmulqdq     : 1;
+    /* ssse3 suplemental sse3 instructions available */
+    jit_uint32_t ssse3         : 1;
+    /* fused multiply/add using ymm state */
+    jit_uint32_t fma           : 1;
+    /* cmpxchg16b instruction */
+    jit_uint32_t cmpxchg16b    : 1;
+    /* sse4.1 instructions available */
+    jit_uint32_t sse4_1                : 1;
+    /* sse4.2 instructions available */
+    jit_uint32_t sse4_2                : 1;
+    /* movbe instruction available */
+    jit_uint32_t movbe         : 1;
+    /* popcnt instruction available */
+    jit_uint32_t popcnt                : 1;
+    /* aes instructions available */
+    jit_uint32_t aes           : 1;
+    /* avx instructions available */
+    jit_uint32_t avx           : 1;
+    /* lahf/sahf available in 64 bits mode */
+    jit_uint32_t lahf          : 1;
+} jit_cpu_t;
+
+/*
+ * Initialization
+ */
+extern jit_cpu_t               jit_cpu;
+
+#endif /* _jit_x86_h */
diff --git a/deps/lightning/lib/Makefile.am b/deps/lightning/lib/Makefile.am
new file mode 100644 (file)
index 0000000..f2ac2ba
--- /dev/null
@@ -0,0 +1,83 @@
+#
+# Copyright 2000, 2001, 2002, 2012-2019 Free Software Foundation, Inc.
+#
+# This file is part of GNU lightning.
+#
+# GNU lightning is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU lightning is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+# License for more details.
+#
+
+AM_CFLAGS = -I$(top_srcdir)/include -D_GNU_SOURCE $(LIGHTNING_CFLAGS)
+liblightning_LTLIBRARIES = liblightning.la
+liblightning_la_LDFLAGS = -version-info 1:0:0
+
+if get_jit_size
+JIT_SIZE_PATH = "$(top_builddir)/jit_$(cpu)-sz.c"
+AM_CPPFLAGS=-DGET_JIT_SIZE=1 -DJIT_SIZE_PATH='$(JIT_SIZE_PATH)'
+endif
+
+liblightningdir = $(libdir)
+liblightning_la_SOURCES =      \
+       jit_disasm.c            \
+       jit_memory.c            \
+       jit_names.c             \
+       jit_note.c              \
+       jit_print.c             \
+       jit_size.c              \
+       lightning.c
+
+EXTRA_DIST =                   \
+       jit_rewind.c            \
+       jit_aarch64.c           \
+       jit_aarch64-cpu.c       \
+       jit_aarch64-fpu.c       \
+       jit_aarch64-sz.c        \
+       jit_alpha.c             \
+       jit_alpha-cpu.c         \
+       jit_alpha-fpu.c         \
+       jit_alpha-sz.c          \
+       jit_arm.c               \
+       jit_arm-cpu.c           \
+       jit_arm-swf.c           \
+       jit_arm-vfp.c           \
+       jit_arm-sz.c            \
+       jit_hppa.c              \
+       jit_hppa-cpu.c          \
+       jit_hppa-fpu.c          \
+       jit_hppa-sz.c           \
+       jit_ia64.c              \
+       jit_ia64-cpu.c          \
+       jit_ia64-fpu.c          \
+       jit_ia64-sz.c           \
+       jit_mips.c              \
+       jit_mips-cpu.c          \
+       jit_mips-fpu.c          \
+       jit_mips-sz.c           \
+       jit_ppc.c               \
+       jit_ppc-cpu.c           \
+       jit_ppc-fpu.c           \
+       jit_ppc-sz.c            \
+       jit_riscv.c             \
+       jit_riscv-cpu.c         \
+       jit_riscv-fpu.c         \
+       jit_riscv-sz.c          \
+       jit_s390.c              \
+       jit_s390-cpu.c          \
+       jit_s390-fpu.c          \
+       jit_s390-sz.c           \
+       jit_sparc.c             \
+       jit_sparc-cpu.c         \
+       jit_sparc-fpu.c         \
+       jit_sparc-sz.c          \
+       jit_x86.c               \
+       jit_x86-cpu.c           \
+       jit_x86-sse.c           \
+       jit_x86-x87.c           \
+       jit_x86-sz.c
diff --git a/deps/lightning/lib/jit_aarch64-cpu.c b/deps/lightning/lib/jit_aarch64-cpu.c
new file mode 100644 (file)
index 0000000..8e8a9a0
--- /dev/null
@@ -0,0 +1,2446 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+typedef union {
+/* aarch64-opc.c */
+#  define ui                   jit_uint32_t
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+    /* cond2: condition in truly conditional-executed inst.  */
+    struct {           ui b:  4; } cond2;
+    /* nzcv: flag bit specifier, encoded in the "nzcv" field.  */
+    struct {           ui b:  4; } nzcv;
+    /* defgh: d:e:f:g:h bits in AdvSIMD modified immediate.  */
+    struct { ui _:  5; ui b:  5; } defgh;
+    /* abc: a:b:c bits in AdvSIMD modified immediate.  */
+    struct { ui _: 16; ui b:  3; } abc;
+    /* imm19: e.g. in CBZ.  */
+    struct { ui _:  5; ui b: 19; } imm19;
+    /* immhi: e.g. in ADRP.  */
+    struct { ui _:  5; ui b: 19; } immhi;
+    /* immlo: e.g. in ADRP.  */
+    struct { ui _: 29; ui b:  2; } immlo;
+    /* size: in most AdvSIMD and floating-point instructions.  */
+    struct { ui _: 22; ui b:  2; } size;
+    /* vldst_size: size field in the AdvSIMD load/store inst.  */
+    struct { ui _: 10; ui b:  2; } vldst_size;
+    /* op: in AdvSIMD modified immediate instructions.  */
+    struct { ui _: 29; ui b:  1; } op;
+    /* Q: in most AdvSIMD instructions.  */
+    struct { ui _: 30; ui b:  1; } Q;
+    /* Rt: in load/store instructions.  */
+    struct {           ui b:  5; } Rt;
+    /* Rd: in many integer instructions.  */
+    struct {           ui b:  5; } Rd;
+    /* Rn: in many integer instructions.  */
+    struct { ui _:  5; ui b:  5; } Rn;
+    /* Rt2: in load/store pair instructions.  */
+    struct { ui _: 10; ui b:  5; } Rt2;
+    /* Ra: in fp instructions.  */
+    struct { ui _: 10; ui b:  5; } Ra;
+    /* op2: in the system instructions.  */
+    struct { ui _:  5; ui b:  3; } op2;
+    /* CRm: in the system instructions.  */
+    struct { ui _:  8; ui b:  4; } CRm;
+    /* CRn: in the system instructions.  */
+    struct { ui _: 12; ui b:  4; } CRn;
+    /* op1: in the system instructions.  */
+    struct { ui _: 16; ui b:  3; } op1;
+    /* op0: in the system instructions.  */
+    struct { ui _: 19; ui b:  2; } op0;
+    /* imm3: in add/sub extended reg instructions.  */
+    struct { ui _: 10; ui b:  3; } imm3;
+    /* cond: condition flags as a source operand.  */
+    struct { ui _: 12; ui b:  4; } cond;
+    /* opcode: in advsimd load/store instructions.  */
+    struct { ui _: 12; ui b:  4; } opcode;
+    /* cmode: in advsimd modified immediate instructions.  */
+    struct { ui _: 12; ui b:  4; } cmode;
+    /* asisdlso_opcode: opcode in advsimd ld/st single element.  */
+    struct { ui _: 13; ui b:  3; } asisdlso_opcode;
+    /* len: in advsimd tbl/tbx instructions.  */
+    struct { ui _: 13; ui b:  2; } len;
+    /* Rm: in ld/st reg offset and some integer inst.  */
+    struct { ui _: 16; ui b:  5; } Rm;
+    /* Rs: in load/store exclusive instructions.  */
+    struct { ui _: 16; ui b:  5; } Rs;
+    /* option: in ld/st reg offset + add/sub extended reg inst.  */
+    struct { ui _: 13; ui b:  3; } option;
+    /* S: in load/store reg offset instructions.  */
+    struct { ui _: 12; ui b:  1; } S;
+    /* hw: in move wide constant instructions.  */
+    struct { ui _: 21; ui b:  2; } hw;
+    /* opc: in load/store reg offset instructions.  */
+    struct { ui _: 22; ui b:  2; } opc;
+    /* opc1: in load/store reg offset instructions.  */
+    struct { ui _: 23; ui b:  1; } opc1;
+    /* shift: in add/sub reg/imm shifted instructions.  */
+    struct { ui _: 22; ui b:  2; } shift;
+    /* type: floating point type field in fp data inst.  */
+    struct { ui _: 22; ui b:  2; } type;
+    /* ldst_size: size field in ld/st reg offset inst.  */
+    struct { ui _: 30; ui b:  2; } ldst_size;
+    /* imm6: in add/sub reg shifted instructions.  */
+    struct { ui _: 10; ui b:  6; } imm6;
+    /* imm4: in advsimd ext and advsimd ins instructions.  */
+    struct { ui _: 11; ui b:  4; } imm4;
+    /* imm5: in conditional compare (immediate) instructions.  */
+    struct { ui _: 16; ui b:  5; } imm5;
+    /* imm7: in load/store pair pre/post index instructions.  */
+    struct { ui _: 15; ui b:  7; } imm7;
+    /* imm8: in floating-point scalar move immediate inst.  */
+    struct { ui _: 13; ui b:  8; } imm8;
+    /* imm9: in load/store pre/post index instructions.  */
+    struct { ui _: 12; ui b:  9; } imm9;
+    /* imm12: in ld/st unsigned imm or add/sub shifted inst.  */
+    struct { ui _: 10; ui b: 12; } imm12;
+    /* imm14: in test bit and branch instructions.  */
+    struct { ui _:  5; ui b: 14; } imm14;
+    /* imm16: in exception instructions.  */
+    struct { ui _:  5; ui b: 16; } imm16;
+    /* imm26: in unconditional branch instructions.  */
+    struct {           ui b: 26; } imm26;
+    /* imms: in bitfield and logical immediate instructions.  */
+    struct { ui _: 10; ui b:  6; } imms;
+    /* immr: in bitfield and logical immediate instructions.  */
+    struct { ui _: 16; ui b:  6; } immr;
+    /* immb: in advsimd shift by immediate instructions.  */
+    struct { ui _: 16; ui b:  3; } immb;
+    /* immh: in advsimd shift by immediate instructions.  */
+    struct { ui _: 19; ui b:  4; } immh;
+    /* N: in logical (immediate) instructions.  */
+    struct { ui _: 22; ui b:  1; } N;
+    /* index: in ld/st inst deciding the pre/post-index.  */
+    struct { ui _: 11; ui b:  1; } index;
+    /* index2: in ld/st pair inst deciding the pre/post-index.  */
+    struct { ui _: 24; ui b:  1; } index2;
+    /* sf: in integer data processing instructions.  */
+    struct { ui _: 31; ui b:  1; } sf;
+    /* H: in advsimd scalar x indexed element instructions.  */
+    struct { ui _: 11; ui b:  1; } H;
+    /* L: in advsimd scalar x indexed element instructions.  */
+    struct { ui _: 21; ui b:  1; } L;
+    /* M: in advsimd scalar x indexed element instructions.  */
+    struct { ui _: 20; ui b:  1; } M;
+    /* b5: in the test bit and branch instructions.  */
+    struct { ui _: 31; ui b:  1; } b5;
+    /* b40: in the test bit and branch instructions.  */
+    struct { ui _: 19; ui b:  5; } b40;
+    /* scale: in the fixed-point scalar to fp converting inst.  */
+    struct { ui _: 10; ui b:  6; } scale;
+#  else
+    struct { ui _: 28; ui b:  4; } cond2;
+    struct { ui _: 28; ui b:  4; } nzcv;
+    struct { ui _: 22; ui b:  5; } defgh;
+    struct { ui _: 13; ui b:  3; } abc;
+    struct { ui _:  8; ui b: 19; } imm19;
+    struct { ui _:  8; ui b: 19; } immhi;
+    struct { ui _:  1; ui b: 29; } immlo;
+    struct { ui _:  8; ui b:  2; } size;
+    struct { ui _: 20; ui b:  2; } vldst_size;
+    struct { ui _:  2; ui b:  1; } op;
+    struct { ui _:  1; ui b:  1; } Q;
+    struct { ui _: 27; ui b:  1; } Rt;
+    struct { ui _: 27; ui b:  1; } Rd;
+    struct { ui _: 22; ui b:  5; } Rn;
+    struct { ui _: 17; ui b:  5; } Rt2;
+    struct { ui _: 17; ui b:  5; } Ra;
+    struct { ui _: 24; ui b:  3; } op2;
+    struct { ui _: 20; ui b:  4; } CRm;
+    struct { ui _: 16; ui b:  4; } CRn;
+    struct { ui _: 13; ui b:  3; } op1;
+    struct { ui _: 11; ui b:  2; } op0;
+    struct { ui _: 19; ui b:  3; } imm3;
+    struct { ui _: 16; ui b:  4; } cond;
+    struct { ui _: 16; ui b:  4; } opcode;
+    struct { ui _: 16; ui b:  4; } cmode;
+    struct { ui _: 16; ui b:  3; } asisdlso_opcode;
+    struct { ui _: 17; ui b:  2; } len;
+    struct { ui _: 11; ui b:  5; } Rm;
+    struct { ui _: 11; ui b:  5; } Rs;
+    struct { ui _: 16; ui b:  3; } option;
+    struct { ui _: 19; ui b:  1; } S;
+    struct { ui _:  9; ui b:  2; } hw;
+    struct { ui _:  8; ui b:  2; } opc;
+    struct { ui _:  8; ui b:  1; } opc1;
+    struct { ui _:  8; ui b:  2; } shift;
+    struct { ui _:  8; ui b:  2; } type;
+    struct {           ui b:  2; } ldst_size;
+    struct { ui _: 16; ui b:  6; } imm6;
+    struct { ui _: 17; ui b:  4; } imm4;
+    struct { ui _: 11; ui b:  5; } imm5;
+    struct { ui _: 10; ui b:  7; } imm7;
+    struct { ui _: 11; ui b:  8; } imm8;
+    struct { ui _: 11; ui b:  9; } imm9;
+    struct { ui _: 10; ui b: 12; } imm12;
+    struct { ui _: 13; ui b: 14; } imm14;
+    struct { ui _: 11; ui b: 16; } imm16;
+    struct { ui _:  6; ui b: 26; } imm26;
+    struct { ui _: 16; ui b:  6; } imms;
+    struct { ui _: 10; ui b:  6; } immr;
+    struct { ui _: 13; ui b:  3; } immb;
+    struct { ui _:  9; ui b:  4; } immh;
+    struct { ui _:  9; ui b:  1; } N;
+    struct { ui _: 20; ui b:  1; } index;
+    struct { ui _:  7; ui b:  1; } index2;
+    struct {           ui b:  1; } sf;
+    struct { ui _: 20; ui b:  1; } H;
+    struct { ui _: 10; ui b:  1; } L;
+    struct { ui _: 11; ui b:  1; } M;
+    struct {           ui b:  1; } b5;
+    struct { ui _:  8; ui b:  5; } b40;
+    struct { ui _: 16; ui b:  6; } scale;
+#  endif
+    jit_int32_t                w;
+#  undef ui
+} instr_t;
+#  define stack_framesize              160
+#  define ii(i)                                *_jit->pc.ui++ = i
+#  define ldr(r0,r1)                   ldr_l(r0,r1)
+#  define ldxr(r0,r1,r2)               ldxr_l(r0,r1,r2)
+#  define ldxi(r0,r1,i0)               ldxi_l(r0,r1,i0)
+#  define stxi(i0,r0,r1)               stxi_l(i0,r0,r1)
+#  define FP_REGNO                     0x1d
+#  define LR_REGNO                     0x1e
+#  define SP_REGNO                     0x1f
+#  define XZR_REGNO                    0x1f
+#  define WZR_REGNO                    XZR_REGNO
+#  define LSL_12                       0x00400000
+#  define MOVI_LSL_16                  0x00200000
+#  define MOVI_LSL_32                  0x00400000
+#  define MOVI_LSL_48                  0x00600000
+#  define XS                           0x80000000      /* Wn -> Xn */
+#  define DS                           0x00400000      /* Sn -> Dn */
+#  define CC_NE                                0x0
+#  define CC_EQ                                0x1
+#  define CC_CC                                0x2
+#  define CC_LO                                CC_CC
+#  define CC_CS                                0x3
+#  define CC_HS                                CC_CS
+#  define CC_PL                                0x4
+#  define CC_MI                                0x5
+#  define CC_VC                                0x6
+#  define CC_VS                                0x7
+#  define CC_LS                                0x8
+#  define CC_HI                                0x9
+#  define CC_LT                                0xa
+#  define CC_GE                                0xb
+#  define CC_LE                                0xc
+#  define CC_GT                                0xd
+#  define CC_NV                                0xe
+#  define CC_AL                                0xf
+/* Branches need inverted condition */
+#  define BCC_EQ                       0x0
+#  define BCC_NE                       0x1
+#  define BCC_CS                       0x2
+#  define BCC_HS                       BCC_CS
+#  define BCC_CC                       0x3
+#  define BCC_LO                       BCC_CC
+#  define BCC_MI                       0x4
+#  define BCC_PL                       0x5
+#  define BCC_VS                       0x6
+#  define BCC_VC                       0x7
+#  define BCC_HI                       0x8
+#  define BCC_LS                       0x9
+#  define BCC_GE                       0xa
+#  define BCC_LT                       0xb
+#  define BCC_GT                       0xc
+#  define BCC_LE                       0xd
+#  define BCC_AL                       0xe
+#  define BCC_NV                       0xf
+/* adapted and cut down to only tested and required by lightning,
+ * from data in binutils/aarch64-tbl.h */
+#  define A64_ADCS                     0x3a000000
+#  define A64_SBCS                     0x7a000000
+#  define A64_ADDI                     0x11000000
+#  define A64_ADDSI                    0xb1000000
+#  define A64_SUBI                     0x51000000
+#  define A64_SUBSI                    0x71000000
+#  define A64_ADD                      0x0b000000
+#  define A64_ADDS                     0x2b000000
+#  define A64_SUB                      0x4b000000
+#  define A64_NEG                      0x4b0003e0
+#  define A64_SUBS                     0x6b000000
+#  define A64_CMP                      0x6b00001f
+#  define A64_SBFM                     0x93400000
+#  define A64_UBFM                     0x53400000
+#  define A64_UBFX                     0x53000000
+#  define A64_B                                0x14000000
+#  define A64_BL                       0x94000000
+#  define A64_BR                       0xd61f0000
+#  define A64_BLR                      0xd63f0000
+#  define A64_RET                      0xd65f0000
+#  define A64_CBZ                      0x34000000
+#  define A64_CBNZ                     0x35000000
+#  define A64_B_C                      0x54000000
+#  define A64_CSINC                    0x1a800400
+#  define A64_REV                      0xdac00c00
+#  define A64_UDIV                     0x1ac00800
+#  define A64_SDIV                     0x1ac00c00
+#  define A64_LSL                      0x1ac02000
+#  define A64_LSR                      0x1ac02400
+#  define A64_ASR                      0x1ac02800
+#  define A64_MUL                      0x1b007c00
+#  define A64_SMULL                    0x9b207c00
+#  define A64_SMULH                    0x9b407c00
+#  define A64_UMULL                    0x9ba07c00
+#  define A64_UMULH                    0x9bc07c00
+#  define A64_STRBI                    0x39000000
+#  define A64_LDRBI                    0x39400000
+#  define A64_LDRSBI                   0x39800000
+#  define A64_STRI                     0xf9000000
+#  define A64_LDRI                     0xf9400000
+#  define A64_STRHI                    0x79000000
+#  define A64_LDRHI                    0x79400000
+#  define A64_LDRSHI                   0x79800000
+#  define A64_STRWI                    0xb9000000
+#  define A64_LDRWI                    0xb9400000
+#  define A64_LDRSWI                   0xb9800000
+#  define A64_STRB                     0x38206800
+#  define A64_LDRB                     0x38606800
+#  define A64_LDRSB                    0x38e06800
+#  define A64_STR                      0xf8206800
+#  define A64_LDR                      0xf8606800
+#  define A64_STRH                     0x78206800
+#  define A64_LDRH                     0x78606800
+#  define A64_LDRSH                    0x78a06800
+#  define A64_STRW                     0xb8206800
+#  define A64_LDRW                     0xb8606800
+#  define A64_LDRSW                    0xb8a06800
+#  define A64_STURB                    0x38000000
+#  define A64_LDURB                    0x38400000
+#  define A64_LDURSB                   0x38800000
+#  define A64_STUR                     0xf8000000
+#  define A64_LDUR                     0xf8400000
+#  define A64_STURH                    0x78000000
+#  define A64_LDURH                    0x78400000
+#  define A64_LDURSH                   0x78800000
+#  define A64_STURW                    0xb8000000
+#  define A64_LDURW                    0xb8400000
+#  define A64_LDURSW                   0xb8800000
+#  define A64_STP                      0x29000000
+#  define A64_LDP                      0x29400000
+#  define A64_STP_POS                  0x29800000
+#  define A64_LDP_PRE                  0x28c00000
+#  define A64_ANDI                     0x12400000
+#  define A64_ORRI                     0x32400000
+#  define A64_EORI                     0x52400000
+#  define A64_ANDSI                    0x72000000
+#  define A64_AND                      0x0a000000
+#  define A64_ORR                      0x2a000000
+#  define A64_MOV                      0x2a0003e0      /* AKA orr Rd,xzr,Rm */
+#  define A64_MVN                      0x2a2003e0
+#  define A64_UXTW                     0x2a0003e0      /* AKA MOV */
+#  define A64_EOR                      0x4a000000
+#  define A64_ANDS                     0x6a000000
+#  define A64_MOVN                     0x12800000
+#  define A64_MOVZ                     0x52800000
+#  define A64_MOVK                     0x72800000
+#  define SBFM(Rd,Rn,ImmR,ImmS)                oxxrs(A64_SBFM|XS,Rd,Rn,ImmR,ImmS)
+#  define UBFM(Rd,Rn,ImmR,ImmS)                oxxrs(A64_UBFM|XS,Rd,Rn,ImmR,ImmS)
+#  define UBFX(Rd,Rn,ImmR,ImmS)                oxxrs(A64_UBFX,Rd,Rn,ImmR,ImmS)
+#  define CMP(Rn,Rm)                   oxx_(A64_CMP|XS,Rn,Rm)
+#  define CMPI(Rn,Imm12)               oxxi(A64_SUBSI|XS,XZR_REGNO,Rn,Imm12)
+#  define CMPI_12(Rn,Imm12)            oxxi(A64_SUBSI|XS|LSL_12,XZR_REGNO,Rn,Imm12)
+#  define CMNI(Rn,Imm12)               oxxi(A64_ADDSI|XS,XZR_REGNO,Rn,Imm12)
+#  define CMNI_12(Rn,Imm12)            oxxi(A64_ADDSI|XS|LSL_12,XZR_REGNO,Rn,Imm12)
+#  define CSINC(Rd,Rn,Rm,Cc)           oxxxc(A64_CSINC|XS,Rd,Rn,Rm,Cc)
+#  define TST(Rn,Rm)                   oxxx(A64_ANDS|XS,XZR_REGNO,Rn,Rm)
+/* actually should use oxxrs but logical_immediate returns proper encoding */
+#  define TSTI(Rn,Imm12)               oxxi(A64_ANDSI,XZR_REGNO,Rn,Imm12)
+#  define MOV(Rd,Rm)                   ox_x(A64_MOV|XS,Rd,Rm)
+#  define MVN(Rd,Rm)                   ox_x(A64_MVN|XS,Rd,Rm)
+#  define NEG(Rd,Rm)                   ox_x(A64_NEG|XS,Rd,Rm)
+#  define MOVN(Rd,Imm16)               ox_h(A64_MOVN|XS,Rd,Imm16)
+#  define MOVN_16(Rd,Imm16)            ox_h(A64_MOVN|XS|MOVI_LSL_16,Rd,Imm16)
+#  define MOVN_32(Rd,Imm16)            ox_h(A64_MOVN|XS|MOVI_LSL_32,Rd,Imm16)
+#  define MOVN_48(Rd,Imm16)            ox_h(A64_MOVN|XS|MOVI_LSL_48,Rd,Imm16)
+#  define MOVZ(Rd,Imm16)               ox_h(A64_MOVZ|XS,Rd,Imm16)
+#  define MOVZ_16(Rd,Imm16)            ox_h(A64_MOVZ|XS|MOVI_LSL_16,Rd,Imm16)
+#  define MOVZ_32(Rd,Imm16)            ox_h(A64_MOVZ|XS|MOVI_LSL_32,Rd,Imm16)
+#  define MOVZ_48(Rd,Imm16)            ox_h(A64_MOVZ|XS|MOVI_LSL_48,Rd,Imm16)
+#  define MOVK(Rd,Imm16)               ox_h(A64_MOVK|XS,Rd,Imm16)
+#  define MOVK_16(Rd,Imm16)            ox_h(A64_MOVK|XS|MOVI_LSL_16,Rd,Imm16)
+#  define MOVK_32(Rd,Imm16)            ox_h(A64_MOVK|XS|MOVI_LSL_32,Rd,Imm16)
+#  define MOVK_48(Rd,Imm16)            ox_h(A64_MOVK|XS|MOVI_LSL_48,Rd,Imm16)
+#  define ADD(Rd,Rn,Rm)                        oxxx(A64_ADD|XS,Rd,Rn,Rm)
+#  define ADDI(Rd,Rn,Imm12)            oxxi(A64_ADDI|XS,Rd,Rn,Imm12)
+#  define ADDI_12(Rd,Rn,Imm12)         oxxi(A64_ADDI|XS|LSL_12,Rd,Rn,Imm12)
+#  define MOV_XSP(Rd,Rn)               ADDI(Rd,Rn,0)
+#  define ADDS(Rd,Rn,Rm)               oxxx(A64_ADDS|XS,Rd,Rn,Rm)
+#  define ADDSI(Rd,Rn,Imm12)           oxxi(A64_ADDSI|XS,Rd,Rn,Imm12)
+#  define ADDSI_12(Rd,Rn,Imm12)                oxxi(A64_ADDSI|XS|LSL_12,Rd,Rn,Imm12)
+#  define ADCS(Rd,Rn,Rm)               oxxx(A64_ADCS|XS,Rd,Rn,Rm)
+#  define SUB(Rd,Rn,Rm)                        oxxx(A64_SUB|XS,Rd,Rn,Rm)
+#  define SUBI(Rd,Rn,Imm12)            oxxi(A64_SUBI|XS,Rd,Rn,Imm12)
+#  define SUBI_12(Rd,Rn,Imm12)         oxxi(A64_SUBI|XS|LSL_12,Rd,Rn,Imm12)
+#  define SUBS(Rd,Rn,Rm)               oxxx(A64_SUBS|XS,Rd,Rn,Rm)
+#  define SUBSI(Rd,Rn,Imm12)           oxxi(A64_SUBSI|XS,Rd,Rn,Imm12)
+#  define SUBSI_12(Rd,Rn,Imm12)                oxxi(A64_SUBSI|XS|LSL_12,Rd,Rn,Imm12)
+#  define SBCS(Rd,Rn,Rm)               oxxx(A64_SBCS|XS,Rd,Rn,Rm)
+#  define MUL(Rd,Rn,Rm)                        oxxx(A64_MUL|XS,Rd,Rn,Rm)
+#  define SMULL(Rd,Rn,Rm)              oxxx(A64_SMULL,Rd,Rn,Rm)
+#  define SMULH(Rd,Rn,Rm)              oxxx(A64_SMULH,Rd,Rn,Rm)
+#  define UMULL(Rd,Rn,Rm)              oxxx(A64_UMULL,Rd,Rn,Rm)
+#  define UMULH(Rd,Rn,Rm)              oxxx(A64_UMULH,Rd,Rn,Rm)
+#  define SDIV(Rd,Rn,Rm)               oxxx(A64_SDIV|XS,Rd,Rn,Rm)
+#  define UDIV(Rd,Rn,Rm)               oxxx(A64_UDIV|XS,Rd,Rn,Rm)
+#  define LSL(Rd,Rn,Rm)                        oxxx(A64_LSL|XS,Rd,Rn,Rm)
+#  define LSLI(r0,r1,i0)               UBFM(r0,r1,(64-i0)&63,63-i0)
+#  define ASR(Rd,Rn,Rm)                        oxxx(A64_ASR|XS,Rd,Rn,Rm)
+#  define ASRI(r0,r1,i0)               SBFM(r0,r1,i0,63)
+#  define LSR(Rd,Rn,Rm)                        oxxx(A64_LSR|XS,Rd,Rn,Rm)
+#  define LSRI(r0,r1,i0)               UBFM(r0,r1,i0,63)
+#  define AND(Rd,Rn,Rm)                        oxxx(A64_AND|XS,Rd,Rn,Rm)
+/* actually should use oxxrs but logical_immediate returns proper encoding */
+#  define ANDI(Rd,Rn,Imm12)            oxxi(A64_ANDI|XS,Rd,Rn,Imm12)
+#  define ORR(Rd,Rn,Rm)                        oxxx(A64_ORR|XS,Rd,Rn,Rm)
+/* actually should use oxxrs but logical_immediate returns proper encoding */
+#  define ORRI(Rd,Rn,Imm12)            oxxi(A64_ORRI|XS,Rd,Rn,Imm12)
+#  define EOR(Rd,Rn,Rm)                        oxxx(A64_EOR|XS,Rd,Rn,Rm)
+/* actually should use oxxrs but logical_immediate returns proper encoding */
+#  define EORI(Rd,Rn,Imm12)            oxxi(A64_EORI|XS,Rd,Rn,Imm12)
+#  define SXTB(Rd,Rn)                  SBFM(Rd,Rn,0,7)
+#  define SXTH(Rd,Rn)                  SBFM(Rd,Rn,0,15)
+#  define SXTW(Rd,Rn)                  SBFM(Rd,Rn,0,31)
+#  define UXTB(Rd,Rn)                  UBFX(Rd,Rn,0,7)
+#  define UXTH(Rd,Rn)                  UBFX(Rd,Rn,0,15)
+#  define UXTW(Rd,Rm)                  ox_x(A64_UXTW,Rd,Rm)
+#  define REV(Rd,Rn)                   o_xx(A64_REV,Rd,Rn)
+#  define LDRSB(Rt,Rn,Rm)              oxxx(A64_LDRSB,Rt,Rn,Rm)
+#  define LDRSBI(Rt,Rn,Imm12)          oxxi(A64_LDRSBI,Rt,Rn,Imm12)
+#  define LDURSB(Rt,Rn,Imm9)           oxx9(A64_LDURSB,Rt,Rn,Imm9)
+#  define LDRB(Rt,Rn,Rm)               oxxx(A64_LDRB,Rt,Rn,Rm)
+#  define LDRBI(Rt,Rn,Imm12)           oxxi(A64_LDRBI,Rt,Rn,Imm12)
+#  define LDURB(Rt,Rn,Imm9)            oxx9(A64_LDURB,Rt,Rn,Imm9)
+#  define LDRSH(Rt,Rn,Rm)              oxxx(A64_LDRSH,Rt,Rn,Rm)
+#  define LDRSHI(Rt,Rn,Imm12)          oxxi(A64_LDRSHI,Rt,Rn,Imm12)
+#  define LDURSH(Rt,Rn,Imm9)           oxx9(A64_LDURSH,Rt,Rn,Imm9)
+#  define LDRH(Rt,Rn,Rm)               oxxx(A64_LDRH,Rt,Rn,Rm)
+#  define LDRHI(Rt,Rn,Imm12)           oxxi(A64_LDRHI,Rt,Rn,Imm12)
+#  define LDURH(Rt,Rn,Imm9)            oxx9(A64_LDURH,Rt,Rn,Imm9)
+#  define LDRSW(Rt,Rn,Rm)              oxxx(A64_LDRSW,Rt,Rn,Rm)
+#  define LDRSWI(Rt,Rn,Imm12)          oxxi(A64_LDRSWI,Rt,Rn,Imm12)
+#  define LDURSW(Rt,Rn,Imm9)           oxx9(A64_LDURSW,Rt,Rn,Imm9)
+#  define LDRW(Rt,Rn,Rm)               oxxx(A64_LDRW,Rt,Rn,Rm)
+#  define LDRWI(Rt,Rn,Imm12)           oxxi(A64_LDRWI,Rt,Rn,Imm12)
+#  define LDURW(Rt,Rn,Imm9)            oxx9(A64_LDURW,Rt,Rn,Imm9)
+#  define LDR(Rt,Rn,Rm)                        oxxx(A64_LDR,Rt,Rn,Rm)
+#  define LDRI(Rt,Rn,Imm12)            oxxi(A64_LDRI,Rt,Rn,Imm12)
+#  define LDUR(Rt,Rn,Imm9)             oxx9(A64_LDUR,Rt,Rn,Imm9)
+#  define STRB(Rt,Rn,Rm)               oxxx(A64_STRB,Rt,Rn,Rm)
+#  define STRBI(Rt,Rn,Imm12)           oxxi(A64_STRBI,Rt,Rn,Imm12)
+#  define STURB(Rt,Rn,Imm9)            oxx9(A64_STURB,Rt,Rn,Imm9)
+#  define STRH(Rt,Rn,Rm)               oxxx(A64_STRH,Rt,Rn,Rm)
+#  define STRHI(Rt,Rn,Imm12)           oxxi(A64_STRHI,Rt,Rn,Imm12)
+#  define STURH(Rt,Rn,Imm9)            oxx9(A64_STURH,Rt,Rn,Imm9)
+#  define STRW(Rt,Rn,Rm)               oxxx(A64_STRW,Rt,Rn,Rm)
+#  define STRWI(Rt,Rn,Imm12)           oxxi(A64_STRWI,Rt,Rn,Imm12)
+#  define STURW(Rt,Rn,Imm9)            oxx9(A64_STURW,Rt,Rn,Imm9)
+#  define STR(Rt,Rn,Rm)                        oxxx(A64_STR,Rt,Rn,Rm)
+#  define STRI(Rt,Rn,Imm12)            oxxi(A64_STRI,Rt,Rn,Imm12)
+#  define STUR(Rt,Rn,Imm9)             oxx9(A64_STUR,Rt,Rn,Imm9)
+#  define LDPI(Rt,Rt2,Rn,Simm7)                oxxx7(A64_LDP|XS,Rt,Rt2,Rn,Simm7)
+#  define STPI(Rt,Rt2,Rn,Simm7)                oxxx7(A64_STP|XS,Rt,Rt2,Rn,Simm7)
+#  define LDPI_PRE(Rt,Rt2,Rn,Simm7)    oxxx7(A64_LDP_PRE|XS,Rt,Rt2,Rn,Simm7)
+#  define STPI_POS(Rt,Rt2,Rn,Simm7)    oxxx7(A64_STP_POS|XS,Rt,Rt2,Rn,Simm7)
+#  define CSET(Rd,Cc)                  CSINC(Rd,XZR_REGNO,XZR_REGNO,Cc)
+#  define B(Simm26)                    o26(A64_B,Simm26)
+#  define BL(Simm26)                   o26(A64_BL,Simm26)
+#  define BR(Rn)                       o_x_(A64_BR,Rn)
+#  define BLR(Rn)                      o_x_(A64_BLR,Rn)
+#  define RET()                                o_x_(A64_RET,LR_REGNO)
+#  define B_C(Cc,Simm19)               oc19(A64_B_C,Cc,Simm19)
+#  define CBZ(Rd,Simm19)               ox19(A64_CBZ|XS,Rd,Simm19)
+#  define CBNZ(Rd,Simm19)              ox19(A64_CBNZ|XS,Rd,Simm19)
+#  define NOP()                                ii(0xd503201f)
+static jit_int32_t logical_immediate(jit_word_t);
+#  define oxxx(Op,Rd,Rn,Rm)            _oxxx(_jit,Op,Rd,Rn,Rm)
+static void _oxxx(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define oxxi(Op,Rd,Rn,Imm12)         _oxxi(_jit,Op,Rd,Rn,Imm12)
+static void _oxxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define oxx9(Op,Rd,Rn,Imm9)          _oxx9(_jit,Op,Rd,Rn,Imm9)
+static void _oxx9(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ox19(Op,Rd,Simm19)           _ox19(_jit,Op,Rd,Simm19)
+static void _ox19(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define oc19(Op,Cc,Simm19)           _oc19(_jit,Op,Cc,Simm19)
+static void _oc19(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define o26(Op,Simm26)               _o26(_jit,Op,Simm26)
+static void _oc26(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ox_x(Op,Rd,Rn)               _ox_x(_jit,Op,Rd,Rn)
+static void _ox_x(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define o_xx(Op,Rd,Rn)               _o_xx(_jit,Op,Rd,Rn)
+static void _o_xx(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define oxx_(Op,Rn,Rm)               _oxx_(_jit,Op,Rn,Rm)
+static void _oxx_(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define o_x_(Op,Rn)                  _o_x_(_jit,Op,Rn)
+static void _o_x_(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ox_h(Op,Rd,Imm16)            _ox_h(_jit,Op,Rd,Imm16)
+static void _ox_h(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define oxxrs(Op,Rd,Rn,R,S)          _oxxrs(_jit,Op,Rd,Rn,R,S)
+static void _oxxrs(jit_state_t*,jit_int32_t,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t);
+#  define oxxxc(Op,Rd,Rn,Rm,Cc)                _oxxxc(_jit,Op,Rd,Rn,Rm,Cc)
+static void _oxxxc(jit_state_t*,jit_int32_t,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t);
+#  define oxxx7(Op,Rt,Rt2,Rn,Simm7)    _oxxx7(_jit,Op,Rt,Rt2,Rn,Simm7)
+static void _oxxx7(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nop(i0)                      _nop(_jit,i0)
+static void _nop(jit_state_t*,jit_int32_t);
+#  define addr(r0,r1,r2)               ADD(r0,r1,r2)
+#  define addi(r0,r1,i0)               _addi(_jit,r0,r1,i0)
+static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addcr(r0,r1,r2)              ADDS(r0,r1,r2)
+#  define addci(r0,r1,i0)              _addci(_jit,r0,r1,i0)
+static void _addci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addxr(r0,r1,r2)              ADCS(r0,r1,r2)
+#  define addxi(r0,r1,i0)              _addxi(_jit,r0,r1,i0)
+static void _addxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subr(r0,r1,r2)               SUB(r0,r1,r2)
+#  define subi(r0,r1,i0)               _subi(_jit,r0,r1,i0)
+static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subcr(r0,r1,r2)              SUBS(r0,r1,r2)
+#  define subci(r0,r1,i0)              _subci(_jit,r0,r1,i0)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subxr(r0,r1,r2)              SBCS(r0,r1,r2)
+#  define subxi(r0,r1,i0)              _subxi(_jit,r0,r1,i0)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rsbi(r0, r1, i0)             _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define mulr(r0,r1,r2)               MUL(r0,r1,r2)
+#  define muli(r0,r1,i0)               _muli(_jit,r0,r1,i0)
+static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr(r0,r1,r2,r3)           _qmulr(_jit,r0,r1,r2,r3)
+static void _qmulr(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qmuli(r0,r1,r2,i0)           _qmuli(_jit,r0,r1,r2,i0)
+static void _qmuli(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr_u(r0,r1,r2,r3)         _qmulr_u(_jit,r0,r1,r2,r3)
+static void _qmulr_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qmuli_u(r0,r1,r2,i0)         _qmuli_u(_jit,r0,r1,r2,i0)
+static void _qmuli_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_word_t);
+#  define divr(r0,r1,r2)               SDIV(r0,r1,r2)
+#  define divi(r0,r1,i0)               _divi(_jit,r0,r1,i0)
+static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define divr_u(r0,r1,r2)             UDIV(r0,r1,r2)
+#  define divi_u(r0,r1,i0)             _divi_u(_jit,r0,r1,i0)
+static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qdivr(r0,r1,r2,r3)           _iqdivr(_jit,1,r0,r1,r2,r3)
+#  define qdivr_u(r0,r1,r2,r3)         _iqdivr(_jit,0,r0,r1,r2,r3)
+static void _iqdivr(jit_state_t*,jit_bool_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qdivi(r0,r1,r2,i0)           _qdivi(_jit,r0,r1,r2,i0)
+static void _qdivi(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_word_t);
+#  define qdivi_u(r0,r1,r2,i0)         _qdivi_u(_jit,r0,r1,r2,i0)
+static void _qdivi_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_word_t);
+#  define remr(r0,r1,r2)               _remr(_jit,r0,r1,r2)
+static void _remr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi(r0,r1,i0)               _remi(_jit,r0,r1,i0)
+static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define remr_u(r0,r1,r2)             _remr_u(_jit,r0,r1,r2)
+static void _remr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi_u(r0,r1,i0)             _remi_u(_jit,r0,r1,i0)
+static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define lshr(r0,r1,r2)               LSL(r0,r1,r2)
+#  define lshi(r0,r1,i0)               _lshi(_jit,r0,r1,i0)
+static void _lshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rshr(r0,r1,r2)               ASR(r0,r1,r2)
+#  define rshi(r0,r1,i0)               _rshi(_jit,r0,r1,i0)
+static void _rshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rshr_u(r0,r1,r2)             LSR(r0,r1,r2)
+#  define rshi_u(r0,r1,i0)             _rshi_u(_jit,r0,r1,i0)
+static void _rshi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define negr(r0,r1)                  NEG(r0,r1)
+#  define comr(r0,r1)                  MVN(r0,r1)
+#  define andr(r0,r1,r2)               AND(r0,r1,r2)
+#  define andi(r0,r1,i0)               _andi(_jit,r0,r1,i0)
+static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define orr(r0,r1,r2)                        ORR(r0,r1,r2)
+#  define ori(r0,r1,i0)                        _ori(_jit,r0,r1,i0)
+static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define xorr(r0,r1,r2)               EOR(r0,r1,r2)
+#  define xori(r0,r1,i0)               _xori(_jit,r0,r1,i0)
+static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_c(r0,r1)                 LDRSBI(r0,r1,0)
+#  define ldi_c(r0,i0)                 _ldi_c(_jit,r0,i0)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_uc(r0,r1)                        _ldr_uc(_jit,r0,r1)
+static void _ldr_uc(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_uc(r0,i0)                        _ldi_uc(_jit,r0,i0)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_s(r0,r1)                 LDRSHI(r0,r1,0)
+#  define ldi_s(r0,i0)                 _ldi_s(_jit,r0,i0)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_us(r0,r1)                        _ldr_us(_jit,r0,r1)
+static void _ldr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_us(r0,i0)                        _ldi_us(_jit,r0,i0)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_i(r0,r1)                 LDRSWI(r0,r1,0)
+#  define ldi_i(r0,i0)                 _ldi_i(_jit,r0,i0)
+static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_ui(r0,r1)                        _ldr_ui(_jit,r0,r1)
+static void _ldr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_ui(r0,i0)                        _ldi_ui(_jit,r0,i0)
+static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_l(r0,r1)                 LDRI(r0,r1,0)
+static void _ldr_l(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_l(r0,i0)                 _ldi_l(_jit,r0,i0)
+static void _ldi_l(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_c(r0,r1,r2)             _ldxr_c(_jit,r0,r1,r2)
+static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_c(r0,r1,i0)             _ldxi_c(_jit,r0,r1,i0)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_uc(r0,r1,r2)            _ldxr_uc(_jit,r0,r1,r2)
+static void _ldxr_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_uc(r0,r1,i0)            _ldxi_uc(_jit,r0,r1,i0)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_s(r0,r1,r2)             LDRSH(r0,r1,r2)
+#  define ldxi_s(r0,r1,i0)             _ldxi_s(_jit,r0,r1,i0)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_us(r0,r1,r2)            _ldxr_us(_jit,r0,r1,r2)
+static void _ldxr_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_us(r0,r1,i0)            _ldxi_us(_jit,r0,r1,i0)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_i(r0,r1,r2)             LDRSW(r0,r1,r2)
+#  define ldxi_i(r0,r1,i0)             _ldxi_i(_jit,r0,r1,i0)
+static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_ui(r0,r1,r2)            _ldxr_ui(_jit,r0,r1,r2)
+static void _ldxr_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_ui(r0,r1,i0)            _ldxi_ui(_jit,r0,r1,i0)
+static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_l(r0,r1,r2)             LDR(r0,r1,r2)
+#  define ldxi_l(r0,r1,i0)             _ldxi_l(_jit,r0,r1,i0)
+static void _ldxi_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_c(r0,r1)                 STRBI(r1,r0,0)
+#  define sti_c(i0,r0)                 _sti_c(_jit,i0,r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_s(r0,r1)                 STRHI(r1,r0,0)
+#  define sti_s(i0,r0)                 _sti_s(_jit,i0,r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_i(r0,r1)                 STRWI(r1,r0,0)
+#  define sti_i(i0,r0)                 _sti_i(_jit,i0,r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_l(r0,r1)                 STRI(r1,r0,0)
+#  define sti_l(i0,r0)                 _sti_l(_jit,i0,r0)
+static void _sti_l(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_c(r0,r1,r2)             STRB(r2,r1,r0)
+#  define stxi_c(i0,r0,r1)             _stxi_c(_jit,i0,r0,r1)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_s(r0,r1,r2)             STRH(r2,r1,r0)
+#  define stxi_s(i0,r0,r1)             _stxi_s(_jit,i0,r0,r1)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_i(r0,r1,r2)             STRW(r2,r1,r0)
+#  define stxi_i(i0,r0,r1)             _stxi_i(_jit,i0,r0,r1)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_l(r0,r1,r2)             STR(r2,r1,r0)
+#  define stxi_l(i0,r0,r1)             _stxi_l(_jit,i0,r0,r1)
+static void _stxi_l(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define htonr_us(r0,r1)              _htonr_us(_jit,r0,r1)
+static void _htonr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define htonr_ui(r0,r1)              _htonr_ui(_jit,r0,r1)
+static void _htonr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#    define htonr_ul(r0,r1)            REV(r0,r1)
+#  else
+#    define htonr_us(r0,r1)            extr_us(r0,r1)
+#    define htonr_ui(r0,r1)            extr_ui(r0,r1)
+#    define htonr_ul(r0,r1)            movr(r0,r1)
+#  endif
+#  define extr_c(r0,r1)                        SXTB(r0,r1)
+#  define extr_uc(r0,r1)               UXTB(r0,r1)
+#  define extr_s(r0,r1)                        SXTH(r0,r1)
+#  define extr_us(r0,r1)               UXTH(r0,r1)
+#  define extr_i(r0,r1)                        SXTW(r0,r1)
+#  define extr_ui(r0,r1)               UXTW(r0,r1)
+#  define movr(r0,r1)                  _movr(_jit,r0,r1)
+static void _movr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi(r0,i0)                  _movi(_jit,r0,i0)
+static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
+#  define movi_p(r0,i0)                        _movi_p(_jit,r0,i0)
+static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ccr(cc,r0,r1,r2)             _ccr(_jit,cc,r0,r1,r2)
+static void _ccr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define cci(cc,r0,r1,i0)             _cci(_jit,cc,r0,r1,i0)
+static void _cci(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ltr(r0,r1,r2)                        ccr(CC_LT,r0,r1,r2)
+#  define lti(r0,r1,i0)                        cci(CC_LT,r0,r1,i0)
+#  define ltr_u(r0,r1,r2)              ccr(CC_CC,r0,r1,r2)
+#  define lti_u(r0,r1,i0)              cci(CC_CC,r0,r1,i0)
+#  define ler(r0,r1,r2)                        ccr(CC_LE,r0,r1,r2)
+#  define lei(r0,r1,i0)                        cci(CC_LE,r0,r1,i0)
+#  define ler_u(r0,r1,r2)              ccr(CC_LS,r0,r1,r2)
+#  define lei_u(r0,r1,i0)              cci(CC_LS,r0,r1,i0)
+#  define eqr(r0,r1,r2)                        ccr(CC_EQ,r0,r1,r2)
+#  define eqi(r0,r1,i0)                        cci(CC_EQ,r0,r1,i0)
+#  define ger(r0,r1,r2)                        ccr(CC_GE,r0,r1,r2)
+#  define gei(r0,r1,i0)                        cci(CC_GE,r0,r1,i0)
+#  define ger_u(r0,r1,r2)              ccr(CC_CS,r0,r1,r2)
+#  define gei_u(r0,r1,i0)              cci(CC_CS,r0,r1,i0)
+#  define gtr(r0,r1,r2)                        ccr(CC_GT,r0,r1,r2)
+#  define gti(r0,r1,i0)                        cci(CC_GT,r0,r1,i0)
+#  define gtr_u(r0,r1,r2)              ccr(CC_HI,r0,r1,r2)
+#  define gti_u(r0,r1,i0)              cci(CC_HI,r0,r1,i0)
+#  define ner(r0,r1,r2)                        ccr(CC_NE,r0,r1,r2)
+#  define nei(r0,r1,i0)                        cci(CC_NE,r0,r1,i0)
+#  define bccr(cc,i0,r0,r1)            _bccr(_jit,cc,i0,r0,r1)
+static jit_word_t
+_bccr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bcci(cc,i0,r0,i1)            _bcci(_jit,cc,i0,r0,i1)
+static jit_word_t
+_bcci(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
+#  define bltr(i0,r0,r1)               bccr(BCC_LT,i0,r0,r1)
+#  define blti(i0,r0,i1)               bcci(BCC_LT,i0,r0,i1)
+#  define bltr_u(i0,r0,r1)             bccr(BCC_CC,i0,r0,r1)
+#  define blti_u(i0,r0,i1)             bcci(BCC_CC,i0,r0,i1)
+#  define bler(i0,r0,r1)               bccr(BCC_LE,i0,r0,r1)
+#  define blei(i0,r0,i1)               bcci(BCC_LE,i0,r0,i1)
+#  define bler_u(i0,r0,r1)             bccr(BCC_LS,i0,r0,r1)
+#  define blei_u(i0,r0,i1)             bcci(BCC_LS,i0,r0,i1)
+#  define beqr(i0,r0,r1)               bccr(BCC_EQ,i0,r0,r1)
+#  define beqi(i0,r0,i1)               _beqi(_jit,i0,r0,i1)
+static jit_word_t _beqi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bger(i0,r0,r1)               bccr(BCC_GE,i0,r0,r1)
+#  define bgei(i0,r0,i1)               bcci(BCC_GE,i0,r0,i1)
+#  define bger_u(i0,r0,r1)             bccr(BCC_CS,i0,r0,r1)
+#  define bgei_u(i0,r0,i1)             bcci(BCC_CS,i0,r0,i1)
+#  define bgtr(i0,r0,r1)               bccr(BCC_GT,i0,r0,r1)
+#  define bgti(i0,r0,i1)               bcci(BCC_GT,i0,r0,i1)
+#  define bgtr_u(i0,r0,r1)             bccr(BCC_HI,i0,r0,r1)
+#  define bgti_u(i0,r0,i1)             bcci(BCC_HI,i0,r0,i1)
+#  define bner(i0,r0,r1)               bccr(BCC_NE,i0,r0,r1)
+#  define bnei(i0,r0,i1)               _bnei(_jit,i0,r0,i1)
+static jit_word_t _bnei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define baddr(cc,i0,r0,r1)           _baddr(_jit,cc,i0,r0,r1)
+static jit_word_t
+_baddr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#  define baddi(cc,i0,r0,i1)           _baddi(_jit,cc,i0,r0,i1)
+static jit_word_t
+_baddi(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
+#  define boaddr(i0,r0,r1)             baddr(BCC_VS,i0,r0,r1)
+#  define boaddi(i0,r0,i1)             baddi(BCC_VS,i0,r0,i1)
+#  define boaddr_u(i0,r0,r1)           baddr(BCC_HS,i0,r0,r1)
+#  define boaddi_u(i0,r0,i1)           baddi(BCC_HS,i0,r0,i1)
+#  define bxaddr(i0,r0,r1)             baddr(BCC_VC,i0,r0,r1)
+#  define bxaddi(i0,r0,i1)             baddi(BCC_VC,i0,r0,i1)
+#  define bxaddr_u(i0,r0,r1)           baddr(BCC_LO,i0,r0,r1)
+#  define bxaddi_u(i0,r0,i1)           baddi(BCC_LO,i0,r0,i1)
+#  define bsubr(cc,i0,r0,r1)           _bsubr(_jit,cc,i0,r0,r1)
+static jit_word_t
+_bsubr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bsubi(cc,i0,r0,i1)           _bsubi(_jit,cc,i0,r0,i1)
+static jit_word_t
+_bsubi(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
+#  define bosubr(i0,r0,r1)             bsubr(BCC_VS,i0,r0,r1)
+#  define bosubi(i0,r0,i1)             bsubi(BCC_VS,i0,r0,i1)
+#  define bosubr_u(i0,r0,r1)           bsubr(BCC_LO,i0,r0,r1)
+#  define bosubi_u(i0,r0,i1)           bsubi(BCC_LO,i0,r0,i1)
+#  define bxsubr(i0,r0,r1)             bsubr(BCC_VC,i0,r0,r1)
+#  define bxsubi(i0,r0,i1)             bsubi(BCC_VC,i0,r0,i1)
+#  define bxsubr_u(i0,r0,r1)           bsubr(BCC_HS,i0,r0,r1)
+#  define bxsubi_u(i0,r0,i1)           bsubi(BCC_HS,i0,r0,i1)
+#  define bmxr(cc,i0,r0,r1)            _bmxr(_jit,cc,i0,r0,r1)
+static jit_word_t
+_bmxr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bmxi(cc,i0,r0,r1)            _bmxi(_jit,cc,i0,r0,r1)
+static jit_word_t
+_bmxi(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
+#  define bmsr(i0,r0,r1)               bmxr(BCC_NE,i0,r0,r1)
+#  define bmsi(i0,r0,i1)               bmxi(BCC_NE,i0,r0,i1)
+#  define bmcr(i0,r0,r1)               bmxr(BCC_EQ,i0,r0,r1)
+#  define bmci(i0,r0,i1)               bmxi(BCC_EQ,i0,r0,i1)
+#  define jmpr(r0)                     BR(r0)
+#  define jmpi(i0)                     _jmpi(_jit,i0)
+static void _jmpi(jit_state_t*,jit_word_t);
+#  define jmpi_p(i0)                   _jmpi_p(_jit,i0)
+static jit_word_t _jmpi_p(jit_state_t*,jit_word_t);
+#  define callr(r0)                    BLR(r0)
+#  define calli(i0)                    _calli(_jit,i0)
+static void _calli(jit_state_t*,jit_word_t);
+#  define calli_p(i0)                  _calli_p(_jit,i0)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t);
+#  define prolog(i0)                   _prolog(_jit,i0)
+static void _prolog(jit_state_t*,jit_node_t*);
+#  define epilog(i0)                   _epilog(_jit,i0)
+static void _epilog(jit_state_t*,jit_node_t*);
+#  define vastart(r0)                  _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#  define vaarg(r0, r1)                        _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define patch_at(jump,label)         _patch_at(_jit,jump,label)
+static void _patch_at(jit_state_t*,jit_word_t,jit_word_t);
+#endif
+
+#if CODE
+static jit_int32_t
+logical_immediate(jit_word_t imm)
+{
+    /* There are 5334 possible immediate values, but to avoid the
+     * need of either too complex code or large lookup tables,
+     * only check for (simply) encodable common/small values */
+    switch (imm) {
+       case -16:       return (0xf3b);
+       case -15:       return (0xf3c);
+       case -13:       return (0xf3d);
+       case -9:        return (0xf3e);
+       case -8:        return (0xf7c);
+       case -7:        return (0xf7d);
+       case -5:        return (0xf7e);
+       case -4:        return (0xfbd);
+       case -3:        return (0xfbe);
+       case -2:        return (0xffe);
+       case 1:         return (0x000);
+       case 2:         return (0xfc0);
+       case 3:         return (0x001);
+       case 4:         return (0xf80);
+       case 6:         return (0xfc1);
+       case 7:         return (0x002);
+       case 8:         return (0xf40);
+       case 12:        return (0xf81);
+       case 14:        return (0xfc2);
+       case 15:        return (0x003);
+       case 16:        return (0xf00);
+       default:        return (-1);
+    }
+}
+
+static void
+_oxxx(jit_state_t *_jit, jit_int32_t Op,
+      jit_int32_t Rd, jit_int32_t Rn, jit_int32_t Rm)
+{
+    instr_t    i;
+    assert(!(Rd &       ~0x1f));
+    assert(!(Rn &       ~0x1f));
+    assert(!(Rm &       ~0x1f));
+    assert(!(Op & ~0xffe0fc00));
+    i.w = Op;
+    i.Rd.b = Rd;
+    i.Rn.b = Rn;
+    i.Rm.b = Rm;
+    ii(i.w);
+}
+
+static void
+_oxxi(jit_state_t *_jit, jit_int32_t Op,
+      jit_int32_t Rd, jit_int32_t Rn, jit_int32_t Imm12)
+{
+    instr_t    i;
+    assert(!(Rd    &       ~0x1f));
+    assert(!(Rn    &       ~0x1f));
+    assert(!(Imm12 &      ~0xfff));
+    assert(!(Op    & ~0xffe00000));
+    i.w = Op;
+    i.Rd.b = Rd;
+    i.Rn.b = Rn;
+    i.imm12.b = Imm12;
+    ii(i.w);
+}
+
+static void
+_oxx9(jit_state_t *_jit, jit_int32_t Op,
+      jit_int32_t Rd, jit_int32_t Rn, jit_int32_t Imm9)
+{
+    instr_t    i;
+    assert(!(Rd   &       ~0x1f));
+    assert(!(Rn   &       ~0x1f));
+    assert(!(Imm9 &      ~0x1ff));
+    assert(!(Op   & ~0xffe00000));
+    i.w = Op;
+    i.Rd.b = Rd;
+    i.Rn.b = Rn;
+    i.imm9.b = Imm9;
+    ii(i.w);
+}
+
+static void
+_ox19(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rd, jit_int32_t Simm19)
+{
+    instr_t    i;
+    assert(!(Rd &         ~0x1f));
+    assert(Simm19 >= -262148 && Simm19 <= 262143);
+    assert(!(Op   & ~0xff000000));
+    i.w = Op;
+    i.Rd.b = Rd;
+    i.imm19.b = Simm19;
+    ii(i.w);
+}
+
+static void
+_oc19(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Cc, jit_int32_t Simm19)
+{
+    instr_t    i;
+    assert(!(Cc &          ~0xf));
+    assert(Simm19 >= -262148 && Simm19 <= 262143);
+    assert(!(Op   & ~0xff000000));
+    i.w = Op;
+    i.cond2.b = Cc;
+    i.imm19.b = Simm19;
+    ii(i.w);
+}
+
+static void
+_o26(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Simm26)
+{
+    instr_t    i;
+    assert(Simm26 >= -33554432 && Simm26 <= 33554431);
+    assert(!(Op   & ~0xfc000000));
+    i.w = Op;
+    i.imm26.b = Simm26;
+    ii(i.w);
+}
+
+static void
+_ox_x(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rd, jit_int32_t Rm)
+{
+    instr_t    i;
+    assert(!(Rd &       ~0x1f));
+    assert(!(Rm &       ~0x1f));
+    assert(!(Op & ~0xffe0ffe0));
+    i.w = Op;
+    i.Rd.b = Rd;
+    i.Rm.b = Rm;
+    ii(i.w);
+}
+
+static void
+_o_xx(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rd, jit_int32_t Rn)
+{
+    instr_t    i;
+    assert(!(Rd &       ~0x1f));
+    assert(!(Rn &       ~0x1f));
+    assert(!(Op & ~0xfffffc00));
+    i.w = Op;
+    i.Rd.b = Rd;
+    i.Rn.b = Rn;
+    ii(i.w);
+}
+
+static void
+_oxx_(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rn, jit_int32_t Rm)
+{
+    instr_t    i;
+    assert(!(Rn &       ~0x1f));
+    assert(!(Rm &       ~0x1f));
+    assert(!(Op & ~0xffc0fc1f));
+    i.w = Op;
+    i.Rn.b = Rn;
+    i.Rm.b = Rm;
+    ii(i.w);
+}
+
+static void
+_o_x_(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rn)
+{
+    instr_t    i;
+    assert(!(Rn & ~0x1f));
+    assert(!(Op & 0x3e0));
+    i.w = Op;
+    i.Rn.b = Rn;
+    ii(i.w);
+}
+
+static void
+_ox_h(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Rd, jit_int32_t Imm16)
+{
+    instr_t    i;
+    assert(!(Rd    &       ~0x1f));
+    assert(!(Imm16 &     ~0xffff));
+    assert(!(Op    & ~0xffe00000));
+    i.w = Op;
+    i.Rd.b = Rd;
+    i.imm16.b = Imm16;
+    ii(i.w);
+}
+
+static void
+_oxxrs(jit_state_t *_jit, jit_int32_t Op,
+       jit_int32_t Rd, jit_int32_t Rn, jit_int32_t R, jit_int32_t S)
+{
+    instr_t    i;
+    assert(!(Rd &       ~0x1f));
+    assert(!(Rn &       ~0x1f));
+    assert(!(R  &       ~0x3f));
+    assert(!(S  &       ~0x3f));
+    assert(!(Op & ~0xffc00000));
+    i.w = Op;
+    i.Rd.b = Rd;
+    i.Rn.b = Rn;
+    i.immr.b = R;
+    i.imms.b = S;
+    ii(i.w);
+}
+
+static void
+_oxxxc(jit_state_t *_jit, jit_int32_t Op,
+       jit_int32_t Rd, jit_int32_t Rn, jit_int32_t Rm, jit_int32_t Cc)
+{
+    instr_t    i;
+    assert(!(Rd &       ~0x1f));
+    assert(!(Rn &       ~0x1f));
+    assert(!(Rm &       ~0x1f));
+    assert(!(Cc  &       ~0xf));
+    assert(!(Op & ~0xffc00c00));
+    i.w = Op;
+    i.Rd.b = Rd;
+    i.Rn.b = Rn;
+    i.Rm.b = Rm;
+    i.cond.b = Cc;
+    ii(i.w);
+}
+
+static void
+_oxxx7(jit_state_t *_jit, jit_int32_t Op,
+       jit_int32_t Rt, jit_int32_t Rt2, jit_int32_t Rn, jit_int32_t Simm7)
+{
+    instr_t    i;
+    assert(!(Rt  &       ~0x1f));
+    assert(!(Rt2 &       ~0x1f));
+    assert(!(Rn  &       ~0x1f));
+    assert(Simm7 >= -128 && Simm7 <= 127);
+    assert(!(Op & ~0xffc003e0));
+    i.w = Op;
+    i.Rt.b = Rt;
+    i.Rt2.b = Rt2;
+    i.Rn.b = Rn;
+    i.imm7.b = Simm7;
+    ii(i.w);
+}
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t i0)
+{
+    for (; i0 > 0; i0 -= 4)
+       NOP();
+    assert(i0 == 0);
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_word_t         is =  i0 >> 12;
+    jit_word_t         in = -i0;
+    jit_word_t         iS =  in >> 12;
+    if (      i0 >= 0 && i0 <= 0xfff)
+       ADDI   (r0, r1, i0);
+    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
+       ADDI_12(r0, r1, is);
+    else if ( in >= 0 && in <= 0xfff)
+       SUBI   (r0, r1, in);
+    else if ((iS << 12) == is && iS >= 0 && iS <= 0xfff)
+       SUBI_12(r0, r1, iS);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_word_t         is =  i0 >> 12;
+    jit_word_t         in = -i0;
+    jit_word_t         iS =  in >> 12;
+    if (      i0 >= 0 && i0 <= 0xfff)
+       ADDSI   (r0, r1, i0);
+    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
+       ADDSI_12(r0, r1, is);
+    else if ( in >= 0 && in <= 0xfff)
+       SUBSI   (r0, r1, in);
+    else if ((iS << 12) == is && iS >= 0 && iS <= 0xfff)
+       SUBSI_12(r0, r1, iS);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addcr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    addxr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_word_t         is = i0 >> 12;
+    if (      i0 >= 0 && i0 <= 0xfff)
+       SUBI   (r0, r1, i0);
+    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
+       SUBI_12(r0, r1, is);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_word_t         is = i0 >> 12;
+    if (      i0 >= 0 && i0 <= 0xfff)
+       SUBSI   (r0, r1, i0);
+    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
+       SUBSI_12(r0, r1, is);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subcr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    subxr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    subi(r0, r1, i0);
+    negr(r0, r0);
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    mulr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_qmulr(jit_state_t *_jit, jit_int32_t r0,
+       jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                reg;
+    if (r0 == r2 || r0 == r3) {
+       reg = jit_get_reg(jit_class_gpr);
+       mulr(rn(reg), r2, r3);
+    }
+    else
+       mulr(r0, r2, r3);
+    SMULH(r1, r2, r3);
+    if (r0 == r2 || r0 == r3) {
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_qmuli(jit_state_t *_jit, jit_int32_t r0,
+       jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    qmulr(r0, r1, r2, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_qmulr_u(jit_state_t *_jit, jit_int32_t r0,
+        jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                reg;
+    if (r0 == r2 || r0 == r3) {
+       reg = jit_get_reg(jit_class_gpr);
+       mulr(rn(reg), r2, r3);
+    }
+    else
+       mulr(r0, r2, r3);
+    UMULH(r1, r2, r3);
+    if (r0 == r2 || r0 == r3) {
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_qmuli_u(jit_state_t *_jit, jit_int32_t r0,
+        jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    qmulr_u(r0, r1, r2, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_iqdivr(jit_state_t *_jit, jit_bool_t sign,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                sv0, rg0;
+    jit_int32_t                sv1, rg1;
+    if (r0 == r2 || r0 == r3) {
+       sv0 = jit_get_reg(jit_class_gpr);
+       rg0 = rn(sv0);
+    }
+    else
+       rg0 = r0;
+    if (r1 == r2 || r1 == r3) {
+       sv1 = jit_get_reg(jit_class_gpr);
+       rg1 = rn(sv1);
+    }
+    else
+       rg1 = r1;
+    if (sign)
+       divr(rg0, r2, r3);
+    else
+       divr_u(rg0, r2, r3);
+    mulr(rg1, r3, rg0);
+    subr(rg1, r2, rg1);
+    if (rg0 != r0) {
+       movr(r0, rg0);
+       jit_unget_reg(sv0);
+    }
+    if (rg1 != r1) {
+       movr(r1, rg1);
+       jit_unget_reg(sv1);
+    }
+}
+
+static void
+_qdivi(jit_state_t *_jit, jit_int32_t r0,
+       jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    qdivr(r0, r1, r2, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_qdivi_u(jit_state_t *_jit, jit_int32_t r0,
+        jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    qdivr_u(r0, r1, r2, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1 || r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       divr(rn(reg), r1, r2);
+       mulr(rn(reg), r2, rn(reg));
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       divr(r0, r1, r2);
+       mulr(r0, r2, r0);
+       subr(r0, r1, r0);
+    }
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1 || r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       divr_u(rn(reg), r1, r2);
+       mulr(rn(reg), r2, rn(reg));
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       divr_u(r0, r1, r2);
+       mulr(r0, r2, r0);
+       subr(r0, r1, r0);
+    }
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else {
+       assert(i0 > 0 && i0 < 64);
+       LSLI(r0, r1, i0);
+    }
+}
+
+static void
+_rshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else {
+       assert(i0 > 0 && i0 < 64);
+       ASRI(r0, r1, i0);
+    }
+}
+
+static void
+_rshi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else {
+       assert(i0 > 0 && i0 < 64);
+       LSRI(r0, r1, i0);
+    }
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_int32_t                imm;
+    if (i0 == 0)
+       movi(r0, 0);
+    else if (i0 == -1)
+       movr(r0, r1);
+    else {
+       imm = logical_immediate(i0);
+       if (imm != -1)
+           ANDI(r0, r1, imm);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           andr(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_int32_t                imm;
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (i0 == -1)
+       movi(r0, -1);
+    else {
+       imm = logical_immediate(i0);
+       if (imm != -1)
+           ORRI(r0, r1, imm);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           orr(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_int32_t                imm;
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (i0 == -1)
+       comr(r0, r1);
+    else {
+       imm = logical_immediate(i0);
+       if (imm != -1)
+           EORI(r0, r1, imm);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           xorr(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static void
+_htonr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    htonr_ul(r0, r1);
+    rshi_u(r0, r0, 48);
+}
+
+static void
+_htonr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    htonr_ul(r0, r1);
+    rshi_u(r0, r0, 32);
+}
+#endif
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_c(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    LDRBI(r0, r1, 0);
+#if 0
+    extr_uc(r0, r0);
+#endif
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_uc(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_s(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    LDRHI(r0, r1, 0);
+#if 0
+    extr_us(r0, r0);
+#endif
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_us(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_i(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    LDRWI(r0, r1, 0);
+#if 0
+    extr_ui(r0, r0);
+#endif
+}
+
+static void
+_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_ui(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_l(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_l(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    LDRSB(r0, r1, r2);
+    extr_c(r0, r0);
+}
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= 0 && i0 <= 4095)
+       LDRSBI(r0, r1, i0);
+    else if (i0 > -256 && i0 < 0)
+       LDURSB(r0, r1, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       LDRSB(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    extr_c(r0, r0);
+}
+
+static void
+_ldxr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    LDRB(r0, r1, r2);
+#if 0
+    extr_uc(r0, r0);
+#endif
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= 0 && i0 <= 4095)
+       LDRBI(r0, r1, i0);
+    else if (i0 > -256 && i0 < 0)
+       LDURB(r0, r1, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_uc(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+#if 0
+    extr_uc(r0, r0);
+#endif
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 1));
+    if (i0 >= 0 && i0 <= 8191)
+       LDRSHI(r0, r1, i0 >> 1);
+    else if (i0 > -256 && i0 < 0)
+       LDURSH(r0, r1, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       LDRSH(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    LDRH(r0, r1, r2);
+#if 0
+    extr_us(r0, r0);
+#endif
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 1));
+    if (i0 >= 0 && i0 <= 8191)
+       LDRHI(r0, r1, i0 >> 1);
+    else if (i0 > -256 && i0 < 0)
+       LDURH(r0, r1, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       LDRH(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+#if 0
+    extr_us(r0, r0);
+#endif
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 3));
+    if (i0 >= 0 && i0 <= 16383)
+       LDRSWI(r0, r1, i0 >> 2);
+    else if (i0 > -256 && i0 < 0)
+       LDURSW(r0, r1, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    LDRW(r0, r1, r2);
+#if 0
+    extr_ui(r0, r0);
+#endif
+}
+
+static void
+_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 3));
+    if (i0 >= 0 && i0 <= 16383)
+       LDRWI(r0, r1, i0 >> 2);
+    else if (i0 > -256 && i0 < 0)
+       LDURW(r0, r1, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       LDRW(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+#if 0
+    extr_ui(r0, r0);
+#endif
+}
+
+static void
+_ldxi_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 7));
+    if (i0 >= 0 && i0 <= 32767)
+       LDRI(r0, r1, i0 >> 3);
+    else if (i0 > -256 && i0 < 0)
+       LDUR(r0, r1, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_l(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_c(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_s(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_i(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_sti_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_l(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 >= 0 && i0 <= 4095)
+       STRBI(r1, r0, i0);
+    else if (i0 > -256 && i0 < 0)
+       STURB(r1, r0, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_c(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 1));
+    if (i0 >= 0 && i0 <= 8191)
+       STRHI(r1, r0, i0 >> 1);
+    else if (i0 > -256 && i0 < 0)
+       STURH(r1, r0, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_s(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 3));
+    if (i0 >= 0 && i0 <= 16383)
+       STRWI(r1, r0, i0 >> 2);
+    else if (i0 > -256 && i0 < 0)
+       STURW(r1, r0, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_i(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxi_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 7));
+    if (i0 >= 0 && i0 <= 32767)
+       STRI(r1, r0, i0 >> 3);
+    else if (i0 > -256 && i0 < 0)
+       STUR(r1, r0, i0 & 0x1ff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_l(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       MOV(r0, r1);
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         n0, ibit, nbit;
+    n0 = ~i0;
+    ibit = nbit = 0;
+    if (i0 & 0x000000000000ffffL)      ibit |= 1;
+    if (i0 & 0x00000000ffff0000L)      ibit |= 2;
+    if (i0 & 0x0000ffff00000000L)      ibit |= 4;
+    if (i0 & 0xffff000000000000L)      ibit |= 8;
+    if (n0 & 0x000000000000ffffL)      nbit |= 1;
+    if (n0 & 0x00000000ffff0000L)      nbit |= 2;
+    if (n0 & 0x0000ffff00000000L)      nbit |= 4;
+    if (n0 & 0xffff000000000000L)      nbit |= 8;
+    switch (ibit) {
+       case 0:
+           MOVZ   (r0,  0);
+           break;
+       case 1:
+           MOVZ   (r0,  i0        & 0xffff);
+           break;
+       case 2:
+           MOVZ_16(r0, (i0 >> 16) & 0xffff);
+           break;
+       case 3:
+           MOVZ   (r0,  i0        & 0xffff);
+           MOVK_16(r0, (i0 >> 16) & 0xffff);
+           break;
+       case 4:
+           MOVZ_32(r0, (i0 >> 32) & 0xffff);
+           break;
+       case 5:
+           MOVZ   (r0,  i0        & 0xffff);
+           MOVK_32(r0, (i0 >> 32) & 0xffff);
+           break;
+       case 6:
+           MOVZ_16(r0, (i0 >> 16) & 0xffff);
+           MOVK_32(r0, (i0 >> 32) & 0xffff);
+           break;
+       case 7:
+           if (nbit == 8)
+               MOVN_48(r0, (n0 >> 48) & 0xffff);
+           else {
+               MOVZ   (r0,  i0        & 0xffff);
+               MOVK_16(r0, (i0 >> 16) & 0xffff);
+               MOVK_32(r0, (i0 >> 32) & 0xffff);
+           }
+           break;
+       case 8:
+           MOVZ_48(r0, (i0 >> 48) & 0xffff);
+           break;
+       case 9:
+           MOVZ   (r0,  i0        & 0xffff);
+           MOVK_48(r0, (i0 >> 48) & 0xffff);
+           break;
+       case 10:
+           MOVZ_16(r0, (i0 >> 16) & 0xffff);
+           MOVK_48(r0, (i0 >> 48) & 0xffff);
+           break;
+       case 11:
+           if (nbit == 4)
+               MOVN_32(r0, (n0 >> 32) & 0xffff);
+           else {
+               MOVZ   (r0,  i0        & 0xffff);
+               MOVK_16(r0, (i0 >> 16) & 0xffff);
+               MOVK_48(r0, (i0 >> 48) & 0xffff);
+           }
+           break;
+       case 12:
+           MOVZ_32(r0, (i0 >> 32) & 0xffff);
+           MOVK_48(r0, (i0 >> 48) & 0xffff);
+           break;
+       case 13:
+           if (nbit == 2)
+               MOVN_16(r0, (n0 >> 16) & 0xffff);
+           else {
+               MOVZ   (r0,  i0        & 0xffff);
+               MOVK_32(r0, (i0 >> 32) & 0xffff);
+               MOVK_48(r0, (i0 >> 48) & 0xffff);
+           }
+           break;
+       case 14:
+           if (nbit == 1)
+               MOVN   (r0, (n0)       & 0xffff);
+           else {
+               MOVZ_16(r0, (i0 >> 16) & 0xffff);
+               MOVK_32(r0, (i0 >> 32) & 0xffff);
+               MOVK_48(r0, (i0 >> 48) & 0xffff);
+           }
+           break;
+       case 15:
+           if (nbit == 0)
+               MOVN   (r0,  0);
+           else if (nbit == 1)
+               MOVN   (r0,  n0        & 0xffff);
+           else if (nbit == 8)
+               MOVN_48(r0, (n0 >> 48) & 0xffff);
+           else {
+               MOVZ   (r0,  i0        & 0xffff);
+               MOVK_16(r0, (i0 >> 16) & 0xffff);
+               MOVK_32(r0, (i0 >> 32) & 0xffff);
+               MOVK_48(r0, (i0 >> 48) & 0xffff);
+           }
+           break;
+       default:
+           abort();
+    }
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    MOVZ   (r0,  i0        & 0xffff);
+    MOVK_16(r0, (i0 >> 16) & 0xffff);
+    MOVK_32(r0, (i0 >> 32) & 0xffff);
+    MOVK_48(r0, (i0 >> 48) & 0xffff);
+    return (w);
+}
+
+static void
+_ccr(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP(r1, r2);
+    CSET(r0, cc);
+}
+
+static void
+_cci(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_word_t         is =  i0 >> 12;
+    jit_word_t         in = -i0;
+    jit_word_t         iS =  in >> 12;
+    if (      i0 >= 0 && i0 <= 0xfff)
+       CMPI   (r1, i0);
+    else if ((is << 12) == i0 && is >= 0 && is <= 0xfff)
+       CMPI_12(r1, is);
+    else if ( in >= 0 && in <= 0xfff)
+       CMNI   (r1, in);
+    else if ((iS << 12) == is && iS >= 0 && iS <= 0xfff)
+       CMNI_12(r1, iS);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMP(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    CSET(r0, cc);
+}
+
+static jit_word_t
+_bccr(jit_state_t *_jit, jit_int32_t cc,
+      jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, d;
+    CMP(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) >> 2;
+    B_C(cc, d);
+    return (w);
+}
+
+static jit_word_t
+_bcci(jit_state_t *_jit, jit_int32_t cc,
+      jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         w, d;
+    jit_word_t         is =  i1 >> 12;
+    jit_word_t         in = -i1;
+    jit_word_t         iS =  in >> 12;
+    if (      i1 >= 0 && i1 <= 0xfff)
+       CMPI   (r0, i1);
+    else if ((is << 12) == i1 && is >= 0 && is <= 0xfff)
+       CMPI_12(r0, is);
+    else if ( in >= 0 && in <= 0xfff)
+       CMNI   (r0, in);
+    else if ((iS << 12) == is && iS >= 0 && iS <= 0xfff)
+       CMNI_12(r0, iS);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMP(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) >> 2;
+    B_C(cc, d);
+    return (w);
+}
+
+static jit_word_t
+_beqi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       CBZ(r0, (i0 - w) >> 2);
+    }
+    else
+       w = bcci(BCC_EQ, i0, r0, i1);
+    return (w);
+}
+
+static jit_word_t
+_bnei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       CBNZ(r0, (i0 - w) >> 2);
+    }
+    else
+       w = bcci(BCC_NE, i0, r0, i1);
+    return (w);
+}
+
+static jit_word_t
+_baddr(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    addcr(r0, r0, r1);
+    w = _jit->pc.w;
+    B_C(cc, (i0 - w) >> 2);
+    return (w);
+}
+
+static jit_word_t
+_baddi(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    addci(r0, r0, i1);
+    w = _jit->pc.w;
+    B_C(cc, (i0 - w) >> 2);
+    return (w);
+}
+
+static jit_word_t
+_bsubr(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    subcr(r0, r0, r1);
+    w = _jit->pc.w;
+    B_C(cc, (i0 - w) >> 2);
+    return (w);
+}
+
+static jit_word_t
+_bsubi(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    subci(r0, r0, i1);
+    w = _jit->pc.w;
+    B_C(cc, (i0 - w) >> 2);
+    return (w);
+}
+
+static jit_word_t
+_bmxr(jit_state_t *_jit, jit_int32_t cc,
+      jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    TST(r0, r1);
+    w = _jit->pc.w;
+    B_C(cc, (i0 - w) >> 2);
+    return (w);
+}
+
+static jit_word_t
+_bmxi(jit_state_t *_jit, jit_int32_t cc,
+      jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    jit_int32_t                imm;
+    imm = logical_immediate(i1);
+    if (imm != -1)
+       TSTI(r0, imm);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       TST(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    B_C(cc, (i0 - w) >> 2);
+    return (w);
+}
+
+static void
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    w = (i0 - _jit->pc.w) >> 2;
+    if (w >= -33554432 && w <= 33554431)
+       B(w);
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i0);
+       jmpr(rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_jmpi_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    w = movi_p(rn(reg), i0);
+    jmpr(rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    w = (i0 - _jit->pc.w) >> 2;
+    if (w >= -33554432 && w <= 33554431)
+       BL(w);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       callr(rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    w = movi_p(rn(reg), i0);
+    callr(rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+/*
+ * prolog and epilog not as "optimized" as one would like, but the
+ * problem of overallocating stack space to save callee save registers
+ * exists on all ports, and is still a todo to use a variable
+ *     stack_framesize
+ * value, what would cause needing to patch some calls, most likely
+ * the offset of jit_arg* of stack arguments.
+ */
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                reg;
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar)
+       _jitc->function->self.aoff &= -16;
+    _jitc->function->stack = ((_jitc->function->self.alen -
+                             /* align stack at 16 bytes */
+                             _jitc->function->self.aoff) + 15) & -16;
+    STPI_POS(FP_REGNO, LR_REGNO, SP_REGNO, -(stack_framesize >> 3));
+    MOV_XSP(FP_REGNO, SP_REGNO);
+#define SPILL(L, R, O)                                                 \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->function->regset, _R##L)) {       \
+           if (jit_regset_tstbit(&_jitc->function->regset, _R##R))     \
+               STPI(L, R, SP_REGNO, O);                                \
+           else                                                        \
+               STRI(L, SP_REGNO, O);                                   \
+       }                                                               \
+       else if (jit_regset_tstbit(&_jitc->function->regset, _R##R))    \
+           STRI(R, SP_REGNO, O + 1);                                   \
+    } while (0)
+    SPILL(19, 20,  2);
+    SPILL(21, 22,  4);
+    SPILL(23, 24,  6);
+    SPILL(25, 26,  8);
+    SPILL(27, 28, 10);
+#undef SPILL
+#define SPILL(R, O)                                                    \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->function->regset, _V##R))         \
+               stxi_d(O, SP_REGNO, R);                                 \
+    } while (0)
+    SPILL( 8,  96);
+    SPILL( 9, 104);
+    SPILL(10, 112);
+    SPILL(11, 120);
+    SPILL(12, 128);
+    SPILL(13, 136);
+    SPILL(14, 144);
+    SPILL(15, 152);
+#undef SPILL
+    if (_jitc->function->stack)
+       subi(SP_REGNO, SP_REGNO, _jitc->function->stack);
+    if (_jitc->function->allocar) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    if (_jitc->function->self.call & jit_call_varargs) {
+       /* Save gp registers in the save area, if any is a vararg */
+       for (reg = 8 - _jitc->function->vagp / -8;
+            jit_arg_reg_p(reg); ++reg)
+           stxi(_jitc->function->vaoff + offsetof(jit_va_list_t, x0) +
+                reg * 8, FP_REGNO, rn(JIT_RA0 - reg));
+
+       for (reg = 8 - _jitc->function->vafp / -16;
+            jit_arg_f_reg_p(reg); ++reg)
+           /* Save fp registers in the save area, if any is a vararg */
+           /* Note that the full 16 byte register is not saved, because
+            * lightning only handles float and double, and, while
+            * attempting to provide a va_list compatible pointer as
+            * jit_va_start return, does not guarantee it (on all ports). */
+           stxi_d(_jitc->function->vaoff + offsetof(jit_va_list_t, q0) +
+                  reg * 16 + offsetof(jit_qreg_t, l), FP_REGNO, rn(_V0 - reg));
+    }
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    if (_jitc->function->assume_frame)
+       return;
+    if (_jitc->function->stack)
+       MOV_XSP(SP_REGNO, FP_REGNO);
+#define LOAD(L, R, O)                                                  \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->function->regset, _R##L)) {       \
+           if (jit_regset_tstbit(&_jitc->function->regset, _R##R))     \
+               LDPI(L, R, SP_REGNO, O);                                \
+           else                                                        \
+               LDRI(L, SP_REGNO, O);                                   \
+       }                                                               \
+       else if (jit_regset_tstbit(&_jitc->function->regset, _R##R))    \
+           LDRI(R, SP_REGNO, O + 1);                                   \
+    } while (0)
+    LOAD(19, 20,  2);
+    LOAD(21, 22,  4);
+    LOAD(23, 24,  6);
+    LOAD(25, 26,  8);
+    LOAD(27, 28, 10);
+#undef LOAD
+#define LOAD(R, O)                                                     \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->function->regset, _V##R))         \
+               ldxi_d(R, SP_REGNO, O);                                 \
+    } while (0)
+    LOAD( 8,  96);
+    LOAD( 9, 104);
+    LOAD(10, 112);
+    LOAD(11, 120);
+    LOAD(12, 128);
+    LOAD(13, 136);
+    LOAD(14, 144);
+    LOAD(15, 152);
+#undef LOAD
+    LDPI_PRE(FP_REGNO, LR_REGNO, SP_REGNO, stack_framesize >> 3);
+    RET();
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Return jit_va_list_t in the register argument */
+    addi(r0, FP_REGNO, _jitc->function->vaoff);
+
+    reg = jit_get_reg(jit_class_gpr);
+
+    /* Initialize stack pointer to the first stack argument. */
+    addi(rn(reg), FP_REGNO, _jitc->function->self.size);
+    stxi(offsetof(jit_va_list_t, stack), r0, rn(reg));
+
+    /* Initialize gp top pointer to the first stack argument. */
+    addi(rn(reg), r0, va_gp_top_offset);
+    stxi(offsetof(jit_va_list_t, gptop), r0, rn(reg));
+
+    /* Initialize fp top pointer to the first stack argument. */
+    addi(rn(reg), r0, va_fp_top_offset);
+    stxi(offsetof(jit_va_list_t, fptop), r0, rn(reg));
+
+    /* Initialize gp offset in the save area. */
+    movi(rn(reg), _jitc->function->vagp);
+    stxi_i(offsetof(jit_va_list_t, gpoff), r0, rn(reg));
+
+    /* Initialize fp offset in the save area. */
+    movi(rn(reg), _jitc->function->vafp);
+    stxi_i(offsetof(jit_va_list_t, fpoff), r0, rn(reg));
+
+    jit_unget_reg(reg);
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         ge_code;
+    jit_word_t         lt_code;
+    jit_int32_t                rg0, rg1;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg(jit_class_gpr);
+    rg1 = jit_get_reg(jit_class_gpr);
+
+    /* Load the gp offset in save area in the first temporary. */
+    ldxi_i(rn(rg0), r1, offsetof(jit_va_list_t, gpoff));
+
+    /* Jump over if there are no remaining arguments in the save area. */
+    ge_code = bgei(_jit->pc.w, rn(rg0), 0);
+
+    /* Load the gp save pointer in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, gptop));
+
+    /* Load the vararg argument in the first argument. */
+    ldxr(r0, rn(rg1), rn(rg0));
+
+    /* Update the gp offset. */
+    addi(rn(rg0), rn(rg0), 8);
+    stxi_i(offsetof(jit_va_list_t, gpoff), r1, rn(rg0));
+
+    /* Will only need one temporary register below. */
+    jit_unget_reg(rg1);
+
+    /* Jump over overflow code. */
+    lt_code = jmpi_p(_jit->pc.w);
+
+    /* Where to land if argument is in overflow area. */
+    patch_at(ge_code, _jit->pc.w);
+
+    /* Load stack pointer. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, stack));
+
+    /* Load argument. */
+    ldr(r0, rn(rg0));
+
+    /* Update stack pointer. */
+    addi(rn(rg0), rn(rg0), 8);
+    stxi(offsetof(jit_va_list_t, stack), r1, rn(rg0));
+
+    /* Where to land if argument is in gp save area. */
+    patch_at(lt_code, _jit->pc.w);
+
+    jit_unget_reg(rg0);
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
+{
+    instr_t             i;
+    jit_word_t          d;
+    jit_int32_t                 fc, ff, ffc;
+    union {
+       jit_int32_t     *i;
+       jit_word_t       w;
+    } u;
+    u.w = instr;
+    i.w = u.i[0];
+    fc  = i.w & 0xfc000000;
+    ff  = i.w & 0xff000000;
+    ffc = i.w & 0xffc00000;
+    if (fc == A64_B || fc == A64_BL) {
+       d = (label - instr) >> 2;
+       assert(d >= -33554432 && d <= 33554431);
+       i.imm26.b = d;
+       u.i[0] = i.w;
+    }
+    else if (ff == A64_B_C || ff == (A64_CBZ|XS) || ff == (A64_CBNZ|XS)) {
+       d = (label - instr) >> 2;
+       assert(d >= -262148 && d <= 262143);
+       i.imm19.b = d;
+       u.i[0] = i.w;
+    }
+    else if (ffc == (A64_MOVZ|XS)) {
+       i.imm16.b = label;
+       u.i[0] = i.w;
+       i.w = u.i[1];
+       assert((i.w & 0xffe00000) == (A64_MOVK|XS|MOVI_LSL_16));
+       i.imm16.b = label >> 16;
+       u.i[1] = i.w;
+       i.w = u.i[2];
+       assert((i.w & 0xffe00000) == (A64_MOVK|XS|MOVI_LSL_32));
+       i.imm16.b = label >> 32;
+       u.i[2] = i.w;
+       i.w = u.i[3];
+       assert((i.w & 0xffe00000) == (A64_MOVK|XS|MOVI_LSL_48));
+       i.imm16.b = label >> 48;
+       u.i[3] = i.w;
+    }
+    else
+       abort();
+}
+#endif
diff --git a/deps/lightning/lib/jit_aarch64-fpu.c b/deps/lightning/lib/jit_aarch64-fpu.c
new file mode 100644 (file)
index 0000000..871ba7e
--- /dev/null
@@ -0,0 +1,914 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  define A64_SCVTF                    0x1e220000
+#  define A64_FMOVWV                   0x1e260000
+#  define A64_FMOVVW                   0x1e270000
+#  define A64_FMOVXV                   0x9e260000
+#  define A64_FMOVVX                   0x9e270000
+#  define A64_FCVTZS                   0x1e380000
+#  define A64_FCMPE                    0x1e202010
+#  define A64_FMOV                     0x1e204000
+#  define A64_FABS                     0x1e20c000
+#  define A64_FNEG                     0x1e214000
+#  define A64_FSQRT                    0x1e21c000
+#  define A64_FCVTS                    0x1e224000
+#  define A64_FCVTD                    0x1e22c000
+#  define A64_FMUL                     0x1e200800
+#  define A64_FDIV                     0x1e201800
+#  define A64_FADD                     0x1e202800
+#  define A64_FSUB                     0x1e203800
+#  define FCMPES(Rn,Rm)                        os_vv(A64_FCMPE,0,Rn,Rm)
+#  define FCMPED(Rn,Rm)                        os_vv(A64_FCMPE,1,Rn,Rm)
+#  define FMOVS(Rd,Rn)                 osvv_(A64_FMOV,0,Rd,Rn)
+#  define FMOVD(Rd,Rn)                 osvv_(A64_FMOV,1,Rd,Rn)
+#  define FMOVWS(Rd,Rn)                        osvv_(A64_FMOVWV,0,Rd,Rn)
+#  define FMOVSW(Rd,Rn)                        osvv_(A64_FMOVVW,0,Rd,Rn)
+#  define FMOVXD(Rd,Rn)                        osvv_(A64_FMOVXV,1,Rd,Rn)
+#  define FMOVDX(Rd,Rn)                        osvv_(A64_FMOVVX,1,Rd,Rn)
+#  define FCVT_SD(Rd,Rn)               osvv_(A64_FCVTS,1,Rd,Rn)
+#  define FCVT_DS(Rd,Rn)               osvv_(A64_FCVTD,0,Rd,Rn)
+#  define SCVTFS(Rd,Rn)                        osvv_(A64_SCVTF|XS,0,Rd,Rn)
+#  define SCVTFD(Rd,Rn)                        osvv_(A64_SCVTF|XS,1,Rd,Rn)
+#  define FCVTSZ_WS(Rd,Rn)             osvv_(A64_FCVTZS,0,Rd,Rn)
+#  define FCVTSZ_WD(Rd,Rn)             osvv_(A64_FCVTZS,1,Rd,Rn)
+#  define FCVTSZ_XS(Rd,Rn)             osvv_(A64_FCVTZS|XS,0,Rd,Rn)
+#  define FCVTSZ_XD(Rd,Rn)             osvv_(A64_FCVTZS|XS,1,Rd,Rn)
+#  define FABSS(Rd,Rn)                 osvv_(A64_FABS,0,Rd,Rn)
+#  define FABSD(Rd,Rn)                 osvv_(A64_FABS,1,Rd,Rn)
+#  define FNEGS(Rd,Rn)                 osvv_(A64_FNEG,0,Rd,Rn)
+#  define FNEGD(Rd,Rn)                 osvv_(A64_FNEG,1,Rd,Rn)
+#  define FSQRTS(Rd,Rn)                        osvv_(A64_FSQRT,0,Rd,Rn)
+#  define FSQRTD(Rd,Rn)                        osvv_(A64_FSQRT,1,Rd,Rn)
+#  define FADDS(Rd,Rn,Rm)              osvvv(A64_FADD,0,Rd,Rn,Rm)
+#  define FADDD(Rd,Rn,Rm)              osvvv(A64_FADD,1,Rd,Rn,Rm)
+#  define FSUBS(Rd,Rn,Rm)              osvvv(A64_FSUB,0,Rd,Rn,Rm)
+#  define FSUBD(Rd,Rn,Rm)              osvvv(A64_FSUB,1,Rd,Rn,Rm)
+#  define FMULS(Rd,Rn,Rm)              osvvv(A64_FMUL,0,Rd,Rn,Rm)
+#  define FMULD(Rd,Rn,Rm)              osvvv(A64_FMUL,1,Rd,Rn,Rm)
+#  define FDIVS(Rd,Rn,Rm)              osvvv(A64_FDIV,0,Rd,Rn,Rm)
+#  define FDIVD(Rd,Rn,Rm)              osvvv(A64_FDIV,1,Rd,Rn,Rm)
+#  define osvvv(Op,Sz,Rd,Rn,Rm)                _osvvv(_jit,Op,Sz,Rd,Rn,Rm)
+static void _osvvv(jit_state_t*,jit_int32_t,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t);
+#  define osvv_(Op,Sz,Rd,Rn)           _osvv_(_jit,Op,Sz,Rd,Rn)
+static void _osvv_(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t);
+#  define os_vv(Op,Sz,Rn,Rm)           _os_vv(_jit,Op,Sz,Rn,Rm)
+static void _os_vv(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t);
+#  define truncr_f_i(r0,r1)            _truncr_f_i(_jit,r0,r1)
+static void _truncr_f_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define truncr_f_l(r0,r1)            FCVTSZ_XS(r0,r1)
+#  define truncr_d_i(r0,r1)            _truncr_d_i(_jit,r0,r1)
+static void _truncr_d_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define truncr_d_l(r0,r1)            FCVTSZ_XD(r0,r1)
+#  define addr_f(r0,r1,r2)             FADDS(r0,r1,r2)
+#  define addi_f(r0,r1,i0)             _addi_f(_jit,r0,r1,i0)
+static void _addi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define subr_f(r0,r1,r2)             FSUBS(r0,r1,r2)
+#  define subi_f(r0,r1,i0)             _subi_f(_jit,r0,r1,i0)
+static void _subi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define rsbr_f(r0, r1, r2)           subr_f(r0, r2, r1)
+#  define rsbi_f(r0, r1, i0)           _rsbi_f(_jit, r0, r1, i0)
+static void _rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define mulr_f(r0,r1,r2)             FMULS(r0,r1,r2)
+#  define muli_f(r0,r1,i0)             _muli_f(_jit,r0,r1,i0)
+static void _muli_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define divr_f(r0,r1,r2)             FDIVS(r0,r1,r2)
+#  define divi_f(r0,r1,i0)             _divi_f(_jit,r0,r1,i0)
+static void _divi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define absr_f(r0,r1)                        FABSS(r0,r1)
+#  define negr_f(r0,r1)                        FNEGS(r0,r1)
+#  define sqrtr_f(r0,r1)               FSQRTS(r0,r1)
+#  define extr_f(r0,r1)                        SCVTFS(r0,r1)
+#  define ldr_f(r0,r1)                 _ldr_f(_jit,r0,r1)
+static void _ldr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_f(r0,i0)                 _ldi_f(_jit,r0,i0)
+static void _ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_f(r0,r1,r2)             _ldxr_f(_jit,r0,r1,r2)
+static void _ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_f(r0,r1,i0)             _ldxi_f(_jit,r0,r1,i0)
+static void _ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_f(r0,r1)                 _str_f(_jit,r0,r1)
+static void _str_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sti_f(i0,r0)                 _sti_f(_jit,i0,r0)
+static void _sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_f(r0,r1,r2)             _stxr_f(_jit,r0,r1,r2)
+static void _stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_f(i0,r0,r1)             _stxi_f(_jit,i0,r0,r1)
+static void _stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define movr_f(r0,r1)                        _movr_f(_jit,r0,r1)
+static void _movr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi_f(r0,i0)                        _movi_f(_jit,r0,i0)
+static void _movi_f(jit_state_t*,jit_int32_t,jit_float32_t);
+#  define extr_d_f(r0,r1)              FCVT_SD(r0,r1)
+#  define fccr(cc,r0,r1,r2)            _fccr(_jit,cc,r0,r1,r2)
+static void _fccr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define fcci(cc,r0,r1,i0)            _fcci(_jit,cc,r0,r1,i0)
+static void _fcci(jit_state_t*,
+                 jit_int32_t,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define ltr_f(r0,r1,r2)              fccr(CC_MI,r0,r1,r2)
+#  define lti_f(r0,r1,i0)              fcci(CC_MI,r0,r1,i0)
+#  define ler_f(r0,r1,r2)              fccr(CC_LS,r0,r1,r2)
+#  define lei_f(r0,r1,i0)              fcci(CC_LS,r0,r1,i0)
+#  define eqr_f(r0,r1,r2)              fccr(CC_EQ,r0,r1,r2)
+#  define eqi_f(r0,r1,i0)              fcci(CC_EQ,r0,r1,i0)
+#  define ger_f(r0,r1,r2)              fccr(CC_GE,r0,r1,r2)
+#  define gei_f(r0,r1,i0)              fcci(CC_GE,r0,r1,i0)
+#  define gtr_f(r0,r1,r2)              fccr(CC_GT,r0,r1,r2)
+#  define gti_f(r0,r1,i0)              fcci(CC_GT,r0,r1,i0)
+#  define ner_f(r0,r1,r2)              fccr(CC_NE,r0,r1,r2)
+#  define nei_f(r0,r1,i0)              fcci(CC_NE,r0,r1,i0)
+#  define unltr_f(r0,r1,r2)            fccr(CC_LT,r0,r1,r2)
+#  define unlti_f(r0,r1,i0)            fcci(CC_LT,r0,r1,i0)
+#  define unler_f(r0,r1,r2)            fccr(CC_LE,r0,r1,r2)
+#  define unlei_f(r0,r1,i0)            fcci(CC_LE,r0,r1,i0)
+#  define uneqr_f(r0,r1,r2)            _uneqr_f(_jit,r0,r1,r2)
+static void _uneqr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define uneqi_f(r0,r1,i0)            _uneqi_f(_jit,r0,r1,i0)
+static void _uneqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define unger_f(r0,r1,r2)            fccr(CC_PL,r0,r1,r2)
+#  define ungei_f(r0,r1,i0)            fcci(CC_PL,r0,r1,i0)
+#  define ungtr_f(r0,r1,r2)            fccr(CC_HI,r0,r1,r2)
+#  define ungti_f(r0,r1,i0)            fcci(CC_HI,r0,r1,i0)
+#  define ltgtr_f(r0,r1,r2)            _ltgtr_f(_jit,r0,r1,r2)
+static void _ltgtr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ltgti_f(r0,r1,i0)            _ltgti_f(_jit,r0,r1,i0)
+static void _ltgti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define ordr_f(r0,r1,r2)             fccr(CC_VC,r0,r1,r2)
+#  define ordi_f(r0,r1,i0)             fcci(CC_VC,r0,r1,i0)
+#  define unordr_f(r0,r1,r2)           fccr(CC_VS,r0,r1,r2)
+#  define unordi_f(r0,r1,i0)           fcci(CC_VS,r0,r1,i0)
+#define fbccr(cc,i0,r0,r1)             _fbccr(_jit,cc,i0,r0,r1)
+static jit_word_t
+_fbccr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#define fbcci(cc,i0,r0,i1)             _fbcci(_jit,cc,i0,r0,i1)
+static jit_word_t
+_fbcci(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bltr_f(i0,r0,r1)             fbccr(BCC_MI,i0,r0,r1)
+#  define blti_f(i0,r0,i1)             fbcci(BCC_MI,i0,r0,i1)
+#  define bler_f(i0,r0,r1)             fbccr(BCC_LS,i0,r0,r1)
+#  define blei_f(i0,r0,i1)             fbcci(BCC_LS,i0,r0,i1)
+#  define beqr_f(i0,r0,r1)             fbccr(BCC_EQ,i0,r0,r1)
+#  define beqi_f(i0,r0,i1)             fbcci(BCC_EQ,i0,r0,i1)
+#  define bger_f(i0,r0,r1)             fbccr(BCC_GE,i0,r0,r1)
+#  define bgei_f(i0,r0,i1)             fbcci(BCC_GE,i0,r0,i1)
+#  define bgtr_f(i0,r0,r1)             fbccr(BCC_GT,i0,r0,r1)
+#  define bgti_f(i0,r0,i1)             fbcci(BCC_GT,i0,r0,i1)
+#  define bner_f(i0,r0,r1)             fbccr(BCC_NE,i0,r0,r1)
+#  define bnei_f(i0,r0,i1)             fbcci(BCC_NE,i0,r0,i1)
+#  define bunltr_f(i0,r0,r1)           fbccr(BCC_LT,i0,r0,r1)
+#  define bunlti_f(i0,r0,i1)           fbcci(BCC_LT,i0,r0,i1)
+#  define bunler_f(i0,r0,r1)           fbccr(BCC_LE,i0,r0,r1)
+#  define bunlei_f(i0,r0,i1)           fbcci(BCC_LE,i0,r0,i1)
+#  define buneqr_f(i0,r0,r1)           _buneqr_f(_jit,i0,r0,r1)
+static jit_word_t _buneqr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define buneqi_f(i0,r0,i1)           _buneqi_f(_jit,i0,r0,i1)
+static jit_word_t _buneqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bunger_f(i0,r0,r1)           fbccr(BCC_PL,i0,r0,r1)
+#  define bungei_f(i0,r0,i1)           fbcci(BCC_PL,i0,r0,i1)
+#  define bungtr_f(i0,r0,r1)           fbccr(BCC_HI,i0,r0,r1)
+#  define bungti_f(i0,r0,i1)           fbcci(BCC_HI,i0,r0,i1)
+#  define bltgtr_f(i0,r0,r1)           _bltgtr_f(_jit,i0,r0,r1)
+static jit_word_t _bltgtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bltgti_f(i0,r0,i1)           _bltgti_f(_jit,i0,r0,i1)
+static jit_word_t _bltgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bordr_f(i0,r0,r1)            fbccr(BCC_VC,i0,r0,r1)
+#  define bordi_f(i0,r0,i1)            fbcci(BCC_VC,i0,r0,i1)
+#  define bunordr_f(i0,r0,r1)          fbccr(BCC_VS,i0,r0,r1)
+#  define bunordi_f(i0,r0,i1)          fbcci(BCC_VS,i0,r0,i1)
+#  define addr_d(r0,r1,r2)             FADDD(r0,r1,r2)
+#  define addi_d(r0,r1,i0)             _addi_d(_jit,r0,r1,i0)
+static void _addi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define subr_d(r0,r1,r2)             FSUBD(r0,r1,r2)
+#  define subi_d(r0,r1,i0)             _subi_d(_jit,r0,r1,i0)
+static void _subi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define rsbr_d(r0, r1, r2)           subr_d(r0, r2, r1)
+#  define rsbi_d(r0, r1, i0)           _rsbi_d(_jit, r0, r1, i0)
+static void _rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define mulr_d(r0,r1,r2)             FMULD(r0,r1,r2)
+#  define muli_d(r0,r1,i0)             _muli_d(_jit,r0,r1,i0)
+static void _muli_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define divr_d(r0,r1,r2)             FDIVD(r0,r1,r2)
+#  define divi_d(r0,r1,i0)             _divi_d(_jit,r0,r1,i0)
+static void _divi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define absr_d(r0,r1)                        FABSD(r0,r1)
+#  define negr_d(r0,r1)                        FNEGD(r0,r1)
+#  define sqrtr_d(r0,r1)               FSQRTD(r0,r1)
+#  define extr_d(r0,r1)                        SCVTFD(r0,r1)
+#  define ldr_d(r0,r1)                 _ldr_d(_jit,r0,r1)
+static void _ldr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_d(r0,i0)                 _ldi_d(_jit,r0,i0)
+static void _ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_d(r0,r1,r2)             _ldxr_d(_jit,r0,r1,r2)
+static void _ldxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_d(r0,r1,i0)             _ldxi_d(_jit,r0,r1,i0)
+static void _ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_d(r0,r1)                 _str_d(_jit,r0,r1)
+static void _str_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sti_d(i0,r0)                 _sti_d(_jit,i0,r0)
+static void _sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_d(r0,r1,r2)             _stxr_d(_jit,r0,r1,r2)
+static void _stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_d(i0,r0,r1)             _stxi_d(_jit,i0,r0,r1)
+static void _stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define movr_d(r0,r1)                        _movr_d(_jit,r0,r1)
+static void _movr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi_d(r0,i0)                        _movi_d(_jit,r0,i0)
+static void _movi_d(jit_state_t*,jit_int32_t,jit_float64_t);
+#  define extr_f_d(r0,r1)              FCVT_DS(r0,r1)
+#  define dccr(cc,r0,r1,r2)            _dccr(_jit,cc,r0,r1,r2)
+static void _dccr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define dcci(cc,r0,r1,i0)            _dcci(_jit,cc,r0,r1,i0)
+static void _dcci(jit_state_t*,
+                 jit_int32_t,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define ltr_d(r0,r1,r2)              dccr(CC_MI,r0,r1,r2)
+#  define lti_d(r0,r1,i0)              dcci(CC_MI,r0,r1,i0)
+#  define ler_d(r0,r1,r2)              dccr(CC_LS,r0,r1,r2)
+#  define lei_d(r0,r1,i0)              dcci(CC_LS,r0,r1,i0)
+#  define eqr_d(r0,r1,r2)              dccr(CC_EQ,r0,r1,r2)
+#  define eqi_d(r0,r1,i0)              dcci(CC_EQ,r0,r1,i0)
+#  define ger_d(r0,r1,r2)              dccr(CC_GE,r0,r1,r2)
+#  define gei_d(r0,r1,i0)              dcci(CC_GE,r0,r1,i0)
+#  define gtr_d(r0,r1,r2)              dccr(CC_GT,r0,r1,r2)
+#  define gti_d(r0,r1,i0)              dcci(CC_GT,r0,r1,i0)
+#  define ner_d(r0,r1,r2)              dccr(CC_NE,r0,r1,r2)
+#  define nei_d(r0,r1,i0)              dcci(CC_NE,r0,r1,i0)
+#  define unltr_d(r0,r1,r2)            dccr(CC_LT,r0,r1,r2)
+#  define unlti_d(r0,r1,i0)            dcci(CC_LT,r0,r1,i0)
+#  define unler_d(r0,r1,r2)            dccr(CC_LE,r0,r1,r2)
+#  define unlei_d(r0,r1,i0)            dcci(CC_LE,r0,r1,i0)
+#  define uneqr_d(r0,r1,r2)            _uneqr_d(_jit,r0,r1,r2)
+static void _uneqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define uneqi_d(r0,r1,i0)            _uneqi_d(_jit,r0,r1,i0)
+static void _uneqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define unger_d(r0,r1,r2)            dccr(CC_PL,r0,r1,r2)
+#  define ungei_d(r0,r1,i0)            dcci(CC_PL,r0,r1,i0)
+#  define ungtr_d(r0,r1,r2)            dccr(CC_HI,r0,r1,r2)
+#  define ungti_d(r0,r1,i0)            dcci(CC_HI,r0,r1,i0)
+#  define ltgtr_d(r0,r1,r2)            _ltgtr_d(_jit,r0,r1,r2)
+static void _ltgtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ltgti_d(r0,r1,i0)            _ltgti_d(_jit,r0,r1,i0)
+static void _ltgti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define ordr_d(r0,r1,r2)             dccr(CC_VC,r0,r1,r2)
+#  define ordi_d(r0,r1,i0)             dcci(CC_VC,r0,r1,i0)
+#  define unordr_d(r0,r1,r2)           dccr(CC_VS,r0,r1,r2)
+#  define unordi_d(r0,r1,i0)           dcci(CC_VS,r0,r1,i0)
+#define dbccr(cc,i0,r0,r1)             _dbccr(_jit,cc,i0,r0,r1)
+static jit_word_t
+_dbccr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#define dbcci(cc,i0,r0,i1)             _dbcci(_jit,cc,i0,r0,i1)
+static jit_word_t
+_dbcci(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bltr_d(i0,r0,r1)             dbccr(BCC_MI,i0,r0,r1)
+#  define blti_d(i0,r0,i1)             dbcci(BCC_MI,i0,r0,i1)
+#  define bler_d(i0,r0,r1)             dbccr(BCC_LS,i0,r0,r1)
+#  define blei_d(i0,r0,i1)             dbcci(BCC_LS,i0,r0,i1)
+#  define beqr_d(i0,r0,r1)             dbccr(BCC_EQ,i0,r0,r1)
+#  define beqi_d(i0,r0,i1)             dbcci(BCC_EQ,i0,r0,i1)
+#  define bger_d(i0,r0,r1)             dbccr(BCC_GE,i0,r0,r1)
+#  define bgei_d(i0,r0,i1)             dbcci(BCC_GE,i0,r0,i1)
+#  define bgtr_d(i0,r0,r1)             dbccr(BCC_GT,i0,r0,r1)
+#  define bgti_d(i0,r0,i1)             dbcci(BCC_GT,i0,r0,i1)
+#  define bner_d(i0,r0,r1)             dbccr(BCC_NE,i0,r0,r1)
+#  define bnei_d(i0,r0,i1)             dbcci(BCC_NE,i0,r0,i1)
+#  define bunltr_d(i0,r0,r1)           dbccr(BCC_LT,i0,r0,r1)
+#  define bunlti_d(i0,r0,i1)           dbcci(BCC_LT,i0,r0,i1)
+#  define bunler_d(i0,r0,r1)           dbccr(BCC_LE,i0,r0,r1)
+#  define bunlei_d(i0,r0,i1)           dbcci(BCC_LE,i0,r0,i1)
+#  define buneqr_d(i0,r0,r1)           _buneqr_d(_jit,i0,r0,r1)
+static jit_word_t _buneqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define buneqi_d(i0,r0,i1)           _buneqi_d(_jit,i0,r0,i1)
+static jit_word_t _buneqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bunger_d(i0,r0,r1)           dbccr(BCC_PL,i0,r0,r1)
+#  define bungei_d(i0,r0,i1)           dbcci(BCC_PL,i0,r0,i1)
+#  define bungtr_d(i0,r0,r1)           dbccr(BCC_HI,i0,r0,r1)
+#  define bungti_d(i0,r0,i1)           dbcci(BCC_HI,i0,r0,i1)
+#  define bltgtr_d(i0,r0,r1)           _bltgtr_d(_jit,i0,r0,r1)
+static jit_word_t _bltgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bltgti_d(i0,r0,i1)           _bltgti_d(_jit,i0,r0,i1)
+static jit_word_t _bltgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bordr_d(i0,r0,r1)            dbccr(BCC_VC,i0,r0,r1)
+#  define bordi_d(i0,r0,i1)            dbcci(BCC_VC,i0,r0,i1)
+#  define bunordr_d(i0,r0,r1)          dbccr(BCC_VS,i0,r0,r1)
+#  define bunordi_d(i0,r0,i1)          dbcci(BCC_VS,i0,r0,i1)
+#  define vaarg_d(r0, r1)              _vaarg_d(_jit, r0, r1)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif
+
+#if CODE
+static void
+_osvvv(jit_state_t *_jit, jit_int32_t Op, jit_int32_t Sz,
+       jit_int32_t Rd, jit_int32_t Rn, jit_int32_t Rm)
+{
+    instr_t    i;
+    assert(!(Rd &       ~0x1f));
+    assert(!(Rn &       ~0x1f));
+    assert(!(Rm &       ~0x1f));
+    assert(!(Sz &        ~0x3));
+    assert(!(Op & ~0xffe0fc00));
+    i.w = Op;
+    i.size.b = Sz;
+    i.Rd.b = Rd;
+    i.Rn.b = Rn;
+    i.Rm.b = Rm;
+    ii(i.w);
+}
+
+static void
+_osvv_(jit_state_t *_jit, jit_int32_t Op,
+       jit_int32_t Sz, jit_int32_t Rd, jit_int32_t Rn)
+{
+    instr_t    i;
+    assert(!(Rd &       ~0x1f));
+    assert(!(Rn &       ~0x1f));
+    assert(!(Sz &        ~0x3));
+    assert(!(Op & ~0xfffffc00));
+    i.w = Op;
+    i.size.b = Sz;
+    i.Rd.b = Rd;
+    i.Rn.b = Rn;
+    ii(i.w);
+}
+
+static void
+_os_vv(jit_state_t *_jit, jit_int32_t Op,
+       jit_int32_t Sz, jit_int32_t Rn, jit_int32_t Rm)
+{
+    instr_t    i;
+    assert(!(Rn &       ~0x1f));
+    assert(!(Rm &       ~0x1f));
+    assert(!(Sz &        ~0x3));
+    assert(!(Op & ~0xff20fc1f));
+    i.w = Op;
+    i.size.b = Sz;
+    i.Rn.b = Rn;
+    i.Rm.b = Rm;
+    ii(i.w);
+}
+
+#define fopi(name)                                                     \
+static void                                                            \
+_##name##i_f(jit_state_t *_jit,                                                \
+            jit_int32_t r0, jit_int32_t r1, jit_float32_t i0)          \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    movi_f(rn(reg), i0);                                               \
+    name##r_f(r0, r1, rn(reg));                                                \
+    jit_unget_reg(reg);                                                        \
+}
+#define dopi(name)                                                     \
+static void                                                            \
+_##name##i_d(jit_state_t *_jit,                                                \
+            jit_int32_t r0, jit_int32_t r1, jit_float64_t i0)          \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    movi_d(rn(reg), i0);                                               \
+    name##r_d(r0, r1, rn(reg));                                                \
+    jit_unget_reg(reg);                                                        \
+}
+#define fbopi(name)                                                    \
+static jit_word_t                                                      \
+_b##name##i_f(jit_state_t *_jit,                                       \
+             jit_word_t i0, jit_int32_t r0, jit_float32_t i1)          \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|                \
+                                         jit_class_nospill);           \
+    movi_f(rn(reg), i1);                                               \
+    word = b##name##r_f(i0, r0, rn(reg));                              \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+#define dbopi(name)                                                    \
+static jit_word_t                                                      \
+_b##name##i_d(jit_state_t *_jit,                                       \
+             jit_word_t i0, jit_int32_t r0, jit_float64_t i1)          \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|                \
+                                         jit_class_nospill);           \
+    movi_d(rn(reg), i1);                                               \
+    word = b##name##r_d(i0, r0, rn(reg));                              \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+
+static void
+_truncr_f_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    FCVTSZ_WS(r0, r1);
+    extr_i(r0, r0);
+}
+
+static void
+_truncr_d_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    FCVTSZ_WD(r0, r1);
+    extr_i(r0, r0);
+}
+
+fopi(add)
+fopi(sub)
+fopi(rsb)
+fopi(mul)
+fopi(div)
+
+static void
+_ldr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    ldr_i(rn(reg), r1);
+    FMOVSW(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    ldi_i(rn(reg), i0);
+    FMOVSW(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    ldxr_i(rn(reg), r1, r2);
+    FMOVSW(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    ldxi_i(rn(reg), r1, i0);
+    FMOVSW(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_str_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    FMOVWS(rn(reg), r1);
+    str_i(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    FMOVWS(rn(reg), r0);
+    sti_i(i0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    FMOVWS(rn(reg), r2);
+    stxr_i(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    FMOVWS(rn(reg), r1);
+    stxi_i(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_movr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       FMOVS(r0, r1);
+}
+
+static void
+_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t i0)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } u;
+    jit_int32_t                reg;
+    u.f = i0;
+    if (u.i == 0)
+       FMOVSW(r0, WZR_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       /* prevent generating unused top 32 bits */
+       movi(rn(reg), ((jit_word_t)u.i) & 0xffffffff);
+       FMOVSW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_fccr(jit_state_t *_jit, jit_int32_t cc,
+      jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPES(r1, r2);
+    CSET(r0, cc);
+}
+
+static void
+_fcci(jit_state_t *_jit, jit_int32_t cc,
+      jit_int32_t r0, jit_int32_t r1, jit_float32_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    movi_f(rn(reg), i0);
+    fccr(cc, r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_uneqr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    FCMPES(r1, r2);
+    CSET(r0, CC_VS);
+    w = _jit->pc.w;
+    B_C(BCC_VS, 1);            /* unordered satisfies condition */
+    CSET(r0, CC_EQ);           /* equal satisfies condition */
+    patch_at(w, _jit->pc.w);
+}
+fopi(uneq)
+
+static void
+_ltgtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    FCMPES(r1, r2);
+    CSET(r0, CC_VC);           /* set to 1 if ordered */
+    w = _jit->pc.w;
+    B_C(BCC_VS, 1);            /* unordered does not satisfy condition */
+    CSET(r0, CC_NE);           /* set to 1 if not equal */
+    patch_at(w, _jit->pc.w);
+}
+fopi(ltgt)
+
+static jit_word_t
+_fbccr(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, d;
+    FCMPES(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) >> 2;
+    B_C(cc, d);
+    return (w);
+}
+
+static jit_word_t
+_fbcci(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_float32_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi_f(rn(reg), i1);
+    w = fbccr(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_buneqr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         u, v, w;
+    FCMPES(r0, r1);
+    u = _jit->pc.w;
+    B_C(BCC_VS, 1);            /* unordered satisfies condition */
+    v = _jit->pc.w;
+    B_C(BCC_NE, 1);            /* not equal (or unordered) does not satisfy */
+    patch_at(u, _jit->pc.w);
+    w = _jit->pc.w;
+    B((i0 - w) >> 2);
+    patch_at(v, _jit->pc.w);
+    return (w);
+}
+fbopi(uneq)
+
+static jit_word_t
+_bltgtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         u, v, w;
+    FCMPES(r0, r1);
+    u = _jit->pc.w;
+    B_C(BCC_VS, 2);            /* jump over if unordered */
+    v = _jit->pc.w;
+    B_C(BCC_EQ, 1);            /* jump over if equal */
+    w = _jit->pc.w;
+    B((i0 - w) >> 2);
+    patch_at(u, _jit->pc.w);
+    patch_at(v, _jit->pc.w);
+    return (w);
+}
+fbopi(ltgt)
+
+dopi(add)
+dopi(sub)
+dopi(rsb)
+dopi(mul)
+dopi(div)
+
+static void
+_ldr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    ldr_l(rn(reg), r1);
+    FMOVDX(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    ldi_l(rn(reg), i0);
+    FMOVDX(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    ldxr_l(rn(reg), r1, r2);
+    FMOVDX(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    ldxi_l(rn(reg), r1, i0);
+    FMOVDX(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_str_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    FMOVXD(rn(reg), r1);
+    str_l(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    FMOVXD(rn(reg), r0);
+    sti_l(i0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    FMOVXD(rn(reg), r2);
+    stxr_l(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    FMOVXD(rn(reg), r1);
+    stxi_l(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       FMOVD(r0, r1);
+}
+
+static void
+_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t i0)
+{
+    union {
+       jit_int64_t     l;
+       jit_float64_t   d;
+    } u;
+    jit_int32_t                reg;
+    u.d = i0;
+    if (u.l == 0)
+       FMOVDX(r0, XZR_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), u.l);
+       FMOVDX(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_dccr(jit_state_t *_jit, jit_int32_t cc,
+      jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPED(r1, r2);
+    CSET(r0, cc);
+}
+
+static void
+_dcci(jit_state_t *_jit, jit_int32_t cc,
+      jit_int32_t r0, jit_int32_t r1, jit_float64_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    movi_d(rn(reg), i0);
+    dccr(cc, r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_uneqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    FCMPED(r1, r2);
+    CSET(r0, CC_VS);
+    w = _jit->pc.w;
+    B_C(BCC_VS, 1);            /* unordered satisfies condition */
+    CSET(r0, CC_EQ);           /* equal satisfies condition */
+    patch_at(w, _jit->pc.w);
+}
+dopi(uneq)
+
+static void
+_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    FCMPED(r1, r2);
+    CSET(r0, CC_VC);           /* set to 1 if ordered */
+    w = _jit->pc.w;
+    B_C(BCC_VS, 1);            /* unordered does not satisfy condition */
+    CSET(r0, CC_NE);           /* set to 1 if not equal */
+    patch_at(w, _jit->pc.w);
+}
+dopi(ltgt)
+
+static jit_word_t
+_dbccr(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, d;
+    FCMPED(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) >> 2;
+    B_C(cc, d);
+    return (w);
+}
+
+static jit_word_t
+_dbcci(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_float64_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi_d(rn(reg), i1);
+    w = dbccr(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_buneqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         u, v, w;
+    FCMPED(r0, r1);
+    u = _jit->pc.w;
+    B_C(BCC_VS, 1);            /* unordered satisfies condition */
+    v = _jit->pc.w;
+    B_C(BCC_NE, 1);            /* not equal (or unordered) does not satisfy */
+    patch_at(u, _jit->pc.w);
+    w = _jit->pc.w;
+    B((i0 - w) >> 2);
+    patch_at(v, _jit->pc.w);
+    return (w);
+}
+dbopi(uneq)
+
+static jit_word_t
+_bltgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         u, v, w;
+    FCMPED(r0, r1);
+    u = _jit->pc.w;
+    B_C(BCC_VS, 2);            /* jump over if unordered */
+    v = _jit->pc.w;
+    B_C(BCC_EQ, 1);            /* jump over if equal */
+    w = _jit->pc.w;
+    B((i0 - w) >> 2);
+    patch_at(u, _jit->pc.w);
+    patch_at(v, _jit->pc.w);
+    return (w);
+}
+dbopi(ltgt)
+
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         ge_code;
+    jit_word_t         lt_code;
+    jit_int32_t                rg0, rg1;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg(jit_class_gpr);
+    rg1 = jit_get_reg(jit_class_gpr);
+
+    /* Load the fp offset in save area in the first temporary. */
+    ldxi_i(rn(rg0), r1, offsetof(jit_va_list_t, fpoff));
+
+    /* Jump over if there are no remaining arguments in the save area. */
+    ge_code = bgei(_jit->pc.w, rn(rg0), 0);
+
+    /* Load the gp save pointer in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, fptop));
+
+    /* Load the vararg argument in the first argument. */
+    ldxr_d(r0, rn(rg1), rn(rg0));
+
+    /* Update the fp offset. */
+    addi(rn(rg0), rn(rg0), 16);
+    stxi_i(offsetof(jit_va_list_t, fpoff), r1, rn(rg0));
+
+    /* Will only need one temporary register below. */
+    jit_unget_reg(rg1);
+
+    /* Jump over overflow code. */
+    lt_code = jmpi_p(_jit->pc.w);
+
+    /* Where to land if argument is in overflow area. */
+    patch_at(ge_code, _jit->pc.w);
+
+    /* Load stack pointer. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, stack));
+
+    /* Load argument. */
+    ldr_d(r0, rn(rg0));
+
+    /* Update stack pointer. */
+    addi(rn(rg0), rn(rg0), 8);
+    stxi(offsetof(jit_va_list_t, stack), r1, rn(rg0));
+
+    /* Where to land if argument is in gp save area. */
+    patch_at(lt_code, _jit->pc.w);
+
+    jit_unget_reg(rg0);
+}
+#endif
diff --git a/deps/lightning/lib/jit_aarch64-sz.c b/deps/lightning/lib/jit_aarch64-sz.c
new file mode 100644 (file)
index 0000000..7e22e0e
--- /dev/null
@@ -0,0 +1,402 @@
+
+#if __WORDSIZE == 64
+#define JIT_INSTR_MAX 120
+    0, /* data */
+    0, /* live */
+    4, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    120,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    44,        /* va_start */
+    64,        /* va_arg */
+    72,        /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    20,        /* addi */
+    4, /* addcr */
+    12,        /* addci */
+    4, /* addxr */
+    8, /* addxi */
+    4, /* subr */
+    20,        /* subi */
+    4, /* subcr */
+    12,        /* subci */
+    4, /* subxr */
+    8, /* subxi */
+    24,        /* rsbi */
+    4, /* mulr */
+    20,        /* muli */
+    12,        /* qmulr */
+    20,        /* qmuli */
+    12,        /* qmulr_u */
+    20,        /* qmuli_u */
+    4, /* divr */
+    20,        /* divi */
+    4, /* divr_u */
+    12,        /* divi_u */
+    20,        /* qdivr */
+    16,        /* qdivi */
+    20,        /* qdivr_u */
+    16,        /* qdivi_u */
+    12,        /* remr */
+    28,        /* remi */
+    12,        /* remr_u */
+    20,        /* remi_u */
+    4, /* andr */
+    20,        /* andi */
+    4, /* orr */
+    20,        /* ori */
+    4, /* xorr */
+    20,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    8, /* ltr */
+    8, /* lti */
+    8, /* ltr_u */
+    8, /* lti_u */
+    8, /* ler */
+    8, /* lei */
+    8, /* ler_u */
+    8, /* lei_u */
+    8, /* eqr */
+    8, /* eqi */
+    8, /* ger */
+    8, /* gei */
+    8, /* ger_u */
+    8, /* gei_u */
+    8, /* gtr */
+    8, /* gti */
+    8, /* gtr_u */
+    8, /* gti_u */
+    8, /* ner */
+    8, /* nei */
+    4, /* movr */
+    16,        /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    4, /* extr_i */
+    4, /* extr_ui */
+    8, /* htonr_us */
+    8, /* htonr_ui */
+    4, /* htonr_ul */
+    4, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    12,        /* ldi_uc */
+    4, /* ldr_s */
+    12,        /* ldi_s */
+    4, /* ldr_us */
+    12,        /* ldi_us */
+    4, /* ldr_i */
+    12,        /* ldi_i */
+    4, /* ldr_ui */
+    12,        /* ldi_ui */
+    4, /* ldr_l */
+    12,        /* ldi_l */
+    8, /* ldxr_c */
+    20,        /* ldxi_c */
+    4, /* ldxr_uc */
+    20,        /* ldxi_uc */
+    4, /* ldxr_s */
+    16,        /* ldxi_s */
+    4, /* ldxr_us */
+    16,        /* ldxi_us */
+    4, /* ldxr_i */
+    20,        /* ldxi_i */
+    4, /* ldxr_ui */
+    16,        /* ldxi_ui */
+    4, /* ldxr_l */
+    20,        /* ldxi_l */
+    4, /* str_c */
+    12,        /* sti_c */
+    4, /* str_s */
+    12,        /* sti_s */
+    4, /* str_i */
+    12,        /* sti_i */
+    4, /* str_l */
+    12,        /* sti_l */
+    4, /* stxr_c */
+    20,        /* stxi_c */
+    4, /* stxr_s */
+    20,        /* stxi_s */
+    4, /* stxr_i */
+    20,        /* stxi_i */
+    4, /* stxr_l */
+    20,        /* stxi_l */
+    8, /* bltr */
+    8, /* blti */
+    8, /* bltr_u */
+    8, /* blti_u */
+    8, /* bler */
+    8, /* blei */
+    8, /* bler_u */
+    8, /* blei_u */
+    8, /* beqr */
+    24,        /* beqi */
+    8, /* bger */
+    8, /* bgei */
+    8, /* bger_u */
+    8, /* bgei_u */
+    8, /* bgtr */
+    8, /* bgti */
+    8, /* bgtr_u */
+    8, /* bgti_u */
+    8, /* bner */
+    24,        /* bnei */
+    8, /* bmsr */
+    8, /* bmsi */
+    8, /* bmcr */
+    8, /* bmci */
+    8, /* boaddr */
+    8, /* boaddi */
+    8, /* boaddr_u */
+    8, /* boaddi_u */
+    8, /* bxaddr */
+    8, /* bxaddi */
+    8, /* bxaddr_u */
+    8, /* bxaddi_u */
+    8, /* bosubr */
+    8, /* bosubi */
+    8, /* bosubr_u */
+    8, /* bosubi_u */
+    8, /* bxsubr */
+    8, /* bxsubi */
+    8, /* bxsubr_u */
+    8, /* bxsubi_u */
+    4, /* jmpr */
+    20,        /* jmpi */
+    4, /* callr */
+    20,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    96,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    12,        /* addi_f */
+    4, /* subr_f */
+    12,        /* subi_f */
+    12,        /* rsbi_f */
+    4, /* mulr_f */
+    12,        /* muli_f */
+    4, /* divr_f */
+    12,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    8, /* ltr_f */
+    16,        /* lti_f */
+    8, /* ler_f */
+    16,        /* lei_f */
+    8, /* eqr_f */
+    16,        /* eqi_f */
+    8, /* ger_f */
+    16,        /* gei_f */
+    8, /* gtr_f */
+    16,        /* gti_f */
+    8, /* ner_f */
+    16,        /* nei_f */
+    8, /* unltr_f */
+    16,        /* unlti_f */
+    8, /* unler_f */
+    16,        /* unlei_f */
+    16,        /* uneqr_f */
+    24,        /* uneqi_f */
+    8, /* unger_f */
+    16,        /* ungei_f */
+    8, /* ungtr_f */
+    16,        /* ungti_f */
+    16,        /* ltgtr_f */
+    24,        /* ltgti_f */
+    8, /* ordr_f */
+    16,        /* ordi_f */
+    8, /* unordr_f */
+    16,        /* unordi_f */
+    8, /* truncr_f_i */
+    4, /* truncr_f_l */
+    4, /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    8, /* movi_f */
+    8, /* ldr_f */
+    16,        /* ldi_f */
+    8, /* ldxr_f */
+    24,        /* ldxi_f */
+    8, /* str_f */
+    16,        /* sti_f */
+    8, /* stxr_f */
+    24,        /* stxi_f */
+    8, /* bltr_f */
+    16,        /* blti_f */
+    8, /* bler_f */
+    16,        /* blei_f */
+    8, /* beqr_f */
+    16,        /* beqi_f */
+    8, /* bger_f */
+    16,        /* bgei_f */
+    8, /* bgtr_f */
+    16,        /* bgti_f */
+    8, /* bner_f */
+    16,        /* bnei_f */
+    8, /* bunltr_f */
+    16,        /* bunlti_f */
+    8, /* bunler_f */
+    16,        /* bunlei_f */
+    16,        /* buneqr_f */
+    24,        /* buneqi_f */
+    8, /* bunger_f */
+    16,        /* bungei_f */
+    8, /* bungtr_f */
+    16,        /* bungti_f */
+    16,        /* bltgtr_f */
+    24,        /* bltgti_f */
+    8, /* bordr_f */
+    16,        /* bordi_f */
+    8, /* bunordr_f */
+    16,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    12,        /* addi_d */
+    4, /* subr_d */
+    12,        /* subi_d */
+    12,        /* rsbi_d */
+    4, /* mulr_d */
+    12,        /* muli_d */
+    4, /* divr_d */
+    12,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    8, /* ltr_d */
+    16,        /* lti_d */
+    8, /* ler_d */
+    16,        /* lei_d */
+    8, /* eqr_d */
+    16,        /* eqi_d */
+    8, /* ger_d */
+    16,        /* gei_d */
+    8, /* gtr_d */
+    16,        /* gti_d */
+    8, /* ner_d */
+    16,        /* nei_d */
+    8, /* unltr_d */
+    16,        /* unlti_d */
+    8, /* unler_d */
+    16,        /* unlei_d */
+    16,        /* uneqr_d */
+    24,        /* uneqi_d */
+    8, /* unger_d */
+    16,        /* ungei_d */
+    8, /* ungtr_d */
+    16,        /* ungti_d */
+    16,        /* ltgtr_d */
+    24,        /* ltgti_d */
+    8, /* ordr_d */
+    16,        /* ordi_d */
+    8, /* unordr_d */
+    16,        /* unordi_d */
+    8, /* truncr_d_i */
+    4, /* truncr_d_l */
+    4, /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    12,        /* movi_d */
+    8, /* ldr_d */
+    16,        /* ldi_d */
+    8, /* ldxr_d */
+    24,        /* ldxi_d */
+    8, /* str_d */
+    16,        /* sti_d */
+    8, /* stxr_d */
+    24,        /* stxi_d */
+    8, /* bltr_d */
+    16,        /* blti_d */
+    8, /* bler_d */
+    16,        /* blei_d */
+    8, /* beqr_d */
+    20,        /* beqi_d */
+    8, /* bger_d */
+    16,        /* bgei_d */
+    8, /* bgtr_d */
+    16,        /* bgti_d */
+    8, /* bner_d */
+    16,        /* bnei_d */
+    8, /* bunltr_d */
+    16,        /* bunlti_d */
+    8, /* bunler_d */
+    16,        /* bunlei_d */
+    16,        /* buneqr_d */
+    24,        /* buneqi_d */
+    8, /* bunger_d */
+    16,        /* bungei_d */
+    8, /* bungtr_d */
+    16,        /* bungti_d */
+    16,        /* bltgtr_d */
+    24,        /* bltgti_d */
+    8, /* bordr_d */
+    16,        /* bordi_d */
+    8, /* bunordr_d */
+    16,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_aarch64.c b/deps/lightning/lib/jit_aarch64.c
new file mode 100644 (file)
index 0000000..5b2ff49
--- /dev/null
@@ -0,0 +1,1582 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#define jit_arg_reg_p(i)               ((i) >= 0 && (i) < 8)
+#define jit_arg_f_reg_p(i)             ((i) >= 0 && (i) < 8)
+
+typedef struct jit_qreg {
+    jit_float64_t      l;
+    jit_float64_t      h;
+} jit_qreg_t;
+
+#define va_gp_top_offset               offsetof(jit_va_list_t, q0)
+#define va_fp_top_offset               sizeof(jit_va_list_t)
+typedef struct jit_va_list {
+    jit_pointer_t      stack;
+    jit_pointer_t      gptop;
+    jit_pointer_t      fptop;
+    jit_int32_t                gpoff;
+    jit_int32_t                fpoff;
+
+    jit_int64_t                x0;
+    jit_int64_t                x1;
+    jit_int64_t                x2;
+    jit_int64_t                x3;
+    jit_int64_t                x4;
+    jit_int64_t                x5;
+    jit_int64_t                x6;
+    jit_int64_t                x7;
+
+    jit_qreg_t         q0;
+    jit_qreg_t         q1;
+    jit_qreg_t         q2;
+    jit_qreg_t         q3;
+    jit_qreg_t         q4;
+    jit_qreg_t         q5;
+    jit_qreg_t         q6;
+    jit_qreg_t         q7;
+} jit_va_list_t;
+
+/*
+ * Prototypes
+ */
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+/* libgcc */
+extern void __clear_cache(void *, void *);
+
+#define PROTO                          1
+#  include "jit_aarch64-cpu.c"
+#  include "jit_aarch64-fpu.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_register_t         _rvs[] = {
+    { rc(gpr) | 0x08,                  "x8" },
+    { rc(gpr) | 0x12,                  "x18" },
+    { rc(gpr) | 0x11,                  "x17" },
+    { rc(gpr) | 0x10,                  "x16" },
+    { rc(gpr) | 0x09,                  "x9" },
+    { rc(gpr) | 0x0a,                  "x10" },
+    { rc(gpr) | 0x0b,                  "x11" },
+    { rc(gpr) | 0x0c,                  "x12" },
+    { rc(gpr) | 0x0d,                  "x13" },
+    { rc(gpr) | 0x0e,                  "x14" },
+    { rc(gpr) | 0x0f,                  "x15" },
+    { rc(sav) | rc(gpr) | 0x13,                "x19" },
+    { rc(sav) | rc(gpr) | 0x14,                "x20" },
+    { rc(sav) | rc(gpr) | 0x15,                "x21" },
+    { rc(sav) | rc(gpr) | 0x16,                "x22" },
+    { rc(sav) | rc(gpr) | 0x17,                "x23" },
+    { rc(sav) | rc(gpr) | 0x18,                "x24" },
+    { rc(sav) | rc(gpr) | 0x19,                "x25" },
+    { rc(sav) | rc(gpr) | 0x1a,                "x26" },
+    { rc(sav) | rc(gpr) | 0x1b,                "x27" },
+    { rc(sav) | rc(gpr) | 0x1c,                "x28" },
+    { 0x1f,                            "sp" },
+    { 0x1e,                            "lr" },
+    { 0x1d,                            "fp" },
+    { rc(arg) | rc(gpr) | 0x07,                "x7" },
+    { rc(arg) | rc(gpr) | 0x06,                "x6" },
+    { rc(arg) | rc(gpr) | 0x05,                "x5" },
+    { rc(arg) | rc(gpr) | 0x04,                "x4" },
+    { rc(arg) | rc(gpr) | 0x03,                "x3" },
+    { rc(arg) | rc(gpr) | 0x02,                "x2" },
+    { rc(arg) | rc(gpr) | 0x01,                "x1" },
+    { rc(arg) | rc(gpr) | 0x00,                "x0" },
+    { rc(fpr) | 0x1f,                  "v31" },
+    { rc(fpr) | 0x1e,                  "v30" },
+    { rc(fpr) | 0x1d,                  "v29" },
+    { rc(fpr) | 0x1c,                  "v28" },
+    { rc(fpr) | 0x1b,                  "v27" },
+    { rc(fpr) | 0x1a,                  "v26" },
+    { rc(fpr) | 0x19,                  "v25" },
+    { rc(fpr) | 0x18,                  "v24" },
+    { rc(fpr) | 0x17,                  "v23" },
+    { rc(fpr) | 0x16,                  "v22" },
+    { rc(fpr) | 0x15,                  "v21" },
+    { rc(fpr) | 0x14,                  "v20" },
+    { rc(fpr) | 0x13,                  "v19" },
+    { rc(fpr) | 0x12,                  "v18" },
+    { rc(fpr) | 0x11,                  "v17" },
+    { rc(fpr) | 0x10,                  "v16" },
+    { rc(sav) | rc(fpr) | 0x08,                "v8" },
+    { rc(sav) | rc(fpr) | 0x09,                "v9" },
+    { rc(sav) | rc(fpr) | 0x0a,                "v10" },
+    { rc(sav) | rc(fpr) | 0x0b,                "v11" },
+    { rc(sav) | rc(fpr) | 0x0c,                "v12" },
+    { rc(sav) | rc(fpr) | 0x0d,                "v13" },
+    { rc(sav) | rc(fpr) | 0x0e,                "v14" },
+    { rc(sav) | rc(fpr) | 0x0f,                "v15" },
+    { rc(arg) | rc(fpr) | 0x07,                "v7" },
+    { rc(arg) | rc(fpr) | 0x06,                "v6" },
+    { rc(arg) | rc(fpr) | 0x05,                "v5" },
+    { rc(arg) | rc(fpr) | 0x04,                "v4" },
+    { rc(arg) | rc(fpr) | 0x03,                "v3" },
+    { rc(arg) | rc(fpr) | 0x02,                "v2" },
+    { rc(arg) | rc(fpr) | 0x01,                "v1" },
+    { rc(arg) | rc(fpr) | 0x00,                "v0" },
+    { _NOREG,                          "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    _jitc->reglen = jit_size(_rvs) - 1;
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                 offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = stack_framesize;
+    _jitc->function->self.argi = _jitc->function->self.argf =
+       _jitc->function->self.alen = 0;
+    _jitc->function->self.aoff = 0;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    return (_jitc->function->self.aoff);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 r0, r1;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    r0 = jit_get_reg(jit_class_gpr);
+    jit_negr(r0, v);
+    jit_andi(r0, r0, -16);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, r0);
+    /* Cannot "addr sp, sp, reg" because in this context "sp" is "[w|x]zr",
+     * the zero register */
+#if 0
+    jit_addr(JIT_SP, JIT_SP, r0);
+#else
+    r1 = jit_get_reg(jit_class_gpr);
+    /* note that "mov r1, sp" does not work, but the proper encoding
+     * can be triggered before actually emiting with "add r1, sp, 0" */
+    jit_addi(r1, JIT_SP, 0);
+    jit_addr(r1, r1, r0);
+    jit_addi(JIT_SP, r1, 0);
+    jit_unget_reg(r1);
+#endif
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(r0);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    if (JIT_RET != u)
+       jit_movr(JIT_RET, u);
+    jit_live(JIT_RET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    if (u != JIT_FRET)
+       jit_movr_f(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    if (u != JIT_FRET)
+       jit_movr_d(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    if (u->code == jit_code_arg)
+       return (jit_arg_reg_p(u->u.w));
+    assert(u->code == jit_code_arg_f || u->code == jit_code_arg_d);
+    return (jit_arg_f_reg_p(u->u.w));
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare) {
+       jit_link_prepare();
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+    }
+    else {
+       jit_link_prolog();
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+
+       /* Allocate va_list like object in the stack,
+        * with enough space to save all argument
+        * registers, and use fixed offsets for them. */
+       _jitc->function->vaoff = jit_allocai(sizeof(jit_va_list_t));
+
+       /* Initialize gp offset in save area. */
+       if (jit_arg_reg_p(_jitc->function->self.argi))
+           _jitc->function->vagp = (8 - _jitc->function->self.argi) * -8;
+       else
+           _jitc->function->vagp = 0;
+
+       /* Initialize fp offset in save area. */
+       if (jit_arg_f_reg_p(_jitc->function->self.argf))
+           _jitc->function->vafp = (8 - _jitc->function->self.argf) * -16;
+       else
+           _jitc->function->vafp = 0;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    assert(!(_jitc->function->self.call & jit_call_varargs));
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    assert(!(_jitc->function->self.call & jit_call_varargs));
+    if (jit_arg_f_reg_p(_jitc->function->self.argf))
+       offset = _jitc->function->self.argf++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg_f, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    assert(!(_jitc->function->self.call & jit_call_varargs));
+    if (jit_arg_f_reg_p(_jitc->function->self.argf))
+       offset = _jitc->function->self.argf++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg_d, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_c(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_uc(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_s(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_us(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_i(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_i(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_ui, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_ui(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_ui(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_l, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_l(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(JIT_RA0 - v->u.w, u);
+    else
+       jit_stxi(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi(JIT_RA0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_f(u, JIT_FA0 - v->u.w);
+    else
+       jit_ldxi_f(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_f(JIT_FA0 - v->u.w, u);
+    else
+       jit_stxi_f(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movi_f(JIT_FA0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(u, JIT_FA0 - v->u.w);
+    else
+       jit_ldxi_d(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_d(JIT_FA0 - v->u.w, u);
+    else
+       jit_stxi_d(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi_d(JIT_FA0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movr_f(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movi_f(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movr_d(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else {
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movi_d(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_int32_t                spec;
+    spec = jit_class(_rvs[regno].spec);
+    if (spec & jit_class_arg) {
+       regno = JIT_RA0 - regno;
+       if (regno >= 0 && regno < node->v.w)
+           return (1);
+       if (spec & jit_class_fpr) {
+           regno = JIT_FA0 - regno;
+           if (regno >= 0 && regno < node->w.w)
+               return (1);
+       }
+    }
+
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_callr(r0);
+    node->v.w = _jitc->function->self.argi;
+    node->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_calli(i0);
+    node->v.w = _jitc->function->call.argi;
+    node->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_c, r0);
+    jit_extr_c(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_uc, r0);
+    jit_extr_uc(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_s, r0);
+    jit_extr_s(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_us, r0);
+    jit_extr_us(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+    jit_extr_i(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_ui, r0);
+    jit_extr_ui(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_l, r0);
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_f, r0);
+    if (r0 != JIT_FRET)
+       jit_movr_f(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_d, r0);
+    if (r0 != JIT_FRET)
+       jit_movr_d(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_word_t          value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_uint8_t     *data;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_int32_t      const_offset;
+       jit_int32_t      patch_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.const_offset = undo.patch_offset = 0;
+#  define assert_data(node)            /**/
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_rrf(name)                                                 \
+           case jit_code_##name##i_f:                                  \
+               assert_data(node);                                      \
+               name##i_f(rn(node->u.w), rn(node->v.w), node->w.f);     \
+               break
+#define case_rrd(name)                                                 \
+           case jit_code_##name##i_d:                                  \
+               assert_data(node);                                      \
+               name##i_d(rn(node->u.w), rn(node->v.w), node->w.d);     \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break;
+#define case_brf(name)                                                 \
+           case jit_code_##name##i_f:                                  \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i_f(temp->u.w, rn(node->v.w), node->w.f);     \
+               else {                                                  \
+                   word = name##i_f(_jit->pc.w, rn(node->v.w),         \
+                                    node->w.f);                        \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brd(name)                                                 \
+           case jit_code_##name##i_d:                                  \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i_d(temp->u.w, rn(node->v.w), node->w.d);     \
+               else {                                                  \
+                   word = name##i_d(_jit->pc.w, rn(node->v.w),         \
+                                    node->w.d);                        \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if (node->u.w == sizeof(jit_word_t) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rr(neg,);
+               case_rr(com,);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rr(trunc, _f_i);
+               case_rr(trunc, _d_i);
+               case_rr(trunc, _f_l);
+               case_rr(trunc, _d_l);
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+               case_rr(ld, _ui);
+               case_rw(ld, _ui);
+               case_rr(ld, _l);
+               case_rw(ld, _l);
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+               case_rrr(ldx, _ui);
+               case_rrw(ldx, _ui);
+               case_rrr(ldx, _l);
+               case_rrw(ldx, _l);
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+               case_rr(st, _l);
+               case_wr(st, _l);
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+               case_rrr(stx, _l);
+               case_wrr(stx, _l);
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+               case_rr(hton, _ul);
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+               case_rr(ext, _i);
+               case_rr(ext, _ui);
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), temp->u.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_rrr(add, _f);
+               case_rrf(add);
+               case_rrr(sub, _f);
+               case_rrf(sub);
+               case_rrf(rsb);
+               case_rrr(mul, _f);
+               case_rrf(mul);
+               case_rrr(div, _f);
+               case_rrf(div);
+               case_rr(abs, _f);
+               case_rr(neg, _f);
+               case_rr(sqrt, _f);
+               case_rr(ext, _f);
+               case_rr(ld, _f);
+               case_rw(ld, _f);
+               case_rrr(ldx, _f);
+               case_rrw(ldx, _f);
+               case_rr(st, _f);
+               case_wr(st, _f);
+               case_rrr(stx, _f);
+               case_wrr(stx, _f);
+               case_rr(mov, _f);
+           case jit_code_movi_f:
+               assert_data(node);
+               movi_f(rn(node->u.w), node->v.f);
+               break;
+               case_rr(ext, _d_f);
+               case_rrr(lt, _f);
+               case_rrf(lt);
+               case_rrr(le, _f);
+               case_rrf(le);
+               case_rrr(eq, _f);
+               case_rrf(eq);
+               case_rrr(ge, _f);
+               case_rrf(ge);
+               case_rrr(gt, _f);
+               case_rrf(gt);
+               case_rrr(ne, _f);
+               case_rrf(ne);
+               case_rrr(unlt, _f);
+               case_rrf(unlt);
+               case_rrr(unle, _f);
+               case_rrf(unle);
+               case_rrr(uneq, _f);
+               case_rrf(uneq);
+               case_rrr(unge, _f);
+               case_rrf(unge);
+               case_rrr(ungt, _f);
+               case_rrf(ungt);
+               case_rrr(ltgt, _f);
+               case_rrf(ltgt);
+               case_rrr(ord, _f);
+               case_rrf(ord);
+               case_rrr(unord, _f);
+               case_rrf(unord);
+               case_brr(blt, _f);
+               case_brf(blt);
+               case_brr(ble, _f);
+               case_brf(ble);
+               case_brr(beq, _f);
+               case_brf(beq);
+               case_brr(bge, _f);
+               case_brf(bge);
+               case_brr(bgt, _f);
+               case_brf(bgt);
+               case_brr(bne, _f);
+               case_brf(bne);
+               case_brr(bunlt, _f);
+               case_brf(bunlt);
+               case_brr(bunle, _f);
+               case_brf(bunle);
+               case_brr(buneq, _f);
+               case_brf(buneq);
+               case_brr(bunge, _f);
+               case_brf(bunge);
+               case_brr(bungt, _f);
+               case_brf(bungt);
+               case_brr(bltgt, _f);
+               case_brf(bltgt);
+               case_brr(bord, _f);
+               case_brf(bord);
+               case_brr(bunord, _f);
+               case_brf(bunord);
+               case_rrr(add, _d);
+               case_rrd(add);
+               case_rrr(sub, _d);
+               case_rrd(sub);
+               case_rrd(rsb);
+               case_rrr(mul, _d);
+               case_rrd(mul);
+               case_rrr(div, _d);
+               case_rrd(div);
+               case_rr(abs, _d);
+               case_rr(neg, _d);
+               case_rr(sqrt, _d);
+               case_rr(ext, _d);
+               case_rr(ld, _d);
+               case_rw(ld, _d);
+               case_rrr(ldx, _d);
+               case_rrw(ldx, _d);
+               case_rr(st, _d);
+               case_wr(st, _d);
+               case_rrr(stx, _d);
+               case_wrr(stx, _d);
+               case_rr(mov, _d);
+           case jit_code_movi_d:
+               assert_data(node);
+               movi_d(rn(node->u.w), node->v.d);
+               break;
+               case_rr(ext, _f_d);
+               case_rrr(lt, _d);
+               case_rrd(lt);
+               case_rrr(le, _d);
+               case_rrd(le);
+               case_rrr(eq, _d);
+               case_rrd(eq);
+               case_rrr(ge, _d);
+               case_rrd(ge);
+               case_rrr(gt, _d);
+               case_rrd(gt);
+               case_rrr(ne, _d);
+               case_rrd(ne);
+               case_rrr(unlt, _d);
+               case_rrd(unlt);
+               case_rrr(unle, _d);
+               case_rrd(unle);
+               case_rrr(uneq, _d);
+               case_rrd(uneq);
+               case_rrr(unge, _d);
+               case_rrd(unge);
+               case_rrr(ungt, _d);
+               case_rrd(ungt);
+               case_rrr(ltgt, _d);
+               case_rrd(ltgt);
+               case_rrr(ord, _d);
+               case_rrd(ord);
+               case_rrr(unord, _d);
+               case_rrd(unord);
+               case_brr(blt, _d);
+               case_brd(blt);
+               case_brr(ble, _d);
+               case_brd(ble);
+               case_brr(beq, _d);
+               case_brd(beq);
+               case_brr(bge, _d);
+               case_brd(bge);
+               case_brr(bgt, _d);
+               case_brd(bgt);
+               case_brr(bne, _d);
+               case_brd(bne);
+               case_brr(bunlt, _d);
+               case_brd(bunlt);
+               case_brr(bunle, _d);
+               case_brd(bunle);
+               case_brr(buneq, _d);
+               case_brd(buneq);
+               case_brr(bunge, _d);
+               case_brd(bunge);
+               case_brr(bungt, _d);
+               case_brd(bungt);
+               case_brr(bltgt, _d);
+               case_brd(bltgt);
+               case_brr(bord, _d);
+               case_brd(bord);
+               case_brr(bunord, _d);
+               case_brd(bunord);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       calli(temp->u.w);
+                   else {
+                       word = calli_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+           restart_function:
+               _jitc->again = 0;
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+                   goto restart_function;
+               }
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:                 case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:             case jit_code_getarg_ui:
+           case jit_code_getarg_l:
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+           case jit_code_retval_ui:            case jit_code_retval_l:
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           default:
+               abort();
+       }
+       jit_regarg_clr(node, value);
+       assert(_jitc->regarg == 0 && _jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+    }
+#undef case_brw
+#undef case_brr
+#undef case_wrr
+#undef case_rrw
+#undef case_rrr
+#undef case_wr
+#undef case_rw
+#undef case_rr
+
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = _jitc->patches.ptr[offset].inst;
+       value = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(word, value);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_aarch64-cpu.c"
+#  include "jit_aarch64-fpu.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+#if defined(__GNUC__)
+    jit_word_t         f, t, s;
+
+    s = sysconf(_SC_PAGE_SIZE);
+    f = (jit_word_t)fptr & -s;
+    t = (((jit_word_t)tptr) + s - 1) & -s;
+    __clear_cache((void *)f, (void *)t);
+#endif
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi(i0, rn(r0), rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi_d(i0, rn(r0), rn(r1));
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                 flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+    assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_alpha-cpu.c b/deps/lightning/lib/jit_alpha-cpu.c
new file mode 100644 (file)
index 0000000..8bfef9c
--- /dev/null
@@ -0,0 +1,2792 @@
+/*
+ * Copyright (C) 2014-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  define _u2(v)                       ((v) & 0x3)
+#  define _s2_p(v)                     ((v) >= -0x2 && (v) <= 0x1)
+#  define _u2_p(v)                     ((v) >= 0 && (v) <= 0x3)
+#  define _u5(v)                       ((v) & 0x1f)
+#  define _s5_p(v)                     ((v) >= -0x10 && (v) <= 0xf)
+#  define _u5_p(v)                     ((v) >= 0 && (v) <= 0x1f)
+#  define _u6(v)                       ((v) & 0x3f)
+#  define _s6_p(v)                     ((v) >= -0x20 && (v) <= 0x1f)
+#  define _u6_p(v)                     ((v) >= 0 && (v) <= 0x3f)
+#  define _u7(v)                       ((v) & 0x7f)
+#  define _s7_p(v)                     ((v) >= -0x40 && (v) <= 0x3f)
+#  define _u7_p(v)                     ((v) >= 0 && (v) <= 0x7f)
+#  define _u8(v)                       ((v) & 0xff)
+#  define _s8_p(v)                     ((v) >= -0x80 && (v) <= 0x7f)
+#  define _u8_p(v)                     ((v) >= 0 && (v) <= 0xff)
+#  define _u11(v)                      ((v) & 0x7ff)
+#  define _s11_p(v)                    ((v) >= -0x400 && (v) <= 0x3ff)
+#  define _u11_p(v)                    ((v) >= 0 && (v) <= 0x7ff)
+#  define _u14(v)                      ((v) & 0x3fff)
+#  define _s14_p(v)                    ((v) >= -0x2000 && (v) <= 0x1fff)
+#  define _u14_p(v)                    ((v) >= 0 && (v) <= 0x3fff)
+#  define _u16(v)                      ((v) & 0xffff)
+#  define _s16_p(v)                    ((v) >= -0x8000 && (v) <= 0x7fff)
+#  define _u16_p(v)                    ((v) >= 0 && (v) <= 0xffff)
+#  define _u21(v)                      ((v) & 0x1fffff)
+#  define _s21_p(v)                    ((v) >= -0x100000 && (v) <= 0xfffff)
+#  define _u21_p(v)                    ((v) >= 0 && (v) <= 0x1fffff)
+#  define _u26(v)                      ((v) & 0x3ffffff)
+#  define _s26_p(v)                    ((v) >= -0x2000000 && (v) <= 0x1ffffff)
+#  define _u26_p(v)                    ((v) >= 0 && (v) <= 0x3ffffff)
+#  define _u32(v)                      ((v) & 0xffffffff)
+#  define _s32_p(v)                    ((v) >= -0x80000000 && (v) <= 0x7fffffff)
+#  define _u32_p(v)                    ((v) >= 0 && (v) <= 0xffffffff)
+#  define ii(i)                                *_jit->pc.ui++ = i
+#  define stack_framesize              224
+#  define _S0_REGNO                    0x09
+#  define _S1_REGNO                    0x0a
+#  define _S2_REGNO                    0x0b
+#  define _S3_REGNO                    0x0c
+#  define _S4_REGNO                    0x0d
+#  define _S5_REGNO                    0x0e
+#  define _FP_REGNO                    0x0f
+#  define _A0_REGNO                    0x10
+#  define _A1_REGNO                    0x11
+#  define _A2_REGNO                    0x12
+#  define _V0_REGNO                    0x00
+#  define _T0_REGNO                    0x01
+#  define _T1_REGNO                    0x02
+#  define _RA_REGNO                    0x1a
+#  define _PV_REGNO                    0x1b
+#  define _GP_REGNO                    0x1d
+#  define _SP_REGNO                    0x1e
+#  define _R31_REGNO                   0x1f
+#  define Pcd(o,n)                     _Pcd(_jit,o,n)
+static void _Pcd(jit_state_t*,int,unsigned int) maybe_unused;
+#  define Bra(o,ra,d)                  _Bra(_jit,o,ra,d)
+static void _Bra(jit_state_t*,int,int,int);
+#  define Mem(o,ra,rb,d)                       _Mem(_jit,o,ra,rb,d)
+static void _Mem(jit_state_t*,int,int,int,unsigned int);
+#  define Mbr(o,ra,rb,h,d)             _Mbr(_jit,o,ra,rb,h,d)
+static void _Mbr(jit_state_t*,int,int,int,int,int);
+#  define Opr(o,ra,rb,f,rc)            _Opr(_jit,o,ra,rb,f,rc)
+static void _Opr(jit_state_t*,int,int,int,unsigned int,int);
+#  define Opi(o,ra,i,f,rc)             _Opi(_jit,o,ra,i,f,rc)
+static void _Opi(jit_state_t*,int,int,unsigned int,unsigned int,int);
+#  define ADDL(ra,rb,rc)               Opr(0x10,ra,rb,0x00,rc)
+#  define ADDLi(ra,im,rc)              Opi(0x10,ra,im,0x00,rc)
+#  define ADDL_V(ra,rb,rc)             Opr(0x10,ra,rb,0x40,rc)
+#  define ADDL_Vi(ra,im,rc)            Opi(0x10,ra,im,0x40,rc)
+#  define ADDQ(ra,rb,rc)               Opr(0x10,ra,rb,0x20,rc)
+#  define ADDQi(ra,im,rc)              Opi(0x10,ra,im,0x20,rc)
+#  define ADDQ_V(ra,rb,rc)             Opr(0x10,ra,rb,0x60,rc)
+#  define ADDQ_Vi(ra,im,rc)            Opi(0x10,ra,im,0x60,rc)
+#  define AMASK(rb,rc)                 Opr(0x11,_R31_REGNO,rb,0x61,rc)
+#  define AND(ra,rb,rc)                        Opr(0x11,ra,rb,0x00,rc)
+#  define ANDi(ra,im,rc)               Opi(0x11,ra,im,0x00,rc)
+#  define BEQ(ra,d)                    Bra(0x39,ra,d)
+#  define BGE(ra,d)                    Bra(0x3e,ra,d)
+#  define BGT(ra,d)                    Bra(0x3f,ra,d)
+#  define BIC(ra,rb,rc)                        Opr(0x11,ra,rb,0x08,rc)
+#  define ANDNOT(ra,rb,rc)             BIC(ra,rb,rc)
+#  define BICi(ra,im,rc)               Opi(0x11,ra,im,0x08,rc)
+#  define ANDNOTi(ra,im,rc)            BICi(ra,im,rc)
+#  define BIS(ra,rb,rc)                        Opr(0x11,ra,rb,0x20,rc)
+#  define BISi(ra,im,rc)               Opi(0x11,ra,im,0x20,rc)
+#  define OR(ra,rb,rc)                 BIS(ra,rb,rc)
+#  define ORi(ra,im,rc)                        BISi(ra,im,rc)
+#  define BLBC(ra,d)                   Bra(0x38,ra,d)
+#  define BLBS(ra,d)                   Bra(0x3c,ra,d)
+#  define BLE(ra,d)                    Bra(0x3b,ra,d)
+#  define BLT(ra,d)                    Bra(0x3a,ra,d)
+#  define BNE(ra,d)                    Bra(0x3d,ra,d)
+#  define BR(ra,d)                     Bra(0x30,ra,d)
+#  define BSR(ra,d)                    Bra(0x34,ra,d)
+#  define CALL_PAL(c)                  Pcd(0x00,c)
+#  define CMOVEQ(ra,rb,rc)             Opr(0x11,ra,rb,0x24,rc)
+#  define CMOVEQi(ra,im,rc)            Opi(0x11,ra,im,0x24,rc)
+#  define CMOVGE(ra,rb,rc)             Opr(0x11,ra,rb,0x46,rc)
+#  define CMOVGEi(ra,im,rc)            Opi(0x11,ra,im,0x46,rc)
+#  define CMOVGT(ra,rb,rc)             Opr(0x11,ra,rb,0x66,rc)
+#  define CMOVGTi(ra,im,rc)            Opi(0x11,ra,im,0x66,rc)
+#  define CMOVLBC(ra,rb,rc)            Opr(0x11,ra,rb,0x16,rc)
+#  define CMOVLBCi(ra,im,rc)           Opi(0x11,ra,im,0x16,rc)
+#  define CMOVLBS(ra,rb,rc)            Opr(0x11,ra,rb,0x14,rc)
+#  define CMOVLBSi(ra,im,rc)           Opi(0x11,ra,im,0x14,rc)
+#  define CMOVLE(ra,rb,rc)             Opr(0x11,ra,rb,0x64,rc)
+#  define CMOVLEi(ra,im,rc)            Opi(0x11,ra,im,0x64,rc)
+#  define CMOVLT(ra,rb,rc)             Opr(0x11,ra,rb,0x44,rc)
+#  define CMOVLTi(ra,im,rc)            Opi(0x11,ra,im,0x44,rc)
+#  define CMOVNE(ra,rb,rc)             Opr(0x11,ra,rb,0x26,rc)
+#  define CMOVNEi(ra,im,rc)            Opi(0x11,ra,im,0x26,rc)
+#  define CMPBGE(ra,rb,rc)             Opr(0x10,ra,rb,0x0f,rc)
+#  define CMPBGEi(ra,im,rc)            Opi(0x10,ra,im,0x0f,rc)
+#  define CMPEQ(ra,rb,rc)              Opr(0x10,ra,rb,0x2d,rc)
+#  define CMPEQi(ra,im,rc)             Opi(0x10,ra,im,0x2d,rc)
+#  define CMPLE(ra,rb,rc)              Opr(0x10,ra,rb,0x6d,rc)
+#  define CMPLEi(ra,im,rc)             Opi(0x10,ra,im,0x6d,rc)
+#  define CMPLT(ra,rb,rc)              Opr(0x10,ra,rb,0x4d,rc)
+#  define CMPLTi(ra,im,rc)             Opi(0x10,ra,im,0x4d,rc)
+#  define CMPULE(ra,rb,rc)             Opr(0x10,ra,rb,0x3d,rc)
+#  define CMPULEi(ra,im,rc)            Opi(0x10,ra,im,0x3d,rc)
+#  define CMPULT(ra,rb,rc)             Opr(0x10,ra,rb,0x1d,rc)
+#  define CMPULTi(ra,im,rc)            Opi(0x10,ra,im,0x1d,rc)
+#  define CTLZ(rb,rc)                  Opr(0x1c,_R31_REGNO,rb,0x32,rc)
+#  define CTPOP(rb,rc)                 Opr(0x1c,_R31_REGNO,rb,0x30,rc)
+#  define CTTZ(rb,rc)                  Opr(0x1c,_R31_REGNO,rb,0x33,rc)
+#  define ECB(rb,d)                    Mem(0x18,_R31_REGNO,rb,0xe800)
+#  define EQV(ra,rb,rc)                        Opr(0x11,ra,rb,0x48,rc)
+#  define XORNOT(ra,rb,rc)             EQV(ra,rb,rc)
+#  define EQVi(ra,im,rc)               Opi(0x11,ra,im,0x48,rc)
+#  define XORNOTi(ra,im,rc)            EQVi(ra,im,rc)
+#  define EXCB()                       Mem(0x18,0,0,0x0400)
+#  define EXTBL(ra,rb,rc)              Opr(0x12,ra,rb,0x06,rc)
+#  define EXTBLi(ra,im,rc)             Opi(0x12,ra,im,0x06,rc)
+#  define EXTLH(ra,rb,rc)              Opr(0x12,ra,rb,0x6a,rc)
+#  define EXTLHi(ra,im,rc)             Opi(0x12,ra,im,0x6a,rc)
+#  define EXTLL(ra,rb,rc)              Opr(0x12,ra,rb,0x26,rc)
+#  define EXTLLi(ra,im,rc)             Opi(0x12,ra,im,0x26,rc)
+#  define EXTQH(ra,rb,rc)              Opr(0x12,ra,rb,0x7a,rc)
+#  define EXTQHi(ra,im,rc)             Opi(0x12,ra,im,0x7a,rc)
+#  define EXTQL(ra,rb,rc)              Opr(0x12,ra,rb,0x36,rc)
+#  define EXTQLi(ra,im,rc)             Opi(0x12,ra,im,0x36,rc)
+#  define EXTWH(ra,rb,rc)              Opr(0x12,ra,rb,0x5a,rc)
+#  define EXTWHi(ra,im,rc)             Opi(0x12,ra,im,0x5a,rc)
+#  define EXTWL(ra,rb,rc)              Opr(0x12,ra,rb,0x16,rc)
+#  define EXTWLi(ra,im,rc)             Opi(0x12,ra,im,0x16,rc)
+#  define FETCH(rb,d)                  Mem(0x18,_R31_REGNO,rb,0x8000)
+#  define FETCH_Mem(rb,d)              Mem(0x18,_R31_REGNO,rb,0xa000)
+/* FIXME IMPLVER not disassembled */
+#  define IMPLVER(rc)                  Opr(0x11,_R31_REGNO,1,0x6c,rc)
+#  define INSBL(ra,rb,rc)              Opr(0x12,ra,rb,0x0b,rc)
+#  define INSBLi(ra,im,rc)             Opi(0x12,ra,im,0x0b,rc)
+#  define INSLH(ra,rb,rc)              Opr(0x12,ra,rb,0x67,rc)
+#  define INSLHi(ra,im,rc)             Opi(0x12,ra,im,0x67,rc)
+#  define INSLL(ra,rb,rc)              Opr(0x12,ra,rb,0x2b,rc)
+#  define INSLLi(ra,im,rc)             Opi(0x12,ra,im,0x2b,rc)
+#  define INSQH(ra,rb,rc)              Opr(0x12,ra,rb,0x77,rc)
+#  define INSQHi(ra,im,rc)             Opi(0x12,ra,im,0x77,rc)
+#  define INSQL(ra,rb,rc)              Opr(0x12,ra,rb,0x3b,rc)
+#  define INSQLi(ra,im,rc)             Opi(0x12,ra,im,0x3b,rc)
+#  define INSWH(ra,rb,rc)              Opr(0x12,ra,rb,0x57,rc)
+#  define INSWHi(ra,im,rc)             Opi(0x12,ra,im,0x57,rc)
+#  define INSWL(ra,rb,rc)              Opr(0x12,ra,rb,0x1b,rc)
+#  define INSWLi(ra,im,rc)             Opi(0x12,ra,im,0x1b,rc)
+#  define JMP(ra,rb,d)                 Mbr(0x1a,ra,rb,0,d)
+#  define JSR(ra,rb,d)                 Mbr(0x1a,ra,rb,1,d)
+#  define JSR_COROUTINE(ra,rb,d)       Mbr(0x1a,ra,rb,3,d)
+#  define JCR(ra,rb,rd)                        JSR_COROUTINE(ra,rb,d)
+#  define LDA(ra,rb,d)                 Mem(0x08,ra,rb,d)
+#  define LDAH(ra,rb,d)                        Mem(0x09,ra,rb,d)
+#  define LDBU(ra,rb,d)                        Mem(0x0a,ra,rb,d)
+#  define LDWU(ra,rb,d)                        Mem(0x0c,ra,rb,d)
+#  define LDL(ra,rb,d)                 Mem(0x28,ra,rb,d)
+#  define LDL_L(ra,rb,d)               Mem(0x2a,ra,rb,d)
+#  define LDQ(ra,rb,d)                 Mem(0x29,ra,rb,d)
+#  define LDQ_L(ra,rb,d)               Mem(0x2b,ra,rb,d)
+#  define LDQ_U(ra,rb,d)               Mem(0x0b,ra,rb,d)
+#  define MAXSB8(ra,rb,rc)             Opr(0x1c,ra,rb,0x3e,rc)
+#  define MAXSW4(ra,rb,rc)             Opr(0x1c,ra,rb,0x3f,rc)
+#  define MAXSUB8(ra,rb,rc)            Opr(0x1c,ra,rb,0x3c,rc)
+#  define MAXSUW4(ra,rb,rc)            Opr(0x1c,ra,rb,0x3d,rc)
+#  define MB()                         Mem(0x18,_R31_REGNO,_R31_REGNO,0x4000)
+#  define MINSB8(ra,rb,rc)             Opr(0x1c,ra,rb,0x38,rc)
+#  define MINSW4(ra,rb,rc)             Opr(0x1c,ra,rb,0x39,rc)
+#  define MINSUB8(ra,rb,rc)            Opr(0x1c,ra,rb,0x3a,rc)
+#  define MINSUW4(ra,rb,rc)            Opr(0x1c,ra,rb,0x3b,rc)
+#  define MSKBL(ra,rb,rc)              Opr(0x12,ra,rb,0x02,rc)
+#  define MSKBLi(ra,im,rc)             Opi(0x12,ra,im,0x02,rc)
+#  define MSKLH(ra,rb,rc)              Opr(0x12,ra,rb,0x62,rc)
+#  define MSKLHi(ra,im,rc)             Opi(0x12,ra,im,0x62,rc)
+#  define MSKLL(ra,rb,rc)              Opr(0x12,ra,rb,0x22,rc)
+#  define MSKLLi(ra,im,rc)             Opi(0x12,ra,im,0x22,rc)
+#  define MSKQH(ra,rb,rc)              Opr(0x12,ra,rb,0x72,rc)
+#  define MSKQHi(ra,im,rc)             Opi(0x12,ra,im,0x72,rc)
+#  define MSKQL(ra,rb,rc)              Opr(0x12,ra,rb,0x32,rc)
+#  define MSKQLi(ra,im,rc)             Opi(0x12,ra,im,0x32,rc)
+#  define MSKWH(ra,rb,rc)              Opr(0x12,ra,rb,0x52,rc)
+#  define MSKWHi(ra,im,rc)             Opi(0x12,ra,im,0x52,rc)
+#  define MSKWL(ra,rb,rc)              Opr(0x12,ra,rb,0x12,rc)
+#  define MSKWLi(ra,im,rc)             Opi(0x12,ra,im,0x12,rc)
+#  define MULL(ra,rb,rc)               Opr(0x13,ra,rb,0x00,rc)
+#  define MULLi(ra,im,rc)              Opi(0x13,ra,im,0x00,rc)
+#  define MULL_V(ra,rb,rc)             Opr(0x13,ra,rb,0x40,rc)
+#  define MULL_Vi(ra,im,rc)            Opi(0x13,ra,im,0x40,rc)
+#  define MULQ(ra,rb,rc)               Opr(0x13,ra,rb,0x20,rc)
+#  define MULQi(ra,im,rc)              Opi(0x13,ra,im,0x20,rc)
+#  define MULQ_V(ra,rb,rc)             Opr(0x13,ra,rb,0x60,rc)
+#  define MULQ_Vi(ra,im,rc)            Opi(0x13,ra,im,0x60,rc)
+#  define ORNOT(ra,rb,rc)              Opr(0x11,ra,rb,0x28,rc)
+#  define ORNOTi(ra,im,rc)             Opi(0x11,ra,im,0x28,rc)
+#  define PERR(ra,rb,rc)               Opr(0x1c,ra,rb,0x31,rc)
+#  define PKLB(rb,rc)                  Opr(0x1c,_R31_REGNO,rb,0x37,rc)
+#  define PKWB(rb,rc)                  Opr(0x1c,_R31_REGNO,rb,0x36,rc)
+/* FIXME PREFETCH* not disassembled */
+#  define PREFETCH(rb,d)               Mem(0x28,_R31_REGNO,rb,d)
+#  define PREFETCH_EN(rb,d)            Mem(0x29,_R31_REGNO,rb,d)
+#  define PREFETCH_M(rb,d)             Mem(0x22,_R31_REGNO,rb,d)
+#  define PREFETCH_MEN(rb,d)           Mem(0x23,_R31_REGNO,rb,d)
+#  define RC(ra)                       Mem(0x18,ra,_R31_REGNO,0xe000)
+#  define RET(ra,rb,d)                 Mbr(0x1a,ra,rb,2,d)
+#  define RPCC(ra)                     Mem(0x18,ra,_R31_REGNO,0xc000)
+#  define RS(ra)                       Mem(0x18,ra,_R31_REGNO,0xf000)
+#  define S4ADDL(ra,rb,rc)             Opr(0x10,ra,rb,0x02,rc)
+#  define S4ADDi(ra,im,rc)             Opi(0x10,ra,im,0x02,rc)
+#  define S4ADDQ(ra,rb,rc)             Opr(0x10,ra,rb,0x22,rc)
+#  define S4ADDQi(ra,im,rc)            Opi(0x10,ra,im,0x22,rc)
+#  define S4SUBL(ra,rb,rc)             Opr(0x10,ra,rb,0x0b,rc)
+#  define S4SUBLi(ra,im,rc)            Opi(0x10,ra,im,0x0b,rc)
+#  define S4SUBQ(ra,rb,rc)             Opr(0x10,ra,rb,0x2b,rc)
+#  define S4SUBQi(ra,im,rc)            Opi(0x10,ra,im,0x2b,rc)
+#  define S8ADDL(ra,rb,rc)             Opr(0x10,ra,rb,0x12,rc)
+#  define S8ADDLi(ra,im,rc)            Opi(0x10,ra,im,0x12,rc)
+#  define S8ADDQ(ra,rb,rc)             Opr(0x10,ra,rb,0x32,rc)
+#  define S8ADDQi(ra,im,rc)            Opi(0x10,ra,im,0x32,rc)
+#  define S8SUBL(ra,rb,rc)             Opr(0x10,ra,rb,0x1b,rc)
+#  define S8SUBLi(ra,im,rc)            Opi(0x10,ra,im,0x1b,rc)
+#  define S8SUBQ(ra,rb,rc)             Opr(0x10,ra,rb,0x3b,rc)
+#  define S8SUBQi(ra,im,rc)            Opi(0x10,ra,im,0x3b,rc)
+#  define SEXTB(rb,rc)                 Opr(0x1c,_R31_REGNO,rb,0x00,rc)
+/* FIXME not disassembled */
+#  define SEXTBi(im,rc)                        Opi(0x1c,_R31_REGNO,im,0x00,rc)
+#  define SEXTW(rb,rc)                 Opr(0x1c,_R31_REGNO,rb,0x01,rc)
+/* FIXME not disassembled */
+#  define SEXTWi(im,rc)                        Opi(0x1c,_R31_REGNO,im,0x01,rc)
+#  define SLL(ra,rb,rc)                        Opr(0x12,ra,rb,0x39,rc)
+#  define SLLi(ra,im,rc)               Opi(0x12,ra,im,0x39,rc)
+#  define SRA(ra,rb,rc)                        Opr(0x12,ra,rb,0x3c,rc)
+#  define SRAi(ra,im,rc)               Opi(0x12,ra,im,0x3c,rc)
+#  define SRL(ra,rb,rc)                        Opr(0x12,ra,rb,0x34,rc)
+#  define SRLi(ra,im,rc)               Opi(0x12,ra,im,0x34,rc)
+#  define STB(ra,rb,d)                 Mem(0x0e,ra,rb,d)
+#  define STL(ra,rb,d)                 Mem(0x2c,ra,rb,d)
+#  define STL_C(ra,rb,d)               Mem(0x2e,ra,rb,d)
+#  define STQ(ra,rb,d)                 Mem(0x2d,ra,rb,d)
+#  define STQ_C(ra,rb,d)               Mem(0x2f,ra,rb,d)
+#  define STQ_U(ra,rb,d)               Mem(0x0f,ra,rb,d)
+#  define STW(ra,rb,d)                 Mem(0x0d,ra,rb,d)
+#  define SUBL(ra,rb,rc)               Opr(0x10,ra,rb,0x09,rc)
+#  define SUBLi(ra,im,rc)              Opi(0x10,ra,im,0x09,rc)
+#  define SUBL_V(ra,rb,rc)             Opr(0x10,ra,rb,0x49,rc)
+#  define SUBL_Vi(ra,im,rc)            Opi(0x10,ra,im,0x49,rc)
+#  define SUBQ(ra,rb,rc)               Opr(0x10,ra,rb,0x29,rc)
+#  define SUBQi(ra,im,rc)              Opi(0x10,ra,im,0x29,rc)
+#  define SUBQ_V(ra,rb,rc)             Opr(0x10,ra,rb,0x69,rc)
+#  define SUBQ_Vi(ra,im,rc)            Opi(0x10,ra,im,0x69,rc)
+#  define TRAPB()                      Mem(0x18,_R31_REGNO,_R31_REGNO,0x0000)
+#  define UMULH(ra,rb,rc)              Opr(0x13,ra,rb,0x30,rc)
+#  define UMULHi(ra,im,rc)             Opi(0x13,ra,im,0x30,rc)
+#  define UNPKBL(rb,rc)                        Opr(0x1c,_R31_REGNO,rb,0x35,rc)
+#  define UNPKBW(rb,rc)                        Opr(0x1c,_R31_REGNO,rb,0x34,rc)
+#  define WH64(ra)                     Mem(0x18,ra,_R31_REGNO,0xf800)
+#  define WH64EN(ra)                   Mem(0x18,ra,_R31_REGNO,0xfc00)
+#  define WMB()                                Mem(0x18,_R31_REGNO,_R31_REGNO,0x4400)
+#  define XOR(ra,rb,rc)                        Opr(0x11,ra,rb,0x40,rc)
+#  define XORi(ra,im,rc)               Opi(0x11,ra,im,0x40,rc)
+#  define ZAP(ra,rb,rc)                        Opr(0x12,ra,rb,0x30,rc)
+#  define ZAPi(ra,im,rc)               Opi(0x12,ra,im,0x30,rc)
+#  define ZAPNOT(ra,rb,rc)             Opr(0x12,ra,rb,0x31,rc)
+#  define ZAPNOTi(ra,im,rc)            Opi(0x12,ra,im,0x31,rc)
+#  define NOP()                                BIS(_R31_REGNO,_R31_REGNO,_R31_REGNO)
+#  define MOV(ra,rc)                   BIS(ra,ra,rc)
+#  define MOVi(im,rc)                  BISi(_R31_REGNO,im,rc)
+#  define NEGL(ra,rc)                  SUBL(_R31_REGNO,ra,rc)
+#  define NEGQ(ra,rc)                  SUBQ(_R31_REGNO,ra,rc)
+#  define NOT(ra,rc)                   ORNOT(_R31_REGNO,ra,rc)
+#  define nop(i0)                      _nop(_jit,i0)
+static void _nop(jit_state_t*,jit_int32_t);
+#  define movr(r0,r1)                  _movr(_jit,r0,r1)
+static void _movr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi(r0,i0)                  _movi(_jit,r0,i0)
+static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
+#  define movi_p(r0,i0)                        _movi_p(_jit,r0,i0)
+static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
+#  define negr(r0,r1)                  NEGQ(r1,r0)
+#  define comr(r0,r1)                  NOT(r1,r0)
+#  define addr(r0,r1,r2)               ADDQ(r1,r2,r0)
+#  define addi(r0,r1,i0)               _addi(_jit,r0,r1,i0)
+static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addcr(r0,r1,i0)              _addcr(_jit,r0,r1,i0)
+static void _addcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addci(r0,r1,i0)              _addci(_jit,r0,r1,i0)
+static void _addci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addxr(r0,r1,i0)              _addxr(_jit,r0,r1,i0)
+static void _addxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addxi(r0,r1,i0)              _addxi(_jit,r0,r1,i0)
+static void _addxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subr(r0,r1,r2)               SUBQ(r1,r2,r0)
+#  define subi(r0,r1,i0)               _subi(_jit,r0,r1,i0)
+static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subcr(r0,r1,i0)              _subcr(_jit,r0,r1,i0)
+static void _subcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subci(r0,r1,i0)              _subci(_jit,r0,r1,i0)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subxr(r0,r1,i0)              _subxr(_jit,r0,r1,i0)
+static void _subxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subxi(r0,r1,i0)              _subxi(_jit,r0,r1,i0)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rsbi(r0, r1, i0)             _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t, jit_word_t);
+#  define mulr(r0,r1,r2)               MULQ(r1,r2,r0)
+#  define muli(r0,r1,i0)               _muli(_jit,r0,r1,i0)
+static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr(r0,r1,r2,r3)           _qmulr(_jit,r0,r1,r2,r3)
+static void _qmulr(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qmuli(r0,r1,r2,i0)           _qmuli(_jit,r0,r1,r2,i0)
+static void _qmuli(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr_u(r0,r1,r2,r3)         _qmulr_u(_jit,r0,r1,r2,r3)
+static void _qmulr_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qmuli_u(r0,r1,r2,i0)         _qmuli_u(_jit,r0,r1,r2,i0)
+static void _qmuli_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_word_t);
+static jit_word_t __idiv(jit_word_t, jit_word_t);
+#  define divr(r0,r1,r2)               _divr(_jit,r0,r1,r2)
+static void _divr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi(r0,r1,i0)               _divi(_jit,r0,r1,i0)
+static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+static jit_uword_t __udiv(jit_uword_t, jit_uword_t);
+#  define divr_u(r0,r1,r2)             _divr_u(_jit,r0,r1,r2)
+static void _divr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi_u(r0,r1,i0)             _divi_u(_jit,r0,r1,i0)
+static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+static jit_word_t __irem(jit_word_t, jit_word_t);
+#  define remr(r0,r1,r2)               _remr(_jit,r0,r1,r2)
+static void _remr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi(r0,r1,i0)               _remi(_jit,r0,r1,i0)
+static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+static jit_uword_t __urem(jit_uword_t, jit_uword_t);
+#  define remr_u(r0,r1,r2)             _remr_u(_jit,r0,r1,r2)
+static void _remr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi_u(r0,r1,i0)             _remi_u(_jit,r0,r1,i0)
+static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+static jit_word_t __idivrem(jit_word_t, jit_word_t, jit_word_t*);
+#  define qdivr(r0,r1,r2,r3)           _qdivr(_jit,r0,r1,r2,r3)
+static void _qdivr(jit_state_t*,
+                  jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qdivi(r0,r1,r2,i0)           _qdivi(_jit,r0,r1,r2,i0)
+static void _qdivi(jit_state_t*,
+                  jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+static jit_word_t __udivrem(jit_uword_t, jit_uword_t, jit_uword_t*);
+#  define qdivr_u(r0,r1,r2,r3)         _qdivr_u(_jit,r0,r1,r2,r3)
+static void _qdivr_u(jit_state_t*,
+                    jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qdivi_u(r0,r1,r2,i0)         _qdivi_u(_jit,r0,r1,r2,i0)
+static void _qdivi_u(jit_state_t*,
+                    jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+#  define lshr(r0,r1,r2)               SLL(r1,r2,r0)
+#  define lshi(r0,r1,i0)               _lshi(_jit,r0,r1,i0)
+static void _lshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rshr(r0,r1,r2)               SRA(r1,r2,r0)
+#  define rshi(r0,r1,i0)               _rshi(_jit,r0,r1,i0)
+static void _rshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rshr_u(r0,r1,r2)             SRL(r1,r2,r0)
+#  define rshi_u(r0,r1,i0)             _rshi_u(_jit,r0,r1,i0)
+static void _rshi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define andr(r0,r1,r2)               AND(r1,r2,r0)
+#  define andi(r0,r1,i0)               _andi(_jit,r0,r1,i0)
+static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define orr(r0,r1,r2)                        OR(r1,r2,r0)
+#  define ori(r0,r1,i0)                        _ori(_jit,r0,r1,i0)
+static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define xorr(r0,r1,r2)               XOR(r1,r2,r0)
+#  define xori(r0,r1,i0)               _xori(_jit,r0,r1,i0)
+static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ltr(r0,r1,r2)                        CMPLT(r1,r2,r0)
+#  define lti(r0,r1,i0)                        _lti(_jit,r0,r1,i0)
+static void _lti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ltr_u(r0,r1,r2)              CMPULT(r1,r2,r0)
+#  define lti_u(r0,r1,i0)              _lti_u(_jit,r0,r1,i0)
+static void _lti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ler(r0,r1,r2)                        CMPLE(r1,r2,r0)
+#  define lei(r0,r1,i0)                        _lei(_jit,r0,r1,i0)
+static void _lei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ler_u(r0,r1,r2)              CMPULE(r1,r2,r0)
+#  define lei_u(r0,r1,i0)              _lei_u(_jit,r0,r1,i0)
+static void _lei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define eqr(r0,r1,r2)                        CMPEQ(r1,r2,r0)
+#  define eqi(r0,r1,i0)                        _eqi(_jit,r0,r1,i0)
+static void _eqi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ger(r0,r1,r2)                        CMPLE(r2,r1,r0)
+#  define gei(r0,r1,i0)                        _gei(_jit,r0,r1,i0)
+static void _gei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ger_u(r0,r1,r2)              CMPULE(r2,r1,r0)
+#  define gei_u(r0,r1,i0)              _gei_u(_jit,r0,r1,i0)
+static void _gei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define gtr(r0,r1,r2)                        CMPLT(r2,r1,r0)
+#  define gti(r0,r1,i0)                        _gti(_jit,r0,r1,i0)
+static void _gti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define gtr_u(r0,r1,r2)              CMPULT(r2,r1,r0)
+#  define gti_u(r0,r1,i0)              _gti_u(_jit,r0,r1,i0)
+static void _gti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ner(r0,r1,r2)                        _ner(_jit,r0,r1,r2)
+static void _ner(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nei(r0,r1,i0)                        _nei(_jit,r0,r1,i0)
+static void _nei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define bltr(i0,r0,r1)               _bltr(_jit,i0,r0,r1)
+static jit_word_t _bltr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti(i0,r0,i1)               _blti(_jit,i0,r0,i1)
+static jit_word_t _blti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bltr_u(i0,r0,r1)             _bltr_u(_jit,i0,r0,r1)
+static jit_word_t _bltr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti_u(i0,r0,i1)             _blti_u(_jit,i0,r0,i1)
+static jit_word_t _blti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bler(i0,r0,r1)               _bler(_jit,i0,r0,r1)
+static jit_word_t _bler(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei(i0,r0,i1)               _blei(_jit,i0,r0,i1)
+static jit_word_t _blei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bler_u(i0,r0,r1)             _bler_u(_jit,i0,r0,r1)
+static jit_word_t _bler_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei_u(i0,r0,i1)             _blei_u(_jit,i0,r0,i1)
+static jit_word_t _blei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define beqr(i0,r0,r1)               _beqr(_jit,i0,r0,r1)
+static jit_word_t _beqr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define beqi(i0,r0,i1)               _beqi(_jit,i0,r0,i1)
+static jit_word_t _beqi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bger(i0,r0,r1)               _bger(_jit,i0,r0,r1)
+static jit_word_t _bger(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei(i0,r0,i1)                       _bgei(_jit,i0,r0,i1)
+static jit_word_t _bgei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bger_u(i0,r0,r1)             _bger_u(_jit,i0,r0,r1)
+static jit_word_t _bger_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei_u(i0,r0,i1)             _bgei_u(_jit,i0,r0,i1)
+static jit_word_t _bgei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bgtr(i0,r0,r1)               _bgtr(_jit,i0,r0,r1)
+static jit_word_t _bgtr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti(i0,r0,i1)               _bgti(_jit,i0,r0,i1)
+static jit_word_t _bgti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bgtr_u(i0,r0,r1)             _bgtr_u(_jit,i0,r0,r1)
+static jit_word_t _bgtr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti_u(i0,r0,i1)             _bgti_u(_jit,i0,r0,i1)
+static jit_word_t _bgti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bner(i0,r0,r1)               _bner(_jit,i0,r0,r1)
+static jit_word_t _bner(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bnei(i0,r0,i1)               _bnei(_jit,i0,r0,i1)
+static jit_word_t _bnei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define baddr(i0,r0,r1,cc)           _baddr(_jit,i0,r0,r1,cc)
+static jit_word_t _baddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t,
+                        jit_bool_t);
+#  define baddi(i0,r0,i1,cc)           _baddi(_jit,i0,r0,i1,cc)
+static jit_word_t _baddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t,
+                        jit_bool_t);
+#  define baddr_u(i0,r0,r1,cc)         _baddr_u(_jit,i0,r0,r1,cc)
+static jit_word_t _baddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t,
+                          jit_bool_t);
+#  define baddi_u(i0,r0,i1,cc)         _baddi_u(_jit,i0,r0,i1,cc)
+static jit_word_t _baddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t,
+                          jit_bool_t);
+#  define boaddr(i0,r0,r1)             baddr(i0,r0,r1,1)
+#  define boaddi(i0,r0,i1)             baddi(i0,r0,i1,1)
+#  define boaddr_u(i0,r0,r1)           baddr_u(i0,r0,r1,1)
+#  define boaddi_u(i0,r0,i1)           baddi_u(i0,r0,i1,1)
+#  define bxaddr(i0,r0,r1)             baddr(i0,r0,r1,0)
+#  define bxaddi(i0,r0,i1)             baddi(i0,r0,i1,0)
+#  define bxaddr_u(i0,r0,r1)           baddr_u(i0,r0,r1,0)
+#  define bxaddi_u(i0,r0,i1)           baddi_u(i0,r0,i1,0)
+#  define bsubr(i0,r0,r1,cc)           _bsubr(_jit,i0,r0,r1,cc)
+static jit_word_t _bsubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t,
+                        jit_bool_t);
+#  define bsubi(i0,r0,i1,cc)           _bsubi(_jit,i0,r0,i1,cc)
+static jit_word_t _bsubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t,
+                        jit_bool_t);
+#  define bsubr_u(i0,r0,r1,cc)         _bsubr_u(_jit,i0,r0,r1,cc)
+static jit_word_t _bsubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t,
+                          jit_bool_t);
+#  define bsubi_u(i0,r0,i1,cc)         _bsubi_u(_jit,i0,r0,i1,cc)
+static jit_word_t _bsubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t,
+                          jit_bool_t);
+#  define bosubr(i0,r0,r1)             bsubr(i0,r0,r1,1)
+#  define bosubi(i0,r0,i1)             bsubi(i0,r0,i1,1)
+#  define bosubr_u(i0,r0,r1)           bsubr_u(i0,r0,r1,1)
+#  define bosubi_u(i0,r0,i1)           bsubi_u(i0,r0,i1,1)
+#  define bxsubr(i0,r0,r1)             bsubr(i0,r0,r1,0)
+#  define bxsubi(i0,r0,i1)             bsubi(i0,r0,i1,0)
+#  define bxsubr_u(i0,r0,r1)           bsubr_u(i0,r0,r1,0)
+#  define bxsubi_u(i0,r0,i1)           bsubi_u(i0,r0,i1,0)
+#  define bmxr(i0,r0,r1,cc)            _bmxr(_jit,i0,r0,r1,cc)
+static jit_word_t _bmxr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t,
+                       jit_bool_t);
+#  define bmxi(i0,r0,i1,cc)            _bmxi(_jit,i0,r0,i1,cc)
+static jit_word_t _bmxi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t,
+                       jit_bool_t);
+#  define bmsr(i0,r0,r1)               bmxr(i0,r0,r1,1)
+#  define bmsi(i0,r0,i1)               bmxi(i0,r0,i1,1)
+#  define bmcr(i0,r0,r1)               bmxr(i0,r0,r1,0)
+#  define bmci(i0,r0,i1)               bmxi(i0,r0,i1,0)
+#  define ldr_c(r0,r1)                 _ldr_c(_jit,r0,r1)
+static void _ldr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_c(r0,i0)                 _ldi_c(_jit,r0,i0)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_uc(r0,r1)                        LDBU(r0,r1,0)
+#  define ldi_uc(r0,i0)                        _ldi_uc(_jit,r0,i0)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_s(r0,r1)                 _ldr_s(_jit,r0,r1)
+static void _ldr_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_s(r0,i0)                 _ldi_s(_jit,r0,i0)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_us(r0,r1)                        LDWU(r0,r1,0)
+#  define ldi_us(r0,i0)                        _ldi_us(_jit,r0,i0)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_i(r0,r1)                 LDL(r0,r1,0)
+#  define ldi_i(r0,i0)                 _ldi_i(_jit,r0,i0)
+static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_ui(r0,r1)                        _ldr_ui(_jit,r0,r1)
+static void _ldr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_ui(r0,i0)                        _ldi_ui(_jit,r0,i0)
+static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr(r0,r1)                   ldr_l(r0,r1)
+#  define ldr_l(r0,r1)                 LDQ(r0,r1,0)
+#  define ldi_l(r0,i0)                 _ldi_l(_jit,r0,i0)
+static void _ldi_l(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_c(r0,r1,r2)             _ldxr_c(_jit,r0,r1,r2)
+static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_c(r0,r1,i0)             _ldxi_c(_jit,r0,r1,i0)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_uc(r0,r1,r2)            _ldxr_uc(_jit,r0,r1,r2)
+static void _ldxr_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_uc(r0,r1,i0)            _ldxi_uc(_jit,r0,r1,i0)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_s(r0,r1,r2)             _ldxr_s(_jit,r0,r1,r2)
+static void _ldxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_s(r0,r1,i0)             _ldxi_s(_jit,r0,r1,i0)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_us(r0,r1,r2)            _ldxr_us(_jit,r0,r1,r2)
+static void _ldxr_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_us(r0,r1,i0)            _ldxi_us(_jit,r0,r1,i0)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_i(r0,r1,r2)             _ldxr_i(_jit,r0,r1,r2)
+static void _ldxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_i(r0,r1,i0)             _ldxi_i(_jit,r0,r1,i0)
+static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_ui(r0,r1,r2)            _ldxr_ui(_jit,r0,r1,r2)
+static void _ldxr_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_ui(r0,r1,i0)            _ldxi_ui(_jit,r0,r1,i0)
+static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr(r0,r1,r2)               ldxr_l(r0,r1,r2)
+#  define ldxr_l(r0,r1,r2)             _ldxr_l(_jit,r0,r1,r2)
+static void _ldxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi(r0,r1,i0)               ldxi_l(r0,r1,i0)
+#  define ldxi_l(r0,r1,i0)             _ldxi_l(_jit,r0,r1,i0)
+static void _ldxi_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_c(r0,r1)                 STB(r1,r0,0)
+#  define sti_c(i0,r0)                 _sti_c(_jit,i0,r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_s(r0,r1)                 STW(r1,r0,0)
+#  define sti_s(i0,r0)                 _sti_s(_jit,i0,r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_i(r0,r1)                 STL(r1,r0,0)
+#  define sti_i(i0,r0)                 _sti_i(_jit,i0,r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str(r0,r1)                   str_l(r0,r1)
+#  define str_l(r0,r1)                 STQ(r1,r0,0)
+#  define sti_l(i0,r0)                 _sti_l(_jit,i0,r0)
+static void _sti_l(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_c(r0,r1,r2)             _stxr_c(_jit,r0,r1,r2)
+static void _stxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_c(i0,r0,r1)             _stxi_c(_jit,i0,r0,r1)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_s(r0,r1,r2)             _stxr_s(_jit,r0,r1,r2)
+static void _stxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_s(i0,r0,r1)             _stxi_s(_jit,i0,r0,r1)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_i(r0,r1,r2)             _stxr_i(_jit,r0,r1,r2)
+static void _stxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_i(i0,r0,r1)             _stxi_i(_jit,i0,r0,r1)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_l(r0,r1,r2)             _stxr_l(_jit,r0,r1,r2)
+static void _stxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi(i0,r0,r1)               stxi_l(i0,r0,r1)
+#  define stxi_l(i0,r0,r1)             _stxi_l(_jit,i0,r0,r1)
+static void _stxi_l(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define extr_c(r0,r1)                        _extr_c(_jit,r0,r1)
+static void _extr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_uc(r0,r1)               _extr_uc(_jit,r0,r1)
+static void _extr_uc(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_s(r0,r1)                        _extr_s(_jit,r0,r1)
+static void _extr_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_us(r0,r1)               _extr_us(_jit,r0,r1)
+static void _extr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_i(r0,r1)                        _extr_i(_jit,r0,r1)
+static void _extr_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_ui(r0,r1)               _extr_ui(_jit,r0,r1)
+static void _extr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+#    define htonr_us(r0,r1)            _htonr_us(_jit,r0,r1)
+static void _htonr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#    define htonr_ui(r0,r1)            _htonr_ui(_jit,r0,r1)
+static void _htonr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#    define htonr_ul(r0,r1)            _htonr_ul(_jit,r0,r1)
+static void _htonr_ul(jit_state_t*,jit_int32_t,jit_int32_t);
+#  else
+#    define htonr_us(r0,r1)            extr_us(r0,r1)
+#    define htonr_ui(r0,r1)            extr_ui(r0,r1)
+#    define htonr_ul(r0,r1)            movr(r0,r1)
+#  endif
+#  define jmpr(r0)                     JMP(_R31_REGNO,r0,0)
+#  define jmpi(i0)                     _jmpi(_jit,i0)
+static void _jmpi(jit_state_t*, jit_word_t);
+#  define jmpi_p(i0)                   _jmpi_p(_jit,i0)
+static jit_word_t _jmpi_p(jit_state_t*, jit_word_t);
+#define callr(r0)                      _callr(_jit,r0)
+static void _callr(jit_state_t*, jit_int32_t);
+#  define calli(i0)                    _calli(_jit,i0)
+static void _calli(jit_state_t*, jit_word_t);
+#  define calli_p(i0)                  _calli_p(_jit,i0)
+static jit_word_t _calli_p(jit_state_t*, jit_word_t);
+#  define prolog(node)                 _prolog(_jit,node)
+static void _prolog(jit_state_t*,jit_node_t*);
+#  define epilog(node)                 _epilog(_jit,node)
+static void _epilog(jit_state_t*,jit_node_t*);
+#  define vastart(r0)                  _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#  define vaarg(r0, r1)                        _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define patch_at(jump,label)         _patch_at(_jit,jump,label)
+static void _patch_at(jit_state_t*,jit_word_t,jit_word_t);
+#endif
+
+#if CODE
+static void
+_Pcd(jit_state_t *_jit, int o, unsigned int n)
+{
+    assert(_u6_p(o));
+    assert(_u26_p(n));
+    ii((o<<26)|_u26(n));
+}
+
+static void
+_Bra(jit_state_t *_jit, int o, int ra, int d)
+{
+    assert(_u6_p(o));
+    assert(_u5_p(ra));
+    assert(_s21_p(d));
+    ii((o<<26)|(ra<<21)|_u21(d));
+}
+
+static void
+_Mem(jit_state_t *_jit, int o, int ra, int rb, unsigned int d)
+{
+    assert(_u6_p(o));
+    assert(_u5_p(ra));
+    assert(_u5_p(rb));
+    assert(_u16_p(d));
+    ii((o<<26)|(ra<<21)|(rb<<16)|_u16(d));
+}
+
+static void
+_Mbr(jit_state_t *_jit, int o, int ra, int rb, int h, int d)
+{
+    assert(_u6_p(o));
+    assert(_u5_p(ra));
+    assert(_u5_p(rb));
+    assert(_u2_p(h));
+    assert(_s14_p(d));
+    ii((o<<26)|(ra<<21)|(rb<<16)|(h<<14)|_u14(d));
+}
+
+static void
+_Opr(jit_state_t *_jit, int o, int ra, int rb, unsigned int f, int rc)
+{
+    assert(_u6_p(o));
+    assert(_u5_p(ra));
+    assert(_u5_p(rb));
+    assert(_u5_p(rc));
+    assert(_u11_p(f));
+    ii((o<<26)|(ra<<21)|(rb<<16)|(_u11(f)<<5)|rc);
+}
+
+static void
+_Opi(jit_state_t *_jit, int o, int ra, unsigned int i, unsigned int f, int rc)
+{
+    assert(_u6_p(o));
+    assert(_u5_p(ra));
+    assert(_u8_p(i));
+    assert(_u5_p(rc));
+    assert(_u7_p(f));
+    ii((o<<26)|(ra<<21)|(_u8(i)<<13)|(1<<12)|(_u7(f)<<5)|rc);
+}
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t i0)
+{
+    for (; i0 > 0; i0 -= 4)
+       NOP();
+    assert(i0 == 0);
+}
+
+static void
+_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       MOV(r1, r0);
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_int16_t                s0, s1, s2, s3;
+    s0 = i0;
+    s1 = i0 >> 16;
+    s2 = i0 >> 32;
+    s3 = i0 >> 48;
+    if (s0 < 0)
+       ++s1;
+    if (s2 < 0)
+       ++s3;
+    if (_u8_p(i0))
+       MOVi(_u8(i0), r0);
+    else if (_s16_p(i0))
+       LDA(r0, _R31_REGNO, _u16(s0));
+    else if (_s32_p(i0)) {
+       LDA(r0, _R31_REGNO, _u16(s0));
+       LDAH(r0, r0, _u16(s1));
+    }
+    else if (_u32_p(i0)) {
+       LDA(r0, _R31_REGNO, _u16(s0));
+       if (s1)
+           LDAH(r0, r0, _u16(s1));
+       lshi(r0, r0, 32);
+       rshi_u(r0, r0, 32);
+    }
+    else if (_u32(i0) == 0) {
+       LDA(r0, _R31_REGNO, _u16(s2));
+       if (s3)
+           LDAH(r0, r0, _u16(s3));
+       lshi(r0, r0, 32);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       LDA(r0, _R31_REGNO, _u16(s0));
+       LDA(rn(reg), _R31_REGNO, _u16(s2));
+       if (s1)
+           LDAH(r0, r0, _u16(s1));
+       if (s3)
+           LDAH(rn(reg), rn(reg), _u16(s3));
+       lshi(r0, r0, 32);
+       rshi_u(r0, r0, 32);
+       lshi(rn(reg), rn(reg), 32);
+       orr(r0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    jit_int16_t                s0, s1, s2, s3;
+    w = _jit->pc.w;
+    reg = jit_get_reg(jit_class_gpr);
+    s0 = i0;
+    s1 = i0 >> 16;
+    s2 = i0 >> 32;
+    s3 = i0 >> 48;
+    if (s0 < 0)
+       ++s1;
+    if (s2 < 0)
+       ++s3;
+    LDA(r0, _R31_REGNO, _u16(s0));
+    LDA(rn(reg), _R31_REGNO, _u16(s2));
+    LDAH(r0, r0, _u16(s1));
+    LDAH(rn(reg), rn(reg), _u16(s3));
+    lshi(r0, r0, 32);
+    rshi_u(r0, r0, 32);
+    lshi(rn(reg), rn(reg), 32);
+    orr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       ADDQi(r1, i0, r0);
+    else if (_s16_p(i0))
+       LDA(r0, r1, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       addr(rn(reg), r1, r2);
+       ltr_u(rn(jit_carry), rn(reg), r1);
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       addr(r0, r1, r2);
+       ltr_u(rn(jit_carry), r0, r1);
+    }
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ltr_u(rn(jit_carry), rn(reg), r1);
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       addi(r0, r1, i0);
+       ltr_u(rn(jit_carry), r0, r1);
+    }
+}
+
+static void
+_addxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    addcr(r0, r1, r2);
+    addcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    addci(r0, r1, i0);
+    addcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       SUBQi(r1, i0, r0);
+    else if (_s16_p(-i0))
+       LDA(r0, r1, _u16(-i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_subcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       subr(rn(reg), r1, r2);
+       ltr_u(rn(jit_carry), r1, rn(reg));
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       subr(r0, r1, r2);
+       ltr_u(rn(jit_carry), r1, r0);
+    }
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, -i0);
+       ltr_u(rn(jit_carry), r1, rn(reg));
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       addi(r0, r1, -i0);
+       ltr_u(rn(jit_carry), r1, r0);
+    }
+}
+
+static void
+_subxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    subcr(r0, r1, r2);
+    subcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    subci(r0, r1, i0);
+    subcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    subi(r0, r1, i0);
+    negr(r0, r0);
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       MULQi(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       mulr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_qmulr(jit_state_t *_jit, jit_int32_t r0,
+       jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                reg;
+    /* The only invalid condition is r0 == r1 */
+    jit_int32_t                t2, t3, s2, s3;
+    if (r2 == r0 || r2 == r1) {
+       s2 = jit_get_reg(jit_class_gpr);
+       t2 = rn(s2);
+       movr(t2, r2);
+    }
+    else
+       t2 = r2;
+    if (r3 == r0 || r3 == r1) {
+       s3 = jit_get_reg(jit_class_gpr);
+       t3 = rn(s3);
+       movr(t3, r3);
+    }
+    else
+       t3 = r3;
+    qmulr_u(r0, r1, r2, r3);
+    reg = jit_get_reg(jit_class_gpr);
+    /**/
+    rshi(rn(reg), t2, 63);
+    mulr(rn(reg), rn(reg), t3);
+    addr(r1, r1, rn(reg));
+    /**/
+    rshi(rn(reg), t3, 63);
+    mulr(rn(reg), rn(reg), t2);
+    addr(r1, r1, rn(reg));
+    jit_unget_reg(reg);
+    if (t2 != r2)
+       jit_unget_reg(s2);
+    if (t3 != r3)
+       jit_unget_reg(s3);
+}
+
+static void
+_qmuli(jit_state_t *_jit, jit_int32_t r0,
+       jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    qmulr(r0, r1, r2, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_qmulr_u(jit_state_t *_jit, jit_int32_t r0,
+        jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                reg;
+    if (r0 == r2 || r0 == r3) {
+       reg = jit_get_reg(jit_class_gpr);
+       mulr(rn(reg), r2, r3);
+    }
+    else
+       mulr(r0, r2, r3);
+    UMULH(r2, r3, r1);
+    if (r0 == r2 || r0 == r3) {
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_qmuli_u(jit_state_t *_jit, jit_int32_t r0,
+        jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0)) {
+       if (r0 == r2) {
+           reg = jit_get_reg(jit_class_gpr);
+           muli(rn(reg), r2, i0);
+       }
+       else
+           muli(r0, r2, i0);
+       UMULHi(r2, i0, r1);
+       if (r0 == r2) {
+           movr(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       qmulr_u(r0, r1, r2, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+__idiv(jit_word_t u, jit_word_t v)
+{
+    return (u / v);
+}
+
+static void
+_divr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    movr(_A0_REGNO, r1);
+    movr(_A1_REGNO, r2);
+    calli((jit_word_t)__idiv);
+    movr(r0, _V0_REGNO);
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(_A0_REGNO, r1);
+    movi(_A1_REGNO, i0);
+    calli((jit_word_t)__idiv);
+    movr(r0, _V0_REGNO);
+}
+
+static jit_uword_t
+__udiv(jit_uword_t u, jit_uword_t v)
+{
+    return (u / v);
+}
+
+static void
+_divr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    movr(_A0_REGNO, r1);
+    movr(_A1_REGNO, r2);
+    calli((jit_word_t)__udiv);
+    movr(r0, _V0_REGNO);
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(_A0_REGNO, r1);
+    movi(_A1_REGNO, i0);
+    calli((jit_word_t)__udiv);
+    movr(r0, _V0_REGNO);
+}
+
+static jit_word_t
+__irem(jit_word_t u, jit_word_t v)
+{
+    return (u % v);
+}
+
+static void
+_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    movr(_A0_REGNO, r1);
+    movr(_A1_REGNO, r2);
+    calli((jit_word_t)__irem);
+    movr(r0, _V0_REGNO);
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(_A0_REGNO, r1);
+    movi(_A1_REGNO, i0);
+    calli((jit_word_t)__irem);
+    movr(r0, _V0_REGNO);
+}
+
+static jit_uword_t
+__urem(jit_uword_t u, jit_uword_t v)
+{
+    return (u % v);
+}
+
+static void
+_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    movr(_A0_REGNO, r1);
+    movr(_A1_REGNO, r2);
+    calli((jit_word_t)__urem);
+    movr(r0, _V0_REGNO);
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(_A0_REGNO, r1);
+    movi(_A1_REGNO, i0);
+    calli((jit_word_t)__urem);
+    movr(r0, _V0_REGNO);
+}
+
+static jit_word_t
+__idivrem(jit_word_t u, jit_word_t v, jit_word_t *rem)
+{
+    *rem = u % v;
+    return (u / v);
+}
+
+static void
+_qdivr(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    movr(_A0_REGNO, r2);
+    movr(_A1_REGNO, r3);
+    subi(_A2_REGNO, _FP_REGNO, 8);
+    calli((jit_word_t)__idivrem);
+    movr(r0, _V0_REGNO);
+    ldxi(r1, _FP_REGNO, -8);
+}
+
+static void
+_qdivi(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    movr(_A0_REGNO, r2);
+    movi(_A1_REGNO, i0);
+    subi(_A2_REGNO, _FP_REGNO, 8);
+    calli((jit_word_t)__idivrem);
+    movr(r0, _V0_REGNO);
+    ldxi(r1, _FP_REGNO, -8);
+}
+
+static jit_word_t
+__udivrem(jit_uword_t u, jit_uword_t v, jit_uword_t *rem)
+{
+    *rem = u % v;
+    return (u / v);
+}
+
+static void
+_qdivr_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    movr(_A0_REGNO, r2);
+    movr(_A1_REGNO, r3);
+    subi(_A2_REGNO, _FP_REGNO, 8);
+    calli((jit_word_t)__udivrem);
+    movr(r0, _V0_REGNO);
+    ldxi(r1, _FP_REGNO, -8);
+}
+
+static void
+_qdivi_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    movr(_A0_REGNO, r2);
+    movi(_A1_REGNO, i0);
+    subi(_A2_REGNO, _FP_REGNO, 8);
+    calli((jit_word_t)__udivrem);
+    movr(r0, _V0_REGNO);
+    ldxi(r1, _FP_REGNO, -8);
+}
+
+static void
+_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    assert(i0 >= 0 && i0 < 64);
+    SLLi(r1, i0, r0);
+}
+
+static void
+_rshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    assert(i0 >= 0 && i0 < 64);
+    SRAi(r1, i0, r0);
+}
+
+static void
+_rshi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    assert(i0 >= 0 && i0 < 64);
+    SRLi(r1, i0, r0);
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       ANDi(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       andr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       ORi(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       orr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       XORi(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       xorr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_lti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       CMPLTi(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ltr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_lti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       CMPULTi(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ltr_u(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_lei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       CMPLEi(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ler(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_lei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_word_t         ni0;
+    ni0 = -i0;
+    if (_u8_p(i0))
+       CMPULEi(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ler_u(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_eqi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0))
+       CMPEQi(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       eqr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_gei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ger(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_gei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ger_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_gti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    gtr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_gti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    gtr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ner(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPEQ(r1, r2, r0);
+    CMPEQi(r0, 0, r0);
+}
+
+static void
+_nei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_u8_p(i0)) {
+       CMPEQi(r1, i0, r0);
+       CMPEQi(r0, 0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ner(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_bltr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ltr(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_blti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BLT(r0, ((i0 - w) >> 2) - 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       lti(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BNE(rn(reg), ((i0 - w) >> 2) - 1);
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bltr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ltr_u(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_blti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    /* FIXME cannot optimize zero because need to return a patcheable address */
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    lti_u(rn(reg), r0, i1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bler(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ler(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_blei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BLE(r0, ((i0 - w) >> 2) - 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       lei(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BNE(rn(reg), ((i0 - w) >> 2) - 1);
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bler_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ler_u(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_blei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BEQ(r0, ((i0 - w) >> 2) - 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       lei_u(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BNE(rn(reg), ((i0 - w) >> 2) - 1);
+       jit_unget_reg(reg);
+     }
+    return (w);
+}
+
+static jit_word_t
+_beqr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    eqr(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_beqi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BEQ(r0, ((i0 - w) >> 2) - 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       eqi(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BNE(rn(reg), ((i0 - w) >> 2) - 1);
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bger(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ger(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bgei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BGE(r0, ((i0 - w) >> 2) - 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       gei(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BNE(rn(reg), ((i0 - w) >> 2) - 1);
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bger_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ger_u(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bgei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    /* always true if i1 == 0 */
+    if (i0 == 0) {
+       w = _jit->pc.w;
+       BR(r0, ((i0 - w) >> 2) - 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       gei_u(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BNE(rn(reg), ((i0 - w) >> 2) - 1);
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bgtr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    gtr(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bgti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BGT(r0, ((i0 - w) >> 2) - 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       gti(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BNE(rn(reg), ((i0 - w) >> 2) - 1);
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bgtr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    gtr_u(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bgti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    gti_u(rn(reg), r0, i1);
+    w = _jit->pc.w;
+    BNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bner(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    eqr(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BEQ(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bnei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BNE(r0, ((i0 - w) >> 2) - 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       eqi(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BEQ(rn(reg), ((i0 - w) >> 2) - 1);
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_baddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1,
+       jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+    jit_int32_t                t3;
+    /* t0 = r0 + r1;   overflow = r1 < 0 ? r0 < t0 : t0 < r0 */
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr);
+    t2 = jit_get_reg(jit_class_gpr);
+    t3 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    addr(rn(t0), r0, r1);              /* t0 = r0 + r1 */
+    ltr(rn(t1), r1, _R31_REGNO);       /* t1 = r1 < 0 */
+    ltr(rn(t2), r0, rn(t0));           /* t2 = r0 < t0 */
+    ltr(rn(t3), rn(t0), r0);           /* t3 = t0 < r0 */
+    movr(r0, rn(t0));                  /* r0 += r1 */
+    CMOVNE(rn(t1), rn(t2), rn(t3));    /* if (t1 == 0) t3 = t2; */
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    w = _jit->pc.w;
+    if (carry)
+       BNE(rn(t3), ((i0 - w) >> 2) - 1);
+    else
+       BEQ(rn(t3), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(t3);
+    return (w);
+}
+
+static jit_word_t
+_baddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1,
+       jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = baddr(i0, r0, rn(reg), carry);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_baddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1,
+        jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    addr(rn(t0), r0, r1);
+    ltr_u(rn(t1), rn(t0), r0);
+    movr(r0, rn(t0));
+    jit_unget_reg(t0);
+    w = _jit->pc.w;
+    if (carry)
+       BNE(rn(t1), ((i0 - w) >> 2) - 1);
+    else
+       BEQ(rn(t1), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(t1);
+    return (w);
+}
+
+static jit_word_t
+_baddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1,
+        jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    addi(rn(t0), r0, i1);
+    ltr_u(rn(t1), rn(t0), r0);
+    movr(r0, rn(t0));
+    jit_unget_reg(t0);
+    w = _jit->pc.w;
+    if (carry)
+       BNE(rn(t1), ((i0 - w) >> 2) - 1);
+    else
+       BEQ(rn(t1), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(t1);
+    return (w);
+}
+
+static jit_word_t
+_bsubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1,
+       jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+    jit_int32_t                t3;
+    /* t0 = r0 - r1;   overflow = 0 < r1 ? r0 < t0 : t0 < r0 */
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr);
+    t2 = jit_get_reg(jit_class_gpr);
+    t3 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    subr(rn(t0), r0, r1);              /* r0 = r0 - r1 */
+    ltr(rn(t1), _R31_REGNO, r1);       /* t1 = 0 < r1 */
+    ltr(rn(t2), r0, rn(t0));           /* t2 = r0 < t0 */
+    ltr(rn(t3), rn(t0), r0);           /* t3 = t0 < r0 */
+    movr(r0, rn(t0));                  /* r0 -= r1 */
+    CMOVNE(rn(t1), rn(t2), rn(t3));    /* if (t1 == 0) t3 = t2; */
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    w = _jit->pc.w;
+    if (carry)
+       BNE(rn(t3), ((i0 - w) >> 2) - 1);
+    else
+       BEQ(rn(t3), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(t3);
+    return (w);
+}
+
+static jit_word_t
+_bsubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1,
+       jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bsubr(i0, r0, rn(reg), carry);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bsubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1,
+        jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    subr(rn(t0), r0, r1);
+    ltr_u(rn(t1), r0, rn(t0));
+    movr(r0, rn(t0));
+    jit_unget_reg(t0);
+    w = _jit->pc.w;
+    if (carry)
+       BNE(rn(t1), ((i0 - w) >> 2) - 1);
+    else
+       BEQ(rn(t1), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(t1);
+    return (w);
+}
+
+static jit_word_t
+_bsubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1,
+        jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    subi(rn(t0), r0, i1);
+    ltr_u(rn(t1), r0, rn(t0));
+    movr(r0, rn(t0));
+    jit_unget_reg(t0);
+    w = _jit->pc.w;
+    if (carry)
+       BNE(rn(t1), ((i0 - w) >> 2) - 1);
+    else
+       BEQ(rn(t1), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(t1);
+    return (w);
+}
+
+static jit_word_t
+_bmxr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1,
+      jit_bool_t set)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    andr(rn(t0), r0, r1);
+    w = _jit->pc.w;
+    if (set)
+       BNE(rn(t0), ((i0 - w) >> 2) - 1);
+    else
+       BEQ(rn(t0), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bmxi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1,
+      jit_bool_t set)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    andi(rn(t0), r0, i1);
+    w = _jit->pc.w;
+    if (set)
+       BNE(rn(t0), ((i0 - w) >> 2) - 1);
+    else
+       BEQ(rn(t0), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static void
+_ldr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ldr_uc(r0, r1);
+    extr_c(r0, r0);
+}
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0)) {
+       LDBU(r0, _R31_REGNO, _u16(i0));
+       extr_c(r0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_c(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       LDBU(r0, _R31_REGNO, _u16(i0));
+    else  {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_uc(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ldr_us(r0, r1);
+    extr_s(r0, r0);
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0)) {
+       LDWU(r0, _R31_REGNO, _u16(i0));
+       extr_s(r0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_s(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       LDWU(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_us(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       LDL(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ldr_i(r0, r1);
+    extr_ui(r0, r0);
+}
+
+static void
+_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0)) {
+       LDL(r0, _R31_REGNO, _u16(i0));
+       extr_ui(r0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_ui(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_l(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       LDQ(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_l(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_c(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0)) {
+       LDBU(r0, r1, _u16(i0));
+       extr_c(r0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_c(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_uc(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       LDBU(r0, r1, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_uc(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_s(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0)) {
+       LDWU(r0, r1, _u16(i0));
+       extr_s(r0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_s(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_us(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       LDWU(r0, r1, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_us(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_i(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       LDL(r0, r1, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_ui(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0)) {
+       LDL(r0, r1, _u16(i0));
+       extr_ui(r0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_ui(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_l(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       LDQ(r0, r1, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_l(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       STB(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_c(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       STW(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_s(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       STL(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_i(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       STQ(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_l(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_c(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       STB(r1, r0, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_c(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_s(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       STW(r1, r0, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_s(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_i(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       STL(r1, r0, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_i(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_l(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (_s16_p(i0))
+       STQ(r1, r0, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_l(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_extr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 56);
+    rshi(r0, r0, 56);
+}
+
+static void
+_extr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 56);
+    rshi_u(r0, r0, 56);
+}
+
+static void
+_extr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 48);
+    rshi(r0, r0, 48);
+}
+
+static void
+_extr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 48);
+    rshi_u(r0, r0, 48);
+}
+
+static void
+_extr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 32);
+    rshi(r0, r0, 32);
+}
+
+static void
+_extr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 32);
+    rshi_u(r0, r0, 32);
+}
+
+static void
+_htonr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    EXTBLi(r1, 0, rn(t0));
+    EXTBLi(r1, 1, r0);
+    SLLi(rn(t0), 8, rn(t0));
+    OR(r0, rn(t0), r0);
+    jit_unget_reg(t0);
+}
+
+static void
+_htonr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+    jit_int32_t                t3;
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr);
+    t2 = jit_get_reg(jit_class_gpr);
+    t3 = jit_get_reg(jit_class_gpr);
+    EXTBLi(r1, 3, rn(t0));
+    INSBLi(r1, 3, rn(t1));
+    SLLi(r1, 8, rn(t2));
+    ZAPNOTi(rn(t2), 4, rn(t2));
+    SRLi(r1, 8, rn(t3));
+    OR(rn(t0), rn(t1), r0);
+    OR(rn(t2), r0, r0);
+    ZAPNOTi(rn(t3), 2, rn(t3));
+    OR(rn(t3), r0, r0);
+    jit_unget_reg(t3);
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+}
+
+static void
+_htonr_ul(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+    assert(_jitc->function != NULL);
+    t0 = jit_get_reg(jit_class_fpr);
+    t1 = jit_get_reg(jit_class_gpr);
+    t2 = jit_get_reg(jit_class_gpr);
+    stxi(-8, _FP_REGNO, r1);                   /* r1 = ABCD EFGH */
+    LDG(rn(t0), _FP_REGNO, _u16(-8));          /* t0 = GHEF CDAB */
+    STT(rn(t0), _FP_REGNO, _u16(-8));
+    ldxi(rn(t1), _FP_REGNO, -8);               /* t1 = GHEF CDAB */
+    lshi(rn(t2), rn(t1), 8);                   /* t2 = HEFC DAB. */
+    rshi_u(rn(t1), rn(t1), 8);                 /* t1 = .GHE FCDA */
+    ZAPi(rn(t2), 0x55, rn(t2));                        /* t2 = H.F. D.B. */
+    ZAPi(rn(t1), 0xaa, rn(t1));                        /* t1 = .G.E .C.A */
+    orr(r0, rn(t1), rn(t2));                   /* r0 = HGFE DCBA */
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+}
+
+static void
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    w = _jit->pc.w;
+    d = ((i0 - w) >> 2) - 1;
+    if (_s21_p(d))
+       BR(_R31_REGNO, d);
+    else
+       (void)jmpi_p(i0);
+}
+
+static jit_word_t
+_jmpi_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    w = movi_p(rn(reg), i0);
+    jmpr(rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_callr(jit_state_t *_jit, jit_int32_t r0)
+{
+    if (r0 != _PV_REGNO)
+       MOV(r0, _PV_REGNO);
+    JSR(_RA_REGNO, _PV_REGNO, 0);
+}
+
+static void
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    /* FIXME use a small buffer to load constants - using gp */
+#if 0
+    jit_word_t         w;
+    jit_word_t         d;
+    w = _jit->pc.w;
+    d = ((i0 - w) >> 2) - 1;
+    if (_s21_p(d))
+       BSR(_RA_REGNO, d);
+    else
+       (void)calli_p(i0);
+#else
+    movi(_PV_REGNO, i0);
+    callr(_PV_REGNO);
+#endif
+}
+
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    w = movi_p(_PV_REGNO, i0);
+    callr(_PV_REGNO);
+    return (w);
+}
+
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                reg;
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar)
+       _jitc->function->self.aoff &= -8;
+    _jitc->function->stack = ((_jitc->function->self.alen -
+                              _jitc->function->self.aoff) + 7) & -8;
+    /* ldgp gp, 0(pv) */
+    LDAH(_PV_REGNO, _GP_REGNO, 0);
+    LDA(_GP_REGNO, _GP_REGNO, 0);
+    /* callee save registers */
+    subi(_SP_REGNO, _SP_REGNO, stack_framesize);
+    stxi(0, _SP_REGNO, _RA_REGNO);
+    stxi(8, _SP_REGNO, _FP_REGNO);
+#  define SPILL(N, O)                                                  \
+    if (jit_regset_tstbit(&_jitc->function->regset, N))                        \
+       stxi(O, _SP_REGNO, N##_REGNO)
+#  define SPILLD(N, O)                                                 \
+    if (jit_regset_tstbit(&_jitc->function->regset, N))                        \
+       stxi_d(O, _SP_REGNO, N##_REGNO)
+    SPILL(_S0, 16);
+    SPILL(_S1, 24);
+    SPILL(_S2, 32);
+    SPILL(_S3, 40);
+    SPILL(_S4, 48);
+    SPILL(_S5, 56);
+    SPILLD(_F2, 64);
+    SPILLD(_F3, 72);
+    SPILLD(_F4, 80);
+    SPILLD(_F5, 88);
+    SPILLD(_F6, 96);
+    SPILLD(_F7, 104);
+    SPILLD(_F8, 112);
+    SPILLD(_F9, 120);
+#  undef SPILLD
+#  undef SPILL
+    movr(_FP_REGNO, _SP_REGNO);
+    /* alloca */
+    if (_jitc->function->stack)
+       subi(_SP_REGNO, _SP_REGNO, _jitc->function->stack);
+    if (_jitc->function->allocar) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    if (_jitc->function->self.call & jit_call_varargs) {
+       for (reg = _jitc->function->self.argi; jit_arg_reg_p(reg); ++reg)
+           stxi(stack_framesize - 48 + reg * 8, _FP_REGNO, rn(_A0 - reg));
+       for (reg = _jitc->function->self.argi; jit_arg_reg_p(reg); ++reg)
+           stxi_d(stack_framesize - 96 + reg * 8, _FP_REGNO, rn(_F16 - reg));
+    }
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    if (_jitc->function->assume_frame)
+       return;
+    movr(_SP_REGNO, _FP_REGNO);
+    ldxi(_RA_REGNO, _SP_REGNO, 0);
+    ldxi(_FP_REGNO, _SP_REGNO, 8);
+#  define LOAD(N, O)                                                   \
+    if (jit_regset_tstbit(&_jitc->function->regset, N))                        \
+       ldxi(N##_REGNO, _SP_REGNO,  O)
+#  define LOADD(N, O)                                                  \
+    if (jit_regset_tstbit(&_jitc->function->regset, N))                        \
+       ldxi_d(N##_REGNO, _SP_REGNO,  O)
+    LOAD(_S0, 16);
+    LOAD(_S1, 24);
+    LOAD(_S2, 32);
+    LOAD(_S3, 40);
+    LOAD(_S4, 48);
+    LOAD(_S5, 56);
+    LOADD(_F2, 64);
+    LOADD(_F3, 72);
+    LOADD(_F4, 80);
+    LOADD(_F5, 88);
+    LOADD(_F6, 96);
+    LOADD(_F7, 104);
+    LOADD(_F8, 112);
+    LOADD(_F9, 120);
+#  undef LOADD
+#  undef LOAD
+    addi(_SP_REGNO, _SP_REGNO, stack_framesize);
+    RET(_R31_REGNO, _RA_REGNO, 1);     /* 1 means procedure return
+                                        * 0 means no procedure return
+                                        * other values are reserved */
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+
+    /* Return jit_va_list_t in the register argument */
+    addi(r0, _FP_REGNO, _jitc->function->vaoff);
+
+    reg = jit_get_reg(jit_class_gpr);
+
+    /* The base field is constant. */
+    addi(rn(reg), _FP_REGNO, stack_framesize - 48);
+    stxi(offsetof(jit_va_list_t, base), r0, rn(reg));
+
+    /* Initialize the offset field */
+    if (_jitc->function->vagp < 6)
+       movi(rn(reg), _jitc->function->vagp * 8);
+    else
+       movi(rn(reg), _jitc->function->self.size - (stack_framesize - 48));
+    stxi(offsetof(jit_va_list_t, offset), r0, rn(reg));
+
+    jit_unget_reg(reg);
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                rg0, rg1;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg(jit_class_gpr);
+    rg1 = jit_get_reg(jit_class_gpr);
+
+    /* Load the base in first temporary. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, base));
+
+    /* Load the offset in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, offset));
+
+    /* Load the argument */
+    ldxr(r0, rn(rg0), rn(rg1));
+
+    /* No longer needed. */
+    jit_unget_reg(rg0);
+
+    /* Update offset. */
+    addi(rn(rg1), rn(rg1), 8);
+    stxi(offsetof(jit_va_list_t, offset), r1, rn(rg1));
+    jit_unget_reg(rg1);
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
+{
+    union {
+       jit_int32_t     *i;
+       jit_word_t       w;
+    } u;
+    jit_word_t          d;
+    jit_int16_t                s0, s1, s2, s3;
+    u.w = instr;
+    switch (_u6(u.i[0] >> 26)) {
+       /*   BLT             BLE             BEQ             BGE */
+       case 0x3a:      case 0x3b:      case 0x39:      case 0x3e:
+       /*   BGT             BNE             BLBC            BLBS */
+       case 0x3f:      case 0x3d:      case 0x38:      case 0x3c:
+       /*   BR              BSR */
+       case 0x30:      case 0x34:
+       /*   FBLT            FBLE            FBEQ            FBGE */
+       case 0x32:      case 0x33:      case 0x31:      case 0x36:
+       /*   FBGT            FBNE */
+       case 0x37:      case 0x35:
+           d = ((label - instr) >> 2) - 1;
+           assert(_s21_p(d));
+           u.i[0] &= ~0x1fffff;
+           u.i[0] |= _u21(d);
+           break;
+       /*   LDA */
+       case 0x08:              /* movi_p */
+           s0 = label;
+           s1 = label >> 16;
+           s2 = label >> 32;
+           s3 = label >> 48;
+           if (s0 < 0)
+               ++s1;
+           if (s2 < 0)
+               ++s3;
+           u.i[0] &= ~0xffff;
+           u.i[0] |= _u16(s0);
+           /*                          LDA */
+           assert(_u6(u.i[1] >> 26) == 0x08);
+           u.i[1] &= ~0xffff;
+           u.i[1] |= _u16(s2);
+           /*                          LDAH */
+           assert(_u6(u.i[2] >> 26) == 0x09);
+           u.i[2] &= ~0xffff;
+           u.i[2] |= _u16(s1);
+           /*                          LDAH */
+           assert(_u6(u.i[3] >> 26) == 0x09);
+           u.i[3] &= ~0xffff;
+           u.i[3] |= _u16(s3);
+           /*                          SLL */
+           assert(_u6(u.i[4] >> 26) == 0x12 && _u7(u.i[4] >> 5) == 0x39);
+           /*                          SRL */
+           assert(_u6(u.i[5] >> 26) == 0x12 && _u7(u.i[5] >> 5) == 0x34);
+           /*                          SLL */
+           assert(_u6(u.i[6] >> 26) == 0x12 && _u7(u.i[6] >> 5) == 0x39);
+           /*                          BIS */
+           assert(_u6(u.i[7] >> 26) == 0x11 && _u7(u.i[7] >> 5) == 0x20);
+           break;
+       default:
+           abort();
+    }
+}
+#endif
diff --git a/deps/lightning/lib/jit_alpha-fpu.c b/deps/lightning/lib/jit_alpha-fpu.c
new file mode 100644 (file)
index 0000000..ea5c746
--- /dev/null
@@ -0,0 +1,1588 @@
+/*
+ * Copyright (C) 2014-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  define _F2_REGNO                    0x02
+#  define _F3_REGNO                    0x03
+#  define _F4_REGNO                    0x04
+#  define _F5_REGNO                    0x05
+#  define _F6_REGNO                    0x06
+#  define _F7_REGNO                    0x07
+#  define _F8_REGNO                    0x08
+#  define _F9_REGNO                    0x09
+#  define F_P(o,ra,rb,f,rc)            _Opr(_jit,o,ra,rb,f,rc)
+static void _Opr(jit_state_t*,int,int,int,unsigned int,int);
+#  define ADDF(ra,rb,rc)               F_P(0x15,ra,rb,0x080,rc)
+#  define ADDG(ra,rb,rc)               F_P(0x15,ra,rb,0x0a0,rc)
+#  define ADDS(ra,rb,rc)               F_P(0x16,ra,rb,0x080,rc)
+#  define ADDS_C(ra,rb,rc)             F_P(0x16,ra,rb,0x000,rc)
+#  define ADDS_M(ra,rb,rc)             F_P(0x16,ra,rb,0x040,rc)
+#  define ADDS_D(ra,rb,rc)             F_P(0x16,ra,rb,0x0c0,rc)
+#  define ADDS_U(ra,rb,rc)             F_P(0x16,ra,rb,0x180,rc)
+#  define ADDS_UC(ra,rb,rc)            F_P(0x16,ra,rb,0x100,rc)
+#  define ADDS_UM(ra,rb,rc)            F_P(0x16,ra,rb,0x140,rc)
+#  define ADDS_UD(ra,rb,rc)            F_P(0x16,ra,rb,0x1c0,rc)
+#  define ADDS_SU(ra,rb,rc)            F_P(0x16,ra,rb,0x580,rc)
+#  define ADDS_SUC(ra,rb,rc)           F_P(0x16,ra,rb,0x500,rc)
+#  define ADDS_SUM(ra,rb,rc)           F_P(0x16,ra,rb,0x540,rc)
+#  define ADDS_SUD(ra,rb,rc)           F_P(0x16,ra,rb,0x5c0,rc)
+#  define ADDS_SUI(ra,rb,rc)           F_P(0x16,ra,rb,0x780,rc)
+#  define ADDS_SUIC(ra,rb,rc)          F_P(0x16,ra,rb,0x700,rc)
+#  define ADDS_SUIM(ra,rb,rc)          F_P(0x16,ra,rb,0x740,rc)
+#  define ADDS_SUID(ra,rb,rc)          F_P(0x16,ra,rb,0x7c0,rc)
+#  define ADDT(ra,rb,rc)               F_P(0x16,ra,rb,0x0a0,rc)
+#  define ADDT_C(ra,rb,rc)             F_P(0x16,ra,rb,0x020,rc)
+#  define ADDT_M(ra,rb,rc)             F_P(0x16,ra,rb,0x060,rc)
+#  define ADDT_D(ra,rb,rc)             F_P(0x16,ra,rb,0x0e0,rc)
+#  define ADDT_U(ra,rb,rc)             F_P(0x16,ra,rb,0x1a0,rc)
+#  define ADDT_UC(ra,rb,rc)            F_P(0x16,ra,rb,0x120,rc)
+#  define ADDT_UM(ra,rb,rc)            F_P(0x16,ra,rb,0x160,rc)
+#  define ADDT_UD(ra,rb,rc)            F_P(0x16,ra,rb,0x1e0,rc)
+#  define ADDT_SU(ra,rb,rc)            F_P(0x16,ra,rb,0x5a0,rc)
+#  define ADDT_SUC(ra,rb,rc)           F_P(0x16,ra,rb,0x520,rc)
+#  define ADDT_SUM(ra,rb,rc)           F_P(0x16,ra,rb,0x560,rc)
+#  define ADDT_SUD(ra,rb,rc)           F_P(0x16,ra,rb,0x5e0,rc)
+#  define ADDT_SUI(ra,rb,rc)           F_P(0x16,ra,rb,0x7a0,rc)
+#  define ADDT_SUIC(ra,rb,rc)          F_P(0x16,ra,rb,0x720,rc)
+#  define ADDT_SUIM(ra,rb,rc)          F_P(0x16,ra,rb,0x760,rc)
+#  define ADDT_SUID(ra,rb,rc)          F_P(0x16,ra,rb,0x7e0,rc)
+#  define CMPGEQ(ra,rb,rc)             F_P(0x15,ra,rb,0x0a5,rc)
+#  define CMPGLE(ra,rb,rc)             F_P(0x15,ra,rb,0x0a7,rc)
+#  define CMPTEQ(ra,rb,rc)             F_P(0x16,ra,rb,0x0a5,rc)
+#  define CMPTEQ_SU(ra,rb,rc)          F_P(0x16,ra,rb,0x5a5,rc)
+#  define CMPTLE(ra,rb,rc)             F_P(0x16,ra,rb,0x0a7,rc)
+#  define CMPTLE_SU(ra,rb,rc)          F_P(0x16,ra,rb,0x5a7,rc)
+#  define CMPTLT(ra,rb,rc)             F_P(0x16,ra,rb,0x0a6,rc)
+#  define CMPTLT_SU(ra,rb,rc)          F_P(0x16,ra,rb,0x5a6,rc)
+#  define CMPTUN(ra,rb,rc)             F_P(0x16,ra,rb,0x0a4,rc)
+#  define CMPTUN_SU(ra,rb,rc)          F_P(0x16,ra,rb,0x5a4,rc)
+#  define CPYS(ra,rb,rc)               F_P(0x17,ra,rb,0x020,rc)
+#  define CPYSE(ra,rb,rc)              F_P(0x17,ra,rb,0x022,rc)
+#  define CPYSN(ra,rb,rc)              F_P(0x17,ra,rb,0x021,rc)
+#  define DIVF(ra,rb,rc)               F_P(0x15,ra,rb,0x083,rc)
+#  define DIVG(ra,rb,rc)               F_P(0x15,ra,rb,0x0a3,rc)
+#  define DIVS(ra,rb,rc)               F_P(0x16,ra,rb,0x083,rc)
+#  define DIVS_C(ra,rb,rc)             F_P(0x16,ra,rb,0x003,rc)
+#  define DIVS_M(ra,rb,rc)             F_P(0x16,ra,rb,0x043,rc)
+#  define DIVS_D(ra,rb,rc)             F_P(0x16,ra,rb,0x0c3,rc)
+#  define DIVS_U(ra,rb,rc)             F_P(0x16,ra,rb,0x183,rc)
+#  define DIVS_UC(ra,rb,rc)            F_P(0x16,ra,rb,0x103,rc)
+#  define DIVS_UM(ra,rb,rc)            F_P(0x16,ra,rb,0x143,rc)
+#  define DIVS_UD(ra,rb,rc)            F_P(0x16,ra,rb,0x1c3,rc)
+#  define DIVS_SU(ra,rb,rc)            F_P(0x16,ra,rb,0x583,rc)
+#  define DIVS_SUC(ra,rb,rc)           F_P(0x16,ra,rb,0x503,rc)
+#  define DIVS_SUM(ra,rb,rc)           F_P(0x16,ra,rb,0x543,rc)
+#  define DIVS_SUD(ra,rb,rc)           F_P(0x16,ra,rb,0x5c3,rc)
+#  define DIVS_SUI(ra,rb,rc)           F_P(0x16,ra,rb,0x783,rc)
+#  define DIVS_SUIC(ra,rb,rc)          F_P(0x16,ra,rb,0x703,rc)
+#  define DIVS_SUIM(ra,rb,rc)          F_P(0x16,ra,rb,0x743,rc)
+#  define DIVS_SUID(ra,rb,rc)          F_P(0x16,ra,rb,0x7c3,rc)
+#  define DIVT(ra,rb,rc)               F_P(0x16,ra,rb,0x0a3,rc)
+#  define DIVT_C(ra,rb,rc)             F_P(0x16,ra,rb,0x023,rc)
+#  define DIVT_M(ra,rb,rc)             F_P(0x16,ra,rb,0x063,rc)
+#  define DIVT_D(ra,rb,rc)             F_P(0x16,ra,rb,0x0e3,rc)
+#  define DIVT_U(ra,rb,rc)             F_P(0x16,ra,rb,0x1a3,rc)
+#  define DIVT_UC(ra,rb,rc)            F_P(0x16,ra,rb,0x123,rc)
+#  define DIVT_UM(ra,rb,rc)            F_P(0x16,ra,rb,0x163,rc)
+#  define DIVT_UD(ra,rb,rc)            F_P(0x16,ra,rb,0x1e3,rc)
+#  define DIVT_SU(ra,rb,rc)            F_P(0x16,ra,rb,0x5a3,rc)
+#  define DIVT_SUC(ra,rb,rc)           F_P(0x16,ra,rb,0x523,rc)
+#  define DIVT_SUM(ra,rb,rc)           F_P(0x16,ra,rb,0x563,rc)
+#  define DIVT_SUD(ra,rb,rc)           F_P(0x16,ra,rb,0x5e3,rc)
+#  define DIVT_SUI(ra,rb,rc)           F_P(0x16,ra,rb,0x7a3,rc)
+#  define DIVT_SUIC(ra,rb,rc)          F_P(0x16,ra,rb,0x723,rc)
+#  define DIVT_SUIM(ra,rb,rc)          F_P(0x16,ra,rb,0x7a3,rc)
+#  define DIVT_SUID(ra,rb,rc)          F_P(0x16,ra,rb,0x7e3,rc)
+#  define CVTDG(rb,rc)                 F_P(0x15,_R31_REGNO,rb,0x09e,rc)
+#  define CVTGD(rb,rc)                 F_P(0x15,_R31_REGNO,rb,0x0ad,rc)
+#  define CVTGF(rb,rc)                 F_P(0x15,_R31_REGNO,rb,0x0ac,rc)
+#  define CVTGQ(rb,rc)                 F_P(0x15,_R31_REGNO,rb,0x0af,rc)
+#  define CVTLQ(rb,rc)                 F_P(0x17,_R31_REGNO,rb,0x010,rc)
+#  define CVTQF(rb,rc)                 F_P(0x15,_R31_REGNO,rb,0x0bc,rc)
+#  define CVTQG(rb,rc)                 F_P(0x15,_R31_REGNO,rb,0x0be,rc)
+#  define CVTQL(rb,rc)                 F_P(0x17,_R31_REGNO,rb,0x030,rc)
+#  define CVTQS(rb,rc)                 F_P(0x16,_R31_REGNO,rb,0x0bc,rc)
+#  define CVTQS_C(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x03c,rc)
+#  define CVTQS_M(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x07c,rc)
+#  define CVTQS_D(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x0fc,rc)
+#  define CVTQS_SUI(rb,rc)             F_P(0x16,_R31_REGNO,rb,0x7bc,rc)
+#  define CVTQS_SUIC(rb,rc)            F_P(0x16,_R31_REGNO,rb,0x73c,rc)
+#  define CVTQS_SUIM(rb,rc)            F_P(0x16,_R31_REGNO,rb,0x77c,rc)
+#  define CVTQS_SUID(rb,rc)            F_P(0x16,_R31_REGNO,rb,0x7fc,rc)
+#  define CVTQT(rb,rc)                 F_P(0x16,_R31_REGNO,rb,0x0be,rc)
+#  define CVTQT_C(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x03e,rc)
+#  define CVTQT_M(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x0te,rc)
+#  define CVTQT_D(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x0fe,rc)
+#  define CVTQT_SUI(rb,rc)             F_P(0x16,_R31_REGNO,rb,0x7be,rc)
+#  define CVTQT_SUIC(rb,rc)            F_P(0x16,_R31_REGNO,rb,0x73e,rc)
+#  define CVTQT_SUIM(rb,rc)            F_P(0x16,_R31_REGNO,rb,0x77e,rc)
+#  define CVTQT_SUID(rb,rc)            F_P(0x16,_R31_REGNO,rb,0x7fe,rc)
+#  define CVTST(rb,rc)                 F_P(0x16,_R31_REGNO,rb,0x2ac,rc)
+#  define CVTST_S(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x6ac,rc)
+#  define CVTTQ(rb,rc)                 F_P(0x16,_R31_REGNO,rb,0x0af,rc)
+#  define CVTTQ_C(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x02f,rc)
+#  define CVTTQ_V(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x1af,rc)
+#  define CVTTQ_VC(rb,rc)              F_P(0x16,_R31_REGNO,rb,0x12f,rc)
+#  define CVTTQ_SV(rb,rc)              F_P(0x16,_R31_REGNO,rb,0x5af,rc)
+#  define CVTTQ_SVC(rb,rc)             F_P(0x16,_R31_REGNO,rb,0x52f,rc)
+#  define CVTTQ_SVI(rb,rc)             F_P(0x16,_R31_REGNO,rb,0x7af,rc)
+#  define CVTTQ_SVIC(rb,rc)            F_P(0x16,_R31_REGNO,rb,0x72f,rc)
+#  define CVTTQ_D(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x0ef,rc)
+#  define CVTTQ_VD(rb,rc)              F_P(0x16,_R31_REGNO,rb,0x1ef,rc)
+#  define CVTTQ_SVD(rb,rc)             F_P(0x16,_R31_REGNO,rb,0x5ef,rc)
+#  define CVTTQ_SVID(rb,rc)            F_P(0x16,_R31_REGNO,rb,0x7ef,rc)
+#  define CVTTQ_M(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x06f,rc)
+#  define CVTTQ_VM(rb,rc)              F_P(0x16,_R31_REGNO,rb,0x16f,rc)
+#  define CVTTQ_SVM(rb,rc)             F_P(0x16,_R31_REGNO,rb,0x56f,rc)
+#  define CVTTQ_SVIM(rb,rc)            F_P(0x16,_R31_REGNO,rb,0x76f,rc)
+#  define CVTTS(rb,rc)                 F_P(0x16,_R31_REGNO,rb,0x0ac,rc)
+#  define CVTTS_C(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x02c,rc)
+#  define CVTTS_M(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x06c,rc)
+#  define CVTTS_D(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x0ec,rc)
+#  define CVTTS_U(rb,rc)               F_P(0x16,_R31_REGNO,rb,0x1ac,rc)
+#  define CVTTS_UC(rb,rc)              F_P(0x16,_R31_REGNO,rb,0x12c,rc)
+#  define CVTTS_UM(rb,rc)              F_P(0x16,_R31_REGNO,rb,0x16c,rc)
+#  define CVTTS_UD(rb,rc)              F_P(0x16,_R31_REGNO,rb,0x1ec,rc)
+#  define FBEQ(ra,d)                   Bra(0x31,ra,d)
+#  define FBGE(ra,d)                   Bra(0x36,ra,d)
+#  define FBGT(ra,d)                   Bra(0x37,ra,d)
+#  define FBLE(ra,d)                   Bra(0x33,ra,d)
+#  define FBLT(ra,d)                   Bra(0x32,ra,d)
+#  define FBNE(ra,d)                   Bra(0x35,ra,d)
+#  define FCMOVEQ(ra,rb,rc)            F_P(0x17,ra,rb,0x02a,rc)
+#  define FCMOVGE(ra,rb,rc)            F_P(0x17,ra,rb,0x02d,rc)
+#  define FCMOVGT(ra,rb,rc)            F_P(0x17,ra,rb,0x02f,rc)
+#  define FCMOVLE(ra,rb,rc)            F_P(0x17,ra,rb,0x02e,rc)
+#  define FCMOVLT(ra,rb,rc)            F_P(0x17,ra,rb,0x02c,rc)
+#  define FCMOVNE(ra,rb,rc)            F_P(0x17,ra,rb,0x02b,rc)
+#  define FTOIS(ra,rc)                 F_P(0x1c,ra,_R31_REGNO,0x078,rc)
+#  define FTOIT(ra,rc)                 F_P(0x1c,ra,_R31_REGNO,0x070,rc)
+#  define ITOFF(ra,rc)                 F_P(0x14,ra,_R31_REGNO,0x014,rc)
+#  define ITOFS(ra,rc)                 F_P(0x14,ra,_R31_REGNO,0x004,rc)
+#  define ITOFT(ra,rc)                 F_P(0x14,ra,_R31_REGNO,0x024,rc)
+#  define LDF(ra,rb,d)                 Mem(0x20,ra,rb,d)
+#  define LDG(ra,rb,d)                 Mem(0x21,ra,rb,d)
+#  define LDS(ra,rb,d)                 Mem(0x22,ra,rb,d)
+#  define LDT(ra,rb,d)                 Mem(0x23,ra,rb,d)
+#  define MF_FPCR(ra)                  F_P(0x17,ra,ra,0x025,ra)
+#  define MT_FPCR(ra)                  F_P(0x17,ra,ra,0x024,ra)
+#  define MULF(ra,rb,rc)               F_P(0x15,ra,rb,0x082,rc)
+#  define MULG(ra,rb,rc)               F_P(0x15,ra,rb,0x0a2,rc)
+#  define MULS(ra,rb,rc)               F_P(0x16,ra,rb,0x082,rc)
+#  define MULS_C(ra,rb,rc)             F_P(0x16,ra,rb,0x002,rc)
+#  define MULS_M(ra,rb,rc)             F_P(0x16,ra,rb,0x042,rc)
+#  define MULS_D(ra,rb,rc)             F_P(0x16,ra,rb,0x0c2,rc)
+#  define MULS_U(ra,rb,rc)             F_P(0x16,ra,rb,0x182,rc)
+#  define MULS_UC(ra,rb,rc)            F_P(0x16,ra,rb,0x102,rc)
+#  define MULS_UM(ra,rb,rc)            F_P(0x16,ra,rb,0x142,rc)
+#  define MULS_UD(ra,rb,rc)            F_P(0x16,ra,rb,0x1c2,rc)
+#  define MULS_SU(ra,rb,rc)            F_P(0x16,ra,rb,0x582,rc)
+#  define MULS_SUC(ra,rb,rc)           F_P(0x16,ra,rb,0x502,rc)
+#  define MULS_SUM(ra,rb,rc)           F_P(0x16,ra,rb,0x642,rc)
+#  define MULS_SUD(ra,rb,rc)           F_P(0x16,ra,rb,0x5c2,rc)
+#  define MULS_SUI(ra,rb,rc)           F_P(0x16,ra,rb,0x782,rc)
+#  define MULS_SUIC(ra,rb,rc)          F_P(0x16,ra,rb,0x702,rc)
+#  define MULS_SUIM(ra,rb,rc)          F_P(0x16,ra,rb,0x742,rc)
+#  define MULS_SUID(ra,rb,rc)          F_P(0x16,ra,rb,0x7c2,rc)
+#  define MULT(ra,rb,rc)               F_P(0x16,ra,rb,0x0a2,rc)
+#  define MULT_C(ra,rb,rc)             F_P(0x16,ra,rb,0x022,rc)
+#  define MULT_M(ra,rb,rc)             F_P(0x16,ra,rb,0x062,rc)
+#  define MULT_D(ra,rb,rc)             F_P(0x16,ra,rb,0x0e2,rc)
+#  define MULT_U(ra,rb,rc)             F_P(0x16,ra,rb,0x1a2,rc)
+#  define MULT_UC(ra,rb,rc)            F_P(0x16,ra,rb,0x122,rc)
+#  define MULT_UM(ra,rb,rc)            F_P(0x16,ra,rb,0x162,rc)
+#  define MULT_UD(ra,rb,rc)            F_P(0x16,ra,rb,0x1e2,rc)
+#  define MULT_SU(ra,rb,rc)            F_P(0x16,ra,rb,0x5a2,rc)
+#  define MULT_SUC(ra,rb,rc)           F_P(0x16,ra,rb,0x522,rc)
+#  define MULT_SUM(ra,rb,rc)           F_P(0x16,ra,rb,0x562,rc)
+#  define MULT_SUD(ra,rb,rc)           F_P(0x16,ra,rb,0x5e2,rc)
+#  define MULT_SUI(ra,rb,rc)           F_P(0x16,ra,rb,0x7a2,rc)
+#  define MULT_SUIC(ra,rb,rc)          F_P(0x16,ra,rb,0x722,rc)
+#  define MULT_SUIM(ra,rb,rc)          F_P(0x16,ra,rb,0x762,rc)
+#  define MULT_SUID(ra,rb,rc)          F_P(0x16,ra,rb,0x7e2,rc)
+#  define SQRTF(rb,rc)                 F_P(0x14,_R31_REGNO,rb,0x08a,rc)
+#  define SQRTG(rb,rc)                 F_P(0x14,_R31_REGNO,rb,0x0aa,rc)
+#  define SQRTS(rb,rc)                 F_P(0x14,_R31_REGNO,rb,0x08b,rc)
+#  define SQRTS_C(rb,rc)               F_P(0x14,_R31_REGNO,rb,0x00b,rc)
+#  define SQRTS_M(rb,rc)               F_P(0x14,_R31_REGNO,rb,0x04b,rc)
+#  define SQRTS_D(rb,rc)               F_P(0x14,_R31_REGNO,rb,0x0cb,rc)
+#  define SQRTS_U(rb,rc)               F_P(0x14,_R31_REGNO,rb,0x18b,rc)
+#  define SQRTS_UC(rb,rc)              F_P(0x14,_R31_REGNO,rb,0x10b,rc)
+#  define SQRTS_UM(rb,rc)              F_P(0x14,_R31_REGNO,rb,0x14b,rc)
+#  define SQRTS_UD(rb,rc)              F_P(0x14,_R31_REGNO,rb,0x1cb,rc)
+#  define SQRTS_SU(rb,rc)              F_P(0x14,_R31_REGNO,rb,0x58b,rc)
+#  define SQRTS_SUC(rb,rc)             F_P(0x14,_R31_REGNO,rb,0x50b,rc)
+#  define SQRTS_SUM(rb,rc)             F_P(0x14,_R31_REGNO,rb,0x54b,rc)
+#  define SQRTS_SUD(rb,rc)             F_P(0x14,_R31_REGNO,rb,0x5cb,rc)
+#  define SQRTS_SUI(rb,rc)             F_P(0x14,_R31_REGNO,rb,0x78b,rc)
+#  define SQRTS_SUIC(rb,rc)            F_P(0x14,_R31_REGNO,rb,0x70b,rc)
+#  define SQRTS_SUIM(rb,rc)            F_P(0x14,_R31_REGNO,rb,0x74b,rc)
+#  define SQRTS_SUID(rb,rc)            F_P(0x14,_R31_REGNO,rb,0x7cb,rc)
+#  define SQRTT(rb,rc)                 F_P(0x14,_R31_REGNO,rb,0x0ab,rc)
+#  define SQRTT_C(rb,rc)               F_P(0x14,_R31_REGNO,rb,0x02b,rc)
+#  define SQRTT_M(rb,rc)               F_P(0x14,_R31_REGNO,rb,0x06b,rc)
+#  define SQRTT_D(rb,rc)               F_P(0x14,_R31_REGNO,rb,0x0eb,rc)
+#  define SQRTT_U(rb,rc)               F_P(0x14,_R31_REGNO,rb,0x1ab,rc)
+#  define SQRTT_UC(rb,rc)              F_P(0x14,_R31_REGNO,rb,0x12b,rc)
+#  define SQRTT_UM(rb,rc)              F_P(0x14,_R31_REGNO,rb,0x16b,rc)
+#  define SQRTT_UD(rb,rc)              F_P(0x14,_R31_REGNO,rb,0x1eb,rc)
+#  define SQRTT_SU(rb,rc)              F_P(0x14,_R31_REGNO,rb,0x5ab,rc)
+#  define SQRTT_SUC(rb,rc)             F_P(0x14,_R31_REGNO,rb,0x52b,rc)
+#  define SQRTT_SUM(rb,rc)             F_P(0x14,_R31_REGNO,rb,0x56b,rc)
+#  define SQRTT_SUD(rb,rc)             F_P(0x14,_R31_REGNO,rb,0x5eb,rc)
+#  define SQRTT_SUI(rb,rc)             F_P(0x14,_R31_REGNO,rb,0x7ab,rc)
+#  define SQRTT_SUIC(rb,rc)            F_P(0x14,_R31_REGNO,rb,0x72b,rc)
+#  define SQRTT_SUIM(rb,rc)            F_P(0x14,_R31_REGNO,rb,0x76b,rc)
+#  define SQRTT_SUID(rb,rc)            F_P(0x14,_R31_REGNO,rb,0x7eb,rc)
+#  define STF(ra,rb,d)                 Mem(0x24,ra,rb,d)
+#  define STG(ra,rb,d)                 Mem(0x25,ra,rb,d)
+#  define STS(ra,rb,d)                 Mem(0x26,ra,rb,d)
+#  define STT(ra,rb,d)                 Mem(0x27,ra,rb,d)
+#  define SUBF(ra,rb,rc)               F_P(0x15,ra,rb,0x081,rc)
+#  define SUBG(ra,rb,rc)               F_P(0x15,ra,rb,0x0a1,rc)
+#  define SUBS(ra,rb,rc)               F_P(0x16,ra,rb,0x081,rc)
+#  define SUBS_C(ra,rb,rc)             F_P(0x16,ra,rb,0x001,rc)
+#  define SUBS_M(ra,rb,rc)             F_P(0x16,ra,rb,0x041,rc)
+#  define SUBS_D(ra,rb,rc)             F_P(0x16,ra,rb,0x0c1,rc)
+#  define SUBS_U(ra,rb,rc)             F_P(0x16,ra,rb,0x181,rc)
+#  define SUBS_UC(ra,rb,rc)            F_P(0x16,ra,rb,0x101,rc)
+#  define SUBS_UM(ra,rb,rc)            F_P(0x16,ra,rb,0x141,rc)
+#  define SUBS_UD(ra,rb,rc)            F_P(0x16,ra,rb,0x1c1,rc)
+#  define SUBS_SU(ra,rb,rc)            F_P(0x16,ra,rb,0x581,rc)
+#  define SUBS_SUC(ra,rb,rc)           F_P(0x16,ra,rb,0x501,rc)
+#  define SUBS_SUM(ra,rb,rc)           F_P(0x16,ra,rb,0x541,rc)
+#  define SUBS_SUD(ra,rb,rc)           F_P(0x16,ra,rb,0x5c1,rc)
+#  define SUBS_SUI(ra,rb,rc)           F_P(0x16,ra,rb,0x781,rc)
+#  define SUBS_SUIC(ra,rb,rc)          F_P(0x16,ra,rb,0x701,rc)
+#  define SUBS_SUIM(ra,rb,rc)          F_P(0x16,ra,rb,0x741,rc)
+#  define SUBS_SUID(ra,rb,rc)          F_P(0x16,ra,rb,0x7c1,rc)
+#  define SUBT(ra,rb,rc)               F_P(0x16,ra,rb,0x0a1,rc)
+#  define SUBT_C(ra,rb,rc)             F_P(0x16,ra,rb,0x021,rc)
+#  define SUBT_M(ra,rb,rc)             F_P(0x16,ra,rb,0x061,rc)
+#  define SUBT_D(ra,rb,rc)             F_P(0x16,ra,rb,0x0e1,rc)
+#  define SUBT_U(ra,rb,rc)             F_P(0x16,ra,rb,0x1a1,rc)
+#  define SUBT_UC(ra,rb,rc)            F_P(0x16,ra,rb,0x121,rc)
+#  define SUBT_UM(ra,rb,rc)            F_P(0x16,ra,rb,0x161,rc)
+#  define SUBT_UD(ra,rb,rc)            F_P(0x16,ra,rb,0x1e1,rc)
+#  define SUBT_SU(ra,rb,rc)            F_P(0x16,ra,rb,0x5a1,rc)
+#  define SUBT_SUC(ra,rb,rc)           F_P(0x16,ra,rb,0x521,rc)
+#  define SUBT_SUM(ra,rb,rc)           F_P(0x16,ra,rb,0x561,rc)
+#  define SUBT_SUD(ra,rb,rc)           F_P(0x16,ra,rb,0x5e1,rc)
+#  define SUBT_SUI(ra,rb,rc)           F_P(0x16,ra,rb,0x7a1,rc)
+#  define SUBT_SUIC(ra,rb,rc)          F_P(0x16,ra,rb,0x721,rc)
+#  define SUBT_SUIM(ra,rb,rc)          F_P(0x16,ra,rb,0x761,rc)
+#  define SUBT_SUID(ra,rb,rc)          F_P(0x16,ra,rb,0x7e1,rc)
+#  define FABS(ra,rc)                  CPYS(_R31_REGNO,ra,rc)
+#  define FMOV(ra,rc)                  CPYS(ra,ra,rc)
+#  define NEGF(ra,rc)                  SUBF(_R31_REGNO,ra,rc)
+#  define NEGG(ra,rc)                  SUBG(_R31_REGNO,ra,rc)
+#  define NEGS(ra,rc)                  SUBS(_R31_REGNO,ra,rc)
+#  define NEGT(ra,rc)                  SUBT(_R31_REGNO,ra,rc)
+#  define FNEGF(ra,rc)                 CPYSN(ra,ra,rc)
+#  define FNEGG(ra,rc)                 CPYSN(ra,ra,rc)
+#  define FNEGS(ra,rc)                 CPYSN(ra,ra,rc)
+#  define FNEGT(ra,rc)                 CPYSN(ra,ra,rc)
+#  define movr_f(r0,r1)                        movr_d(r0,r1)
+#  define movr_d(r0,r1)                        _movr_d(_jit,r0,r1)
+static void _movr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi_f(r0,i0)                        _movi_f(_jit,r0,i0)
+static void _movi_f(jit_state_t*,jit_int32_t,jit_float32_t*);
+#  define movi_d(r0,i0)                        _movi_d(_jit,r0,i0)
+static void _movi_d(jit_state_t*,jit_int32_t,jit_float64_t*);
+#  define absr_f(r0,r1)                        FABS(r1,r0)
+#  define absr_d(r0,r1)                        FABS(r1,r0)
+#  define negr_f(r0,r1)                        FNEGS(r1,r0)
+#  define negr_d(r0,r1)                        FNEGT(r1,r0)
+#  define sqrtr_f(r0,r1)               _sqrtr_f(_jit,r0,r1)
+static void _sqrtr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sqrtr_d(r0,r1)               _sqrtr_d(_jit,r0,r1)
+static void _sqrtr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_f_d(r0,r1)              movr_d(r0,r1)
+#  define extr_d_f(r0,r1)              movr_f(r0,r1)
+#  define truncr_f_i(r0,r1)            truncr_d_i(r0,r1)
+#  define truncr_f_l(r0,r1)            truncr_d_l(r0,r1)
+#  define truncr_d_i(r0,r1)            truncr_d_l(r0,r1)
+#  define truncr_d_l(r0,r1)            _truncr_d_l(_jit,r0,r1)
+static void _truncr_d_l(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_f(r0,r1)                        _extr_f(_jit,r0,r1)
+static void _extr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_d(r0,r1)                        _extr_d(_jit,r0,r1)
+static void _extr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define addr_f(r0,r1,r2)             _addr_f(_jit,r0,r1,r2)
+static void _addr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addi_f(r0,r1,i0)             _addi_f(_jit,r0,r1,i0)
+static void _addi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define addr_d(r0,r1,r2)             _addr_d(_jit,r0,r1,r2)
+static void _addr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addi_d(r0,r1,i0)             _addi_d(_jit,r0,r1,i0)
+static void _addi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define subr_f(r0,r1,r2)             _subr_f(_jit,r0,r1,r2)
+static void _subr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subi_f(r0,r1,i0)             _subi_f(_jit,r0,r1,i0)
+static void _subi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define subr_d(r0,r1,r2)             _subr_d(_jit,r0,r1,r2)
+static void _subr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subi_d(r0,r1,i0)             _subi_d(_jit,r0,r1,i0)
+static void _subi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define rsbr_f(r0, r1, r2)           subr_f(r0, r2, r1)
+#  define rsbi_f(r0, r1, i0)           _rsbi_f(_jit, r0, r1, i0)
+static void _rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define rsbr_d(r0, r1, r2)           subr_d(r0, r2, r1)
+#  define rsbi_d(r0, r1, i0)           _rsbi_d(_jit, r0, r1, i0)
+static void _rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define mulr_f(r0,r1,r2)             _mulr_f(_jit,r0,r1,r2)
+static void _mulr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define muli_f(r0,r1,i0)             _muli_f(_jit,r0,r1,i0)
+static void _muli_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define mulr_d(r0,r1,r2)             _mulr_d(_jit,r0,r1,r2)
+static void _mulr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define muli_d(r0,r1,i0)             _muli_d(_jit,r0,r1,i0)
+static void _muli_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define divr_f(r0,r1,r2)             _divr_f(_jit,r0,r1,r2)
+static void _divr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi_f(r0,r1,i0)             _divi_f(_jit,r0,r1,i0)
+static void _divi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define divr_d(r0,r1,r2)             _divr_d(_jit,r0,r1,r2)
+static void _divr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi_d(r0,r1,i0)             _divi_d(_jit,r0,r1,i0)
+static void _divi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ltr_f(r0,r1,r2)              ltr_d(r0,r1,r2)
+#  define ltr_d(r0,r1,r2)              _ltr_d(_jit,r0,r1,r2)
+static void _ltr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lti_f(r0,r1,i0)              _lti_f(_jit,r0,r1,i0)
+static void _lti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define lti_d(r0,r1,i0)              _lti_d(_jit,r0,r1,i0)
+static void _lti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ler_f(r0,r1,r2)              ler_d(r0,r1,r2)
+#  define ler_d(r0,r1,r2)              _ler_d(_jit,r0,r1,r2)
+static void _ler_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lei_f(r0,r1,i0)              _lei_f(_jit,r0,r1,i0)
+static void _lei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define lei_d(r0,r1,i0)              _lei_d(_jit,r0,r1,i0)
+static void _lei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define eqr_f(r0,r1,r2)              eqr_d(r0,r1,r2)
+#  define eqr_d(r0,r1,r2)              _eqr_d(_jit,r0,r1,r2)
+static void _eqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define eqi_f(r0,r1,i0)              _eqi_f(_jit,r0,r1,i0)
+static void _eqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define eqi_d(r0,r1,i0)              _eqi_d(_jit,r0,r1,i0)
+static void _eqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ger_f(r0,r1,r2)              ger_d(r0,r1,r2)
+#  define ger_d(r0,r1,r2)              _ger_d(_jit,r0,r1,r2)
+static void _ger_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gei_f(r0,r1,i0)              _gei_f(_jit,r0,r1,i0)
+static void _gei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define gei_d(r0,r1,i0)              _gei_d(_jit,r0,r1,i0)
+static void _gei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define gtr_f(r0,r1,r2)              gtr_d(r0,r1,r2)
+#  define gtr_d(r0,r1,r2)              _gtr_d(_jit,r0,r1,r2)
+static void _gtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gti_f(r0,r1,i0)              _gti_f(_jit,r0,r1,i0)
+static void _gti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define gti_d(r0,r1,i0)              _gti_d(_jit,r0,r1,i0)
+static void _gti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ner_f(r0,r1,r2)              ner_d(r0,r1,r2)
+#  define ner_d(r0,r1,r2)              _ner_d(_jit,r0,r1,r2)
+static void _ner_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nei_f(r0,r1,i0)              _nei_f(_jit,r0,r1,i0)
+static void _nei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define nei_d(r0,r1,i0)              _nei_d(_jit,r0,r1,i0)
+static void _nei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unltr_f(r0,r1,r2)            unltr_d(r0,r1,r2)
+#  define unltr_d(r0,r1,r2)            _unltr_d(_jit,r0,r1,r2)
+static void _unltr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unlti_f(r0,r1,i0)            _unlti_f(_jit,r0,r1,i0)
+static void _unlti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unlti_d(r0,r1,i0)            _unlti_d(_jit,r0,r1,i0)
+static void _unlti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unler_f(r0,r1,r2)            unler_d(r0,r1,r2)
+#  define unler_d(r0,r1,r2)            _unler_d(_jit,r0,r1,r2)
+static void _unler_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unlei_f(r0,r1,i0)            _unlei_f(_jit,r0,r1,i0)
+static void _unlei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unlei_d(r0,r1,i0)            _unlei_d(_jit,r0,r1,i0)
+static void _unlei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define uneqr_f(r0,r1,r2)            uneqr_d(r0,r1,r2)
+#  define uneqr_d(r0,r1,r2)            _uneqr_d(_jit,r0,r1,r2)
+static void _uneqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define uneqi_f(r0,r1,i0)            _uneqi_f(_jit,r0,r1,i0)
+static void _uneqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define uneqi_d(r0,r1,i0)            _uneqi_d(_jit,r0,r1,i0)
+static void _uneqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unger_f(r0,r1,r2)            unger_d(r0,r1,r2)
+#  define unger_d(r0,r1,r2)            _unger_d(_jit,r0,r1,r2)
+static void _unger_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ungei_f(r0,r1,i0)            _ungei_f(_jit,r0,r1,i0)
+static void _ungei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ungei_d(r0,r1,i0)            _ungei_d(_jit,r0,r1,i0)
+static void _ungei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ungtr_f(r0,r1,r2)            ungtr_d(r0,r1,r2)
+#  define ungtr_d(r0,r1,r2)            _ungtr_d(_jit,r0,r1,r2)
+static void _ungtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ungti_f(r0,r1,i0)            _ungti_f(_jit,r0,r1,i0)
+static void _ungti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ungti_d(r0,r1,i0)            _ungti_d(_jit,r0,r1,i0)
+static void _ungti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ltgtr_f(r0,r1,r2)            ltgtr_d(r0,r1,r2)
+#  define ltgtr_d(r0,r1,r2)            _ltgtr_d(_jit,r0,r1,r2)
+static void _ltgtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ltgti_f(r0,r1,i0)            _ltgti_f(_jit,r0,r1,i0)
+static void _ltgti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ltgti_d(r0,r1,i0)            _ltgti_d(_jit,r0,r1,i0)
+static void _ltgti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ordr_f(r0,r1,r2)             ordr_d(r0,r1,r2)
+#  define ordr_d(r0,r1,r2)             _ordr_d(_jit,r0,r1,r2)
+static void _ordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ordi_f(r0,r1,i0)             _ordi_f(_jit,r0,r1,i0)
+static void _ordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ordi_d(r0,r1,i0)             _ordi_d(_jit,r0,r1,i0)
+static void _ordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unordr_f(r0,r1,r2)           unordr_d(r0,r1,r2)
+#  define unordr_d(r0,r1,r2)           _unordr_d(_jit,r0,r1,r2)
+static void _unordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unordi_f(r0,r1,i0)           _unordi_f(_jit,r0,r1,i0)
+static void _unordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unordi_d(r0,r1,i0)           _unordi_d(_jit,r0,r1,i0)
+static void _unordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define bltr_f(i0,r0,r1)             bltr_d(i0,r0,r1)
+#  define bltr_d(i0,r0,r1)             _bltr_d(_jit,i0,r0,r1)
+static jit_word_t _bltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti_f(i0,r0,i1)             _blti_f(_jit,i0,r0,i1)
+static jit_word_t _blti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define blti_d(i0,r0,i1)             _blti_d(_jit,i0,r0,i1)
+static jit_word_t _blti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bler_f(i0,r0,r1)             bler_d(i0,r0,r1)
+#  define bler_d(i0,r0,r1)             _bler_d(_jit,i0,r0,r1)
+static jit_word_t _bler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei_f(i0,r0,i1)             _blei_f(_jit,i0,r0,i1)
+static jit_word_t _blei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define blei_d(i0,r0,i1)             _blei_d(_jit,i0,r0,i1)
+static jit_word_t _blei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define beqr_f(i0,r0,r1)             beqr_d(i0,r0,r1)
+#  define beqr_d(i0,r0,r1)             _beqr_d(_jit,i0,r0,r1)
+static jit_word_t _beqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define beqi_f(i0,r0,i1)             _beqi_f(_jit,i0,r0,i1)
+static jit_word_t _beqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define beqi_d(i0,r0,i1)             _beqi_d(_jit,i0,r0,i1)
+static jit_word_t _beqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bger_f(i0,r0,r1)             bger_d(i0,r0,r1)
+#  define bger_d(i0,r0,r1)             _bger_d(_jit,i0,r0,r1)
+static jit_word_t _bger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei_f(i0,r0,i1)             _bgei_f(_jit,i0,r0,i1)
+static jit_word_t _bgei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bgei_d(i0,r0,i1)             _bgei_d(_jit,i0,r0,i1)
+static jit_word_t _bgei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bgtr_f(i0,r0,r1)             bgtr_d(i0,r0,r1)
+#  define bgtr_d(i0,r0,r1)             _bgtr_d(_jit,i0,r0,r1)
+static jit_word_t _bgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti_f(i0,r0,i1)             _bgti_f(_jit,i0,r0,i1)
+static jit_word_t _bgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bgti_d(i0,r0,i1)             _bgti_d(_jit,i0,r0,i1)
+static jit_word_t _bgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bner_f(i0,r0,r1)             bner_d(i0,r0,r1)
+#  define bner_d(i0,r0,r1)             _bner_d(_jit,i0,r0,r1)
+static jit_word_t _bner_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bnei_f(i0,r0,i1)             _bnei_f(_jit,i0,r0,i1)
+static jit_word_t _bnei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bnei_d(i0,r0,i1)             _bnei_d(_jit,i0,r0,i1)
+static jit_word_t _bnei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bunltr_f(i0,r0,r1)           bunltr_d(i0,r0,r1)
+#  define bunltr_d(i0,r0,r1)           _bunltr_d(_jit,i0,r0,r1)
+static jit_word_t _bunltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlti_f(i0,r0,i1)           _bunlti_f(_jit,i0,r0,i1)
+static jit_word_t _bunlti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bunlti_d(i0,r0,i1)           _bunlti_d(_jit,i0,r0,i1)
+static jit_word_t _bunlti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bunler_f(i0,r0,r1)           bunler_d(i0,r0,r1)
+#  define bunler_d(i0,r0,r1)           _bunler_d(_jit,i0,r0,r1)
+static jit_word_t _bunler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlei_f(i0,r0,i1)           _bunlei_f(_jit,i0,r0,i1)
+static jit_word_t _bunlei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bunlei_d(i0,r0,i1)           _bunlei_d(_jit,i0,r0,i1)
+static jit_word_t _bunlei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define buneqr_f(i0,r0,r1)           buneqr_d(i0,r0,r1)
+#  define buneqr_d(i0,r0,r1)           _buneqr_d(_jit,i0,r0,r1)
+static jit_word_t _buneqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define buneqi_f(i0,r0,i1)           _buneqi_f(_jit,i0,r0,i1)
+static jit_word_t _buneqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define buneqi_d(i0,r0,i1)           _buneqi_d(_jit,i0,r0,i1)
+static jit_word_t _buneqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bunger_f(i0,r0,r1)           bunger_d(i0,r0,r1)
+#  define bunger_d(i0,r0,r1)           _bunger_d(_jit,i0,r0,r1)
+static jit_word_t _bunger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungei_f(i0,r0,i1)           _bungei_f(_jit,i0,r0,i1)
+static jit_word_t _bungei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bungei_d(i0,r0,i1)           _bungei_d(_jit,i0,r0,i1)
+static jit_word_t _bungei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bungtr_f(i0,r0,r1)           bungtr_d(i0,r0,r1)
+#  define bungtr_d(i0,r0,r1)           _bungtr_d(_jit,i0,r0,r1)
+static jit_word_t _bungtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungti_f(i0,r0,i1)           _bungti_f(_jit,i0,r0,i1)
+static jit_word_t _bungti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bungti_d(i0,r0,i1)           _bungti_d(_jit,i0,r0,i1)
+static jit_word_t _bungti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bltgtr_f(i0,r0,r1)           bltgtr_d(i0,r0,r1)
+#  define bltgtr_d(i0,r0,r1)           _bltgtr_d(_jit,i0,r0,r1)
+static jit_word_t _bltgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bltgti_f(i0,r0,i1)           _bltgti_f(_jit,i0,r0,i1)
+static jit_word_t _bltgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bltgti_d(i0,r0,i1)           _bltgti_d(_jit,i0,r0,i1)
+static jit_word_t _bltgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bordr_f(i0,r0,r1)            bordr_d(i0,r0,r1)
+#  define bordr_d(i0,r0,r1)            _bordr_d(_jit,i0,r0,r1)
+static jit_word_t _bordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bordi_f(i0,r0,i1)            _bordi_f(_jit,i0,r0,i1)
+static jit_word_t _bordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bordi_d(i0,r0,i1)            _bordi_d(_jit,i0,r0,i1)
+static jit_word_t _bordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bunordr_f(i0,r0,r1)          bunordr_d(i0,r0,r1)
+#  define bunordr_d(i0,r0,r1)          _bunordr_d(_jit,i0,r0,r1)
+static jit_word_t _bunordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunordi_f(i0,r0,i1)          _bunordi_f(_jit,i0,r0,i1)
+static jit_word_t _bunordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bunordi_d(i0,r0,i1)          _bunordi_d(_jit,i0,r0,i1)
+static jit_word_t _bunordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define ldr_f(r0,r1)                 LDS(r0,r1,0)
+#  define ldi_f(r0,i0)                 _ldi_f(_jit,r0,i0)
+static void _ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_d(r0,r1)                 LDT(r0,r1,0)
+#  define ldi_d(r0,i0)                 _ldi_d(_jit,r0,i0)
+static void _ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_f(r0,r1,r2)             _ldxr_f(_jit,r0,r1,r2)
+static void _ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_f(r0,r1,i0)             _ldxi_f(_jit,r0,r1,i0)
+static void _ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_d(r0,r1,r2)             _ldxr_d(_jit,r0,r1,r2)
+static void _ldxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_d(r0,r1,i0)             _ldxi_d(_jit,r0,r1,i0)
+static void _ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_f(r0,r1)                 STS(r1,r0,0)
+#  define sti_f(i0,r0)                 _sti_f(_jit,i0,r0)
+static void _sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_d(r0,r1)                 STT(r1,r0,0)
+#  define sti_d(i0,r0)                 _sti_d(_jit,i0,r0)
+static void _sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_f(r0,r1,r2)             _stxr_f(_jit,r0,r1,r2)
+static void _stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_f(i0,r0,r1)             _stxi_f(_jit,i0,r0,r1)
+static void _stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_d(r0,r1,r2)             _stxr_d(_jit,r0,r1,r2)
+static void _stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_d(i0,r0,r1)             _stxi_d(_jit,i0,r0,r1)
+static void _stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vaarg_d(r0, r1)              _vaarg_d(_jit, r0, r1)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif
+
+#if CODE
+#  define fpr_opi(name, type, size)                                    \
+static void                                                            \
+_##name##i_##type(jit_state_t *_jit,                                   \
+                 jit_int32_t r0, jit_int32_t r1,                       \
+                 jit_float##size##_t *i0)                              \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    movi_##type(rn(reg), i0);                                          \
+    name##r_##type(r0, r1, rn(reg));                                   \
+    jit_unget_reg(reg);                                                        \
+}
+#  define fpr_bopi(name, type, size)                                   \
+static jit_word_t                                                      \
+_b##name##i_##type(jit_state_t *_jit,                                  \
+                 jit_word_t i0, jit_int32_t r0,                        \
+                 jit_float##size##_t *i1)                              \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|jit_class_nospill);\
+    movi_##type(rn(reg), i1);                                          \
+    word = b##name##r_##type(i0, r0, rn(reg));                         \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+#  define fopi(name)                   fpr_opi(name, f, 32)
+#  define fbopi(name)                  fpr_bopi(name, f, 32)
+#  define dopi(name)                   fpr_opi(name, d, 64)
+#  define dbopi(name)                  fpr_bopi(name, d, 64)
+
+static void
+_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       FMOV(r1, r0);
+}
+
+static void
+_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t      i;
+       jit_float32_t    f;
+    } data;
+    jit_int32_t                 reg;
+
+    if (_jitc->no_data) {
+       data.f = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.i & 0xffffffff);
+       stxi_i(-8, _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+       ldxi_f(r0, _FP_REGNO, -8);
+    }
+    else
+       ldi_f(r0, (jit_word_t)i0);
+}
+
+static void
+_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+       jit_word_t       w;
+       jit_float64_t    d;
+    } data;
+    jit_int32_t                 reg;
+
+    if (_jitc->no_data) {
+       data.d = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.w);
+       stxi_l(-8, _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+       ldxi_d(r0, _FP_REGNO, -8);
+    }
+    else
+       ldi_d(r0, (jit_word_t)i0);
+}
+
+static void
+_truncr_d_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    CVTTQ_SVC(r1, rn(reg));
+    TRAPB();
+    stxi_d(-8, _FP_REGNO, rn(reg));
+    ldxi(r0, _FP_REGNO, -8);
+    jit_unget_reg(reg);
+}
+
+static void
+_sqrtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    SQRTS_SU(r1, r0);
+    TRAPB();
+}
+
+static void
+_sqrtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    SQRTT_SU(r1, r0);
+    TRAPB();
+}
+
+static void
+_extr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi_l(-8, _FP_REGNO, r1);
+    ldxi_d(r0, _FP_REGNO, -8);
+    CVTQS(r0, r0);
+}
+
+static void
+_extr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi_l(-8, _FP_REGNO, r1);
+    ldxi_d(r0, _FP_REGNO, -8);
+    CVTQT(r0, r0);
+}
+
+static void
+_addr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    ADDS_SU(r1, r2, r0);
+    TRAPB();
+}
+fopi(add)
+
+static void
+_addr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    ADDT_SU(r1, r2, r0);
+    TRAPB();
+}
+dopi(add)
+
+static void
+_subr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SUBS_SU(r1, r2, r0);
+    TRAPB();
+}
+fopi(sub)
+fopi(rsb)
+
+static void
+_subr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SUBT_SU(r1, r2, r0);
+    TRAPB();
+}
+dopi(sub)
+dopi(rsb)
+
+static void
+_mulr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    MULS_SU(r1, r2, r0);
+    TRAPB();
+}
+fopi(mul)
+
+static void
+_mulr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    MULT_SU(r1, r2, r0);
+    TRAPB();
+}
+dopi(mul)
+
+static void
+_divr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    DIVS_SU(r1, r2, r0);
+    TRAPB();
+}
+fopi(div)
+
+static void
+_divr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    DIVT_SU(r1, r2, r0);
+    TRAPB();
+}
+dopi(div)
+
+static void
+_ltr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 0);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLT_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBEQ(rn(reg), 1);
+    movi(r0, 1);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(lt);
+dopi(lt);
+
+static void
+_ler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 0);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLE_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBEQ(rn(reg), 1);
+    movi(r0, 1);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(le);
+dopi(le);
+
+static void
+_eqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 0);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTEQ_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBEQ(rn(reg), 1);
+    movi(r0, 1);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(eq);
+dopi(eq);
+
+static void
+_ger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 0);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLT_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    movi(r0, 1);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(ge);
+dopi(ge);
+
+static void
+_gtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 0);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLE_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    movi(r0, 1);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(gt);
+dopi(gt);
+
+static void
+_ner_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 1);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 3);
+    CMPTEQ_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBEQ(rn(reg), 1);
+    movi(r0, 0);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(ne);
+dopi(ne);
+
+static void
+_unltr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 1);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLT_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    movi(r0, 0);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(unlt);
+dopi(unlt);
+
+static void
+_unler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 1);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLE_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    movi(r0, 0);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(unle);
+dopi(unle);
+
+static void
+_uneqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 1);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTEQ_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    movi(r0, 0);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(uneq);
+dopi(uneq);
+
+static void
+_unger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 1);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLT_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBEQ(rn(reg), 1);
+    movi(r0, 0);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(unge);
+dopi(unge);
+
+static void
+_ungtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 1);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLE_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBEQ(rn(reg), 1);
+    movi(r0, 0);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(ungt);
+dopi(ungt);
+
+static void
+_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 0);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTEQ_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    movi(r0, 1);
+    patch_at(v, _jit->pc.w);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(ltgt);
+dopi(ltgt);
+
+static void
+_ordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 0);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    movi(r0, 1);
+    patch_at(w, _jit->pc.w);
+    jit_unget_reg(reg);
+}
+fopi(ord);
+dopi(ord);
+
+static void
+_unordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi(r0, 1);
+    CMPTUN_SU(r1, r2, rn(reg));
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    jit_unget_reg(reg);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(unord);
+dopi(unord);
+
+static jit_word_t
+_bltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord does not satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 3);
+    CMPTLT_SU(r0, r1, rn(reg));                /* lt satisfy condition */
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(lt);
+dbopi(lt);
+
+static jit_word_t
+_bler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord does not satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 3);
+    CMPTLE_SU(r0, r1, rn(reg));                /* le satisfy condition */
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(le);
+dbopi(le);
+
+static jit_word_t
+_beqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord does not satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 3);
+    CMPTEQ_SU(r0, r1, rn(reg));                /* eq satisfy condition */
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(eq);
+dbopi(eq);
+
+static jit_word_t
+_bger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord does not satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 3);
+    CMPTLT_SU(r0, r1, rn(reg));                /* ge satisfy condition */
+    TRAPB();
+    w = _jit->pc.w;
+    FBEQ(rn(reg), ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(ge);
+dbopi(ge);
+
+static jit_word_t
+_bgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord does not satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 3);
+    CMPTLE_SU(r0, r1, rn(reg));                /* gt satisfy condition */
+    TRAPB();
+    w = _jit->pc.w;
+    FBEQ(rn(reg), ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(gt);
+dbopi(gt);
+
+static jit_word_t
+_bner_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         u, v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord satisfy condition */
+    TRAPB();
+    u = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTEQ_SU(r0, r1, rn(reg));                /* ne satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    patch_at(u, _jit->pc.w);
+    w = _jit->pc.w;
+    BR(_R31_REGNO, ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(ne);
+dbopi(ne);
+
+static jit_word_t
+_bunltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         u, v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord satisfy condition */
+    TRAPB();
+    u = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLT_SU(r0, r1, rn(reg));                /* lt satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBEQ(rn(reg), 1);
+    w = _jit->pc.w;
+    patch_at(u, _jit->pc.w);
+    BR(_R31_REGNO, ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(unlt);
+dbopi(unlt);
+
+static jit_word_t
+_bunler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         u, v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord satisfy condition */
+    TRAPB();
+    u = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLE_SU(r0, r1, rn(reg));                /* le satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBEQ(rn(reg), 1);
+    w = _jit->pc.w;
+    patch_at(u, _jit->pc.w);
+    BR(_R31_REGNO, ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(unle);
+dbopi(unle);
+
+static jit_word_t
+_buneqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         u, v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord satisfy condition */
+    TRAPB();
+    u = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTEQ_SU(r0, r1, rn(reg));                /* eq satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBEQ(rn(reg), 1);
+    w = _jit->pc.w;
+    patch_at(u, _jit->pc.w);
+    BR(_R31_REGNO, ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(uneq);
+dbopi(uneq);
+
+static jit_word_t
+_bunger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         u, v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord satisfy condition */
+    TRAPB();
+    u = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLT_SU(r0, r1, rn(reg));                /* ge satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    w = _jit->pc.w;
+    patch_at(u, _jit->pc.w);
+    BR(_R31_REGNO, ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(unge);
+dbopi(unge);
+
+static jit_word_t
+_bungtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_word_t         u, v, w;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord satisfy condition */
+    TRAPB();
+    u = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTLE_SU(r0, r1, rn(reg));                /* gt does satisfy condition */
+    TRAPB();
+    v = _jit->pc.w;
+    FBNE(rn(reg), 1);
+    w = _jit->pc.w;
+    patch_at(u, _jit->pc.w);
+    BR(_R31_REGNO, ((i0 - w) >> 2) - 1);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(ungt);
+dbopi(ungt);
+
+static jit_word_t
+_bltgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         u, v, w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord does not satisfy condition */
+    TRAPB();
+    u = _jit->pc.w;
+    FBNE(rn(reg), 4);
+    CMPTEQ_SU(r1, r0, rn(reg));
+    TRAPB();
+    v = _jit->pc.w;                    /* eq does not satisfy condition */
+    FBNE(rn(reg), 1);
+    w = _jit->pc.w;
+    BR(_R31_REGNO, ((i0 - w) >> 2) - 1);
+    patch_at(u, _jit->pc.w);
+    patch_at(v, _jit->pc.w);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(ltgt);
+dbopi(ltgt);
+
+static jit_word_t
+_bordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord does not satisfy condition */
+    TRAPB();
+    w = _jit->pc.w;
+    FBEQ(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(ord);
+dbopi(ord);
+
+static jit_word_t
+_bunordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    CMPTUN_SU(r0, r1, rn(reg));                /* unord satisfy condition */
+    TRAPB();
+    w = _jit->pc.w;
+    FBNE(rn(reg), ((i0 - w) >> 2) - 1);
+    jit_unget_reg(reg);
+    return (w);
+}
+fbopi(unord);
+dbopi(unord);
+
+static void
+_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         reg;
+    if (_s16_p(i0))
+       LDS(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         reg;
+    if (_s16_p(i0))
+       LDT(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_f(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_word_t         reg;
+    if (_s16_p(i0))
+       LDS(r0, r1, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_d(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_word_t         reg;
+    if (_s16_p(i0))
+       LDT(r0, r1, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_word_t         reg;
+    if (_s16_p(i0))
+       STS(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_f(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_word_t         reg;
+    if (_s16_p(i0))
+       STT(r0, _R31_REGNO, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_d(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_f(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         reg;
+    if (_s16_p(i0))
+       STS(r1, r0, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_f(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_d(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         reg;
+    if (_s16_p(i0))
+       STT(r1, r0, _u16(i0));
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_d(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         ge_code;
+    jit_int32_t                rg0, rg1, rg2;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg(jit_class_gpr);
+    rg1 = jit_get_reg(jit_class_gpr);
+    rg2 = jit_get_reg(jit_class_gpr);
+
+    /* Load the base in first temporary. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, base));
+
+    /* Load the offset in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, offset));
+
+    /* Remember absolute offset */
+    movr(rn(rg2), rn(rg1));
+
+    /* Jump if overflowed register saved area. */
+    ge_code = bgei(_jit->pc.w, rn(rg1), 48);
+    /* Otherwise load from the float registers save area. */
+    subi(rn(rg1), rn(rg1), 48);
+    patch_at(ge_code, _jit->pc.w);
+
+    /* Load the argument */
+    ldxr_d(r0, rn(rg0), rn(rg1));
+
+    /* No longer needed. */
+    jit_unget_reg(rg1);
+    jit_unget_reg(rg0);
+
+    /* Update offset. */
+    addi(rn(rg2), rn(rg2), 8);
+    stxi(offsetof(jit_va_list_t, offset), r1, rn(rg2));
+    jit_unget_reg(rg2);
+}
+#endif
diff --git a/deps/lightning/lib/jit_alpha-sz.c b/deps/lightning/lib/jit_alpha-sz.c
new file mode 100644 (file)
index 0000000..e1a572a
--- /dev/null
@@ -0,0 +1,402 @@
+
+#if __WORDSIZE == 64
+#define JIT_INSTR_MAX 76
+    0, /* data */
+    0, /* live */
+    4, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    76,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    0, /* va_start */
+    0, /* va_arg */
+    0, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    32,        /* addi */
+    12,        /* addcr */
+    40,        /* addci */
+    28,        /* addxr */
+    28,        /* addxi */
+    4, /* subr */
+    32,        /* subi */
+    12,        /* subcr */
+    40,        /* subci */
+    28,        /* subxr */
+    28,        /* subxi */
+    36,        /* rsbi */
+    4, /* mulr */
+    32,        /* muli */
+    44,        /* qmulr */
+    56,        /* qmuli */
+    12,        /* qmulr_u */
+    32,        /* qmuli_u */
+    48,        /* divr */
+    72,        /* divi */
+    48,        /* divr_u */
+    72,        /* divi_u */
+    56,        /* qdivr */
+    56,        /* qdivi */
+    56,        /* qdivr_u */
+    56,        /* qdivi_u */
+    48,        /* remr */
+    72,        /* remi */
+    48,        /* remr_u */
+    72,        /* remi_u */
+    4, /* andr */
+    32,        /* andi */
+    4, /* orr */
+    32,        /* ori */
+    4, /* xorr */
+    32,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    4, /* ltr */
+    4, /* lti */
+    4, /* ltr_u */
+    8, /* lti_u */
+    4, /* ler */
+    8, /* lei */
+    4, /* ler_u */
+    4, /* lei_u */
+    4, /* eqr */
+    4, /* eqi */
+    4, /* ger */
+    8, /* gei */
+    4, /* ger_u */
+    8, /* gei_u */
+    4, /* gtr */
+    8, /* gti */
+    4, /* gtr_u */
+    8, /* gti_u */
+    8, /* ner */
+    12,        /* nei */
+    4, /* movr */
+    32,        /* movi */
+    8, /* extr_c */
+    8, /* extr_uc */
+    8, /* extr_s */
+    8, /* extr_us */
+    8, /* extr_i */
+    8, /* extr_ui */
+    16,        /* htonr_us */
+    36,        /* htonr_ui */
+    36,        /* htonr_ul */
+    12,        /* ldr_c */
+    40,        /* ldi_c */
+    4, /* ldr_uc */
+    32,        /* ldi_uc */
+    12,        /* ldr_s */
+    40,        /* ldi_s */
+    4, /* ldr_us */
+    32,        /* ldi_us */
+    4, /* ldr_i */
+    32,        /* ldi_i */
+    12,        /* ldr_ui */
+    40,        /* ldi_ui */
+    4, /* ldr_l */
+    32,        /* ldi_l */
+    16,        /* ldxr_c */
+    12,        /* ldxi_c */
+    8, /* ldxr_uc */
+    4, /* ldxi_uc */
+    16,        /* ldxr_s */
+    12,        /* ldxi_s */
+    8, /* ldxr_us */
+    4, /* ldxi_us */
+    8, /* ldxr_i */
+    4, /* ldxi_i */
+    16,        /* ldxr_ui */
+    12,        /* ldxi_ui */
+    8, /* ldxr_l */
+    4, /* ldxi_l */
+    4, /* str_c */
+    32,        /* sti_c */
+    4, /* str_s */
+    32,        /* sti_s */
+    4, /* str_i */
+    32,        /* sti_i */
+    4, /* str_l */
+    32,        /* sti_l */
+    8, /* stxr_c */
+    4, /* stxi_c */
+    8, /* stxr_s */
+    4, /* stxi_s */
+    8, /* stxr_i */
+    4, /* stxi_i */
+    8, /* stxr_l */
+    4, /* stxi_l */
+    8, /* bltr */
+    8, /* blti */
+    8, /* bltr_u */
+    12,        /* blti_u */
+    8, /* bler */
+    12,        /* blei */
+    8, /* bler_u */
+    12,        /* blei_u */
+    8, /* beqr */
+    40,        /* beqi */
+    8, /* bger */
+    12,        /* bgei */
+    8, /* bger_u */
+    12,        /* bgei_u */
+    8, /* bgtr */
+    12,        /* bgti */
+    8, /* bgtr_u */
+    12,        /* bgti_u */
+    8, /* bner */
+    36,        /* bnei */
+    8, /* bmsr */
+    8, /* bmsi */
+    8, /* bmcr */
+    8, /* bmci */
+    28,        /* boaddr */
+    32,        /* boaddi */
+    16,        /* boaddr_u */
+    16,        /* boaddi_u */
+    28,        /* bxaddr */
+    32,        /* bxaddi */
+    16,        /* bxaddr_u */
+    16,        /* bxaddi_u */
+    28,        /* bosubr */
+    32,        /* bosubi */
+    16,        /* bosubr_u */
+    16,        /* bosubi_u */
+    28,        /* bxsubr */
+    32,        /* bxsubi */
+    16,        /* bxsubr_u */
+    16,        /* bxsubi_u */
+    0, /* jmpr */
+    36,        /* jmpi */
+    8, /* callr */
+    36,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    68,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    8, /* addr_f */
+    32,        /* addi_f */
+    8, /* subr_f */
+    32,        /* subi_f */
+    32,        /* rsbi_f */
+    8, /* mulr_f */
+    32,        /* muli_f */
+    8, /* divr_f */
+    32,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    8, /* sqrtr_f */
+    32,        /* ltr_f */
+    56,        /* lti_f */
+    32,        /* ler_f */
+    56,        /* lei_f */
+    32,        /* eqr_f */
+    56,        /* eqi_f */
+    32,        /* ger_f */
+    56,        /* gei_f */
+    32,        /* gtr_f */
+    56,        /* gti_f */
+    32,        /* ner_f */
+    56,        /* nei_f */
+    32,        /* unltr_f */
+    56,        /* unlti_f */
+    32,        /* unler_f */
+    56,        /* unlei_f */
+    32,        /* uneqr_f */
+    56,        /* uneqi_f */
+    32,        /* unger_f */
+    56,        /* ungei_f */
+    32,        /* ungtr_f */
+    56,        /* ungti_f */
+    32,        /* ltgtr_f */
+    56,        /* ltgti_f */
+    20,        /* ordr_f */
+    44,        /* ordi_f */
+    20,        /* unordr_f */
+    44,        /* unordi_f */
+    16,        /* truncr_f_i */
+    16,        /* truncr_f_l */
+    12,        /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    24,        /* movi_f */
+    4, /* ldr_f */
+    32,        /* ldi_f */
+    8, /* ldxr_f */
+    4, /* ldxi_f */
+    4, /* str_f */
+    32,        /* sti_f */
+    8, /* stxr_f */
+    4, /* stxi_f */
+    24,        /* bltr_f */
+    48,        /* blti_f */
+    24,        /* bler_f */
+    48,        /* blei_f */
+    24,        /* beqr_f */
+    48,        /* beqi_f */
+    24,        /* bger_f */
+    48,        /* bgei_f */
+    24,        /* bgtr_f */
+    48,        /* bgti_f */
+    28,        /* bner_f */
+    52,        /* bnei_f */
+    28,        /* bunltr_f */
+    52,        /* bunlti_f */
+    28,        /* bunler_f */
+    52,        /* bunlei_f */
+    28,        /* buneqr_f */
+    52,        /* buneqi_f */
+    28,        /* bunger_f */
+    52,        /* bungei_f */
+    28,        /* bungtr_f */
+    52,        /* bungti_f */
+    28,        /* bltgtr_f */
+    52,        /* bltgti_f */
+    12,        /* bordr_f */
+    36,        /* bordi_f */
+    12,        /* bunordr_f */
+    36,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    8, /* addr_d */
+    28,        /* addi_d */
+    8, /* subr_d */
+    28,        /* subi_d */
+    28,        /* rsbi_d */
+    8, /* mulr_d */
+    28,        /* muli_d */
+    8, /* divr_d */
+    28,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    8, /* sqrtr_d */
+    32,        /* ltr_d */
+    52,        /* lti_d */
+    32,        /* ler_d */
+    52,        /* lei_d */
+    32,        /* eqr_d */
+    52,        /* eqi_d */
+    32,        /* ger_d */
+    52,        /* gei_d */
+    32,        /* gtr_d */
+    52,        /* gti_d */
+    32,        /* ner_d */
+    52,        /* nei_d */
+    32,        /* unltr_d */
+    52,        /* unlti_d */
+    32,        /* unler_d */
+    52,        /* unlei_d */
+    32,        /* uneqr_d */
+    52,        /* uneqi_d */
+    32,        /* unger_d */
+    52,        /* ungei_d */
+    32,        /* ungtr_d */
+    52,        /* ungti_d */
+    32,        /* ltgtr_d */
+    52,        /* ltgti_d */
+    20,        /* ordr_d */
+    40,        /* ordi_d */
+    20,        /* unordr_d */
+    40,        /* unordi_d */
+    16,        /* truncr_d_i */
+    16,        /* truncr_d_l */
+    12,        /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    20,        /* movi_d */
+    4, /* ldr_d */
+    32,        /* ldi_d */
+    8, /* ldxr_d */
+    4, /* ldxi_d */
+    4, /* str_d */
+    32,        /* sti_d */
+    8, /* stxr_d */
+    4, /* stxi_d */
+    24,        /* bltr_d */
+    44,        /* blti_d */
+    24,        /* bler_d */
+    44,        /* blei_d */
+    24,        /* beqr_d */
+    44,        /* beqi_d */
+    24,        /* bger_d */
+    44,        /* bgei_d */
+    24,        /* bgtr_d */
+    44,        /* bgti_d */
+    28,        /* bner_d */
+    48,        /* bnei_d */
+    28,        /* bunltr_d */
+    48,        /* bunlti_d */
+    28,        /* bunler_d */
+    48,        /* bunlei_d */
+    28,        /* buneqr_d */
+    48,        /* buneqi_d */
+    28,        /* bunger_d */
+    48,        /* bungei_d */
+    28,        /* bungtr_d */
+    48,        /* bungti_d */
+    28,        /* bltgtr_d */
+    48,        /* bltgti_d */
+    12,        /* bordr_d */
+    32,        /* bordi_d */
+    12,        /* bunordr_d */
+    32,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_alpha.c b/deps/lightning/lib/jit_alpha.c
new file mode 100644 (file)
index 0000000..9a067aa
--- /dev/null
@@ -0,0 +1,1552 @@
+/*
+ * Copyright (C) 2014-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#define jit_arg_reg_p(i)               ((i) >= 0 && (i) < 6)
+#define jit_arg_f_reg_p(i)             ((i) >= 0 && (i) < 6)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define C_DISP                       0
+#  define S_DISP                       0
+#  define I_DISP                       0
+#  define F_DISP                       0
+#else
+#  define C_DISP                       8 - sizeof(jit_int8_t)
+#  define S_DISP                       8 - sizeof(jit_int16_t)
+#  define I_DISP                       8 - sizeof(jit_int32_t)
+#  define F_DISP                       8 - sizeof(jit_float32_t)
+#endif
+
+/*
+ * Types
+ */
+/*
+ * What I could understand from gcc/config/alpha/alpha.c:alpha_build_builtin_va_list()
+ * and other helpers, as well as objdump of simple test programs; could not
+ * get gdb working on the test system I had access...
+ *
+ * base-48 to base is where up to 6 float registers are saved.
+ * base to base+48 is where up to 6 integer registers are saved.
+ * base+48... is where varargs arguments are stored.
+ *
+ *     if (offset < 48) {
+ *             if (type == double)
+ *                     offset -= 48;
+ *     }
+ *     load(reg, base, offset);
+ *     offset += 8;
+ */
+typedef struct jit_va_list {
+    jit_pointer_t      base;
+    jit_word_t         offset;
+} jit_va_list_t;
+
+/*
+ * Prototypes
+ */
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+#define PROTO                          1
+#  include "jit_alpha-cpu.c"
+#  include "jit_alpha-fpu.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_register_t         _rvs[] = {
+    { rc(gpr) | 0x1c,                  "at" },
+    { rc(gpr) | 0x00,                  "v0" },
+    { rc(gpr) | 0x01,                  "t0" },
+    { rc(gpr) | 0x02,                  "t1" },
+    { rc(gpr) | 0x03,                  "t2" },
+    { rc(gpr) | 0x04,                  "t3" },
+    { rc(gpr) | 0x05,                  "t4" },
+    { rc(gpr) | 0x06,                  "t5" },
+    { rc(gpr) | 0x07,                  "t6" },
+    { rc(gpr) | 0x08,                  "t7" },
+    { rc(gpr) | 0x16,                  "t8" },
+    { rc(gpr) | 0x17,                  "t9" },
+    { rc(gpr) | 0x18,                  "t10" },
+    { rc(gpr) | 0x19,                  "t11" },
+    { rc(sav) | rc(gpr) | 0x09,                "s0" },
+    { rc(sav) | rc(gpr) | 0x0a,                "s1" },
+    { rc(sav) | rc(gpr) | 0x0b,                "s2" },
+    { rc(sav) | rc(gpr) | 0x0c,                "s3" },
+    { rc(sav) | rc(gpr) | 0x0d,                "s4" },
+    { rc(sav) | rc(gpr) | 0x0e,                "s5" },
+    { 0x0f,                            "fp" },
+    { rc(arg) | rc(gpr) | 0x15,                "a5" },
+    { rc(arg) | rc(gpr) | 0x14,                "a4" },
+    { rc(arg) | rc(gpr) | 0x13,                "a3" },
+    { rc(arg) | rc(gpr) | 0x12,                "a2" },
+    { rc(arg) | rc(gpr) | 0x11,                "a1" },
+    { rc(arg) | rc(gpr) | 0x10,                "a0" },
+    { 0x1a,                            "ra" },
+    { 0x1b,                            "pv" },
+    { 0x1d,                            "gp" },
+    { 0x1e,                            "sp" },
+    { 0x1f,                            "zero" },
+    { rc(fpr) | 0x00,                  "$f0" },
+    { rc(fpr) | 0x01,                  "$f1" },
+    { rc(sav) | rc(fpr) | 0x02,                "$f2" },
+    { rc(sav) | rc(fpr) | 0x03,                "$f3" },
+    { rc(sav) | rc(fpr) | 0x04,                "$f4" },
+    { rc(sav) | rc(fpr) | 0x05,                "$f5" },
+    { rc(sav) | rc(fpr) | 0x06,                "$f6" },
+    { rc(sav) | rc(fpr) | 0x07,                "$f7" },
+    { rc(sav) | rc(fpr) | 0x08,                "$f8" },
+    { rc(sav) | rc(fpr) | 0x09,                "$f9" },
+    { rc(fpr) | 0x0a,                  "$f10" },
+    { rc(fpr) | 0x0b,                  "$f11" },
+    { rc(fpr) | 0x0c,                  "$f12" },
+    { rc(fpr) | 0x0d,                  "$f13" },
+    { rc(fpr) | 0x0e,                  "$f14" },
+    { rc(fpr) | 0x0f,                  "$f15" },
+    { rc(arg) | rc(fpr) | 0x15,                "$f21" },
+    { rc(arg) | rc(fpr) | 0x14,                "$f20" },
+    { rc(arg) | rc(fpr) | 0x13,                "$f19" },
+    { rc(arg) | rc(fpr) | 0x12,                "$f18" },
+    { rc(arg) | rc(fpr) | 0x11,                "$f17" },
+    { rc(arg) | rc(fpr) | 0x10,                "$f16" },
+    { rc(fpr) | 0x16,                  "$f22" },
+    { rc(fpr) | 0x17,                  "$f23" },
+    { rc(fpr) | 0x18,                  "$f24" },
+    { rc(fpr) | 0x19,                  "$f25" },
+    { rc(fpr) | 0x1a,                  "$f26" },
+    { rc(fpr) | 0x1b,                  "$f27" },
+    { rc(fpr) | 0x1c,                  "$f28" },
+    { rc(fpr) | 0x1d,                  "$f29" },
+    { rc(fpr) | 0x1e,                  "$f30" },
+    { 0x1f,                            "$f31" },
+    { _NOREG,                          "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    _jitc->reglen = jit_size(_rvs) - 1;
+    jit_carry = _NOREG;
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                 offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = stack_framesize;
+    _jitc->function->self.argi = _jitc->function->self.alen = 0;
+    /* float conversion */
+    _jitc->function->self.aoff = -8;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function != NULL);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    return (_jitc->function->self.aoff);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 reg;
+    assert(_jitc->function != NULL);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    jit_negr(reg, v);
+    jit_andi(reg, reg, -8);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, reg);
+    jit_addr(JIT_SP, JIT_SP, reg);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(reg);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function != NULL);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    if (JIT_RET != u)
+       jit_movr(JIT_RET, u);
+    jit_live(JIT_RET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    if (u != JIT_FRET)
+       jit_movr_f(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    if (u != JIT_FRET)
+       jit_movr_d(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function != NULL);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    if (u->code == jit_code_arg)
+       return (jit_arg_reg_p(u->u.w));
+    assert(u->code == jit_code_arg_f || u->code == jit_code_arg_d);
+    return (jit_arg_f_reg_p(u->u.w));
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare) {
+       jit_link_prepare();
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+    }
+    else {
+       jit_link_prolog();
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+
+       /* Allocate va_list like object in the stack */
+       _jitc->function->vaoff = jit_allocai(sizeof(jit_va_list_t));
+       _jitc->function->vagp = _jitc->function->self.argi;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_int32_t                reg;
+    jit_inc_synth_w(va_push, u);
+    reg = jit_get_reg(jit_class_gpr);
+    jit_ldxi(reg, u, offsetof(jit_va_list_t, base));
+    jit_pushargr(reg);
+    jit_ldxi(reg, u, offsetof(jit_va_list_t, offset));
+    jit_pushargr(reg);
+    jit_unget_reg(reg);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function != NULL);
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += 8;
+    }
+    node = jit_new_node_ww(jit_code_arg, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function != NULL);
+    if (jit_arg_f_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += 8;
+    }
+    node = jit_new_node_ww(jit_code_arg_f, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function != NULL);
+    if (jit_arg_f_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += 8;
+    }
+    node = jit_new_node_ww(jit_code_arg_d, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, _A0 - v->u.w);
+    else
+       jit_ldxi_c(u, _FP, v->u.w + C_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, _A0 - v->u.w);
+    else
+       jit_ldxi_uc(u, _FP, v->u.w + C_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, _A0 - v->u.w);
+    else
+       jit_ldxi_s(u, _FP, v->u.w + S_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, _A0 - v->u.w);
+    else
+       jit_ldxi_us(u, _FP, v->u.w + S_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_i(u, _A0 - v->u.w);
+    else
+       jit_ldxi_i(u, _FP, v->u.w + I_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_ui, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_ui(u, _A0 - v->u.w);
+    else
+       jit_ldxi_ui(u, _FP, v->u.w + I_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_l, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, _A0 - v->u.w);
+    else
+       jit_ldxi_l(u, _FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(_A0 - v->u.w, u);
+    else
+       jit_stxi(v->u.w, _FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi(_A0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, _FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_f(u, _F16 - v->u.w);
+    else
+       jit_ldxi_f(u, _FP, v->u.w + F_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_f(_F16 - v->u.w, u);
+    else
+       jit_stxi_f(v->u.w, _FP, u + F_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movi_f(_F16 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(v->u.w, _FP, regno + F_DISP);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(u, _F16 - v->u.w);
+    else
+       jit_ldxi_d(u, _FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(_F16 - v->u.w, u);
+    else
+       jit_stxi_d(v->u.w, _FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movi_d(_F16 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, _FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function != NULL);
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(_A0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += 8;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_int64_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function != NULL);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(_A0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size, JIT_SP, regno);
+       _jitc->function->call.size += 8;
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function != NULL);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argi)) {
+       jit_movr_f(_F16 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size + F_DISP, JIT_SP, u);
+       _jitc->function->call.size += 8;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function != NULL);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argi)) {
+       jit_movi_f(_F16 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(_jitc->function->call.size + F_DISP, JIT_SP, regno);
+       _jitc->function->call.size += 8;
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function != NULL);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argi)) {
+       jit_movr_d(_F16 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += 8;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function != NULL);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argi)) {
+       jit_movi_d(_F16 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, regno);
+       _jitc->function->call.size += 8;
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_int32_t                spec;
+
+    spec = jit_class(_rvs[regno].spec);
+    if (spec & jit_class_arg) {
+       if (spec & jit_class_gpr) {
+           regno = _A0 - regno;
+           if (regno >= 0 && regno < node->v.w)
+               return (1);
+       }
+       else if (spec & jit_class_fpr) {
+           regno = _F16 - regno;
+           if (regno >= 0 && regno < node->w.w)
+               return (1);
+       }
+    }
+
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *call;
+    assert(_jitc->function != NULL);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    call = jit_callr(r0);
+    call->v.w = call->w.w = _jitc->function->self.argi;
+    _jitc->function->call.argi = _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *call;
+    assert(_jitc->function != NULL);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    call = jit_calli(i0);
+    call->v.w = call->w.w = _jitc->function->self.argf;
+    _jitc->function->call.argi = _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (call);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_c, r0);
+    jit_extr_c(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_uc, r0);
+    jit_extr_uc(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_s, r0);
+    jit_extr_s(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_us, r0);
+    jit_extr_us(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+    jit_extr_i(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_ui, r0);
+    jit_extr_ui(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_l, r0);
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_f, r0);
+    if (r0 != JIT_FRET)
+       jit_movr_f(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_d, r0);
+    if (r0 != JIT_FRET)
+       jit_movr_d(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_word_t          value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_uint8_t     *data;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_int32_t      const_offset;
+       jit_int32_t      patch_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.const_offset = undo.patch_offset = 0;
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
+               break
+#define case_rrf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               assert(node->flag & jit_flag_data);                     \
+               name##i##type(rn(node->u.w), rn(node->v.w),             \
+                             (jit_float##size##_t *)node->w.n->u.w);   \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w, rn(node->v.w),             \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w, rn(node->v.w),     \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if (node->u.w == sizeof(jit_word_t) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rr(trunc, _f_i);
+               case_rr(trunc, _d_i);
+               case_rr(trunc, _f_l);
+               case_rr(trunc, _d_l);
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+               case_rr(ld, _ui);
+               case_rw(ld, _ui);
+               case_rr(ld, _l);
+               case_rw(ld, _l);
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+               case_rrr(ldx, _ui);
+               case_rrw(ldx, _ui);
+               case_rrr(ldx, _l);
+               case_rrw(ldx, _l);
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+               case_rr(st, _l);
+               case_wr(st, _l);
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+               case_rrr(stx, _l);
+               case_wrr(stx, _l);
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+               case_rr(hton, _ul);
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+               case_rr(ext, _i);
+               case_rr(ext, _ui);
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), node->v.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rr(neg,);
+               case_rr(com,);
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_rrr(add, _f);
+               case_rrf(add, _f, 32);
+               case_rrr(sub, _f);
+               case_rrf(sub, _f, 32);
+               case_rrf(rsb, _f, 32);
+               case_rrr(mul, _f);
+               case_rrf(mul, _f, 32);
+               case_rrr(div, _f);
+               case_rrf(div, _f, 32);
+               case_rr(abs, _f);
+               case_rr(neg, _f);
+               case_rr(sqrt, _f);
+               case_rr(ext, _f);
+               case_rr(ld, _f);
+               case_rw(ld, _f);
+               case_rrr(ldx, _f);
+               case_rrw(ldx, _f);
+               case_rr(st, _f);
+               case_wr(st, _f);
+               case_rrr(stx, _f);
+               case_wrr(stx, _f);
+               case_rr(mov, _f);
+           case jit_code_movi_f:
+               assert(node->flag & jit_flag_data);
+               movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _d_f);
+               case_rrr(lt, _f);
+               case_rrf(lt, _f, 32);
+               case_rrr(le, _f);
+               case_rrf(le, _f, 32);
+               case_rrr(eq, _f);
+               case_rrf(eq, _f, 32);
+               case_rrr(ge, _f);
+               case_rrf(ge, _f, 32);
+               case_rrr(gt, _f);
+               case_rrf(gt, _f, 32);
+               case_rrr(ne, _f);
+               case_rrf(ne, _f, 32);
+               case_rrr(unlt, _f);
+               case_rrf(unlt, _f, 32);
+               case_rrr(unle, _f);
+               case_rrf(unle, _f, 32);
+               case_rrr(uneq, _f);
+               case_rrf(uneq, _f, 32);
+               case_rrr(unge, _f);
+               case_rrf(unge, _f, 32);
+               case_rrr(ungt, _f);
+               case_rrf(ungt, _f, 32);
+               case_rrr(ltgt, _f);
+               case_rrf(ltgt, _f, 32);
+               case_rrr(ord, _f);
+               case_rrf(ord, _f, 32);
+               case_rrr(unord, _f);
+               case_rrf(unord, _f, 32);
+               case_brr(blt, _f);
+               case_brf(blt, _f, 32);
+               case_brr(ble, _f);
+               case_brf(ble, _f, 32);
+               case_brr(beq, _f);
+               case_brf(beq, _f, 32);
+               case_brr(bge, _f);
+               case_brf(bge, _f, 32);
+               case_brr(bgt, _f);
+               case_brf(bgt, _f, 32);
+               case_brr(bne, _f);
+               case_brf(bne, _f, 32);
+               case_brr(bunlt, _f);
+               case_brf(bunlt, _f, 32);
+               case_brr(bunle, _f);
+               case_brf(bunle, _f, 32);
+               case_brr(buneq, _f);
+               case_brf(buneq, _f, 32);
+               case_brr(bunge, _f);
+               case_brf(bunge, _f, 32);
+               case_brr(bungt, _f);
+               case_brf(bungt, _f, 32);
+               case_brr(bltgt, _f);
+               case_brf(bltgt, _f, 32);
+               case_brr(bord, _f);
+               case_brf(bord, _f, 32);
+               case_brr(bunord, _f);
+               case_brf(bunord, _f, 32);
+               case_rrr(add, _d);
+               case_rrf(add, _d, 64);
+               case_rrr(sub, _d);
+               case_rrf(sub, _d, 64);
+               case_rrf(rsb, _d, 64);
+               case_rrr(mul, _d);
+               case_rrf(mul, _d, 64);
+               case_rrr(div, _d);
+               case_rrf(div, _d, 64);
+               case_rr(abs, _d);
+               case_rr(neg, _d);
+               case_rr(sqrt, _d);
+               case_rr(ext, _d);
+               case_rr(ld, _d);
+               case_rw(ld, _d);
+               case_rrr(ldx, _d);
+               case_rrw(ldx, _d);
+               case_rr(st, _d);
+               case_wr(st, _d);
+               case_rrr(stx, _d);
+               case_wrr(stx, _d);
+               case_rr(mov, _d);
+           case jit_code_movi_d:
+               assert(node->flag & jit_flag_data);
+               movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _f_d);
+               case_rrr(lt, _d);
+               case_rrf(lt, _d, 64);
+               case_rrr(le, _d);
+               case_rrf(le, _d, 64);
+               case_rrr(eq, _d);
+               case_rrf(eq, _d, 64);
+               case_rrr(ge, _d);
+               case_rrf(ge, _d, 64);
+               case_rrr(gt, _d);
+               case_rrf(gt, _d, 64);
+               case_rrr(ne, _d);
+               case_rrf(ne, _d, 64);
+               case_rrr(unlt, _d);
+               case_rrf(unlt, _d, 64);
+               case_rrr(unle, _d);
+               case_rrf(unle, _d, 64);
+               case_rrr(uneq, _d);
+               case_rrf(uneq, _d, 64);
+               case_rrr(unge, _d);
+               case_rrf(unge, _d, 64);
+               case_rrr(ungt, _d);
+               case_rrf(ungt, _d, 64);
+               case_rrr(ltgt, _d);
+               case_rrf(ltgt, _d, 64);
+               case_rrr(ord, _d);
+               case_rrf(ord, _d, 64);
+               case_rrr(unord, _d);
+               case_rrf(unord, _d, 64);
+               case_brr(blt, _d);
+               case_brf(blt, _d, 64);
+               case_brr(ble, _d);
+               case_brf(ble, _d, 64);
+               case_brr(beq, _d);
+               case_brf(beq, _d, 64);
+               case_brr(bge, _d);
+               case_brf(bge, _d, 64);
+               case_brr(bgt, _d);
+               case_brf(bgt, _d, 64);
+               case_brr(bne, _d);
+               case_brf(bne, _d, 64);
+               case_brr(bunlt, _d);
+               case_brf(bunlt, _d, 64);
+               case_brr(bunle, _d);
+               case_brf(bunle, _d, 64);
+               case_brr(buneq, _d);
+               case_brf(buneq, _d, 64);
+               case_brr(bunge, _d);
+               case_brf(bunge, _d, 64);
+               case_brr(bungt, _d);
+               case_brf(bungt, _d, 64);
+               case_brr(bltgt, _d);
+               case_brf(bltgt, _d, 64);
+               case_brr(bord, _d);
+               case_brf(bord, _d, 64);
+               case_brr(bunord, _d);
+               case_brf(bunord, _d, 64);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (!(temp->flag & jit_flag_patch)) {
+                       word = calli_p(temp->u.w);
+                       patch(word, node);
+                   }
+                   else
+                       calli(temp->u.w);
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+           restart_function:
+               _jitc->again = 0;
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+                   goto restart_function;
+               }
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:                 case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:             case jit_code_getarg_ui:
+           case jit_code_getarg_l:
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+           case jit_code_retval_ui:            case jit_code_retval_l:
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           default:
+               abort();
+       }
+       if (jit_carry != _NOREG) {
+           switch (node->code) {
+               case jit_code_note:
+               case jit_code_addcr:            case jit_code_addci:
+               case jit_code_addxr:            case jit_code_addxi:
+               case jit_code_subcr:            case jit_code_subci:
+               case jit_code_subxr:            case jit_code_subxi:
+                   break;
+               default:
+                   jit_unget_reg(jit_carry);
+                   jit_carry = _NOREG;
+                   break;
+           }
+       }
+       jit_regarg_clr(node, value);
+       assert(_jitc->regarg == 0 ||
+              (jit_carry != _NOREG && _jitc->regarg == (1 << jit_carry)));
+       assert(_jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+    }
+#undef case_brf
+#undef case_brw
+#undef case_brr
+#undef case_wrr
+#undef case_rrrw
+#undef case_rrrr
+#undef case_rrf
+#undef case_rrw
+#undef case_rrr
+#undef case_wr
+#undef case_rw
+#undef case_rr
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(_jitc->patches.ptr[offset].inst, word);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_alpha-cpu.c"
+#  include "jit_alpha-fpu.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi(i0, rn(r0), rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi_d(i0, rn(r0), rn(r1));
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                 flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+     assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_arm-cpu.c b/deps/lightning/lib/jit_arm-cpu.c
new file mode 100644 (file)
index 0000000..b6ee260
--- /dev/null
@@ -0,0 +1,3955 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  define stxi(i0,r0,r1)               stxi_i(i0,r0,r1)
+#  define ldxi(r0,r1,i0)               ldxi_i(r0,r1,i0)
+#  define ldr(r0,r1)                   ldr_i(r0,r1)
+#  define _s20P(d)                     ((d) >= -(int)0x80000 && d <= 0x7ffff)
+#  define _s24P(d)                     ((d) >= -(int)0x800000 && d <= 0x7fffff)
+#  define _u3(v)                       ((v) & 0x7)
+#  define _u4(v)                       ((v) & 0xf)
+#  define _u5(v)                       ((v) & 0x1f)
+#  define _u8(v)                       ((v) & 0xff)
+#  define _u12(v)                      ((v) & 0xfff)
+#  define _u13(v)                      ((v) & 0x1fff)
+#  define _u16(v)                      ((v) & 0xffff)
+#  define _u24(v)                      ((v) & 0xffffff)
+#  define jit_thumb_p()                        jit_cpu.thumb
+#  define jit_no_set_flags()           _jitc->no_set_flags
+#  define jit_armv5_p()                        (jit_cpu.version >= 5)
+#  define jit_armv5e_p()               (jit_cpu.version > 5 || (jit_cpu.version == 5 && jit_cpu.extend))
+#  define jit_armv6_p()                        (jit_cpu.version >= 6)
+#  define jit_armv7r_p()               0
+#  define stack_framesize              48
+extern int     __aeabi_idivmod(int, int);
+extern unsigned        __aeabi_uidivmod(unsigned, unsigned);
+#  define _R0_REGNO                    0x00
+#  define _R1_REGNO                    0x01
+#  define _R2_REGNO                    0x02
+#  define _R3_REGNO                    0x03
+#  define _R4_REGNO                    0x04
+#  define _R5_REGNO                    0x05
+#  define _R6_REGNO                    0x06
+#  define _R7_REGNO                    0x07
+#  define _R8_REGNO                    0x08
+#  define _R9_REGNO                    0x09
+#  define _R10_REGNO                   0x0a
+#  define _R11_REGNO                   0x0b
+#  define _R12_REGNO                   0x0c
+#  define _R13_REGNO                   0x0d
+#  define _R14_REGNO                   0x0e
+#  define _R15_REGNO                   0x0f
+#  define _FP_REGNO                    _R11_REGNO
+#  define _SP_REGNO                    _R13_REGNO
+#  define _LR_REGNO                    _R14_REGNO
+#  define _PC_REGNO                    _R15_REGNO
+#  define ARM_CC_EQ                    0x00000000      /* Z=1 */
+#  define ARM_CC_NE                    0x10000000      /* Z=0 */
+#  define ARM_CC_HS                    0x20000000      /* C=1 */
+#    define ARM_CC_CS                  ARM_CC_HS
+#  define ARM_CC_LO                    0x30000000      /* C=0 */
+#    define ARM_CC_CC                  ARM_CC_LO
+#  define ARM_CC_MI                    0x40000000      /* N=1 */
+#  define ARM_CC_PL                    0x50000000      /* N=0 */
+#  define ARM_CC_VS                    0x60000000      /* V=1 */
+#  define ARM_CC_VC                    0x70000000      /* V=0 */
+#  define ARM_CC_HI                    0x80000000      /* C=1 && Z=0 */
+#  define ARM_CC_LS                    0x90000000      /* C=0 || Z=1 */
+#  define ARM_CC_GE                    0xa0000000      /* N=V */
+#  define ARM_CC_LT                    0xb0000000      /* N!=V */
+#  define ARM_CC_GT                    0xc0000000      /* Z=0 && N=V */
+#  define ARM_CC_LE                    0xd0000000      /* Z=1 || N!=V */
+#  define ARM_CC_AL                    0xe0000000      /* always */
+#  define ARM_CC_NV                    0xf0000000      /* reserved */
+#  define THUMB2_IT                    0
+#  define THUMB2_ITT                   1
+#  define THUMB2_ITE                   2
+#  define THUMB2_ITTT                  3
+#  define THUMB2_ITET                  4
+#  define THUMB2_ITTE                  5
+#  define THUMB2_ITEE                  6
+#  define THUMB2_ITTTT                 7
+#  define THUMB2_ITETT                 8
+#  define THUMB2_ITTET                 9
+#  define THUMB2_ITEET                 10
+#  define THUMB2_ITTTE                 11
+#  define THUMB2_ITETE                 12
+#  define THUMB2_ITTEE                 13
+#  define THUMB2_ITEEE                 14
+#  define ARM_MOV                      0x01a00000
+#  define THUMB_MOV                        0x4600
+#  define ARM_MOVWI                    0x03000000      /* v6t2, v7 */
+#  define THUMB_MOVI                       0x2000
+#  define THUMB2_MOVI                  0xf0400000
+#  define THUMB2_MOVWI                 0xf2400000
+#  define ARM_MOVTI                    0x03400000
+#  define THUMB2_MOVTI                 0xf2c00000
+#  define ARM_MVN                      0x01e00000
+#  define THUMB_MVN                        0x43c0
+#  define THUMB2_MVN                   0xea600000
+#  define THUMB2_MVNI                  0xf0600000
+#  define ARM_I                                0x02000000 /* immediate */
+#  define ARM_S                                0x00100000 /* set flags */
+#  define ARM_ADD                      0x00800000
+#  define THUMB_ADD                        0x1800
+#  define THUMB_ADDX                       0x4400
+#  define THUMB2_ADD                   0xeb000000
+#  define THUMB_ADDI3                      0x1c00
+#  define THUMB_ADDI8                      0x3000
+#  define THUMB2_ADDI                  0xf1000000
+#  define THUMB2_ADDWI                 0xf2000000
+#  define ARM_ADC                      0x00a00000
+#  define THUMB_ADC                        0x4140
+#  define THUMB2_ADC                   0xeb400000
+#  define THUMB2_ADCI                  0xf1400000
+#  define ARM_SUB                      0x00400000
+#  define THUMB_SUB                        0x1a00
+#  define THUMB2_SUB                   0xeba00000
+#  define THUMB_SUBI3                      0x1e00
+#  define THUMB_SUBI8                      0x3800
+#  define THUMB2_SUBI                  0xf1a00000
+#  define THUMB2_SUBWI                 0xf2a00000
+#  define ARM_SBC                      0x00c00000
+#  define THUMB_SBC                        0x4180
+#  define THUMB2_SBC                   0xeb600000
+#  define THUMB2_SBCI                  0xf1600000
+#  define ARM_RSB                      0x00600000
+#  define THUMB_RSBI                       0x4240
+#  define THUMB2_RSBI                  0xf1c00000
+#  define ARM_MUL                      0x00000090
+#  define THUMB_MUL                        0x4340
+#  define THUMB2_MUL                   0xfb00f000
+#  define ARM_UMULL                    0x00800090
+#  define THUMB2_UMULL                 0xfba00000
+#  define ARM_SMULL                    0x00c00090
+#  define THUMB2_SMULL                 0xfb800000
+#  define THUMB2_SDIV                  0xfb90f0f0
+#  define THUMB2_UDIV                  0xfbb0f0f0
+#  define ARM_AND                      0x00000000
+#  define THUMB_AND                        0x4000
+#  define THUMB2_AND                   0xea000000
+#  define THUMB2_ANDI                  0xf0000000
+#  define ARM_BIC                      0x01c00000
+#  define THUMB2_BIC                   0xea200000
+#  define THUMB2_BICI                  0xf0200000
+#  define ARM_ORR                      0x01800000
+#  define THUMB_ORR                        0x4300
+#  define THUMB2_ORR                   0xea400000
+#  define THUMB2_ORRI                  0xf0400000
+#  define ARM_EOR                      0x00200000
+#  define THUMB_EOR                        0x4040
+#  define THUMB2_EOR                   0xea800000
+#  define THUMB2_EORI                  0xf0800000
+/* >> ARMv6* */
+#  define ARM_REV                      0x06bf0f30
+#  define THUMB_REV                        0xba00
+#  define THUMB2_REV                   0xfa90f080
+#  define ARM_REV16                    0x06bf0fb0
+#  define THUMB_REV16                      0xba40
+#  define THUMB2_REV16                 0xfa90f090
+#  define ARM_SXTB                     0x06af0070
+#  define THUMB_SXTB                       0xb240
+#  define THUMB2_SXTB                  0xfa40f080
+#  define ARM_UXTB                     0x06ef0070
+#  define THUMB_UXTB                       0xb2c0
+#  define THUMB2_UXTB                  0xfa50f080
+#  define ARM_SXTH                     0x06bf0070
+#  define THUMB_SXTH                       0xb200
+#  define THUMB2_SXTH                  0xfa00f080
+#  define ARM_UXTH                     0x06ff0070
+#  define THUMB_UXTH                       0xb280
+#  define THUMB2_UXTH                  0xfa10f080
+#  define ARM_XTR8                     0x00000400 /* ?xt? rotate 8 bits */
+#  define ARM_XTR16                    0x00000800 /* ?xt? rotate 16 bits */
+#  define ARM_XTR24                    0x00000c00 /* ?xt? rotate 24 bits */
+/* << ARMv6* */
+#  define ARM_SHIFT                    0x01a00000
+#  define ARM_R                                0x00000010 /* register shift */
+#  define ARM_LSL                      0x00000000
+#  define THUMB_LSL                        0x4080
+#  define THUMB2_LSL                   0xfa00f000
+#  define THUMB_LSLI                       0x0000
+#  define THUMB2_LSLI                  0xea4f0000
+#  define ARM_LSR                      0x00000020
+#  define THUMB_LSR                        0x40c0
+#  define THUMB2_LSR                   0xfa20f000
+#  define THUMB_LSRI                       0x0800
+#  define THUMB2_LSRI                  0xea4f0010
+#  define ARM_ASR                      0x00000040
+#  define THUMB_ASR                        0x4100
+#  define THUMB2_ASR                   0xfa40f000
+#  define THUMB_ASRI                       0x1000
+#  define THUMB2_ASRI                  0xea4f0020
+#  define ARM_ROR                      0x00000060
+#  define ARM_CMP                      0x01500000
+#  define THUMB_CMP                        0x4280
+#  define THUMB_CMPX                       0x4500
+#  define THUMB2_CMP                   0xebb00000
+#  define THUMB_CMPI                       0x2800
+#  define THUMB2_CMPI                  0xf1b00000
+#  define ARM_CMN                      0x01700000
+#  define THUMB_CMN                        0x42c0
+#  define THUMB2_CMN                   0xeb100000
+#  define THUMB2_CMNI                  0xf1100000
+#  define ARM_TST                      0x01100000
+#  define THUMB_TST                        0x4200
+#  define THUMB2_TST                   0xea100000
+#  define THUMB2_TSTI                  0xf0100000
+#  define ARM_TEQ                      0x01300000
+/* branch */
+#  define ARM_BX                       0x012fff10
+#  define ARM_BLX                      0x012fff30
+#  define THUMB_BLX                        0x4780
+#  define ARM_BLXI                     0xfa000000
+#  define THUMB2_BLXI                  0xf000c000
+#  define ARM_B                                0x0a000000
+#  define THUMB_CC_B                       0xd000
+#  define THUMB_B                          0xe000
+#  define THUMB2_CC_B                  0xf0008000
+#  define THUMB2_B                     0xf0009000
+#  define ARM_BLI                      0x0b000000
+#  define THUMB2_BLI                   0xf000d000
+/* ldr/str */
+#  define ARM_P                                0x00800000 /* positive offset */
+#  define THUMB2_P                     0x00000400
+#  define THUMB2_U                     0x00000200
+#  define THUMB2_W                     0x00000100
+#  define ARM_LDRSB                    0x011000d0
+#  define THUMB_LDRSB                      0x5600
+#  define THUMB2_LDRSB                 0xf9100000
+#  define ARM_LDRSBI                   0x015000d0
+#  define THUMB2_LDRSBI                        0xf9100c00
+#  define THUMB2_LDRSBWI               0xf9900000
+#  define ARM_LDRB                     0x07500000
+#  define THUMB_LDRB                       0x5c00
+#  define THUMB2_LDRB                  0xf8100000
+#  define ARM_LDRBI                    0x05500000
+#  define THUMB_LDRBI                      0x7800
+#  define THUMB2_LDRBI                 0xf8100c00
+#  define THUMB2_LDRBWI                        0xf8900000
+#  define ARM_LDRSH                    0x011000f0
+#  define THUMB_LDRSH                      0x5e00
+#  define THUMB2_LDRSH                 0xf9300000
+#  define ARM_LDRSHI                   0x015000f0
+#  define THUMB2_LDRSHI                        0xf9300c00
+#  define THUMB2_LDRSHWI               0xf9b00000
+#  define ARM_LDRH                     0x011000b0
+#  define THUMB_LDRH                       0x5a00
+#  define THUMB2_LDRH                  0xf8300000
+#  define ARM_LDRHI                    0x015000b0
+#  define THUMB_LDRHI                      0x8800
+#  define THUMB2_LDRHI                 0xf8300c00
+#  define THUMB2_LDRHWI                        0xf8b00000
+#  define ARM_LDR                      0x07100000
+#  define THUMB_LDR                        0x5800
+#  define THUMB2_LDR                   0xf8500000
+#  define ARM_LDRI                     0x05100000
+#  define THUMB_LDRI                       0x6800
+#  define THUMB_LDRISP                     0x9800
+#  define THUMB2_LDRI                  0xf8500c00
+#  define THUMB2_LDRWI                 0xf8d00000
+#  define ARM_LDRD                     0x010000d0
+#  define ARM_LDRDI                    0x014000d0
+#  define THUMB2_LDRDI                 0xe8500000
+#  define ARM_STRB                     0x07400000
+#  define THUMB_STRB                       0x5400
+#  define THUMB2_STRB                  0xf8000000
+#  define ARM_STRBI                    0x05400000
+#  define THUMB_STRBI                      0x7000
+#  define THUMB2_STRBI                 0xf8000c00
+#  define THUMB2_STRBWI                        0xf8800000
+#  define ARM_STRH                     0x010000b0
+#  define THUMB_STRH                       0x5200
+#  define THUMB2_STRH                  0xf8200000
+#  define ARM_STRHI                    0x014000b0
+#  define THUMB_STRHI                      0x8000
+#  define THUMB2_STRHI                 0xf8200c00
+#  define THUMB2_STRHWI                        0xf8a00000
+#  define ARM_STR                      0x07000000
+#  define THUMB_STR                        0x5000
+#  define THUMB2_STR                   0xf8400000
+#  define ARM_STRI                     0x05000000
+#  define THUMB_STRI                       0x6000
+# define THUMB2_STRWI                  0xf8c00000
+#  define THUMB_STRISP                     0x9000
+#  define THUMB2_STRI                  0xf8400c00
+#  define ARM_STRD                     0x010000f0
+# define ARM_STRDI                     0x014000f0
+#  define THUMB2_STRDI                 0xe8400000
+/* ldm/stm */
+#  define ARM_M                                0x08000000
+#  define ARM_M_L                      0x00100000 /* load; store if not set */
+#  define ARM_M_I                      0x00800000 /* inc; dec if not set */
+#  define ARM_M_B                      0x01000000 /* before; after if not set */
+#  define ARM_M_U                      0x00200000 /* update Rn */
+#  define THUMB2_LDM_W                 0x00200000
+#  define THUMB2_LDM_P                 0x00008000
+#  define THUMB2_LDM_M                 0x00004000
+#  define THUMB_LDMIA                      0xc800
+#  define THUMB2_LDMIA                 0xe8900000
+#  define THUMB2_LDMB                  0xe9100000
+#  define THUMB_PUSH                       0xb400
+#  define THUMB2_PUSH                  0xe92d0000
+#  define THUMB_POP                        0xbc00
+#  define THUMB2_POP                   0xe8bd0000
+#  define ii(i)                                *_jit->pc.ui++ = i
+#  define is(i)                                *_jit->pc.us++ = i
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+#    define iss(i, j)                  do { is(j); is(i); } while (0)
+#    define code2thumb(t0, t1, c0, c1) do { t1 = c0; t0 = c1; } while (0)
+#    define thumb2code(t0, t1, c0, c1) do { c0 = t1; c1 = t0; } while (0)
+#  else
+#    define iss(i, j)                  do { is(i); is(j); } while (0)
+#    define code2thumb(t0, t1, c0, c1) do { t0 = c0; t1 = c1; } while (0)
+#    define thumb2code(t0, t1, c0, c1) do { c0 = t0; c1 = t1; } while (0)
+#  endif
+static int encode_arm_immediate(unsigned int v);
+static int encode_thumb_immediate(unsigned int v);
+static int encode_thumb_word_immediate(unsigned int v);
+static int encode_thumb_jump(int v);
+static int encode_thumb_cc_jump(int v);
+static int encode_thumb_shift(int v, int type) maybe_unused;
+#  define corrr(cc,o,rn,rd,rm)         _corrr(_jit,cc,o,rn,rd,rm)
+static void _corrr(jit_state_t*,int,int,int,int,int);
+#  define corri(cc,o,rn,rd,im)         _corri(_jit,cc,o,rn,rd,im)
+static void _corri(jit_state_t*,int,int,int,int,int);
+#define corri8(cc,o,rn,rt,im)  _corri8(_jit,cc,o,rn,rt,im)
+static void _corri8(jit_state_t*,int,int,int,int,int);
+#  define torrr(o,rn,rd,rm)            _torrr(_jit,o,rn,rd,rm)
+static void _torrr(jit_state_t*,int,int,int,int);
+#  define torrrs(o,rn,rd,rm,im)                _torrrs(_jit,o,rn,rd,rm,im)
+static void _torrrs(jit_state_t*,int,int,int,int,int) maybe_unused;
+#  define torxr(o,rn,rt,rm)            _torxr(_jit,o,rn,rt,rm)
+static void _torxr(jit_state_t*,int,int,int,int);
+#  define torrrr(o,rn,rl,rh,rm)                _torrrr(_jit,o,rn,rl,rh,rm)
+static void _torrrr(jit_state_t*,int,int,int,int,int) maybe_unused;
+#  define torrri8(o,rn,rt,rt2,im)      _torrri8(_jit,o,rn,rt,rt2,im)
+static void _torrri8(jit_state_t*,int,int,int,int,int) maybe_unused;
+#  define coriw(cc,o,rd,im)            _coriw(_jit,cc,o,rd,im)
+static void _coriw(jit_state_t*,int,int,int,int);
+#  define torri(o,rd,rn,im)            _torri(_jit,o,rd,rn,im)
+static void _torri(jit_state_t*,int,int,int,int);
+#  define torri8(o,rn,rt,im)           _torri8(_jit,o,rn,rt,im)
+static void _torri8(jit_state_t*,int,int,int,int);
+#  define torri12(o,rn,rt,im)          _torri12(_jit,o,rn,rt,im)
+static void _torri12(jit_state_t*,int,int,int,int);
+#  define tshift(o,rd,rm,im)           _tshift(_jit,o,rd,rm,im)
+static void _tshift(jit_state_t*,int,int,int,int);
+#  define toriw(o,rd,im)               _toriw(_jit,o,rd,im)
+static void _toriw(jit_state_t*,int,int,int);
+#  define tc8(cc,im)                   _tc8(_jit,cc,im)
+static void _tc8(jit_state_t*,int,int) maybe_unused;
+#  define t11(im)                      _t11(_jit,im)
+static void _t11(jit_state_t*,int);
+#  define tcb(cc,im)                   _tcb(_jit,cc,im)
+static void _tcb(jit_state_t*,int,int);
+#  define blxi(im)                     _blxi(_jit,im)
+static void _blxi(jit_state_t*,int) maybe_unused;
+#  define tb(o,im)                     _tb(_jit,o,im)
+static void _tb(jit_state_t*,int,int);
+#  define corrrr(cc,o,rh,rl,rm,rn)     _corrrr(_jit,cc,o,rh,rl,rm,rn)
+static void _corrrr(jit_state_t*,int,int,int,int,int,int);
+#  define corrrs(cc,o,rn,rd,rm,im)     _corrrs(_jit,cc,o,rn,rd,rm,im)
+static void _corrrs(jit_state_t*,int,int,int,int,int,int);
+#  define cshift(cc,o,rd,rm,rn,im)     _cshift(_jit,cc,o,rd,rm,rn,im)
+static void _cshift(jit_state_t*,int,int,int,int,int,int);
+#  define cb(cc,o,im)                  _cb(_jit,cc,o,im)
+static void _cb(jit_state_t*,int,int,int);
+#  define cbx(cc,o,rm)                 _cbx(_jit,cc,o,rm)
+static void _cbx(jit_state_t*,int,int,int);
+#  define corl(cc,o,r0,i0)             _corl(_jit,cc,o,r0,i0)
+static void _corl(jit_state_t*,int,int,int,int);
+#  define c6orr(cc,o,r0,r1)            _c6orr(_jit,cc,o,r0,r1)
+static void _c6orr(jit_state_t*,int,int,int,int);
+#  define tcit(cc,it)                  _tcit(_jit,cc,it)
+static void _tcit(jit_state_t*,unsigned int,int);
+#  define IT(cc)                       tcit(cc,THUMB2_IT)
+#  define ITT(cc)                      tcit(cc,THUMB2_ITT)
+#  define ITE(cc)                      tcit(cc,THUMB2_ITE)
+#  define ITTT(cc)                     tcit(cc,THUMB2_ITTT)
+#  define ITTE(cc)                     tcit(cc,THUMB2_ITTE)
+#  define ITET(cc)                     tcit(cc,THUMB2_ITET)
+#  define ITEE(cc)                     tcit(cc,THUMB2_ITEE)
+#  define ITTTT(cc)                    tcit(cc,THUMB2_ITTTT)
+#  define ITETT(cc)                    tcit(cc,THUMB2_ITETT)
+#  define ITTET(cc)                    tcit(cc,THUMB2_ITTET)
+#  define ITEET(cc)                    tcit(cc,THUMB2_ITEET)
+#  define ITTTE(cc)                    tcit(cc,THUMB2_ITTTE)
+#  define ITETE(cc)                    tcit(cc,THUMB2_ITETE)
+#  define ITTEE(cc)                    tcit(cc,THUMB2_ITTEE)
+#  define ITEEE(cc)                    tcit(cc,THUMB2_ITEEE)
+#  define tpp(o,im)                    _tpp(_jit,o,im)
+static void _tpp(jit_state_t*,int,int);
+#  define torl(o,rn,im)                        _torl(_jit,o,rn,im)
+static void _torl(jit_state_t*,int,int,int) maybe_unused;
+#  define CC_MOV(cc,rd,rm)             corrr(cc,ARM_MOV,0,rd,rm)
+#  define MOV(rd,rm)                   CC_MOV(ARM_CC_AL,rd,rm)
+#  define T1_MOV(rd,rm)                        is(THUMB_MOV|((_u4(rd)&8)<<4)|(_u4(rm)<<3)|(rd&7))
+#  define T2_MOV(rd,rm)                        T2_ORR(rd,_R15_REGNO,rm)
+#  define CC_MOVI(cc,rd,im)            corri(cc,ARM_MOV|ARM_I,0,rd,im)
+#  define MOVI(rd,im)                  CC_MOVI(ARM_CC_AL,rd,im)
+#  define CC_MOVWI(cc,rd,im)           coriw(cc,ARM_MOVWI,rd,im)
+#  define MOVWI(rd,im)                 CC_MOVWI(ARM_CC_AL,rd,im)
+#  define T1_MOVI(rd,im)               is(THUMB_MOVI|(_u3(rd)<<8)|_u8(im))
+#  define T2_MOVI(rd,im)               torri(THUMB2_MOVI,_R15_REGNO,rd,im)
+#  define T2_MOVWI(rd,im)              toriw(THUMB2_MOVWI,rd,im)
+#  define CC_MOVTI(cc,rd,im)           coriw(cc,ARM_MOVTI,rd,im)
+#  define MOVTI(rd,im)                 CC_MOVTI(ARM_CC_AL,rd,im)
+#  define T2_MOVTI(rd,im)              toriw(THUMB2_MOVTI,rd,im)
+#  define CC_MVN(cc,rd,rm)             corrr(cc,ARM_MVN,0,rd,rm)
+#  define MVN(rd,rm)                   CC_MVN(ARM_CC_AL,rd,rm)
+#  define T1_MVN(rd,rm)                        is(THUMB_MVN|(_u3(rm)<<3)|_u3(rd))
+#  define T2_MVN(rd,rm)                        torrr(THUMB2_MVN,_R15_REGNO,rd,rm)
+#  define CC_MVNI(cc,rd,im)            corri(cc,ARM_MVN|ARM_I,0,rd,im)
+#  define MVNI(rd,im)                  CC_MVNI(ARM_CC_AL,rd,im)
+#  define T2_MVNI(rd,im)               torri(THUMB2_MVNI,_R15_REGNO,rd,im)
+#  define CC_NOT(cc,rd,rm)             CC_MVN(cc,rd,rm)
+#  define NOT(rd,rm)                   CC_NOT(ARM_CC_AL,rd,rm)
+#  define T1_NOT(rd,rm)                        T1_MVN(rd,rm)
+#  define T2_NOT(rd,rm)                        T2_MVN(rd,rm)
+#  define NOP()                                MOV(_R0_REGNO, _R0_REGNO)
+#  define T1_NOP()                     is(0xbf00)
+#  define CC_ADD(cc,rd,rn,rm)          corrr(cc,ARM_ADD,rn,rd,rm)
+#  define ADD(rd,rn,rm)                        CC_ADD(ARM_CC_AL,rd,rn,rm)
+#  define T1_ADD(rd,rn,rm)             is(THUMB_ADD|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rd))
+#  define T1_ADDX(rdn,rm)              is(THUMB_ADDX|((_u4(rdn)&8)<<4)|(_u4(rm)<<3)|(rdn&7))
+#  define T2_ADD(rd,rn,rm)             torrr(THUMB2_ADD,rn,rd,rm)
+#  define CC_ADDI(cc,rd,rn,im)         corri(cc,ARM_ADD|ARM_I,rn,rd,im)
+#  define ADDI(rd,rn,im)               CC_ADDI(ARM_CC_AL,rd,rn,im)
+#  define T1_ADDI3(rd,rn,im)           is(THUMB_ADDI3|(_u3(im)<<6)|(_u3(rn)<<3)|_u3(rd))
+#  define T1_ADDI8(rdn,im)             is(THUMB_ADDI8|(_u3(rdn)<<8)|_u8(im))
+#  define T2_ADDI(rd,rn,im)            torri(THUMB2_ADDI,rn,rd,im)
+#  define T2_ADDWI(rd,rn,im)           torri(THUMB2_ADDWI,rn,rd,im)
+#  define CC_ADDS(cc,rd,rn,rm)         corrr(cc,ARM_ADD|ARM_S,rn,rd,rm)
+#  define ADDS(rd,rn,rm)               CC_ADDS(ARM_CC_AL,rd,rn,rm)
+#  define T2_ADDS(rd,rn,rm)            torrr(THUMB2_ADD|ARM_S,rn,rd,rm)
+#  define ADDSI(rd,rn,im)              corri(ARM_CC_AL,ARM_ADD|ARM_S|ARM_I,rn,rd,im)
+#  define T2_ADDSI(rd,rn,im)           torri(THUMB2_ADDI|ARM_S,rn,rd,im)
+#  define CC_ADC(cc,rd,rn,rm)          corrr(cc,ARM_ADC,rn,rd,rm)
+#  define ADC(rd,rn,rm)                        CC_ADC(ARM_CC_AL,rd,rn,rm)
+#  define T1_ADC(rdn,rm)               is(THUMB_ADC|(_u3(rm)<<3)|_u3(rdn))
+#  define T2_ADC(rd,rn,rm)             torrr(THUMB2_ADC,rn,rd,rm)
+#  define CC_ADCI(cc,rd,rn,im)         corri(cc,ARM_ADC|ARM_I,rn,rd,im)
+#  define ADCI(rd,rn,im)               CC_ADCI(ARM_CC_AL,rd,rn,im)
+#  define T2_ADCI(rd,rn,im)            torri(THUMB2_ADCI,rn,rd,im)
+#  define CC_ADCS(cc,rd,rn,rm)         corrr(cc,ARM_ADC|ARM_S,rn,rd,rm)
+#  define ADCS(rd,rn,rm)               CC_ADCS(ARM_CC_AL,rd,rn,rm)
+#  define T2_ADCS(rd,rn,rm)            torrr(THUMB2_ADC|ARM_S,rn,rd,rm)
+#  define CC_ADCSI(cc,rd,rn,im)                corri(cc,ARM_ADC|ARM_S|ARM_I,rn,rd,im)
+#  define ADCSI(rd,rn,im)              CC_ADCSI(ARM_CC_AL,rd,rn,im)
+#  define T2_ADCSI(rd,rn,im)           torri(THUMB2_ADCI|ARM_S,rn,rd,im)
+#  define CC_SUB(cc,rd,rn,rm)          corrr(cc,ARM_SUB,rn,rd,rm)
+#  define SUB(rd,rn,rm)                        CC_SUB(ARM_CC_AL,rd,rn,rm)
+#  define T1_SUB(rd,rn,rm)             is(THUMB_SUB|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rd))
+#  define T2_SUB(rd,rn,rm)             torrr(THUMB2_SUB,rn,rd,rm)
+#  define CC_SUBI(cc,rd,rn,im)         corri(cc,ARM_SUB|ARM_I,rn,rd,im)
+#  define SUBI(rd,rn,im)               CC_SUBI(ARM_CC_AL,rd,rn,im)
+#  define T1_SUBI3(rd,rn,im)           is(THUMB_SUBI3|(_u3(im)<<6)|(_u3(rn)<<3)|_u3(rd))
+#  define T1_SUBI8(rdn,im)             is(THUMB_SUBI8|(_u3(rdn)<<8)|_u8(im))
+#  define T2_SUBI(rd,rn,im)            torri(THUMB2_SUBI,rn,rd,im)
+#  define T2_SUBWI(rd,rn,im)           torri(THUMB2_SUBWI,rn,rd,im)
+#  define CC_SUBS(cc,rd,rn,rm)         corrr(cc,ARM_SUB|ARM_S,rn,rd,rm)
+#  define SUBS(rd,rn,rm)               CC_SUBS(ARM_CC_AL,rd,rn,rm)
+#  define T2_SUBS(rd,rn,rm)            torrr(THUMB2_SUB|ARM_S,rn,rd,rm)
+#  define CC_SUBSI(cc,rd,rn,im)                corri(cc,ARM_SUB|ARM_S|ARM_I,rn,rd,im)
+#  define SUBSI(rd,rn,im)              CC_SUBSI(ARM_CC_AL,rd,rn,im)
+#  define T2_SUBSI(rd,rn,im)           torri(THUMB2_SUBI|ARM_S,rn,rd,im)
+#  define CC_SBC(cc,rd,rn,rm)          corrr(cc,ARM_SBC,rn,rd,rm)
+#  define SBC(rd,rn,rm)                        CC_SBC(ARM_CC_AL,rd,rn,rm)
+#  define T1_SBC(rdn,rm)               is(THUMB_SBC|(_u3(rm)<<3)|_u3(rdn))
+#  define T2_SBC(rd,rn,rm)             torrr(THUMB2_SBC,rn,rd,rm)
+#  define CC_SBCI(cc,rd,rn,im)         corri(cc,ARM_SBC|ARM_I,rn,rd,im)
+#  define SBCI(rd,rn,im)               CC_SBCI(ARM_CC_AL,rd,rn,im)
+#  define T2_SBCI(rd,rn,im)            torri(THUMB2_SBCI,rn,rd,im)
+#  define CC_SBCS(cc,rd,rn,rm)         corrr(cc,ARM_SBC|ARM_S,rn,rd,rm)
+#  define SBCS(rd,rn,rm)               CC_SBCS(ARM_CC_AL,rd,rn,rm)
+#  define T2_SBCS(rd,rn,rm)            torrr(THUMB2_SBC|ARM_S,rn,rd,rm)
+#  define CC_SBCSI(cc,rd,rn,im)                corri(cc,ARM_SBC|ARM_S|ARM_I,rn,rd,im)
+#  define SBCSI(rd,rn,im)              CC_SBCSI(ARM_CC_AL,rd,rn,im)
+#  define T2_SBCSI(rd,rn,im)           torri(THUMB2_SBCI|ARM_S,rn,rd,im)
+#  define CC_RSB(cc,rd,rn,rm)          corrr(cc,ARM_RSB,rn,rd,rm)
+#  define RSB(rd,rn,rm)                        CC_RSB(ARM_CC_AL,rd,rn,rm)
+#  define T2_RSB(rd,rn,rm)             torrr(THUMB2_RSB,rn,rd,rm)
+#  define CC_RSBI(cc,rd,rn,im)         corri(cc,ARM_RSB|ARM_I,rn,rd,im)
+#  define RSBI(rd,rn,im)               CC_RSBI(ARM_CC_AL,rd,rn,im)
+#  define T1_RSBI(rd,rn)               is(THUMB_RSBI|(_u3(rn)<<3)|_u3(rd))
+#  define T2_RSBI(rd,rn,im)            torri(THUMB2_RSBI,rn,rd,im)
+#  define CC_MUL(cc,rl,rn,rm)          corrrr(cc,ARM_MUL,rl,0,rm,rn)
+#  define MUL(rl,rn,rm)                        CC_MUL(ARM_CC_AL,rl,rn,rm)
+#  define T1_MUL(rdm,rn)               is(THUMB_MUL|(_u3(rn)<<3)|_u3(rdm))
+#  define T2_MUL(rd,rn,rm)             torrr(THUMB2_MUL,rn,rd,rm)
+#  define CC_SMULL(cc,rl,rh,rn,rm)     corrrr(cc,ARM_SMULL,rh,rl,rm,rn)
+#  define SMULL(rl,rh,rn,rm)           CC_SMULL(ARM_CC_AL,rl,rh,rn,rm)
+#  define T2_SMULL(rl,rh,rn,rm)                torrrr(THUMB2_SMULL,rn,rl,rh,rm)
+#  define CC_UMULL(cc,rl,rh,rn,rm)     corrrr(cc,ARM_UMULL,rh,rl,rm,rn)
+#  define UMULL(rl,rh,rn,rm)           CC_UMULL(ARM_CC_AL,rl,rh,rn,rm)
+#  define T2_UMULL(rl,rh,rn,rm)                torrrr(THUMB2_UMULL,rn,rl,rh,rm)
+#  define T2_SDIV(rd,rn,rm)            torrr(THUMB2_SDIV,rn,rd,rm)
+#  define T2_UDIV(rd,rn,rm)            torrr(THUMB2_UDIV,rn,rd,rm)
+#  define CC_AND(cc,rd,rn,rm)          corrr(cc,ARM_AND,rn,rd,rm)
+#  define AND(rd,rn,rm)                        CC_AND(ARM_CC_AL,rd,rn,rm)
+#  define T1_AND(rdn,rm)               is(THUMB_AND|(_u3(rm)<<3)|_u3(rdn))
+#  define T2_AND(rd,rn,rm)             torrr(THUMB2_AND,rn,rd,rm)
+#  define CC_ANDI(cc,rd,rn,im)         corri(cc,ARM_AND|ARM_I,rn,rd,im)
+#  define ANDI(rd,rn,im)               CC_ANDI(ARM_CC_AL,rd,rn,im)
+#  define T2_ANDI(rd,rn,im)            torri(THUMB2_ANDI,rn,rd,im)
+#  define CC_ANDS(cc,rd,rn,rm)         corrr(cc,ARM_AND|ARM_S,rn,rd,rm)
+#  define ANDS(rd,rn,rm)               CC_ANDS(ARM_CC_AL,rd,rn,rm)
+#  define T2_ANDS(rd,rn,rm)            torrr(THUMB2_AND|ARM_S,rn,rd,rm)
+#  define CC_ANDSI(cc,rd,rn,im)                corri(cc,ARM_AND|ARM_S|ARM_I,rn,rd,im)
+#  define ANDSI(rd,rn,im)              CC_ANDSI(ARM_CC_AL,rd,rn,im)
+#  define T2_ANDSI(rd,rn,im)           torri(ARM_CC_AL,THUMB2_ANDI|ARM_S,rn,rd,im)
+#  define CC_BIC(cc,rd,rn,rm)          corrr(cc,ARM_BIC,rn,rd,rm)
+#  define BIC(rd,rn,rm)                        CC_BIC(ARM_CC_AL,rd,rn,rm)
+#  define T2_BIC(rd,rn,rm)             torrr(THUMB2_BIC,rn,rd,rm)
+#  define CC_BICI(cc,rd,rn,im)         corri(cc,ARM_BIC|ARM_I,rn,rd,im)
+#  define BICI(rd,rn,im)               CC_BICI(ARM_CC_AL,rd,rn,im)
+#  define T2_BICI(rd,rn,im)            torri(THUMB2_BICI,rn,rd,im)
+#  define CC_BICS(cc,rd,rn,rm)         corrr(cc,ARM_BIC|ARM_S,rn,rd,rm)
+#  define BICS(rd,rn,rm)               CC_BICS(ARM_CC_AL,rd,rn,rm)
+#  define T2_BICS(rd,rn,rm)            torrr(THUMB2_BIC|ARM_S,rn,rd,rm)
+#  define CC_BICSI(cc,rd,rn,im)                corri(cc,ARM_BIC|ARM_S|ARM_I,rn,rd,im)
+#  define BICSI(rd,rn,im)              CC_BICSI(ARM_CC_AL,rd,rn,im)
+#  define T2_BICSI(rd,rn,im)           torri(ARM_CC_AL,THUMB2_BICI|ARM_S,rn,rd,im)
+#  define CC_ORR(cc,rd,rn,rm)          corrr(cc,ARM_ORR,rn,rd,rm)
+#  define ORR(rd,rn,rm)                        CC_ORR(ARM_CC_AL,rd,rn,rm)
+#  define T1_ORR(rdn,rm)               is(THUMB_ORR|(_u3(rm)<<3)|_u3(rdn))
+#  define T2_ORR(rd,rn,rm)             torrr(THUMB2_ORR,rn,rd,rm)
+#  define CC_ORR_SI(cc,rd,rn,rt,sh,im) corrrs(cc,ARM_ORR|sh,rn,rd,rm,im)
+#  define ORR_SI(r0,r1,r2,sh,im)       CC_ORR_SI(ARM_CC_AL,r0,r1,r2,sh,im)
+#  define CC_ORRI(cc,rd,rn,im)         corri(cc,ARM_ORR|ARM_I,rn,rd,im)
+#  define ORRI(rd,rn,im)               CC_ORRI(ARM_CC_AL,rd,rn,im)
+#  define T2_ORRI(rd,rn,im)            torri(THUMB2_ORRI,rn,rd,im)
+#  define CC_EOR(cc,rd,rn,rm)          corrr(cc,ARM_EOR,rn,rd,rm)
+#  define EOR(rd,rn,rm)                        CC_EOR(ARM_CC_AL,rd,rn,rm)
+#  define T1_EOR(rdn,rm)               is(THUMB_EOR|(_u3(rm)<<3)|_u3(rdn))
+#  define T2_EOR(rd,rn,rm)             torrr(THUMB2_EOR,rn,rd,rm)
+#  define CC_EOR_SI(cc,rd,rn,rm,sh,im) corrrs(cc,ARM_EOR|sh,rn,rd,rm,im)
+#  define EOR_SI(r0,r1,r2,sh,im)       CC_EOR_SI(ARM_CC_AL,r0,r1,r2,sh,im)
+#  define CC_EORI(cc,rd,rn,im)         corri(cc,ARM_EOR|ARM_I,rn,rd,im)
+#  define EORI(rd,rn,im)               CC_EORI(ARM_CC_AL,rd,rn,im)
+#  define T2_EORI(rd,rn,im)            torri(THUMB2_EORI,rn,rd,im)
+#  define CC_REV(cc,rd,rm)             c6orr(cc,ARM_REV,rd,rm)
+#  define REV(rd,rm)                   CC_REV(ARM_CC_AL,rd,rm)
+#  define T1_REV(rd,rm)                        is(THUMB_REV|(_u3(rm)<<3)|_u3(rd))
+#  define T2_REV(rd,rm)                        torrr(THUMB2_REV,rm,rd,rm)
+#  define CC_REV16(cc,rd,rm)           c6orr(cc,ARM_REV16,rd,rm)
+#  define REV16(rd,rm)                 CC_REV16(ARM_CC_AL,rd,rm)
+#  define T1_REV16(rd,rm)              is(THUMB_REV16|(_u3(rm)<<3)|_u3(rd))
+#  define T2_REV16(rd,rm)              torrr(THUMB2_REV16,rm,rd,rm)
+#  define CC_SXTB(cc,rd,rm)            c6orr(cc,ARM_SXTB,rd,rm)
+#  define SXTB(rd,rm)                  CC_SXTB(ARM_CC_AL,rd,rm)
+#  define T1_SXTB(rd,rm)               is(THUMB_SXTB|(_u3(rm)<<3)|_u3(rd))
+#  define T2_SXTB(rd,rm)               torrr(THUMB2_SXTB,_R15_REGNO,rd,rm)
+#  define CC_UXTB(cc,rd,rm)            c6orr(cc,ARM_UXTB,rd,rm)
+#  define UXTB(rd,rm)                  CC_UXTB(ARM_CC_AL,rd,rm)
+#  define T1_UXTB(rd,rm)               is(THUMB_UXTB|(_u3(rm)<<3)|_u3(rd))
+#  define T2_UXTB(rd,rm)               torrr(THUMB2_UXTB,_R15_REGNO,rd,rm)
+#  define CC_SXTH(cc,rd,rm)            c6orr(cc,ARM_SXTH,rd,rm)
+#  define SXTH(rd,rm)                  CC_SXTH(ARM_CC_AL,rd,rm)
+#  define T1_SXTH(rd,rm)               is(THUMB_SXTH|(_u3(rm)<<3)|_u3(rd))
+#  define T2_SXTH(rd,rm)               torrr(THUMB2_SXTH,_R15_REGNO,rd,rm)
+#  define CC_UXTH(cc,rd,rm)            c6orr(cc,ARM_UXTH,rd,rm)
+#  define UXTH(rd,rm)                  CC_UXTH(ARM_CC_AL,rd,rm)
+#  define T1_UXTH(rd,rm)               is(THUMB_UXTH|(_u3(rm)<<3)|_u3(rd))
+#  define T2_UXTH(rd,rm)               torrr(THUMB2_UXTH,_R15_REGNO,rd,rm)
+#  define CC_SHIFT(cc,o,rd,rm,rn,im)   cshift(cc,o,rd,rm,rn,im)
+#  define CC_LSL(cc,rd,rn,rm)          CC_SHIFT(cc,ARM_LSL|ARM_R,rd,rm,rn,0)
+#  define LSL(rd,rn,rm)                        CC_LSL(ARM_CC_AL,rd,rn,rm)
+#  define T1_LSL(rdn,rm)               is(THUMB_LSL|(_u3(rm)<<3)|_u3(rdn))
+#  define T2_LSL(rd,rn,rm)             torrr(THUMB2_LSL,rn,rd,rm)
+#  define CC_LSLI(cc,rd,rn,im)         CC_SHIFT(cc,ARM_LSL,rd,0,rn,im)
+#  define LSLI(rd,rn,im)               CC_LSLI(ARM_CC_AL,rd,rn,im)
+#  define T1_LSLI(rd,rm,im)            is(THUMB_LSLI|(_u5(im)<<6)|(_u3(rm)<<3)|_u3(rd))
+#  define T2_LSLI(rd,rm,im)            tshift(THUMB2_LSLI,rd,rm,im)
+#  define CC_LSR(cc,rd,rn,rm)          CC_SHIFT(cc,ARM_LSR|ARM_R,rd,rm,rn,0)
+#  define LSR(rd,rn,rm)                        CC_LSR(ARM_CC_AL,rd,rn,rm)
+#  define T1_LSR(rdn,rm)               is(THUMB_LSR|(_u3(rm)<<3)|_u3(rdn))
+#  define T2_LSR(rd,rn,rm)             torrr(THUMB2_LSR,rn,rd,rm)
+#  define CC_LSRI(cc,rd,rn,im)         CC_SHIFT(cc,ARM_LSR,rd,0,rn,im)
+#  define LSRI(rd,rn,im)               CC_LSRI(ARM_CC_AL,rd,rn,im)
+#  define T1_LSRI(rd,rm,im)            is(THUMB_LSRI|(_u5(im)<<6)|(_u3(rm)<<3)|_u3(rd))
+#  define T2_LSRI(rd,rm,im)            tshift(THUMB2_LSRI,rd,rm,im)
+#  define CC_ASR(cc,rd,rn,rm)          CC_SHIFT(cc,ARM_ASR|ARM_R,rd,rm,rn,0)
+#  define ASR(rd,rn,rm)                        CC_ASR(ARM_CC_AL,rd,rn,rm)
+#  define T1_ASR(rdn,rm)               is(THUMB_ASR|(_u3(rm)<<3)|_u3(rdn))
+#  define T2_ASR(rd,rn,rm)             torrr(THUMB2_ASR,rn,rd,rm)
+#  define CC_ASRI(cc,rd,rn,im)         CC_SHIFT(cc,ARM_ASR,rd,0,rn,im)
+#  define ASRI(rd,rn,im)               CC_ASRI(ARM_CC_AL,rd,rn,im)
+#  define T1_ASRI(rd,rm,im)            is(THUMB_ASRI|(_u5(im)<<6)|(_u3(rm)<<3)|_u3(rd))
+#  define T2_ASRI(rd,rm,im)            tshift(THUMB2_ASRI,rd,rm,im)
+#  define CC_CMP(cc,rn,rm)             corrr(cc,ARM_CMP,rn,0,rm)
+#  define CMP(rn,rm)                   CC_CMP(ARM_CC_AL,rn,rm)
+#  define T1_CMP(rn,rm)                        is(THUMB_CMP|(_u3(rm)<<3)|_u3(rn))
+#  define T1_CMPX(rn,rm)               is(THUMB_CMPX|((_u4(rn)&8)<<4)|(_u4(rm)<<3)|(rn&7))
+#  define T2_CMP(rn,rm)                        torrr(THUMB2_CMP,rn,_R15_REGNO,rm)
+#  define CC_CMPI(cc,rn,im)            corri(cc,ARM_CMP|ARM_I,rn,0,im)
+#  define CMPI(rn,im)                  CC_CMPI(ARM_CC_AL,rn,im)
+#  define T1_CMPI(rn,im)               is(THUMB_CMPI|(_u3(rn)<<8)|_u8(im))
+#  define T2_CMPI(rn,im)               torri(THUMB2_CMPI,rn,_R15_REGNO,im)
+#  define CC_CMN(cc,rn,rm)             corrr(cc,ARM_CMN,rn,0,rm)
+#  define CMN(rn,rm)                   CC_CMN(ARM_CC_AL,rn,rm)
+#  define T1_CMN(rn,rm)                        is(THUMB_CMN|(_u3(rm)<<3)|_u3(rm))
+#  define T2_CMN(rn,rm)                        torrr(THUMB2_CMN,rn,_R15_REGNO,rm)
+#  define CC_CMNI(cc,rn,im)            corri(cc,ARM_CMN|ARM_I,rn,0,im)
+#  define CMNI(rn,im)                  CC_CMNI(ARM_CC_AL,rn,im)
+#  define T2_CMNI(rn,im)               torri(THUMB2_CMNI,rn,_R15_REGNO,im)
+#  define CC_TST(cc,rn,rm)             corrr(cc,ARM_TST,rn,r0,rm)
+#  define TST(rn,rm)                   CC_TST(ARM_CC_AL,rn,rm)
+#  define T1_TST(rn,rm)                        is(THUMB_TST|(_u3(rm)<<3)|_u3(rn))
+#  define T2_TST(rn,rm)                        torrr(THUMB2_TST,rn,_R15_REGNO,rm)
+#  define CC_TSTI(cc,rn,im)            corri(cc,ARM_TST|ARM_I,rn,0,im)
+#  define TSTI(rn,im)                  CC_TSTI(ARM_CC_AL,rn,im)
+#  define T2_TSTI(rn,im)               torri(THUMB2_TSTI,rn,_R15_REGNO,im)
+#  define CC_TEQ(cc,rn,rm)             corrr(cc,ARM_TEQ,rn,0,rm)
+#  define TEQ(rn,rm)                   CC_TEQ(ARM_CC_AL,rn,rm)
+#  define CC_TEQI(cc,rm,im)            corri(cc,ARM_TEQ|ARM_I,rn,0,im)
+#  define TEQI(rn,im)                  CC_TEQI(ARM_CC_AL,rn,im)
+#  define CC_BX(cc,rm)                 cbx(cc,ARM_BX,rm)
+#  define BX(rm)                       CC_BX(ARM_CC_AL,rm)
+#  define T1_BX(rm)                    is(0x4700|(_u4(rm)<<3))
+#  define CC_BLX(cc,rm)                        cbx(cc,ARM_BLX,rm)
+#  define BLX(rm)                      CC_BLX(ARM_CC_AL,rm)
+#  define T1_BLX(rm)                   is(THUMB_BLX|(_u4(rm)<<3))
+#  define BLXI(im)                     blxi(im)
+#  define T2_BLXI(im)                  tb(THUMB2_BLXI,im)
+#  define CC_B(cc,im)                  cb(cc,ARM_B,im)
+#  define B(im)                                CC_B(ARM_CC_AL,im)
+#  define T1_CC_B(cc,im)               tc8(cc,im)
+#  define T1_B(im)                     t11(im)
+#  define T2_CC_B(cc,im)               tcb(cc,im)
+#  define T2_B(im)                     tb(THUMB2_B,im)
+#  define CC_BLI(cc,im)                        cb(cc,ARM_BLI,im)
+#  define BLI(im)                      CC_BLI(ARM_CC_AL,im)
+#  define T2_BLI(im)                   tb(THUMB2_BLI,im)
+#  define CC_LDRSB(cc,rt,rn,rm)                corrr(cc,ARM_LDRSB|ARM_P,rn,rt,rm)
+#  define LDRSB(rt,rn,rm)              CC_LDRSB(ARM_CC_AL,rt,rn,rm)
+#  define T1_LDRSB(rt,rn,rm)           is(THUMB_LDRSB|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_LDRSB(rt,rn,rm)           torxr(THUMB2_LDRSB,rn,rt,rm)
+#  define CC_LDRSBN(cc,rt,rn,rm)       corrr(cc,ARM_LDRSB,rn,rt,rm)
+#  define LDRSBN(rt,rn,rm)             CC_LDRSBN(ARM_CC_AL,rt,rn,rm)
+#  define CC_LDRSBI(cc,rt,rn,im)       corri8(cc,ARM_LDRSBI|ARM_P,rn,rt,im)
+#  define LDRSBI(rt,rn,im)             CC_LDRSBI(ARM_CC_AL,rt,rn,im)
+#  define T2_LDRSBI(rt,rn,im)          torri8(THUMB2_LDRSBI|THUMB2_U,rn,rt,im)
+#  define T2_LDRSBWI(rt,rn,im)         torri12(THUMB2_LDRSBWI,rn,rt,im)
+#  define CC_LDRSBIN(cc,rt,rn,im)      corri8(cc,ARM_LDRSBI,rn,rt,im)
+#  define LDRSBIN(rt,rn,im)            CC_LDRSBIN(ARM_CC_AL,rt,rn,im)
+#  define T2_LDRSBIN(rt,rn,im)         torri8(THUMB2_LDRSBI,rn,rt,im)
+#  define CC_LDRB(cc,rt,rn,rm)         corrr(cc,ARM_LDRB|ARM_P,rn,rt,rm)
+#  define LDRB(rt,rn,rm)               CC_LDRB(ARM_CC_AL,rt,rn,rm)
+#  define T1_LDRB(rt,rn,rm)            is(THUMB_LDRB|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_LDRB(rt,rn,rm)            torxr(THUMB2_LDRB,rn,rt,rm)
+#  define CC_LDRBN(cc,rt,rn,rm)                corrr(cc,ARM_LDRB,rn,rt,rm)
+#  define LDRBN(rt,rn,rm)              CC_LDRBN(ARM_CC_AL,rt,rn,rm)
+#  define CC_LDRBI(cc,rt,rn,im)                corri(cc,ARM_LDRBI|ARM_P,rn,rt,im)
+#  define LDRBI(rt,rn,im)              CC_LDRBI(ARM_CC_AL,rt,rn,im)
+#  define T1_LDRBI(rt,rn,im)           is(THUMB_LDRBI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_LDRBI(rt,rn,im)           torri8(THUMB2_LDRBI|THUMB2_U,rn,rt,im)
+#  define T2_LDRBWI(rt,rn,im)          torri12(THUMB2_LDRBWI,rn,rt,im)
+#  define CC_LDRBIN(cc,rt,rn,im)       corri(cc,ARM_LDRBI,rn,rt,im)
+#  define LDRBIN(rt,rn,im)             CC_LDRBIN(ARM_CC_AL,rt,rn,im)
+#  define T2_LDRBIN(rt,rn,im)          torri8(THUMB2_LDRBI,rn,rt,im)
+#  define CC_LDRSH(cc,rt,rn,rm)                corrr(cc,ARM_LDRSH|ARM_P,rn,rt,rm)
+#  define LDRSH(rt,rn,rm)              CC_LDRSH(ARM_CC_AL,rt,rn,rm)
+#  define T1_LDRSH(rt,rn,rm)           is(THUMB_LDRSH|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_LDRSH(rt,rn,rm)           torxr(THUMB2_LDRSH,rn,rt,rm)
+#  define CC_LDRSHN(cc,rt,rn,rm)       corrr(cc,ARM_LDRSH,rn,rt,rm)
+#  define LDRSHN(rt,rn,rm)             CC_LDRSHN(ARM_CC_AL,rt,rn,rm)
+#  define CC_LDRSHI(cc,rt,rn,im)       corri8(cc,ARM_LDRSHI|ARM_P,rn,rt,im)
+#  define LDRSHI(rt,rn,im)             CC_LDRSHI(ARM_CC_AL,rt,rn,im)
+#  define T2_LDRSHI(rt,rn,im)          torri8(THUMB2_LDRSHI|THUMB2_U,rn,rt,im)
+#  define T2_LDRSHWI(rt,rn,im)         torri12(THUMB2_LDRSHWI,rn,rt,im)
+#  define CC_LDRSHIN(cc,rt,rn,im)      corri8(cc,ARM_LDRSHI,rn,rt,im)
+#  define LDRSHIN(rt,rn,im)            CC_LDRSHIN(ARM_CC_AL,rt,rn,im)
+#  define T2_LDRSHIN(rt,rn,im)         torri8(THUMB2_LDRSHI,rn,rt,im)
+#  define CC_LDRH(cc,rt,rn,rm)         corrr(cc,ARM_LDRH|ARM_P,rn,rt,rm)
+#  define LDRH(rt,rn,rm)               CC_LDRH(ARM_CC_AL,rt,rn,rm)
+#  define T1_LDRH(rt,rn,rm)            is(THUMB_LDRH|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_LDRH(rt,rn,rm)            torxr(THUMB2_LDRH,rn,rt,rm)
+#  define CC_LDRHN(cc,rt,rn,rm)                corrr(cc,ARM_LDRH,rn,rt,rm)
+#  define LDRHN(rt,rn,rm)              CC_LDRHN(ARM_CC_AL,rt,rn,rm)
+#  define CC_LDRHI(cc,rt,rn,im)                corri8(cc,ARM_LDRHI|ARM_P,rn,rt,im)
+#  define LDRHI(rt,rn,im)              CC_LDRHI(ARM_CC_AL,rt,rn,im)
+#  define T1_LDRHI(rt,rn,im)           is(THUMB_LDRHI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_LDRHI(rt,rn,im)           torri8(THUMB2_LDRHI|THUMB2_U,rn,rt,im)
+#  define T2_LDRHWI(rt,rn,im)          torri12(THUMB2_LDRHWI,rn,rt,im)
+#  define CC_LDRHIN(cc,rt,rn,im)       corri8(cc,ARM_LDRHI,rn,rt,im)
+#  define LDRHIN(rt,rn,im)             CC_LDRHIN(ARM_CC_AL,rt,rn,im)
+#  define T2_LDRHIN(rt,rn,im)          torri8(THUMB2_LDRHI,rn,rt,im)
+#  define CC_LDR(cc,rt,rn,rm)          corrr(cc,ARM_LDR|ARM_P,rn,rt,rm)
+#  define LDR(rt,rn,rm)                        CC_LDR(ARM_CC_AL,rt,rn,rm)
+#  define T1_LDR(rt,rn,rm)             is(THUMB_LDR|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_LDR(rt,rn,rm)             torxr(THUMB2_LDR,rn,rt,rm)
+#  define CC_LDRN(cc,rt,rn,rm)         corrr(cc,ARM_LDR,rn,rt,rm)
+#  define LDRN(rt,rn,rm)               CC_LDRN(ARM_CC_AL,rt,rn,rm)
+#  define CC_LDRI(cc,rt,rn,im)         corri(cc,ARM_LDRI|ARM_P,rn,rt,im)
+#  define LDRI(rt,rn,im)               CC_LDRI(ARM_CC_AL,rt,rn,im)
+#  define T1_LDRI(rt,rn,im)            is(THUMB_LDRI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T1_LDRISP(rt,im)             is(THUMB_LDRISP|(_u3(rt)<<8)|_u8(im))
+#  define T2_LDRI(rt,rn,im)            torri8(THUMB2_LDRI|THUMB2_U,rn,rt,im)
+#  define T2_LDRWI(rt,rn,im)           torri12(THUMB2_LDRWI,rn,rt,im)
+#  define CC_LDRIN(cc,rt,rn,im)                corri(cc,ARM_LDRI,rn,rt,im)
+#  define LDRIN(rt,rn,im)              CC_LDRIN(ARM_CC_AL,rt,rn,im)
+#  define T2_LDRIN(rt,rn,im)           torri8(THUMB2_LDRI,rn,rt,im)
+#  define CC_LDRD(cc,rt,rn,rm)         corrr(cc,ARM_LDRD|ARM_P,rn,rt,rm)
+#  define LDRD(rt,rn,rm)               CC_LDRD(ARM_CC_AL,rt,rn,rm)
+#  define T2_LDRDI(rt,rt2,rn,im)       torrri8(THUMB2_LDRDI|ARM_P,rn,rt,rt2,im)
+#  define CC_LDRDN(cc,rt,rn,rm)                corrr(cc,ARM_LDRD,rn,rt,rm)
+#  define LDRDN(rd,rn,rm)              CC_LDRDN(ARM_CC_AL,rt,rn,rm)
+#  define CC_LDRDI(cc,rt,rn,im)                corri8(cc,ARM_LDRDI|ARM_P,rn,rt,im)
+#  define LDRDI(rt,rn,im)              CC_LDRDI(ARM_CC_AL,rt,rn,im)
+#  define CC_LDRDIN(cc,rt,rn,im)       corri8(cc,ARM_LDRDI,rn,rt,im)
+#  define LDRDIN(rt,rn,im)             CC_LDRDIN(ARM_CC_AL,rt,rn,im)
+#  define T2_LDRDIN(rt,rt2,rn,im)      torrri8(THUMB2_LDRDI,rn,rt,rt2,im)
+#  define CC_STRB(cc,rt,rn,rm)         corrr(cc,ARM_STRB|ARM_P,rn,rt,rm)
+#  define STRB(rt,rn,rm)               CC_STRB(ARM_CC_AL,rt,rn,rm)
+#  define T1_STRB(rt,rn,rm)            is(THUMB_STRB|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_STRB(rt,rn,rm)            torxr(THUMB2_STRB,rn,rt,rm)
+#  define CC_STRBN(cc,rt,rn,rm)                corrr(cc,ARM_STRB,rn,rt,rm)
+#  define STRBN(rt,rn,rm)              CC_STRBN(ARM_CC_AL,rt,rn,rm)
+#  define CC_STRBI(cc,rt,rn,im)                corri(cc,ARM_STRBI|ARM_P,rn,rt,im)
+#  define STRBI(rt,rn,im)              CC_STRBI(ARM_CC_AL,rt,rn,im)
+#  define T1_STRBI(rt,rn,im)           is(THUMB_STRBI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_STRBI(rt,rn,im)           torri8(THUMB2_STRBI|THUMB2_U,rn,rt,im)
+#  define T2_STRBWI(rt,rn,im)          torri12(THUMB2_STRBWI,rn,rt,im)
+#  define CC_STRBIN(cc,rt,rn,im)       corri(cc,ARM_STRBI,rn,rt,im)
+#  define STRBIN(rt,rn,im)             CC_STRBIN(ARM_CC_AL,rt,rn,im)
+#  define T2_STRBIN(rt,rn,im)          torri8(THUMB2_STRBI,rn,rt,im)
+#  define CC_STRH(cc,rt,rn,rm)         corrr(cc,ARM_STRH|ARM_P,rn,rt,rm)
+#  define STRH(rt,rn,rm)               CC_STRH(ARM_CC_AL,rt,rn,rm)
+#  define T1_STRH(rt,rn,rm)            is(THUMB_STRH|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_STRH(rt,rn,rm)            torxr(THUMB2_STRH,rn,rt,rm)
+#  define CC_STRHN(cc,rt,rn,rm)                corrr(cc,ARM_STRH,rn,rt,rm)
+#  define STRHN(rt,rn,rm)              CC_STRHN(ARM_CC_AL,rt,rn,rm)
+#  define CC_STRHI(cc,rt,rn,im)                corri8(cc,ARM_STRHI|ARM_P,rn,rt,im)
+#  define STRHI(rt,rn,im)              CC_STRHI(ARM_CC_AL,rt,rn,im)
+#  define T1_STRHI(rt,rn,im)           is(THUMB_STRHI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_STRHI(rt,rn,im)           torri8(THUMB2_STRHI|THUMB2_U,rn,rt,im)
+#  define T2_STRHWI(rt,rn,im)          torri12(THUMB2_STRHWI,rn,rt,im)
+#  define CC_STRHIN(cc,rt,rn,im)       corri8(cc,ARM_STRHI,rn,rt,im)
+#  define STRHIN(rt,rn,im)             CC_STRHIN(ARM_CC_AL,rt,rn,im)
+#  define T2_STRHIN(rt,rn,im)          torri8(THUMB2_STRHI,rn,rt,im)
+#  define CC_STR(cc,rt,rn,rm)          corrr(cc,ARM_STR|ARM_P,rn,rt,rm)
+#  define STR(rt,rn,rm)                        CC_STR(ARM_CC_AL,rt,rn,rm)
+#  define T1_STR(rt,rn,rm)             is(THUMB_STR|(_u3(rm)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T2_STR(rt,rn,rm)             torxr(THUMB2_STR,rn,rt,rm)
+#  define CC_STRN(cc,rt,rn,rm)         corrr(cc,ARM_STR,rn,rt,rm)
+#  define STRN(rt,rn,rm)               CC_STRN(ARM_CC_AL,rt,rn,rm)
+#  define CC_STRI(cc,rt,rn,im)         corri(cc,ARM_STRI|ARM_P,rn,rt,im)
+#  define STRI(rt,rn,im)               CC_STRI(ARM_CC_AL,rt,rn,im)
+#  define T1_STRI(rt,rn,im)            is(THUMB_STRI|(_u5(im)<<6)|(_u3(rn)<<3)|_u3(rt))
+#  define T1_STRISP(rt,im)             is(THUMB_STRISP|(_u3(rt)<<8)|(_u8(im)))
+#  define T2_STRI(rt,rn,im)            torri8(THUMB2_STRI|THUMB2_U,rn,rt,im)
+#  define T2_STRWI(rt,rn,im)           torri12(THUMB2_STRWI,rn,rt,im)
+#  define CC_STRIN(cc,rt,rn,im)                corri(cc,ARM_STRI,rn,rt,im)
+#  define STRIN(rt,rn,im)              CC_STRIN(ARM_CC_AL,rt,rn,im)
+#  define T2_STRIN(rt,rn,im)           torri8(THUMB2_STRI,rn,rt,im)
+#  define CC_STRD(cc,rt,rn,rm)         corrr(cc,ARM_STRD|ARM_P,rn,rt,rm)
+#  define STRD(rt,rn,rm)               CC_STRD(ARM_CC_AL,rt,rn,rm)
+#  define CC_STRDN(cc,rt,rn,rm)                corrr(cc,ARM_STRD,rn,rt,rm)
+#  define STRDN(rt,rn,rm)              CC_STRDN(ARM_CC_AL,rt,rn,rm)
+#  define CC_STRDI(cc,rt,rn,im)                corri8(cc,ARM_STRDI|ARM_P,rn,rt,im)
+#  define STRDI(rt,rn,im)              CC_STRDI(ARM_CC_AL,rt,rn,im)
+#  define T2_STRDI(rt,rt2,rn,im)       torrri8(THUMB2_STRDI|ARM_P,rn,rt,rt2,im)
+#  define CC_STRDIN(cc,rt,rn,im)       corri8(cc,ARM_STRDI,rn,rt,im)
+#  define STRDIN(rt,rn,im)             CC_STRDIN(ARM_CC_AL,rt,rn,im)
+#  define T2_STRDIN(rt,rt2,rn,im)      torrri8(THUMB2_STRDI,rn,rt,rt2,im)
+#  define CC_LDMIA(cc,rn,im)           corl(cc,ARM_M|ARM_M_L|ARM_M_I,rn,im)
+#  define LDMIA(rn,im)                 CC_LDMIA(ARM_CC_AL,rn,im)
+#  define CC_LDM(cc,rn,im)             CC_LDMIA(cc,rn,im)
+#  define LDM(rn,im)                   LDMIA(rn,im)
+#  define T1_LDMIA(rn,im)              is(THUMB_LDMIA|(_u3(rn)<<8)|im)
+#  define T2_LDMIA(rn,im)              torl(THUMB2_LDMIA,rn,im)
+#  define CC_LDMIA_U(cc,rn,im)         corl(cc,ARM_M|ARM_M_L|ARM_M_I|ARM_M_U,rn,im)
+#  define LDMIA_U(rn,im)               CC_LDMIA_U(ARM_CC_AL,rn,im)
+#  define LDM_U(r0,i0)                 LDMIA_U(r0,i0)
+#  define CC_LDMIB(cc,rn,im)           corl(cc,ARM_M|ARM_M_L|ARM_M_I|ARM_M_B,rn,im)
+#  define LDMIB(rn,im)                 CC_LDMIB(ARM_CC_AL,rn,im)
+#  define CC_LDMIB_U(cc,rn,im)         corl(cc,ARM_M|ARM_M_L|ARM_M_I|ARM_M_B|ARM_M_U,rn,im)
+#  define LDMIB_U(rn,im)               CC_LDMIB_U(ARM_CC_AL,rn,im)
+#  define CC_LDMDA(cc,rn,im)           corl(cc,ARM_M|ARM_M_L,rn,im)
+#  define LDMDA(rn,im)                 CC_LDMDA(ARM_CC_AL,rn,im)
+#  define CC_LDMDA_U(cc,rn,im)         corl(cc,ARM_M|ARM_M_L|ARM_M_U,rn,im)
+#  define LDMDA_U(rn,im)               CC_LDMDA_U(ARM_CC_AL,rn,im)
+#  define CC_LDMDB(cc,rn,im)           corl(cc,ARM_M|ARM_M_L|ARM_M_B,rn,im)
+#  define LDMDB(rn,im)                 CC_LDMDB(ARM_CC_AL,rn,im)
+#  define T2_LDMDB(rn,im)              torl(THUMB2_LDMDB,rn,im)
+#  define CC_LDMDB_U(cc,rn,im)         corl(cc,ARM_M|ARM_M_L|ARM_M_B|ARM_M_U,rn,im)
+#  define LDMDB_U(rn,im)               CC_LDMDB_U(ARM_CC_AL,rn,im)
+#  define CC_STMIA(cc,rn,im)           corl(cc,ARM_M|ARM_M_I,rn,im)
+#  define STMIA(rn,im)                 CC_STMIA(ARM_CC_AL,rn,im)
+#  define CC_STM(cc,rn,im)             CC_STMIA(cc,rn,im)
+#  define STM(rn,im)                   STMIA(rn,im)
+#  define CC_STMIA_U(cc,rn,im)         corl(cc,ARM_M|ARM_M_I|ARM_M_U,rn,im)
+#  define STMIA_U(rn,im)               CC_STMIA_U(ARM_CC_AL,rn,im)
+#  define CC_STM_U(cc,rn,im)           CC_STMIA_U(cc,rn,im)
+#  define STM_U(rn,im)                 STMIA_U(rn,im)
+#  define CC_STMIB(cc,rn,im)           corl(cc,ARM_M|ARM_M_I|ARM_M_B,rn,im)
+#  define STMIB(rn,im)                 CC_STMIB(ARM_CC_AL,rn,im)
+#  define CC_STMIB_U(cc,rn,im)         corl(cc,ARM_M|ARM_M_I|ARM_M_B|ARM_M_U,rn,im)
+#  define STMIB_U(rn,im)               CC_STMIB_U(ARM_CC_AL,rn,im)
+#  define CC_STMDA(cc,rn,im)           corl(cc,ARM_M,rn,im)
+#  define STMDA(rn,im)                 CC_STMDA(ARM_CC_AL,rn,im)
+#  define CC_STMDA_U(cc,rn,im)         corl(cc,ARM_M|ARM_M_U,rn,im)
+#  define STMDA_U(rn,im)               CC_STMDA_U(ARM_CC_AL,rn,im)
+#  define CC_STMDB(cc,rn,im)           corl(cc,ARM_M|ARM_M_B,rn,im)
+#  define STMDB(rn,im)                 CC_STMDB(ARM_CC_AL,rn,im)
+#  define CC_STMDB_U(cc,rn,im)         corl(cc,ARM_M|ARM_M_B|ARM_M_U,rn,im)
+#  define STMDB_U(rn,im)               CC_STMDB_U(ARM_CC_AL,rn,im)
+#  define CC_PUSH(cc,im)               CC_STMDB_U(cc,_SP_REGNO,im)
+#  define PUSH(im)                     STMDB_U(_SP_REGNO,im)
+#  define T1_PUSH(im)                  is(THUMB_PUSH|((im&0x4000)>>6)|(im&0xff))
+#  define T2_PUSH(im)                  tpp(THUMB2_PUSH,im)
+#  define CC_POP(cc,im)                        LDMIA_U(cc,_SP_REGNO,im)
+#  define POP(im)                      LDMIA_U(_SP_REGNO,im)
+#  define T1_POP(im)                   is(THUMB_POP|((im&0x8000)>>7)|(im&0xff))
+#  define T2_POP(im)                   tpp(THUMB2_POP,im)
+#  define jit_get_reg_args()                                           \
+    do {                                                               \
+       (void)jit_get_reg(_R0|jit_class_named|jit_class_gpr);           \
+       (void)jit_get_reg(_R1|jit_class_named|jit_class_gpr);           \
+       (void)jit_get_reg(_R2|jit_class_named|jit_class_gpr);           \
+       (void)jit_get_reg(_R3|jit_class_named|jit_class_gpr);           \
+    } while (0)
+#  define jit_unget_reg_args()                                         \
+    do {                                                               \
+       jit_unget_reg(_R3);                                             \
+       jit_unget_reg(_R2);                                             \
+       jit_unget_reg(_R1);                                             \
+       jit_unget_reg(_R0);                                             \
+    } while (0)
+#  define nop(i0)                      _nop(_jit,i0)
+static void _nop(jit_state_t*,jit_int32_t);
+#  define movr(r0,r1)                  _movr(_jit,r0,r1)
+static void _movr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi(r0,i0)                  _movi(_jit,r0,i0)
+static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
+#  define movi_p(r0,i0)                        _movi_p(_jit,r0,i0)
+static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
+#  define comr(r0,r1)                  _comr(_jit,r0,r1)
+static void _comr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define negr(r0,r1)                  _negr(_jit,r0,r1)
+static void _negr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define addr(r0,r1,r2)               _addr(_jit,r0,r1,r2)
+static void _addr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addi(r0,r1,i0)               _addi(_jit,r0,r1,i0)
+static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addcr(r0,r1,r2)              _addcr(_jit,r0,r1,r2)
+static void _addcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addci(r0,r1,i0)              _addci(_jit,r0,r1,i0)
+static void _addci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addxr(r0,r1,r2)              _addxr(_jit,r0,r1,r2)
+static void _addxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addxi(r0,r1,i0)              _addxi(_jit,r0,r1,i0)
+static void _addxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subr(r0,r1,r2)               _subr(_jit,r0,r1,r2)
+static void _subr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subi(r0,r1,i0)               _subi(_jit,r0,r1,i0)
+static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subcr(r0,r1,r2)              _subcr(_jit,r0,r1,r2)
+static void _subcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subci(r0,r1,i0)              _subci(_jit,r0,r1,i0)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subxr(r0,r1,r2)              _subxr(_jit,r0,r1,r2)
+static void _subxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subxi(r0,r1,i0)              _subxi(_jit,r0,r1,i0)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rsbi(r0, r1, i0)             _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define mulr(r0,r1,r2)               _mulr(_jit,r0,r1,r2)
+static void _mulr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define muli(r0,r1,i0)               _muli(_jit,r0,r1,i0)
+static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr(r0,r1,r2,r3)           iqmulr(r0,r1,r2,r3,1)
+#  define qmulr_u(r0,r1,r2,r3)         iqmulr(r0,r1,r2,r3,0)
+#  define iqmulr(r0,r1,r2,r3,cc)       _iqmulr(_jit,r0,r1,r2,r3,cc)
+static void _iqmulr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#  define qmuli(r0,r1,r2,i0)           iqmuli(r0,r1,r2,i0,1)
+#  define qmuli_u(r0,r1,r2,i0)         iqmuli(r0,r1,r2,i0,0)
+#  define iqmuli(r0,r1,r2,i0,cc)       _iqmuli(_jit,r0,r1,r2,i0,cc)
+static void _iqmuli(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#  define divrem(d,s,r0,r1,r2)         _divrem(_jit,d,s,r0,r1,r2)
+static void _divrem(jit_state_t*,int,int,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divr(r0,r1,r2)               _divr(_jit,r0,r1,r2)
+static void _divr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi(r0,r1,i0)               _divi(_jit,r0,r1,i0)
+static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define divr_u(r0,r1,r2)             _divr_u(_jit,r0,r1,r2)
+static void _divr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi_u(r0,r1,i0)             _divi_u(_jit,r0,r1,i0)
+static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qdivr(r0,r1,r2,r3)           iqdivr(r0,r1,r2,r3,1)
+#  define qdivr_u(r0,r1,r2,r3)         iqdivr(r0,r1,r2,r3,0)
+#  define iqdivr(r0,r1,r2,r3,cc)       _iqdivr(_jit,r0,r1,r2,r3,cc)
+static void _iqdivr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#  define qdivi(r0,r1,r2,i0)           iqdivi(r0,r1,r2,i0,1)
+#  define qdivi_u(r0,r1,r2,i0)         iqdivi(r0,r1,r2,i0,0)
+#  define iqdivi(r0,r1,r2,i0,cc)       _iqdivi(_jit,r0,r1,r2,i0,cc)
+static void _iqdivi(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#  define remr(r0,r1,r2)               _remr(_jit,r0,r1,r2)
+static void _remr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi(r0,r1,i0)               _remi(_jit,r0,r1,i0)
+static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define remr_u(r0,r1,r2)             _remr_u(_jit,r0,r1,r2)
+static void _remr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi_u(r0,r1,i0)             _remi_u(_jit,r0,r1,i0)
+static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define andr(r0,r1,r2)               _andr(_jit,r0,r1,r2)
+static void _andr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define andi(r0,r1,i0)               _andi(_jit,r0,r1,i0)
+static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define orr(r0,r1,r2)                        _orr(_jit,r0,r1,r2)
+static void _orr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ori(r0,r1,i0)                        _ori(_jit,r0,r1,i0)
+static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define xorr(r0,r1,r2)               _xorr(_jit,r0,r1,r2)
+static void _xorr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define xori(r0,r1,i0)               _xori(_jit,r0,r1,i0)
+static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define lshr(r0,r1,r2)               _lshr(_jit,r0,r1,r2)
+static void _lshr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lshi(r0,r1,i0)               _lshi(_jit,r0,r1,i0)
+static void _lshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rshr(r0,r1,r2)               _rshr(_jit,r0,r1,r2)
+static void _rshr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define rshi(r0,r1,i0)               _rshi(_jit,r0,r1,i0)
+static void _rshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rshr_u(r0,r1,r2)             _rshr_u(_jit,r0,r1,r2)
+static void _rshr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define rshi_u(r0,r1,i0)             _rshi_u(_jit,r0,r1,i0)
+static void _rshi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ccr(ct,cf,r0,r1,r2)          _ccr(_jit,ct,cf,r0,r1,r2)
+static void _ccr(jit_state_t*,int,int,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define cci(ct,cf,r0,r1,i0)          _cci(_jit,ct,cf,r0,r1,i0)
+static void _cci(jit_state_t*,int,int,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ltr(r0, r1, r2)              ccr(ARM_CC_LT,ARM_CC_GE,r0,r1,r2)
+#  define lti(r0, r1, i0)              cci(ARM_CC_LT,ARM_CC_GE,r0,r1,i0)
+#  define ltr_u(r0, r1, r2)            ccr(ARM_CC_LO,ARM_CC_HS,r0,r1,r2)
+#  define lti_u(r0, r1, i0)            cci(ARM_CC_LO,ARM_CC_HS,r0,r1,i0)
+#  define ler(r0, r1, r2)              ccr(ARM_CC_LE,ARM_CC_GT,r0,r1,r2)
+#  define lei(r0, r1, i0)              cci(ARM_CC_LE,ARM_CC_GT,r0,r1,i0)
+#  define ler_u(r0, r1, r2)            ccr(ARM_CC_LS,ARM_CC_HI,r0,r1,r2)
+#  define lei_u(r0, r1, i0)            cci(ARM_CC_LS,ARM_CC_HI,r0,r1,i0)
+#  define eqr(r0, r1, r2)              ccr(ARM_CC_EQ,ARM_CC_NE,r0,r1,r2)
+#  define eqi(r0, r1, i0)              cci(ARM_CC_EQ,ARM_CC_NE,r0,r1,i0)
+#  define ger(r0, r1, r2)              ccr(ARM_CC_GE,ARM_CC_LT,r0,r1,r2)
+#  define gei(r0, r1, i0)              cci(ARM_CC_GE,ARM_CC_LT,r0,r1,i0)
+#  define ger_u(r0, r1, r2)            ccr(ARM_CC_HS,ARM_CC_LO,r0,r1,r2)
+#  define gei_u(r0, r1, i0)            cci(ARM_CC_HS,ARM_CC_LO,r0,r1,i0)
+#  define gtr(r0, r1, r2)              ccr(ARM_CC_GT,ARM_CC_LE,r0,r1,r2)
+#  define gti(r0, r1, i0)              cci(ARM_CC_GT,ARM_CC_LE,r0,r1,i0)
+#  define gtr_u(r0, r1, r2)            ccr(ARM_CC_HI,ARM_CC_LS,r0,r1,r2)
+#  define gti_u(r0, r1, i0)            cci(ARM_CC_HI,ARM_CC_LS,r0,r1,i0)
+#  define ner(r0,r1,r2)                        _ner(_jit,r0,r1,r2)
+static void _ner(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nei(r0,r1,i0)                        _nei(_jit,r0,r1,i0)
+static void _nei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define jmpr(r0)                     _jmpr(_jit,r0)
+static void _jmpr(jit_state_t*,jit_int32_t);
+#  define jmpi(i0)                     _jmpi(_jit,i0)
+static void _jmpi(jit_state_t*,jit_word_t);
+#  define jmpi_p(i0, i1)               _jmpi_p(_jit,i0, i1)
+static jit_word_t _jmpi_p(jit_state_t*,jit_word_t,jit_bool_t);
+#  define bccr(cc,i0,r0,r1)            _bccr(_jit,cc,i0,r0,r1)
+static jit_word_t _bccr(jit_state_t*,int,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bcci(cc,i0,r0,i1)            _bcci(_jit,cc,i0,r0,i1)
+static jit_word_t _bcci(jit_state_t*,int,jit_word_t,jit_int32_t,jit_word_t);
+#  define bltr(i0, r0, r1)             bccr(ARM_CC_LT,i0,r0,r1)
+#  define blti(i0, r0, i1)             bcci(ARM_CC_LT,i0,r0,i1)
+#  define bltr_u(i0, r0, r1)           bccr(ARM_CC_LO,i0,r0,r1)
+#  define blti_u(i0, r0, i1)           bcci(ARM_CC_LO,i0,r0,i1)
+#  define bler(i0, r0, r1)             bccr(ARM_CC_LE,i0,r0,r1)
+#  define blei(i0, r0, i1)             bcci(ARM_CC_LE,i0,r0,i1)
+#  define bler_u(i0, r0, r1)           bccr(ARM_CC_LS,i0,r0,r1)
+#  define blei_u(i0, r0, i1)           bcci(ARM_CC_LS,i0,r0,i1)
+#  define beqr(i0, r0, r1)             bccr(ARM_CC_EQ,i0,r0,r1)
+#  define beqi(i0, r0, i1)             bcci(ARM_CC_EQ,i0,r0,i1)
+#  define bger(i0, r0, r1)             bccr(ARM_CC_GE,i0,r0,r1)
+#  define bgei(i0, r0, i1)             bcci(ARM_CC_GE,i0,r0,i1)
+#  define bger_u(i0, r0, r1)           bccr(ARM_CC_HS,i0,r0,r1)
+#  define bgei_u(i0, r0, i1)           bcci(ARM_CC_HS,i0,r0,i1)
+#  define bgtr(i0, r0, r1)             bccr(ARM_CC_GT,i0,r0,r1)
+#  define bgti(i0, r0, i1)             bcci(ARM_CC_GT,i0,r0,i1)
+#  define bgtr_u(i0, r0, r1)           bccr(ARM_CC_HI,i0,r0,r1)
+#  define bgti_u(i0, r0, i1)           bcci(ARM_CC_HI,i0,r0,i1)
+#  define bner(i0, r0, r1)             bccr(ARM_CC_NE,i0,r0,r1)
+#  define bnei(i0, r0, i1)             bcci(ARM_CC_NE,i0,r0,i1)
+#  define baddr(cc,i0,r0,r1)           _baddr(_jit,cc,i0,r0,r1)
+static jit_word_t _baddr(jit_state_t*,int,jit_word_t,jit_int32_t,jit_int32_t);
+#  define baddi(cc,i0,r0,r1)           _baddi(_jit,cc,i0,r0,r1)
+static jit_word_t _baddi(jit_state_t*,int,jit_word_t,jit_int32_t,jit_word_t);
+#  define boaddr(i0,r0,r1)             baddr(ARM_CC_VS,i0,r0,r1)
+#  define boaddi(i0,r0,i1)             baddi(ARM_CC_VS,i0,r0,i1)
+#  define boaddr_u(i0,r0,r1)           baddr(ARM_CC_HS,i0,r0,r1)
+#  define boaddi_u(i0,r0,i1)           baddi(ARM_CC_HS,i0,r0,i1)
+#  define bxaddr(i0,r0,r1)             baddr(ARM_CC_VC,i0,r0,r1)
+#  define bxaddi(i0,r0,i1)             baddi(ARM_CC_VC,i0,r0,i1)
+#  define bxaddr_u(i0,r0,r1)           baddr(ARM_CC_LO,i0,r0,r1)
+#  define bxaddi_u(i0,r0,i1)           baddi(ARM_CC_LO,i0,r0,i1)
+#  define bsubr(cc,i0,r0,r1)           _bsubr(_jit,cc,i0,r0,r1)
+static jit_word_t _bsubr(jit_state_t*,int,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bsubi(cc,i0,r0,r1)           _bsubi(_jit,cc,i0,r0,r1)
+static jit_word_t _bsubi(jit_state_t*,int,jit_word_t,jit_int32_t,jit_word_t);
+#  define bosubr(i0,r0,r1)             bsubr(ARM_CC_VS,i0,r0,r1)
+#  define bosubi(i0,r0,i1)             bsubi(ARM_CC_VS,i0,r0,i1)
+#  define bosubr_u(i0,r0,r1)           bsubr(ARM_CC_LO,i0,r0,r1)
+#  define bosubi_u(i0,r0,i1)           bsubi(ARM_CC_LO,i0,r0,i1)
+#  define bxsubr(i0,r0,r1)             bsubr(ARM_CC_VC,i0,r0,r1)
+#  define bxsubi(i0,r0,i1)             bsubi(ARM_CC_VC,i0,r0,i1)
+#  define bxsubr_u(i0,r0,r1)           bsubr(ARM_CC_HS,i0,r0,r1)
+#  define bxsubi_u(i0,r0,i1)           bsubi(ARM_CC_HS,i0,r0,i1)
+#  define bmxr(cc,i0,r0,r1)            _bmxr(_jit,cc,i0,r0,r1)
+static jit_word_t _bmxr(jit_state_t*,int,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bmxi(cc,i0,r0,r1)            _bmxi(_jit,cc,i0,r0,r1)
+static jit_word_t _bmxi(jit_state_t*,int,jit_word_t,jit_int32_t,jit_word_t);
+#  define bmsr(i0,r0,r1)               bmxr(ARM_CC_NE,i0,r0,r1)
+#  define bmsi(i0,r0,i1)               bmxi(ARM_CC_NE,i0,r0,i1)
+#  define bmcr(i0,r0,r1)               bmxr(ARM_CC_EQ,i0,r0,r1)
+#  define bmci(i0,r0,i1)               bmxi(ARM_CC_EQ,i0,r0,i1)
+#  define ldr_c(r0,r1)                 _ldr_c(_jit,r0,r1)
+static void _ldr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_c(r0,i0)                 _ldi_c(_jit,r0,i0)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_c(r0,r1,r2)             _ldxr_c(_jit,r0,r1,r2)
+static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_c(r0,r1,i0)             _ldxi_c(_jit,r0,r1,i0)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_uc(r0,r1)                        _ldr_uc(_jit,r0,r1)
+static void _ldr_uc(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_uc(r0,i0)                        _ldi_uc(_jit,r0,i0)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_uc(r0,r1,r2)            _ldxr_uc(_jit,r0,r1,r2)
+static void _ldxr_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_uc(r0,r1,i0)            _ldxi_uc(_jit,r0,r1,i0)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_s(r0,r1)                 _ldr_s(_jit,r0,r1)
+static void _ldr_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_s(r0,i0)                 _ldi_s(_jit,r0,i0)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_s(r0,r1,r2)             _ldxr_s(_jit,r0,r1,r2)
+static void _ldxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_s(r0,r1,i0)             _ldxi_s(_jit,r0,r1,i0)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_us(r0,r1)                        _ldr_us(_jit,r0,r1)
+static void _ldr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_us(r0,i0)                        _ldi_us(_jit,r0,i0)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_us(r0,r1,r2)            _ldxr_us(_jit,r0,r1,r2)
+static void _ldxr_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_us(r0,r1,i0)            _ldxi_us(_jit,r0,r1,i0)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_i(r0,r1)                 _ldr_i(_jit,r0,r1)
+static void _ldr_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_i(r0,i0)                 _ldi_i(_jit,r0,i0)
+static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_i(r0,r1,r2)             _ldxr_i(_jit,r0,r1,r2)
+static void _ldxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_i(r0,r1,i0)             _ldxi_i(_jit,r0,r1,i0)
+static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_c(r0,r1)                 _str_c(_jit,r0,r1)
+static void _str_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sti_c(i0,r0)                 _sti_c(_jit,i0,r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_c(r0,r1,r2)             _stxr_c(_jit,r0,r1,r2)
+static void _stxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_c(r0,r1,i0)             _stxi_c(_jit,r0,r1,i0)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define str_s(r0,r1)                 _str_s(_jit,r0,r1)
+static void _str_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sti_s(i0,r0)                 _sti_s(_jit,i0,r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_s(r0,r1,r2)             _stxr_s(_jit,r0,r1,r2)
+static void _stxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_s(r0,r1,i0)             _stxi_s(_jit,r0,r1,i0)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define str_i(r0,r1)                 _str_i(_jit,r0,r1)
+static void _str_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sti_i(i0,r0)                 _sti_i(_jit,i0,r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_i(r0,r1,r2)             _stxr_i(_jit,r0,r1,r2)
+static void _stxr_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxi_i(r0,r1,i0)             _stxi_i(_jit,r0,r1,i0)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define htonr_us(r0,r1)              _htonr_us(_jit,r0,r1)
+static void _htonr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define htonr_ui(r0,r1)              _htonr_ui(_jit,r0,r1)
+static void _htonr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  else
+#    define htonr_us(r0,r1)            extr_us(r0,r1)
+#    define htonr(r0,r1)               movr(r0,r1)
+#  endif
+#  define extr_c(r0,r1)                        _extr_c(_jit,r0,r1)
+static void _extr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_uc(r0,r1)               _extr_uc(_jit,r0,r1)
+static void _extr_uc(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_s(r0,r1)                        _extr_s(_jit,r0,r1)
+static void _extr_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_us(r0,r1)               _extr_us(_jit,r0,r1)
+static void _extr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define prolog(i0)                   _prolog(_jit,i0)
+static void _prolog(jit_state_t*,jit_node_t*);
+#  define epilog(i0)                   _epilog(_jit,i0)
+static void _epilog(jit_state_t*,jit_node_t*);
+#  define callr(r0)                    _callr(_jit,r0)
+static void _callr(jit_state_t*,jit_int32_t);
+#  define calli(i0)                    _calli(_jit,i0)
+static void _calli(jit_state_t*,jit_word_t);
+#  define calli_p(i0)                  _calli_p(_jit,i0)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t);
+#  define vastart(r0)                  _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#  define vaarg(r0, r1)                        _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define patch_at(kind,jump,label)    _patch_at(_jit,kind,jump,label)
+static void _patch_at(jit_state_t*,jit_int32_t,jit_word_t,jit_word_t);
+#endif
+
+#if CODE
+/* from binutils */
+#  define rotate_left(v, n)    (v << n | v >> (32 - n))
+static int
+encode_arm_immediate(unsigned int v)
+{
+    unsigned int       a, i;
+
+    for (i = 0; i < 32; i += 2)
+       if ((a = rotate_left(v, i)) <= 0xff)
+           return (a | (i << 7));
+
+    return (-1);
+}
+
+static int
+encode_thumb_immediate(unsigned int v)
+{
+    int                        i;
+    unsigned int       m;
+    unsigned int       n;
+    /* 00000000 00000000 00000000 abcdefgh */
+    if ((v & 0xff) == v)
+       return (v);
+    /* 00000000 abcdefgh 00000000 abcdefgh */
+    if ((v & 0xff00ff) == v && ((v & 0xff0000) >> 16) == (v & 0xff))
+       return ((v & 0xff) | (1 << 12));
+    /* abcdefgh 00000000 abcdefgh 00000000 */
+    if (((v & 0xffff0000) >> 16) == (v & 0xffff) && (v & 0xff) == 0)
+       return ((v & 0x000000ff) | (2 << 12));
+    /* abcdefgh abcdefgh abcdefgh abcdefgh */
+    if ( (v &    0xff)        == ((v &     0xff00) >>  8) &&
+       ((v &   0xff00) >> 8) == ((v &   0xff0000) >> 16) &&
+       ((v & 0xff0000) << 8) ==  (v & 0xff000000))
+       return ((v & 0xff) | (3 << 12));
+    /* 1bcdefgh << 24 ... 1bcdefgh << 1 */
+    for (i = 8, m = 0xff000000, n = 0x80000000;
+        i < 23; i++, m >>= 1,  n >>= 1) {
+       if ((v & m) == v && (v & n)) {
+           v >>= 32 - i;
+           if (!(i & 1))
+               v &= 0x7f;
+           i >>= 1;
+           return (((i & 7) << 12) | ((i & 8) << 23) | v);
+       }
+    }
+    return (-1);
+}
+
+static int
+encode_thumb_word_immediate(unsigned int v)
+{
+    if ((v & 0xfffff000) == 0)
+       return (((v & 0x800) << 15) | ((v & 0x700) << 4) | (v & 0xff));
+    return (-1);
+}
+
+static int
+encode_thumb_jump(int v)
+{
+    int                s, i1, i2, j1, j2;
+    if (v >= (int)-0x800000 && v <= 0x7fffff) {
+       s  = !!(v & 0x800000);
+       i1 = !!(v & 0x400000);
+       i2 = !!(v & 0x200000);
+       j1 = s ? i1 : !i1;
+       j2 = s ? i2 : !i2;
+       return ((s<<26)|((v&0x1ff800)<<5)|(j1<<13)|(j2<<11)|(v&0x7ff));
+    }
+    return (-1);
+}
+
+static int
+encode_thumb_cc_jump(int v)
+{
+    int                s, j1, j2;
+    if (v >= (int)-0x80000 && v <= 0x7ffff) {
+       s  = !!(v & 0x80000);
+       j1 = !!(v & 0x20000);
+       j2 = !!(v & 0x40000);
+       return ((s<<26)|((v&0x1f800)<<5)|(j1<<13)|(j2<<11)|(v&0x7ff));
+    }
+    return (-1);
+}
+
+static int
+encode_thumb_shift(int v, int type)
+{
+    switch (type) {
+       case ARM_ASR:
+       case ARM_LSL:
+       case ARM_LSR:           type >>= 1;     break;
+       default:                assert(!"handled shift");
+    }
+    assert(v >= 0 && v <= 31);
+    return (((v & 0x1c) << 10) | ((v & 3) << 6) | type);
+}
+
+static void
+_tcit(jit_state_t *_jit, unsigned int tc, int it)
+{
+    int                c;
+    int                m;
+    c = (tc >> 28) & 1;
+    assert(!(tc & 0xfffffff) && tc != ARM_CC_NV);
+    switch (it) {
+       case THUMB2_IT:         m =   1<<3;                     break;
+       case THUMB2_ITT:        m =  (c<<3)| (1<<2);            break;
+       case THUMB2_ITE:        m = (!c<<3)| (1<<2);            break;
+       case THUMB2_ITTT:       m =  (c<<3)| (c<<2)| (1<<1);    break;
+       case THUMB2_ITET:       m = (!c<<3)| (c<<2)| (1<<1);    break;
+       case THUMB2_ITTE:       m =  (c<<3)|(!c<<2)| (1<<1);    break;
+       case THUMB2_ITEE:       m = (!c<<3)|(!c<<2)| (1<<1);    break;
+       case THUMB2_ITTTT:      m =  (c<<3)| (c<<2)| (c<<1)|1;  break;
+       case THUMB2_ITETT:      m = (!c<<3)| (c<<2)| (c<<1)|1;  break;
+       case THUMB2_ITTET:      m =  (c<<3)|(!c<<2)| (c<<1)|1;  break;
+       case THUMB2_ITEET:      m = (!c<<3)|(!c<<2)| (c<<1)|1;  break;
+       case THUMB2_ITTTE:      m =  (c<<3)| (c<<2)|(!c<<1)|1;  break;
+       case THUMB2_ITETE:      m = (!c<<3)| (c<<2)|(!c<<1)|1;  break;
+       case THUMB2_ITTEE:      m =  (c<<3)|(!c<<2)|(!c<<1)|1;  break;
+       case THUMB2_ITEEE:      m = (!c<<3)|(!c<<2)|(!c<<1)|1;  break;
+       default:                abort();
+    }
+    assert(m && (tc != ARM_CC_AL || !(m & (m - 1))));
+    is(0xbf00 | (tc >> 24) | m);
+}
+
+static void
+_corrr(jit_state_t *_jit, int cc, int o, int rn, int rd, int rm)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00fff0f));
+    ii(cc|o|(_u4(rn)<<16)|(_u4(rd)<<12)|_u4(rm));
+}
+
+static void
+_corri(jit_state_t *_jit, int cc, int o, int rn, int rd, int im)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00fffff));
+    assert(!(im & 0xfffff000));
+    ii(cc|o|(_u4(rn)<<16)|(_u4(rd)<<12)|_u12(im));
+}
+
+static void
+_corri8(jit_state_t *_jit, int cc, int o, int rn, int rt, int im)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00fff0f));
+    assert(!(im & 0xffffff00));
+    ii(cc|o|(_u4(rn)<<16)|(_u4(rt)<<12)|((im&0xf0)<<4)|(im&0x0f));
+}
+
+static void
+_coriw(jit_state_t *_jit, int cc, int o, int rd, int im)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00fffff));
+    assert(!(im & 0xffff0000));
+    ii(cc|o|((im&0xf000)<<4)|(_u4(rd)<<12)|(im&0xfff));
+}
+
+static void
+_torrr(jit_state_t *_jit, int o, int rn, int rd, int rm)
+{
+    jit_thumb_t        thumb;
+    assert(!(o & 0xf0f0f));
+    thumb.i = o|(_u4(rn)<<16)|(_u4(rd)<<8)|_u4(rm);
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_torrrs(jit_state_t *_jit, int o, int rn, int rd, int rm, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(o  & 0x000f0f0f));
+    assert(!(im & 0xffff8f0f));
+    thumb.i = o|(_u4(rn)<<16)|(_u4(rd)<<8)|im|_u4(rm);
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_torxr(jit_state_t *_jit, int o, int rn, int rt, int rm)
+{
+    jit_thumb_t        thumb;
+    assert(!(o & 0xf0f0f));
+    thumb.i = o|(_u4(rn)<<16)|(_u4(rt)<<12)|_u4(rm);
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_torrrr(jit_state_t *_jit, int o, int rn, int rl, int rh, int rm)
+{
+    jit_thumb_t        thumb;
+    assert(!(o & 0x000fff0f));
+    thumb.i = o|(_u4(rn)<<16)|(_u4(rl)<<12)|(_u4(rh)<<8)|_u4(rm);
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_torrri8(jit_state_t *_jit, int o, int rn, int rt, int rt2, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(o  & 0x000fffff));
+    assert(!(im & 0xffffff00));
+    thumb.i = o|(_u4(rn)<<16)|(_u4(rt)<<12)|(_u4(rt2)<<8)|im;
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_torri(jit_state_t *_jit, int o, int rn, int rd, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(o  & 0x0c0f7fff));
+    assert(!(im & 0xfbff8f00));
+    thumb.i = o|(_u4(rn)<<16)|(_u4(rd)<<8)|im;
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_torri8(jit_state_t *_jit, int o, int rn, int rt, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(o  & 0x000ff0ff));
+    assert(!(im & 0xffffff00));
+    thumb.i = o|(_u4(rn)<<16)|(_u4(rt)<<12)|im;
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_torri12(jit_state_t *_jit, int o, int rn, int rt, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(o  & 0x000fffff));
+    assert(!(im & 0xfffff000));
+    thumb.i = o|(_u4(rn)<<16)|(_u4(rt)<<12)|im;
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_tshift(jit_state_t *_jit, int o, int rd, int rm, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(o & 0x7fcf));
+    assert(im >= 0 && im < 32);
+    thumb.i = o|((im&0x1c)<<10)|(_u4(rd)<<8)|((im&3)<<6)|_u4(rm);
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_toriw(jit_state_t *_jit, int o, int rd, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(im & 0xffff0000));
+    thumb.i = o|((im&0xf000)<<4)|((im&0x800)<<15)|((im&0x700)<<4)|(_u4(rd)<<8)|(im&0xff);
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_tc8(jit_state_t *_jit, int cc, int im)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(cc != ARM_CC_AL && cc != ARM_CC_NV);
+    assert(im >= -128 && im <= 127);
+    is(THUMB_CC_B|(cc>>20)|(im&0xff));
+}
+
+static void
+_t11(jit_state_t *_jit, int im)
+{
+    assert(!(im & 0xfffff800));
+    is(THUMB_B|im);
+}
+
+static void
+_tcb(jit_state_t *_jit, int cc, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0xfffffff));
+    assert(cc != ARM_CC_AL && cc != ARM_CC_NV);
+    cc = ((jit_uint32_t)cc) >> 6;
+    assert(!(im & (THUMB2_CC_B|cc)));
+    thumb.i = THUMB2_CC_B|cc|im;
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_blxi(jit_state_t *_jit, int im)
+{
+    assert(!(im & 0xfe000000));
+    ii(ARM_BLXI|im);
+}
+
+static void
+_tb(jit_state_t *_jit, int o, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(o & 0x07ff2fff));
+    assert(!(o & im));
+    thumb.i = o|im;
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_corrrr(jit_state_t *_jit, int cc, int o, int rh, int rl, int rm, int rn)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o & 0xf00fff0f));
+    ii(cc|o|(_u4(rh)<<16)|(_u4(rl)<<12)|(_u4(rm)<<8)|_u4(rn));
+}
+
+static void
+_corrrs(jit_state_t *_jit, int cc, int o, int rn, int rd, int rm, int im)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000ff8f));
+    ii(cc|o|(_u4(rd)<<12)|(_u4(rn)<<16)|(im<<7)|_u4(rm));
+}
+
+static void
+_cshift(jit_state_t *_jit, int cc, int o, int rd, int rm, int rn, int im)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xffe0ff8f));
+    assert(((_u4(rm)<<8)&(im<<7)) == 0);
+    ii(cc|ARM_SHIFT|o|(_u4(rd)<<12)|(_u4(rm)<<8)|(im<<7)|_u4(rn));
+}
+
+static void
+_cb(jit_state_t *_jit, int cc, int o, int im)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf0ffffff));
+    ii(cc|o|_u24(im));
+}
+
+static void
+_cbx(jit_state_t *_jit, int cc, int o, int rm)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000000f));
+    ii(cc|o|_u4(rm));
+}
+
+static void
+_corl(jit_state_t *_jit, int cc, int o, int r0, int i0)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00fffff));
+    ii(cc|o|(_u4(r0)<<16)|_u16(i0));
+}
+
+static void
+_c6orr(jit_state_t *_jit, int cc, int o, int rd, int rm)
+{
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000f00f));
+    ii(cc|o|(_u4(rd)<<12)|_u4(rm));
+}
+
+static void
+_tpp(jit_state_t *_jit, int o, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(o & 0x0000ffff));
+    if (o == THUMB2_PUSH)
+       assert(!(im & 0x8000));
+    assert(__builtin_popcount(im & 0x1fff) > 1);
+    thumb.i = o|im;
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_torl(jit_state_t *_jit, int o, int rn, int im)
+{
+    jit_thumb_t        thumb;
+    assert(!(o & 0xf1fff));
+    assert(rn != _R15 || !im || ((o & 0xc000) == 0xc000));
+    assert(!(o & THUMB2_LDM_W) || !(im & (1 << rn)));
+    thumb.i = o | (_u4(rn)<<16)|_u13(im);
+    iss(thumb.s[0], thumb.s[1]);
+}
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t i0)
+{
+    if (jit_thumb_p()) {
+       for (; i0 > 0; i0 -= 2)
+           T1_NOP();
+    }
+    else {
+       for (; i0 > 0; i0 -= 4)
+           NOP();
+    }
+    assert(i0 == 0);
+}
+
+static void
+_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1) {
+       if (jit_thumb_p())
+           T1_MOV(r0, r1);
+       else
+           MOV(r0, r1);
+    }
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    int                        i;
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && r0 < 8 && !(i0 & 0xffffff80))
+           T1_MOVI(r0, i0);
+       else if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_MOVI(r0, i);
+       else if ((i = encode_thumb_immediate(~i0)) != -1)
+           T2_MVNI(r0, i);
+       else {
+           T2_MOVWI(r0, (jit_uint16_t)i0);
+           if (i0 & 0xffff0000)
+               T2_MOVTI(r0, (jit_uint16_t)((unsigned)i0 >> 16));
+       }
+    }
+    else {
+       if (jit_armv6_p() && !(i0 & 0xffff0000))
+           MOVWI(r0, i0);
+       else if ((i = encode_arm_immediate(i0)) != -1)
+           MOVI(r0, i);
+       else if ((i = encode_arm_immediate(~i0)) != -1)
+           MVNI(r0, i);
+       else if (jit_armv6_p()) {
+           MOVWI(r0, (jit_uint16_t)(i0));
+           if ((i0 & 0xffff0000))
+               MOVTI(r0, (jit_uint16_t)((unsigned)i0 >> 16));
+       }
+       else
+           load_const(0, r0, i0);
+    }
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    if (jit_thumb_p()) {
+       T2_MOVWI(r0, (jit_uint16_t)(i0));
+       T2_MOVTI(r0, (jit_uint16_t)((unsigned)i0 >> 16));
+    }
+    else
+       load_const(1, r0, 0);
+    return (w);
+}
+
+static void
+_comr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1) < 8)
+           T1_NOT(r0, r1);
+       else
+           T2_NOT(r0, r1);
+    }
+    else
+       NOT(r0, r1);
+}
+
+static void
+_negr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1) < 8)
+           T1_RSBI(r0, r1);
+       else
+           T2_RSBI(r0, r1, 0);
+    }
+    else
+       RSBI(r0, r1, 0);
+}
+
+static void
+_addr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1|r2) < 8)
+           T1_ADD(r0, r1, r2);
+       else if (r0 == r1 || r0 == r2)
+           T1_ADDX(r0, r0 == r1 ? r2 : r1);
+       else
+           T2_ADD(r0, r1, r2);
+    }
+    else
+       ADD(r0, r1, r2);
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1) < 8 && !(i0 & ~7))
+           T1_ADDI3(r0, r1, i0);
+       else if (!jit_no_set_flags() && (r0|r1) < 8 && !(-i0 & ~7))
+           T1_SUBI3(r0, r1, -i0);
+       else if (!jit_no_set_flags() && r0 < 8 && r0 == r1 && !(i0 & ~0xff))
+           T1_ADDI8(r0, i0);
+       else if (!jit_no_set_flags() && r0 < 8 && r0 == r1 && !(-i0 & ~0xff))
+           T1_SUBI8(r0, -i0);
+       else if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_ADDI(r0, r1, i);
+       else if ((i = encode_thumb_immediate(-i0)) != -1)
+           T2_SUBI(r0, r1, i);
+       else if ((i = encode_thumb_word_immediate(i0)) != -1)
+           T2_ADDWI(r0, r1, i);
+       else if ((i = encode_thumb_word_immediate(-i0)) != -1)
+           T2_SUBWI(r0, r1, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           T2_ADD(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           ADDI(r0, r1, i);
+       else if ((i = encode_arm_immediate(-i0)) != -1)
+           SUBI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           ADD(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           ADD(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_addcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       /* thumb auto set carry if not inside IT block */
+       if ((r0|r1|r2) < 8)
+           T1_ADD(r0, r1, r2);
+       else
+           T2_ADDS(r0, r1, r2);
+    }
+    else
+       ADDS(r0, r1, r2);
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8 && !(i0 & ~7))
+           T1_ADDI3(r0, r1, i0);
+       else if ((r0|r1) < 8 && !(-i0 & ~7))
+           T1_SUBI3(r0, r1, -i0);
+       else if (r0 < 8 && r0 == r1 && !(i0 & ~0xff))
+           T1_ADDI8(r0, i0);
+       else if (r0 < 8 && r0 == r1 && !(-i0 & ~0xff))
+           T1_SUBI8(r0, -i0);
+       else if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_ADDSI(r0, r1, i);
+       else if ((i = encode_thumb_immediate(-i0)) != -1)
+           T2_SUBSI(r0, r1, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           T2_ADDS(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           ADDSI(r0, r1, i);
+       else if ((i = encode_arm_immediate(-i0)) != -1)
+           SUBSI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           ADDS(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           ADDS(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_addxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    /* keep setting carry because don't know last ADC */
+    if (jit_thumb_p()) {
+       /* thumb auto set carry if not inside IT block */
+       if ((r0|r1|r2) < 8 && (r0 == r1 || r0 == r2))
+           T1_ADC(r0, r0 == r1 ? r2 : r1);
+       else
+           T2_ADCS(r0, r1, r2);
+    }
+    else
+       ADCS(r0, r1, r2);
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    int                        no_set_flags;
+    if (jit_thumb_p()) {
+       no_set_flags = jit_no_set_flags();
+       jit_no_set_flags() = 1;
+       if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_ADCSI(r0, r1, i);
+       else if ((i = encode_thumb_immediate(-i0)) != -1)
+           T2_SBCSI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           T2_ADCS(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           T2_ADCS(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+       jit_no_set_flags() = no_set_flags;
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           ADCSI(r0, r1, i);
+       else if ((i = encode_arm_immediate(-i0)) != -1)
+           SBCSI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           ADCS(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           ADCS(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_subr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1|r2) < 8)
+           T1_SUB(r0, r1, r2);
+       else
+           T2_SUB(r0, r1, r2);
+    }
+    else
+       SUB(r0, r1, r2);
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1) < 8 && !(i0 & ~7))
+           T1_SUBI3(r0, r1, i0);
+       else if (!jit_no_set_flags() && (r0|r1) < 8 && !(-i0 & ~7))
+           T1_ADDI3(r0, r1, -i0);
+       else if (!jit_no_set_flags() && r0 < 8 && r0 == r1 && !(i0 & ~0xff))
+           T1_SUBI8(r0, i0);
+       else if (!jit_no_set_flags() && r0 < 8 && r0 == r1 && !(-i0 & ~0xff))
+           T1_ADDI8(r0, -i0);
+       else if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_SUBI(r0, r1, i);
+       else if ((i = encode_thumb_immediate(-i0)) != -1)
+           T2_ADDI(r0, r1, i);
+       else if ((i = encode_thumb_word_immediate(i0)) != -1)
+           T2_SUBWI(r0, r1, i);
+       else if ((i = encode_thumb_word_immediate(-i0)) != -1)
+           T2_ADDWI(r0, r1, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           T2_SUB(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           SUBI(r0, r1, i);
+       else if ((i = encode_arm_immediate(-i0)) != -1)
+           ADDI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           SUB(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           SUB(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_subcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       /* thumb auto set carry if not inside IT block */
+       if ((r0|r1|r2) < 8)
+           T1_SUB(r0, r1, r2);
+       else
+           T2_SUBS(r0, r1, r2);
+    }
+    else
+       SUBS(r0, r1, r2);
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8 && !(i0 & ~7))
+           T1_SUBI3(r0, r1, i0);
+       else if ((r0|r1) < 8 && !(-i0 & ~7))
+           T1_ADDI3(r0, r1, -i0);
+       else if (r0 < 8 && r0 == r1 && !(i0 & ~0xff))
+           T1_SUBI8(r0, i0);
+       else if (r0 < 8 && r0 == r1 && !(-i0 & ~0xff))
+           T1_ADDI8(r0, -i0);
+       else if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_SUBSI(r0, r1, i);
+       else if ((i = encode_thumb_immediate(-i0)) != -1)
+           T2_ADDSI(r0, r1, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           T2_SUBS(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           SUBSI(r0, r1, i);
+       else if ((i = encode_arm_immediate(-i0)) != -1)
+           ADDSI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           SUBS(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           SUBS(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_subxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    /* keep setting carry because don't know last SBC */
+    if (jit_thumb_p()) {
+       /* thumb auto set carry if not inside IT block */
+       if ((r0|r1|r2) < 8 && r0 == r1)
+           T1_SBC(r0, r2);
+       else
+           T2_SBCS(r0, r1, r2);
+    }
+    else
+       SBCS(r0, r1, r2);
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    int                        no_set_flags;
+    if (jit_thumb_p()) {
+       no_set_flags = jit_no_set_flags();
+       jit_no_set_flags() = 1;
+       if ((i = encode_arm_immediate(i0)) != -1)
+           T2_SBCSI(r0, r1, i);
+       else if ((i = encode_arm_immediate(-i0)) != -1)
+           T2_ADCSI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           T2_SBCS(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           SBCS(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+       jit_no_set_flags() = no_set_flags;
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           SBCSI(r0, r1, i);
+       else if ((i = encode_arm_immediate(-i0)) != -1)
+           ADCSI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           SBCS(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           SBCS(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    subi(r0, r1, i0);
+    negr(r0, r0);
+}
+
+static void
+_mulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && r0 == r2 && (r0|r1) < 8)
+           T1_MUL(r0, r1);
+       else if (!jit_no_set_flags() && r0 == r1 && (r0|r2) < 8)
+           T1_MUL(r0, r2);
+       else
+           T2_MUL(r0, r1, r2);
+    }
+    else {
+       if (r0 == r1 && !jit_armv6_p()) {
+           if (r0 != r2)
+               MUL(r0, r2, r1);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               MOV(rn(reg), r1);
+               MUL(r0, rn(reg), r2);
+               jit_unget_reg(reg);
+           }
+       }
+       else
+           MUL(r0, r1, r2);
+    }
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    mulr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_iqmulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (r2 == r3) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r2);
+           if (sign)
+               T2_SMULL(r0, r1, rn(reg), r2);
+           else
+               T2_UMULL(r0, r1, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+       else if (r0 != r2 && r1 != r2) {
+           if (sign)
+               T2_SMULL(r0, r1, r2, r3);
+           else
+               T2_UMULL(r0, r1, r2, r3);
+       }
+       else {
+           if (sign)
+               T2_SMULL(r0, r1, r3, r2);
+           else
+               T2_UMULL(r0, r1, r3, r2);
+       }
+    }
+    else {
+       if (r2 == r3) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r2);
+           if (sign)
+               SMULL(r0, r1, rn(reg), r2);
+           else
+               UMULL(r0, r1, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+       else if (r0 != r2 && r1 != r2) {
+           if (sign)
+               SMULL(r0, r1, r2, r3);
+           else
+               UMULL(r0, r1, r2, r3);
+       }
+       else {
+           if (sign)
+               SMULL(r0, r1, r3, r2);
+           else
+               UMULL(r0, r1, r3, r2);
+       }
+    }
+}
+
+static void
+_iqmuli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    iqmulr(r0, r1, r2, rn(reg), sign);
+    jit_unget_reg(reg);
+}
+
+static void
+_divrem(jit_state_t *_jit, int div, int sign,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         d;
+    jit_word_t         w;
+    jit_get_reg_args();
+    movr(_R0_REGNO, r1);
+    movr(_R1_REGNO, r2);
+    if (sign)                  w = (jit_word_t)__aeabi_idivmod;
+    else                       w = (jit_word_t)__aeabi_uidivmod;
+    if (!jit_exchange_p()) {
+       if (jit_thumb_p())      d = ((w - _jit->pc.w) >> 1) - 2;
+       else                    d = ((w - _jit->pc.w) >> 2) - 2;
+       if (_s24P(d)) {
+           if (jit_thumb_p())  T2_BLI(encode_thumb_jump(d));
+           else                BLI(d & 0x00ffffff);
+       }
+       else                    goto fallback;
+    }
+    else {
+    fallback:
+       movi(_R2_REGNO, w);
+       if (jit_thumb_p())      T1_BLX(_R2_REGNO);
+       else                    BLX(_R2_REGNO);
+    }
+    if (div)                   movr(r0, _R0_REGNO);
+    else                       movr(r0, _R1_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_divr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_armv7r_p() && jit_thumb_p())
+       T2_SDIV(r0, r1, r2);
+    else
+       divrem(1, 1, r0, r1, r2);
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_divr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_armv7r_p() && jit_thumb_p())
+       T2_UDIV(r0, r1, r2);
+    else
+       divrem(1, 0, r0, r1, r2);
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_iqdivr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    jit_word_t         d;
+    jit_word_t         w;
+    jit_get_reg_args();
+    movr(_R0_REGNO, r2);
+    movr(_R1_REGNO, r3);
+    if (sign)                  w = (jit_word_t)__aeabi_idivmod;
+    else                       w = (jit_word_t)__aeabi_uidivmod;
+    if (!jit_exchange_p()) {
+       if (jit_thumb_p())      d = ((w - _jit->pc.w) >> 1) - 2;
+       else                    d = ((w - _jit->pc.w) >> 2) - 2;
+       if (_s24P(d)) {
+           if (jit_thumb_p())  T2_BLI(encode_thumb_jump(d));
+           else                BLI(d & 0x00ffffff);
+       }
+       else                    goto fallback;
+    }
+    else {
+    fallback:
+       movi(_R2_REGNO, w);
+       if (jit_thumb_p())      T1_BLX(_R2_REGNO);
+       else                    BLX(_R2_REGNO);
+    }
+    movr(r0, _R0_REGNO);
+    movr(r1, _R1_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_iqdivi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    iqdivr(r0, r1, r2, rn(reg), sign);
+    jit_unget_reg(reg);
+}
+
+static void
+_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    divrem(0, 1, r0, r1, r2);
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    divrem(0, 0, r0, r1, r2);
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr_u(r0, r1,rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_andr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1|r2) < 8 && (r0 == r1 || r0 == r2))
+           T1_AND(r0, r0 == r1 ? r2 : r1);
+       else
+           T2_AND(r0, r1, r2);
+    }
+    else
+       AND(r0, r1, r2);
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_ANDI(r0, r1, i);
+       else if ((i = encode_thumb_immediate(~i0)) != -1)
+           T2_BICI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           T2_AND(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           T2_AND(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           ANDI(r0, r1, i);
+       else if ((i = encode_arm_immediate(~i0)) != -1)
+           BICI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           AND(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           AND(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_orr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1|r2) < 8 && (r0 == r1 || r0 == r2))
+           T1_ORR(r0, r0 == r1 ? r2 : r1);
+       else
+           T2_ORR(r0, r1, r2);
+    }
+    else
+       ORR(r0, r1, r2);
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_ORRI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           T2_ORR(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           T2_ORR(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           ORRI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           ORR(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           ORR(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_xorr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1|r2) < 8 && (r0 == r1 || r0 == r2))
+           T1_EOR(r0, r0 == r1 ? r2 : r1);
+       else
+           T2_EOR(r0, r1, r2);
+    }
+    else
+       EOR(r0, r1, r2);
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_EORI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           T2_EOR(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           T2_EOR(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           EORI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           EOR(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           EOR(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_lshr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1|r2) < 8 && r0 == r1)
+           T1_LSL(r0, r2);
+       else
+           T2_LSL(r0, r1, r2);
+    }
+    else
+       LSL(r0, r1, r2);
+}
+
+static void
+_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    assert(i0 >= 0 && i0 <= 31);
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1) < 8)
+           T1_LSLI(r0, r1, i0);
+       else
+           T2_LSLI(r0, r1, i0);
+    }
+    else
+       LSLI(r0, r1, i0);
+}
+
+static void
+_rshr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1|r2) < 8 && r0 == r1)
+           T1_ASR(r0, r2);
+       else
+           T2_ASR(r0, r1, r2);
+    }
+    else
+       ASR(r0, r1, r2);
+}
+
+static void
+_rshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    assert(i0 >= 0 && i0 <= 31);
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1) < 8)
+           T1_ASRI(r0, r1, i0);
+       else
+           T2_ASRI(r0, r1, i0);
+    }
+    else
+       ASRI(r0, r1, i0);
+}
+
+static void
+_rshr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1|r2) < 8 && r0 == r1)
+           T1_LSR(r0, r2);
+       else
+           T2_LSR(r0, r1, r2);
+    }
+    else
+       LSR(r0, r1, r2);
+}
+
+static void
+_rshi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    assert(i0 >= 0 && i0 <= 31);
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (jit_thumb_p()) {
+       if (!jit_no_set_flags() && (r0|r1) < 8)
+           T1_LSRI(r0, r1, i0);
+       else
+           T2_LSRI(r0, r1, i0);
+    }
+    else
+       LSRI(r0, r1, i0);
+}
+
+static void
+_ccr(jit_state_t *_jit, int ct, int cf,
+     jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       assert((ct ^ cf) >> 28 == 1);
+       if ((r1|r2) < 8)
+           T1_CMP(r1, r2);
+       else if ((r1&r2) & 8)
+           T1_CMPX(r1, r2);
+       else
+           T2_CMP(r1, r2);
+       ITE(ct);
+       if (r0 < 8) {
+           T1_MOVI(r0, 1);
+           T1_MOVI(r0, 0);
+       }
+       else {
+           T2_MOVI(r0, 1);
+           T2_MOVI(r0, 0);
+       }
+    }
+    else {
+       CMP(r1, r2);
+       CC_MOVI(ct, r0, 1);
+       CC_MOVI(cf, r0, 0);
+    }
+}
+
+static void
+_cci(jit_state_t *_jit, int ct, int cf,
+     jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (r1 < 7 && !(i0 & 0xffffff00))
+           T1_CMPI(r1, i0);
+       else if ((i = encode_thumb_immediate(i0)) != -1)
+           T2_CMPI(r1, i);
+       else if ((i = encode_thumb_immediate(-i0)) != -1)
+           T2_CMNI(r1, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           ccr(ct, cf, r0, r1, rn(reg));
+           jit_unget_reg(reg);
+           return;
+       }
+       ITE(ct);
+       if (r0 < 8) {
+           T1_MOVI(r0, 1);
+           T1_MOVI(r0, 0);
+       }
+       else {
+           T2_MOVI(r0, 1);
+           T2_MOVI(r0, 0);
+       }
+    }
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           CMPI(r1, i);
+       else if ((i = encode_arm_immediate(-i0)) != -1)
+           CMNI(r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           CMP(r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           CMP(r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+       CC_MOVI(ct, r0, 1);
+       CC_MOVI(cf, r0, 0);
+    }
+}
+
+static void
+_ner(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p())
+       ccr(ARM_CC_NE, ARM_CC_EQ, r0, r1, r2);
+    else {
+       SUBS(r0, r1, r2);
+       CC_MOVI(ARM_CC_NE, r0, 1);
+    }
+}
+
+static void
+_nei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p())
+       cci(ARM_CC_NE, ARM_CC_EQ, r0, r1, i0);
+    else {
+       if ((i = encode_arm_immediate(i0)) != -1)
+           SUBSI(r0, r1, i);
+       else if ((i = encode_arm_immediate(-i0)) != -1)
+           ADDSI(r0, r1, i);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           SUBS(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           SUBS(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+       CC_MOVI(ARM_CC_NE, r0, 1);
+    }
+}
+
+static void
+_jmpr(jit_state_t *_jit, jit_int32_t r0)
+{
+    if (jit_thumb_p())
+       T1_MOV(_R15_REGNO, r0);
+    else
+       MOV(_R15_REGNO, r0);
+}
+
+static void
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    jit_int32_t                reg;
+    w = _jit->pc.w;
+    /* if thumb and in thumb mode */
+    if (jit_thumb_p() && _jitc->thumb) {
+       d = ((i0 - w) >> 1) - 2;
+       if (d >= -1024 && d <= 1023)
+           T1_B(d & 0x7ff);
+       else if (_s24P(d))
+           T2_B(encode_thumb_jump(d));
+       else {
+           reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+           movi(rn(reg), i0);
+           jmpr(rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       d = ((i0 - w) >> 2) - 2;
+       if (_s24P(d))
+           B(d & 0x00ffffff);
+       else {
+           reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+           movi(rn(reg), i0);
+           jmpr(rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static jit_word_t
+_jmpi_p(jit_state_t *_jit, jit_word_t i0, jit_bool_t i1)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    jit_int32_t                reg;
+    if (i1) {
+       /* Assume jump is not longer than 23 bits if inside jit */
+       w = _jit->pc.w;
+       /* if thumb and in thumb mode */
+       if (jit_thumb_p() && _jitc->thumb) {
+           d = ((i0 - w) >> 1) - 2;
+           assert(_s24P(d));
+           T2_B(encode_thumb_jump(d));
+       }
+       else {
+           d = ((i0 - w) >> 2) - 2;
+           assert(_s24P(d));
+           B(d & 0x00ffffff);
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       w = movi_p(rn(reg), i0);
+       jmpr(rn(reg));
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bccr(jit_state_t *_jit, int cc, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_CMP(r0, r1);
+       else if ((r0&r1) & 8)
+           T1_CMPX(r0, r1);
+       else
+           T2_CMP(r0, r1);
+       /* use only thumb2 conditional as does not know if will be patched */
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       CMP(r0, r1);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bcci(jit_state_t *_jit, int cc, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    int                        i;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (r0 < 7 && !(i1 & 0xffffff00))
+           T1_CMPI(r0, i1);
+       else if ((i = encode_thumb_immediate(i1)) != -1)
+           T2_CMPI(r0, i);
+       else if ((i = encode_thumb_immediate(-i1)) != -1)
+           T2_CMNI(r0, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i1);
+           T2_CMP(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       /* use only thumb2 conditional as does not know if will be patched */
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       if ((i = encode_arm_immediate(i1)) != -1)
+           CMPI(r0, i);
+       else if ((i = encode_arm_immediate(-i1)) != -1)
+           CMNI(r0, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i1);
+           CMP(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    return (w);
+}
+
+static jit_word_t
+_baddr(jit_state_t *_jit, int cc, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_ADD(r0, r0, r1);
+       else
+           T2_ADDS(r0, r0, r1);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       ADDS(r0, r0, r1);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    return (w);
+}
+
+static jit_word_t
+_baddi(jit_state_t *_jit, int cc, jit_word_t i0, jit_int32_t r0, int i1)
+{
+    int                        i;
+    jit_word_t         w;
+    jit_word_t         d;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (r0 < 8 && !(i1 & ~7))
+           T1_ADDI3(r0, r0, i1);
+       else if (r0 < 8 && !(-i1 & ~7))
+           T1_SUBI3(r0, r0, -i1);
+       else if (r0 < 8 && !(i1 & ~0xff))
+           T1_ADDI8(r0, i1);
+       else if (r0 < 8 && !(-i1 & ~0xff))
+           T1_SUBI8(r0, -i1);
+       else if ((i = encode_thumb_immediate(i1)) != -1)
+           T2_ADDSI(r0, r0, i);
+       else if ((i = encode_thumb_immediate(-i1)) != -1)
+           T2_SUBSI(r0, r0, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i1);
+           T2_ADDS(r0, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       if ((i = encode_arm_immediate(i1)) != -1)
+           ADDSI(r0, r0, i);
+       else if ((i = encode_arm_immediate(-i1)) != -1)
+           SUBSI(r0, r0, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i1);
+           ADDS(r0, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bsubr(jit_state_t *_jit, int cc, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_SUB(r0, r0, r1);
+       else
+           T2_SUBS(r0, r0, r1);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       SUBS(r0, r0, r1);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bsubi(jit_state_t *_jit, int cc, jit_word_t i0, jit_int32_t r0, int i1)
+{
+    int                        i;
+    jit_word_t         w;
+    jit_word_t         d;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (r0 < 8 && !(i1 & ~7))
+           T1_SUBI3(r0, r0, i1);
+       else if (r0 < 8 && !(-i1 & ~7))
+           T1_ADDI3(r0, r0, -i1);
+       else if (r0 < 8 && !(i1 & ~0xff))
+           T1_SUBI8(r0, i1);
+       else if (r0 < 8 && !(-i1 & ~0xff))
+           T1_ADDI8(r0, -i1);
+       else if ((i = encode_thumb_immediate(i1)) != -1)
+           T2_SUBSI(r0, r0, i);
+       else if ((i = encode_thumb_immediate(-i1)) != -1)
+           T2_SUBSI(r0, r0, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i1);
+           T2_SUBS(r0, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       if ((i = encode_arm_immediate(i1)) != -1)
+           SUBSI(r0, r0, i);
+       else if ((i = encode_arm_immediate(-i1)) != -1)
+           ADDSI(r0, r0, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i1);
+           SUBS(r0, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bmxr(jit_state_t *_jit, int cc, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_TST(r0, r1);
+       else
+           T2_TST(r0, r1);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       if (jit_armv5_p())
+           TST(r0, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           ANDS(rn(reg), r0, r1);
+           jit_unget_reg(reg);
+       }
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bmxi(jit_state_t *_jit, int cc, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    int                        i;
+    jit_word_t         w;
+    jit_word_t         d;
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((i = encode_thumb_immediate(i1)) != -1)
+           T2_TSTI(r0, i);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i1);
+           T2_TST(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       if (jit_armv5_p()) {
+           if ((i = encode_arm_immediate(i1)) != -1)
+               TSTI(r0, i);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               movi(rn(reg), i1);
+               TST(r0, rn(reg));
+               jit_unget_reg(reg);
+           }
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           if ((i = encode_arm_immediate(i1)) != -1)
+               ANDSI(rn(reg), r0, i);
+           else if ((i = encode_arm_immediate(~i1)) != -1)
+               BICSI(rn(reg), r0, i);
+           else {
+               movi(rn(reg), i1);
+               ANDS(rn(reg), r0, rn(reg));
+           }
+           jit_unget_reg(reg);
+       }
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    return (w);
+}
+
+static void
+_ldr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p())
+       T2_LDRSBI(r0, r1, 0);
+    else
+       LDRSBI(r0, r1, 0);
+}
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_thumb_p())
+       T2_LDRSBI(r0, rn(reg), 0);
+    else
+       LDRSBI(r0, rn(reg), 0);
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1|r2) < 8)
+           T1_LDRSB(r0, r1, r2);
+       else
+           T2_LDRSB(r0, r1, r2);
+    }
+    else
+       LDRSB(r0, r1, r2);
+}
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
+           T2_LDRSBI(r0, r1, i0);
+       else if (i0 < 0 && i0 >= -255)
+           T2_LDRSBIN(r0, r1, -i0);
+       else if (i0 >= 0 && i0 <= 4095)
+           T2_LDRSBWI(r0, r1, i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           if ((r0|r1) < 8)
+               T1_LDRSB(r0, r1, r0);
+           else
+               T2_LDRSB(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           if ((r0|r1|rn(reg)) < 8)
+               T1_LDRSB(r0, r1, rn(reg));
+           else
+               T2_LDRSB(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if (i0 >= 0 && i0 <= 255)
+           LDRSBI(r0, r1, i0);
+       else if (i0 < 0 && i0 >= -255)
+           LDRSBIN(r0, r1, -i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           LDRSB(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           LDRSB(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_ldr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p())
+       T2_LDRBI(r0, r1, 0);
+    else
+       LDRBI(r0, r1, 0);
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_thumb_p())
+       T2_LDRBI(r0, rn(reg), 0);
+    else
+       LDRBI(r0, rn(reg), 0);
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1|r2) < 8)
+           T1_LDRB(r0, r1, r2);
+       else
+           T2_LDRB(r0, r1, r2);
+    }
+    else
+       LDRB(r0, r1, r2);
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8 && i0 >= 0 && i0 < 0x20)
+           T1_LDRBI(r0, r1, i0);
+       else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
+           T2_LDRBI(r0, r1, i0);
+       else if (i0 < 0 && i0 >= -255)
+           T2_LDRBIN(r0, r1, -i0);
+       else if (i0 >= 0 && i0 <= 4095)
+           T2_LDRBWI(r0, r1, i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           if ((r0|r1) < 8)
+               T1_LDRB(r0, r1, r0);
+           else
+               T2_LDRB(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           if ((r0|r1|rn(reg)) < 8)
+               T1_LDRB(r0, r1, rn(reg));
+           else
+               T2_LDRB(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if (i0 >= 0 && i0 <= 4095)
+           LDRBI(r0, r1, i0);
+       else if (i0 < 0 && i0 >= -4095)
+           LDRBIN(r0, r1, -i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           LDRB(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           LDRB(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_ldr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p())
+       T2_LDRSHI(r0, r1, 0);
+    else
+       LDRSHI(r0, r1, 0);
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_thumb_p())
+       T2_LDRSHI(r0, rn(reg), 0);
+    else
+       LDRSHI(r0, rn(reg), 0);
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1|r2) < 8)
+           T1_LDRSH(r0, r1, r2);
+       else
+           T2_LDRSH(r0, r1, r2);
+    }
+    else
+       LDRSH(r0, r1, r2);
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
+           T2_LDRSHI(r0, r1, i0);
+       else if (i0 < 0 && i0 >= -255)
+           T2_LDRSHIN(r0, r1, -i0);
+       else if (i0 >= 0 && i0 <= 4095)
+           T2_LDRSHWI(r0, r1, i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           if ((r0|r1) < 8)
+               T1_LDRSH(r0, r1, r0);
+           else
+               T2_LDRSH(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           if ((r0|r1|rn(reg)) < 8)
+               T1_LDRSH(r0, r1, rn(reg));
+           else
+               T2_LDRSH(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if (i0 >= 0 && i0 <= 255)
+           LDRSHI(r0, r1, i0);
+       else if (i0 < 0 && i0 >= -255)
+           LDRSHIN(r0, r1, -i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           LDRSH(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           LDRSH(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_ldr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p())
+       T2_LDRHI(r0, r1, 0);
+    else
+       LDRHI(r0, r1, 0);
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_thumb_p())
+       T2_LDRHI(r0, rn(reg), 0);
+    else
+       LDRHI(r0, rn(reg), 0);
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1|r2) < 8)
+           T1_LDRH(r0, r1, r2);
+       else
+           T2_LDRH(r0, r1, r2);
+    }
+    else
+       LDRH(r0, r1, r2);
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8 && i0 >= 0 && !(i0 & 1) && (i0 >> 1) < 0x20)
+           T1_LDRHI(r0, r1, i0 >> 1);
+       else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
+           T2_LDRHI(r0, r1, i0);
+       else if (i0 < 0 && i0 >= -255)
+           T2_LDRHIN(r0, r1, -i0);
+       else if (i0 >= 0 && i0 <= 4095)
+           T2_LDRHWI(r0, r1, i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           if ((r0|r1) < 8)
+               T1_LDRH(r0, r1, r0);
+           else
+               T2_LDRH(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           if ((r0|r1|rn(reg)) < 8)
+               T1_LDRH(r0, r1, rn(reg));
+           else
+               T2_LDRH(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if (i0 >= 0 && i0 <= 255)
+           LDRHI(r0, r1, i0);
+       else if (i0 < 0 && i0 >= -255)
+           LDRHIN(r0, r1, -i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           LDRH(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           LDRH(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_ldr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p())
+       T2_LDRI(r0, r1, 0);
+    else
+       LDRI(r0, r1, 0);
+}
+
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_thumb_p())
+       T2_LDRI(r0, rn(reg), 0);
+    else
+       LDRI(r0, rn(reg), 0);
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1|r2) < 8)
+           T1_LDR(r0, r1, r2);
+       else
+           T2_LDR(r0, r1, r2);
+    }
+    else
+       LDR(r0, r1, r2);
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8 && i0 >= 0 && !(i0 & 3) && (i0 >> 2) < 0x20)
+           T1_LDRI(r0, r1, i0 >> 2);
+       else if (r1 == _R13_REGNO && r0 < 8 &&
+                i0 >= 0 && !(i0 & 3) && (i0 >> 2) <= 255)
+           T1_LDRISP(r0, i0 >> 2);
+       else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
+           T2_LDRI(r0, r1, i0);
+       else if (i0 < 0 && i0 > -255)
+           T2_LDRIN(r0, r1, -i0);
+       else if (i0 >= 0 && i0 <= 4095)
+           T2_LDRWI(r0, r1, i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           if ((r0|r1) < 8)
+               T1_LDR(r0, r1, r0);
+           else
+               T2_LDR(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           if ((r0|r1|rn(reg)) < 8)
+               T1_LDR(r0, r1, rn(reg));
+           else
+               T2_LDR(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if (i0 >= 0 && i0 <= 4095)
+           LDRI(r0, r1, i0);
+       else if (i0 < 0 && i0 >= -4095)
+           LDRIN(r0, r1, -i0);
+       else if (r0 != r1) {
+           movi(r0, i0);
+           LDR(r0, r1, r0);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           LDR(r0, r1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_str_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p())
+       T2_STRBI(r1, r0, 0);
+    else
+       STRBI(r1, r0, 0);
+}
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_thumb_p())
+       T2_STRBI(r0, rn(reg), 0);
+    else
+       STRBI(r0, rn(reg), 0);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1|r2) < 8)
+           T1_STRB(r2, r1, r0);
+       else
+           T2_STRB(r2, r1, r0);
+    }
+    else
+       STRB(r2, r1, r0);
+}
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8 && i0 >= 0 && i0 < 0x20)
+           T1_STRBI(r1, r0, i0);
+       else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
+           T2_STRBI(r1, r0, i0);
+       else if (i0 < 0 && i0 >= -255)
+           T2_STRBIN(r1, r0, -i0);
+       else if (i0 >= 0 && i0 <= 4095)
+           T2_STRBWI(r1, r0, i0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           if ((r0|r1|rn(reg)) < 8)
+               T1_STRB(r1, r0, rn(reg));
+           else
+               T2_STRB(r1, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if (i0 >= 0 && i0 <= 4095)
+           STRBI(r1, r0, i0);
+       else if (i0 < 0 && i0 >= -4095)
+           STRBIN(r1, r0, -i0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           STRB(r1, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_str_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p())
+       T2_STRHI(r1, r0, 0);
+    else
+       STRHI(r1, r0, 0);
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_thumb_p())
+       T2_STRHI(r0, rn(reg), 0);
+    else
+       STRHI(r0, rn(reg), 0);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1|r2) < 8)
+           T1_STRH(r2, r1, r0);
+       else
+           T2_STRH(r2, r1, r0);
+    }
+    else
+       STRH(r2, r1, r0);
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8 && i0 >= 0 && !(i0 & 1) && (i0 >> 1) < 0x20)
+           T1_STRHI(r1, r0, i0 >> 1);
+       else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
+           T2_STRHI(r1, r0, i0);
+       else if (i0 < 0 && i0 >= -255)
+           T2_STRHIN(r1, r0, -i0);
+       else if (i0 >= 0 && i0 <= 4095)
+           T2_STRHWI(r1, r0, i0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           if ((r0|r1|rn(reg)) < 8)
+               T1_STRH(r1, r0, rn(reg));
+           else
+               T2_STRH(r1, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if (i0 >= 0 && i0 <= 255)
+           STRHI(r1, r0, i0);
+       else if (i0 < 0 && i0 >= -255)
+           STRHIN(r1, r0, -i0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           STRH(r1, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+static void
+_str_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p())
+       T2_STRI(r1, r0, 0);
+    else
+       STRI(r1, r0, 0);
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_thumb_p())
+       T2_STRI(r0, rn(reg), 0);
+    else
+       STRI(r0, rn(reg), 0);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1|r2) < 8)
+           T1_STR(r2, r1, r0);
+       else
+           T2_STR(r2, r1, r0);
+    }
+    else
+       STR(r2, r1, r0);
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8 && i0 >= 0 && !(i0 & 3) && (i0 >> 2) < 0x20)
+           T1_STRI(r1, r0, i0 >> 2);
+       else if (r0 == _R13_REGNO && r1 < 8 &&
+                i0 >= 0 && !(i0 & 3) && (i0 >> 2) <= 255)
+           T1_STRISP(r1, i0 >> 2);
+       else if (jit_ldrt_strt_p() && i0 >= 0 && i0 <= 255)
+           T2_STRI(r1, r0, i0);
+       else if (i0 < 0 && i0 >= -255)
+           T2_STRIN(r1, r0, -i0);
+       else if (i0 >= 0 && i0 <= 4095)
+           T2_STRWI(r1, r0, i0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           if ((r0|r1|rn(reg)) < 8)
+               T1_STR(r1, r0, rn(reg));
+           else
+               T2_STR(r1, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if (i0 >= 0 && i0 <= 4095)
+           STRI(r1, r0, i0);
+       else if (i0 < 0 && i0 >= -4095)
+           STRIN(r1, r0, -i0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           STR(r1, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+static void
+_htonr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_REV(r0, r1);
+       else
+           T2_REV(r0, r1);
+       rshi_u(r0, r0, 16);
+    }
+    else {
+       if (jit_armv6_p()) {
+           REV(r0, r1);
+           rshi_u(r0, r0, 16);
+       }
+       else {
+           t0 = jit_get_reg(jit_class_gpr);
+           rshi(rn(t0), r1, 8);
+           andi(r0, r1, 0xff);
+           andi(rn(t0), rn(t0), 0xff);
+           lshi(r0, r0, 8);
+           orr(r0, r0, rn(t0));
+           jit_unget_reg(t0);
+       }
+    }
+}
+
+/* inline glibc htonl (without register clobber) */
+static void
+_htonr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_REV(r0, r1);
+       else
+           T2_REV(r0, r1);
+    }
+    else {
+       if (jit_armv6_p())
+           REV(r0, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           EOR_SI(rn(reg), r1, r1, ARM_ROR, 16);
+           LSRI(rn(reg), rn(reg), 8);
+           BICI(rn(reg), rn(reg), encode_arm_immediate(0xff00));
+           EOR_SI(r0, rn(reg), r1, ARM_ROR, 8);
+           jit_unget_reg(reg);
+       }
+    }
+}
+#endif
+
+static void
+_extr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_SXTB(r0, r1);
+       else
+           T2_SXTB(r0, r1);
+    }
+    else {
+       if (jit_armv6_p())
+           SXTB(r0, r1);
+       else {
+           LSLI(r0, r1, 24);
+           ASRI(r0, r0, 24);
+       }
+    }
+}
+
+static void
+_extr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_UXTB(r0, r1);
+       else
+           T2_UXTB(r0, r1);
+    }
+    else {
+       if (jit_armv6_p())
+           UXTB(r0, r1);
+       else
+           ANDI(r0, r1, 0xff);
+    }
+}
+
+static void
+_extr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_SXTH(r0, r1);
+       else
+           T2_SXTH(r0, r1);
+    }
+    else {
+       if (jit_armv6_p())
+           SXTH(r0, r1);
+       else {
+           LSLI(r0, r1, 16);
+           ASRI(r0, r0, 16);
+       }
+    }
+}
+
+static void
+_extr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_thumb_p()) {
+       if ((r0|r1) < 8)
+           T1_UXTH(r0, r1);
+       else
+           T2_UXTH(r0, r1);
+    }
+    else {
+       if (jit_armv6_p())
+           UXTH(r0, r1);
+       else {
+           LSLI(r0, r1, 16);
+           LSRI(r0, r0, 16);
+       }
+    }
+}
+
+static void
+_callr(jit_state_t *_jit, jit_int32_t r0)
+{
+    if (jit_thumb_p())
+       T1_BLX(r0);
+    else
+       BLX(r0);
+}
+
+static void
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         d;
+    jit_int32_t                reg;
+    d = ((i0 - _jit->pc.w) >> 2) - 2;
+    if (!jit_exchange_p() && !jit_thumb_p() && _s24P(d))
+       BLI(d & 0x00ffffff);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       if (jit_thumb_p())
+           T1_BLX(rn(reg));
+       else
+           BLX(rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    w = _jit->pc.w;
+    movi_p(rn(reg), i0);
+    if (jit_thumb_p())
+       T1_BLX(rn(reg));
+    else
+       BLX(rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                reg;
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame) {
+           if (jit_thumb_p() && !_jitc->thumb)
+               _jitc->thumb = _jit->pc.w;
+           return;
+       }
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar)
+       _jitc->function->self.aoff &= -8;
+    _jitc->function->stack = ((_jitc->function->self.alen -
+                             /* align stack at 8 bytes */
+                             _jitc->function->self.aoff) + 7) & -8;
+
+    if (jit_thumb_p()) {
+       /*  switch to thumb mode (better approach would be to
+        * ORR 1 address being called, but no clear distinction
+        * of what is a pointer to a jit function, or if patching
+        * a pointer to a jit function) */
+       ADDI(_R12_REGNO, _R15_REGNO, 1);
+       BX(_R12_REGNO);
+       if (!_jitc->thumb)
+           _jitc->thumb = _jit->pc.w;
+       if (jit_cpu.abi) {
+           T2_PUSH(0xf);
+           T2_PUSH(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO));
+           VPUSH_F64(_D8_REGNO, 8);
+       }
+       else {
+           T2_PUSH(0xf);
+           T2_PUSH(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO));
+       }
+    }
+    else {
+       if (jit_cpu.abi) {
+           PUSH(0xf);
+           PUSH(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO));
+           VPUSH_F64(_D8_REGNO, 8);
+       }
+       else {
+           PUSH(0xf);
+           PUSH(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO));
+       }
+    }
+    movr(_FP_REGNO, _SP_REGNO);
+    if (_jitc->function->stack)
+       subi(_SP_REGNO, _SP_REGNO, _jitc->function->stack);
+    if (_jitc->function->allocar) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    if (_jitc->function->assume_frame)
+       return;
+
+    movr(_SP_REGNO, _FP_REGNO);
+    if (jit_cpu.abi)
+       VPOP_F64(_D8_REGNO, 8);
+    if (jit_thumb_p())
+       T2_POP(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO));
+    else
+       POP(0x3f0|(1<<_FP_REGNO)|(1<<_LR_REGNO));
+    addi(_SP_REGNO, _SP_REGNO, 16);
+    if (jit_thumb_p())
+       T1_BX(_LR_REGNO);
+    else
+       BX(_LR_REGNO);
+    if (jit_thumb_p() && (_jit->pc.w & 2))
+       T1_NOP();
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Initialize stack pointer to the first stack argument.
+     * The -16 is to account for the 4 argument registers
+     * always saved, and _jitc->function->vagp is to account
+     * for declared arguments. */
+    addi(r0, _FP_REGNO, _jitc->function->self.size -
+        16 + _jitc->function->vagp);
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Load argument. */
+    ldr(r0, r1);
+
+    /* Update stack pointer. */
+    addi(r1, r1, sizeof(jit_word_t));
+}
+
+static void
+_patch_at(jit_state_t *_jit,
+         jit_int32_t kind, jit_word_t instr, jit_word_t label)
+{
+    jit_word_t          d;
+    jit_thumb_t                 thumb;
+    union {
+       jit_int16_t     *s;
+       jit_int32_t     *i;
+       jit_word_t       w;
+    } u;
+    u.w = instr;
+    if (kind == arm_patch_jump) {
+       if (jit_thumb_p() && (jit_uword_t)instr >= _jitc->thumb) {
+           code2thumb(thumb.s[0], thumb.s[1], u.s[0], u.s[1]);
+           if ((thumb.i & THUMB2_B) == THUMB2_B) {
+               d = ((label - instr) >> 1) - 2;
+               assert(_s24P(d));
+               thumb.i = THUMB2_B | encode_thumb_jump(d);
+               thumb2code(thumb.s[0], thumb.s[1], u.s[0], u.s[1]);
+           }
+           else if ((thumb.i & THUMB2_B) == THUMB2_CC_B) {
+               d = ((label - instr) >> 1) - 2;
+               assert(_s20P(d));
+               thumb.i = THUMB2_CC_B | (thumb.i & 0x3c00000) |
+                         encode_thumb_cc_jump(d);
+               thumb2code(thumb.s[0], thumb.s[1], u.s[0], u.s[1]);
+           }
+           else {
+               /* for the sake of simplicity in case choose to
+                * movw+movt+[bx|blx], e.g. if changing to instead
+                * of asserting target is reachable, load constant
+                * and do indirect jump if not reachable */
+               if ((thumb.i & 0xfbf00000) == THUMB2_MOVWI)
+                   goto indirect_jump;
+               assert(!"handled branch opcode");
+           }
+       }
+       else {
+           thumb.i = u.i[0];
+           /* 0x0e000000 because 0x01000000 is (branch&) link modifier */
+           assert((thumb.i & 0x0e000000) == ARM_B);
+           d = ((label - instr) >> 2) - 2;
+           assert(_s24P(d));
+           u.i[0] = (thumb.i & 0xff000000) | (d & 0x00ffffff);
+       }
+    }
+    else if (kind == arm_patch_load) {
+       /* offset may be negative for a forward patch because it
+        * is relative to pc + 8, for example:
+        *          ldr r0, [pc, #-4]
+        *          bx r0               ;; [pc, #-8]
+        *          .data ...           ;; [pc, #-4]
+        *          ...                 ;; [pc]
+        */
+       assert(!jit_thumb_p());
+       thumb.i = u.i[0];
+       assert((thumb.i & 0x0f700000) == ARM_LDRI);
+       d = label - (instr + 8);
+       if (d < 0) {
+           thumb.i &= ~ARM_P;
+           d = -d;
+       }
+       else
+           thumb.i |= ARM_P;
+       assert(!(d & 0xfffff000));
+       u.i[0] = (thumb.i & 0xfffff000) | d;
+    }
+    else if (kind == arm_patch_word) {
+       if (jit_thumb_p()) {
+           code2thumb(thumb.s[0], thumb.s[1], u.s[0], u.s[1]);
+           assert((thumb.i & 0xfbf00000) == THUMB2_MOVWI);
+       indirect_jump:
+           thumb.i = ((thumb.i & 0xfbf00f00) |
+                      ( (label & 0x0000f000) <<  4) |
+                      ( (label & 0x00000800) << 15) |
+                      ( (label & 0x00000700) <<  4) |
+                      (  label & 0x000000ff));
+           thumb2code(thumb.s[0], thumb.s[1], u.s[0], u.s[1]);
+           label >>= 16;
+           code2thumb(thumb.s[0], thumb.s[1], u.s[2], u.s[3]);
+           assert((thumb.i & 0xfbf00000) == THUMB2_MOVTI);
+           thumb.i = ((thumb.i & 0xfbf00f00) |
+                      ( (label & 0x0000f000) <<  4) |
+                      ( (label & 0x00000800) << 15) |
+                      ( (label & 0x00000700) <<  4) |
+                      (  label & 0x000000ff));
+           thumb2code(thumb.s[0], thumb.s[1], u.s[2], u.s[3]);
+       }
+       else
+           u.i[0] = label;
+    }
+    else
+       assert(!"handled patch");
+}
+#endif
diff --git a/deps/lightning/lib/jit_arm-swf.c b/deps/lightning/lib/jit_arm-swf.c
new file mode 100644 (file)
index 0000000..bf86ca1
--- /dev/null
@@ -0,0 +1,2640 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+/* match vfpv3 result */
+#define NAN_TO_INT_IS_ZERO             1
+extern float   sqrtf(float);
+extern double  sqrt(double);
+extern float   __addsf3(float, float);
+extern double  __adddf3(double, double);
+extern float   __aeabi_fsub(float, float);
+extern double  __aeabi_dsub(double, double);
+extern float   __aeabi_fmul(float, float);
+extern double  __aeabi_dmul(double, double);
+extern float   __aeabi_fdiv(float, float);
+extern double  __aeabi_ddiv(double, double);
+extern float   __aeabi_i2f(int);
+extern double  __aeabi_i2d(int);
+extern float   __aeabi_d2f(double);
+extern double  __aeabi_f2d(float);
+extern int     __aeabi_f2iz(float);
+extern int     __aeabi_d2iz(double);
+extern int     __aeabi_fcmplt(float, float);
+extern int     __aeabi_dcmplt(double, double);
+extern int     __aeabi_fcmple(float, float);
+extern int     __aeabi_dcmple(double, double);
+extern int     __aeabi_fcmpeq(float, float);
+extern int     __aeabi_dcmpeq(double, double);
+extern int     __aeabi_fcmpge(float, float);
+extern int     __aeabi_dcmpge(double, double);
+extern int     __aeabi_fcmpgt(float, float);
+extern int     __aeabi_dcmpgt(double, double);
+extern int     __aeabi_fcmpun(float, float);
+extern int     __aeabi_dcmpun(double, double);
+#  define swf_ff(i0,r0,r1)             _swf_ff(_jit,i0,r0,r1)
+static void
+_swf_ff(jit_state_t*,float(*)(float),jit_int32_t,jit_int32_t) maybe_unused;
+#  define swf_dd(i0,r0,r1)             _swf_dd(_jit,i0,r0,r1)
+static void
+_swf_dd(jit_state_t*,double(*)(double),jit_int32_t,jit_int32_t) maybe_unused;
+#  define swf_fff(i0,r0,r1,r2)         _swf_fff(_jit,i0,r0,r1,r2)
+static void _swf_fff(jit_state_t*,float(*)(float,float),
+                    jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_ddd(i0,r0,r1,r2)         _swf_ddd(_jit,i0,r0,r1,r2)
+static void _swf_ddd(jit_state_t*,double(*)(double,double),
+                    jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_fff_(i0,r0,r1,i1)                _swf_fff_(_jit,i0,r0,r1,i1)
+static void _swf_fff_(jit_state_t*,float(*)(float,float),
+                     jit_int32_t,jit_int32_t,jit_float32_t);
+#  define swf_ddd_(i0,r0,r1,i1)                _swf_ddd_(_jit,i0,r0,r1,i1)
+static void _swf_ddd_(jit_state_t*,double(*)(double,double),
+                     jit_int32_t,jit_int32_t,jit_float64_t);
+#  define swf_iff(i0,r0,r1,r2)         _swf_iff(_jit,i0,r0,r1,r2)
+static void _swf_iff(jit_state_t*,int(*)(float,float),
+                    jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_idd(i0,r0,r1,r2)         _swf_idd(_jit,i0,r0,r1,r2)
+static void _swf_idd(jit_state_t*,int(*)(double,double),
+                    jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_iff_(i0,r0,r1,r2)                _swf_iff_(_jit,i0,r0,r1,r2)
+static void _swf_iff_(jit_state_t*,int(*)(float,float),
+                     jit_int32_t,jit_int32_t,jit_float32_t);
+#  define swf_idd_(i0,r0,r1,r2)                _swf_idd_(_jit,i0,r0,r1,r2)
+static void _swf_idd_(jit_state_t*,int(*)(double,double),
+                     jit_int32_t,jit_int32_t,jit_float64_t);
+#  define swf_iunff(i0,r0,r1,r2)       _swf_iunff(_jit,i0,r0,r1,r2)
+static void _swf_iunff(jit_state_t*,int(*)(float,float),
+                      jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_iundd(i0,r0,r1,r2)       _swf_iundd(_jit,i0,r0,r1,r2)
+static void _swf_iundd(jit_state_t*,int(*)(double,double),
+                      jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_iunff_(i0,r0,r1,i1)      _swf_iunff_(_jit,i0,r0,r1,i1)
+static void _swf_iunff_(jit_state_t*,int(*)(float,float),
+                       jit_int32_t,jit_int32_t,jit_float32_t);
+#  define swf_iundd_(i0,r0,r1,i1)      _swf_iundd_(_jit,i0,r0,r1,i1)
+static void _swf_iundd_(jit_state_t*,int(*)(double,double),
+                       jit_int32_t,jit_int32_t,jit_float64_t);
+#  define swf_bff(i0,cc,i1,r0,r1)      _swf_bff(_jit,i0,cc,i1,r0,r1)
+static jit_word_t _swf_bff(jit_state_t*,int(*)(float,float),int,
+                          jit_word_t,jit_int32_t,jit_int32_t);
+#  define swf_bdd(i0,cc,i1,r0,r1)      _swf_bdd(_jit,i0,cc,i1,r0,r1)
+static jit_word_t _swf_bdd(jit_state_t*,int(*)(double,double),int,
+                          jit_word_t,jit_int32_t,jit_int32_t);
+#  define swf_bff_(i0,cc,i1,r0,i2)     _swf_bff_(_jit,i0,cc,i1,r0,i2)
+static jit_word_t _swf_bff_(jit_state_t*,int(*)(float,float),int,
+                           jit_word_t,jit_int32_t,jit_float32_t);
+#  define swf_bdd_(i0,cc,i1,r0,i2)     _swf_bdd_(_jit,i0,cc,i1,r0,i2)
+static jit_word_t _swf_bdd_(jit_state_t*,int(*)(double,double),int,
+                           jit_word_t,jit_int32_t,jit_float64_t);
+#  define swf_bunff(eq,i0,r0,r1)       _swf_bunff(_jit,eq,i0,r0,r1)
+static jit_word_t _swf_bunff(jit_state_t*,int,
+                            jit_word_t,jit_int32_t,jit_int32_t);
+#  define swf_bundd(eq,i0,r0,r1)       _swf_bundd(_jit,eq,i0,r0,r1)
+static jit_word_t _swf_bundd(jit_state_t*,int,
+                            jit_word_t,jit_int32_t,jit_int32_t);
+#  define swf_bunff_(eq,i0,r0,i1)      _swf_bunff_(_jit,eq,i0,r0,i1)
+static jit_word_t _swf_bunff_(jit_state_t*,int,
+                             jit_word_t,jit_int32_t,jit_float32_t);
+#  define swf_bundd_(eq,i0,r0,i1)      _swf_bundd_(_jit,eq,i0,r0,i1)
+static jit_word_t _swf_bundd_(jit_state_t*,int,
+                             jit_word_t,jit_int32_t,jit_float64_t);
+#  define swf_extr_f(r0,r1)            _swf_extr_f(_jit,r0,r1)
+static void _swf_extr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_extr_d(r0,r1)            _swf_extr_d(_jit,r0,r1)
+static void _swf_extr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_extr_d_f(r0,r1)          _swf_extr_d_f(_jit,r0,r1)
+static void _swf_extr_d_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_extr_f_d(r0,r1)          _swf_extr_f_d(_jit,r0,r1)
+static void _swf_extr_f_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_truncr_f_i(r0,r1)                _swf_truncr_f_i(_jit,r0,r1)
+static void _swf_truncr_f_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_truncr_d_i(r0,r1)                _swf_truncr_d_i(_jit,r0,r1)
+static void _swf_truncr_d_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_movr_f(r0,r1)            _swf_movr_f(_jit,r0,r1)
+static void _swf_movr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_movr_d(r0,r1)            _swf_movr_d(_jit,r0,r1)
+static void _swf_movr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_movi_f(r0,i0)            _swf_movi_f(_jit,r0,i0)
+static void _swf_movi_f(jit_state_t*,jit_int32_t,jit_float32_t);
+#  define swf_movi_d(r0,i0)            _swf_movi_d(_jit,r0,i0)
+static void _swf_movi_d(jit_state_t*,jit_int32_t,jit_float64_t);
+#  define swf_absr_f(r0,r1)            _swf_absr_f(_jit,r0,r1)
+static void _swf_absr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_absr_d(r0,r1)            _swf_absr_d(_jit,r0,r1)
+static void _swf_absr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_negr_f(r0,r1)            _swf_negr_f(_jit,r0,r1)
+static void _swf_negr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_negr_d(r0,r1)            _swf_negr_d(_jit,r0,r1)
+static void _swf_negr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_sqrtr_f(r0,r1)           swf_ff(sqrtf,r0,r1)
+#  define swf_sqrtr_d(r0,r1)           swf_dd(sqrt,r0,r1)
+#  define swf_addr_f(r0,r1,r2)         swf_fff(__addsf3,r0,r1,r2)
+#  define swf_addi_f(r0,r1,i0)         swf_fff_(__addsf3,r0,r1,i0)
+#  define swf_addr_d(r0,r1,r2)         swf_ddd(__adddf3,r0,r1,r2)
+#  define swf_addi_d(r0,r1,i0)         swf_ddd_(__adddf3,r0,r1,i0)
+#  define swf_subr_f(r0,r1,r2)         swf_fff(__aeabi_fsub,r0,r1,r2)
+#  define swf_subi_f(r0,r1,i0)         swf_fff_(__aeabi_fsub,r0,r1,i0)
+#  define swf_subr_d(r0,r1,r2)         swf_ddd(__aeabi_dsub,r0,r1,r2)
+#  define swf_subi_d(r0,r1,i0)         swf_ddd_(__aeabi_dsub,r0,r1,i0)
+#  define swf_rsbr_f(r0, r1, r2)       swf_subr_f(r0, r2, r1)
+#  define swf_rsbi_f(r0, r1, i0)       _swf_rsbi_f(_jit, r0, r1, i0)
+static void _swf_rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define swf_rsbr_d(r0, r1, r2)       swf_subr_d(r0, r2, r1)
+#  define swf_rsbi_d(r0, r1, i0)       _swf_rsbi_d(_jit, r0, r1, i0)
+static void _swf_rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define swf_mulr_f(r0,r1,r2)         swf_fff(__aeabi_fmul,r0,r1,r2)
+#  define swf_muli_f(r0,r1,i0)         swf_fff_(__aeabi_fmul,r0,r1,i0)
+#  define swf_mulr_d(r0,r1,r2)         swf_ddd(__aeabi_dmul,r0,r1,r2)
+#  define swf_muli_d(r0,r1,i0)         swf_ddd_(__aeabi_dmul,r0,r1,i0)
+#  define swf_divr_f(r0,r1,r2)         swf_fff(__aeabi_fdiv,r0,r1,r2)
+#  define swf_divi_f(r0,r1,i0)         swf_fff_(__aeabi_fdiv,r0,r1,i0)
+#  define swf_divr_d(r0,r1,r2)         swf_ddd(__aeabi_ddiv,r0,r1,r2)
+#  define swf_divi_d(r0,r1,i0)         swf_ddd_(__aeabi_ddiv,r0,r1,i0)
+#  define swf_ltr_f(r0,r1,r2)          swf_iff(__aeabi_fcmplt,r0,r1,r2)
+#  define swf_lti_f(r0,r1,i0)          swf_iff_(__aeabi_fcmplt,r0,r1,i0)
+#  define swf_ltr_d(r0,r1,r2)          swf_idd(__aeabi_dcmplt,r0,r1,r2)
+#  define swf_lti_d(r0,r1,i0)          swf_idd_(__aeabi_dcmplt,r0,r1,i0)
+#  define swf_ler_f(r0,r1,r2)          swf_iff(__aeabi_fcmple,r0,r1,r2)
+#  define swf_lei_f(r0,r1,i0)          swf_iff_(__aeabi_fcmple,r0,r1,i0)
+#  define swf_ler_d(r0,r1,r2)          swf_idd(__aeabi_dcmple,r0,r1,r2)
+#  define swf_lei_d(r0,r1,i0)          swf_idd_(__aeabi_dcmple,r0,r1,i0)
+#  define swf_eqr_f(r0,r1,r2)          swf_iff(__aeabi_fcmpeq,r0,r1,r2)
+#  define swf_eqi_f(r0,r1,i0)          swf_iff_(__aeabi_fcmpeq,r0,r1,i0)
+#  define swf_eqr_d(r0,r1,r2)          swf_idd(__aeabi_dcmpeq,r0,r1,r2)
+#  define swf_eqi_d(r0,r1,i0)          swf_idd_(__aeabi_dcmpeq,r0,r1,i0)
+#  define swf_ger_f(r0,r1,r2)          swf_iff(__aeabi_fcmpge,r0,r1,r2)
+#  define swf_gei_f(r0,r1,i0)          swf_iff_(__aeabi_fcmpge,r0,r1,i0)
+#  define swf_ger_d(r0,r1,r2)          swf_idd(__aeabi_dcmpge,r0,r1,r2)
+#  define swf_gei_d(r0,r1,i0)          swf_idd_(__aeabi_dcmpge,r0,r1,i0)
+#  define swf_gtr_f(r0,r1,r2)          swf_iff(__aeabi_fcmpgt,r0,r1,r2)
+#  define swf_gti_f(r0,r1,i0)          swf_iff_(__aeabi_fcmpgt,r0,r1,i0)
+#  define swf_gtr_d(r0,r1,r2)          swf_idd(__aeabi_dcmpgt,r0,r1,r2)
+#  define swf_gti_d(r0,r1,i0)          swf_idd_(__aeabi_dcmpgt,r0,r1,i0)
+#  define swf_ner_f(r0,r1,r2)          _swf_ner_f(_jit,r0,r1,r2)
+static void _swf_ner_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_nei_f(r0,r1,i0)          _swf_nei_f(_jit,r0,r1,i0)
+static void _swf_nei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define swf_ner_d(r0,r1,r2)          _swf_ner_d(_jit,r0,r1,r2)
+static void _swf_ner_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_nei_d(r0,r1,i0)          _swf_nei_d(_jit,r0,r1,i0)
+static void _swf_nei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define swf_unltr_f(r0,r1,r2)                swf_iunff(__aeabi_fcmplt,r0,r1,r2)
+#  define swf_unlti_f(r0,r1,i0)                swf_iunff_(__aeabi_fcmplt,r0,r1,i0)
+#  define swf_unltr_d(r0,r1,r2)                swf_iundd(__aeabi_dcmplt,r0,r1,r2)
+#  define swf_unlti_d(r0,r1,i0)                swf_iundd_(__aeabi_dcmplt,r0,r1,i0)
+#  define swf_unler_f(r0,r1,r2)                swf_iunff(__aeabi_fcmple,r0,r1,r2)
+#  define swf_unlei_f(r0,r1,i0)                swf_iunff_(__aeabi_fcmple,r0,r1,i0)
+#  define swf_unler_d(r0,r1,r2)                swf_iundd(__aeabi_dcmple,r0,r1,r2)
+#  define swf_unlei_d(r0,r1,i0)                swf_iundd_(__aeabi_dcmple,r0,r1,i0)
+#  define swf_uneqr_f(r0,r1,r2)                swf_iunff(__aeabi_fcmpeq,r0,r1,r2)
+#  define swf_uneqi_f(r0,r1,i0)                swf_iunff_(__aeabi_fcmpeq,r0,r1,i0)
+#  define swf_uneqr_d(r0,r1,r2)                swf_iundd(__aeabi_dcmpeq,r0,r1,r2)
+#  define swf_uneqi_d(r0,r1,i0)                swf_iundd_(__aeabi_dcmpeq,r0,r1,i0)
+#  define swf_unger_f(r0,r1,r2)                swf_iunff(__aeabi_fcmpge,r0,r1,r2)
+#  define swf_ungei_f(r0,r1,i0)                swf_iunff_(__aeabi_fcmpge,r0,r1,i0)
+#  define swf_unger_d(r0,r1,r2)                swf_iundd(__aeabi_dcmpge,r0,r1,r2)
+#  define swf_ungei_d(r0,r1,i0)                swf_iundd_(__aeabi_dcmpge,r0,r1,i0)
+#  define swf_ungtr_f(r0,r1,r2)                swf_iunff(__aeabi_fcmpgt,r0,r1,r2)
+#  define swf_ungti_f(r0,r1,i0)                swf_iunff_(__aeabi_fcmpgt,r0,r1,i0)
+#  define swf_ungtr_d(r0,r1,r2)                swf_iundd(__aeabi_dcmpgt,r0,r1,r2)
+#  define swf_ungti_d(r0,r1,i0)                swf_iundd_(__aeabi_dcmpgt,r0,r1,i0)
+#  define swf_ltgtr_f(r0,r1,r2)                _swf_ltgtr_f(_jit,r0,r1,r2)
+static void _swf_ltgtr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_ltgti_f(r0,r1,i0)                _swf_ltgti_f(_jit,r0,r1,i0)
+static void _swf_ltgti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define swf_ltgtr_d(r0,r1,r2)                _swf_ltgtr_d(_jit,r0,r1,r2)
+static void _swf_ltgtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_ltgti_d(r0,r1,i0)                _swf_ltgti_d(_jit,r0,r1,i0)
+static void _swf_ltgti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define swf_ordr_f(r0,r1,r2)         _swf_ordr_f(_jit,r0,r1,r2)
+static void _swf_ordr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_ordi_f(r0,r1,i0)         _swf_ordi_f(_jit,r0,r1,i0)
+static void _swf_ordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define swf_ordr_d(r0,r1,r2)         _swf_ordr_d(_jit,r0,r1,r2)
+static void _swf_ordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_ordi_d(r0,r1,i0)         _swf_ordi_d(_jit,r0,r1,i0)
+static void _swf_ordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define swf_unordr_f(r0,r1,r2)       swf_iunff(__aeabi_fcmpun,r0,r1,r2)
+#  define swf_unordi_f(r0,r1,i0)       swf_iunff_(__aeabi_fcmpun,r0,r1,i0)
+#  define swf_unordr_d(r0,r1,r2)       swf_iundd(__aeabi_dcmpun,r0,r1,r2)
+#  define swf_unordi_d(r0,r1,i0)       swf_iundd_(__aeabi_dcmpun,r0,r1,i0)
+#  define swf_bltr_f(i0,r0,r1)         swf_bff(__aeabi_fcmplt,ARM_CC_NE,i0,r0,r1)
+#  define swf_blti_f(i0,r0,i1)         swf_bff_(__aeabi_fcmplt,ARM_CC_NE,i0,r0,i1)
+#  define swf_bltr_d(i0,r0,r1)         swf_bdd(__aeabi_dcmplt,ARM_CC_NE,i0,r0,r1)
+#  define swf_blti_d(i0,r0,i1)         swf_bdd_(__aeabi_dcmplt,ARM_CC_NE,i0,r0,i1)
+#  define swf_bler_f(i0,r0,r1)         swf_bff(__aeabi_fcmple,ARM_CC_NE,i0,r0,r1)
+#  define swf_blei_f(i0,r0,i1)         swf_bff_(__aeabi_fcmple,ARM_CC_NE,i0,r0,i1)
+#  define swf_bler_d(i0,r0,r1)         swf_bdd(__aeabi_dcmple,ARM_CC_NE,i0,r0,r1)
+#  define swf_blei_d(i0,r0,i1)         swf_bdd_(__aeabi_dcmple,ARM_CC_NE,i0,r0,i1)
+#  define swf_beqr_f(i0,r0,r1)         swf_bff(__aeabi_fcmpeq,ARM_CC_NE,i0,r0,r1)
+#  define swf_beqi_f(i0,r0,i1)         swf_bff_(__aeabi_fcmpeq,ARM_CC_NE,i0,r0,i1)
+#  define swf_beqr_d(i0,r0,r1)         swf_bdd(__aeabi_dcmpeq,ARM_CC_NE,i0,r0,r1)
+#  define swf_beqi_d(i0,r0,i1)         swf_bdd_(__aeabi_dcmpeq,ARM_CC_NE,i0,r0,i1)
+#  define swf_bger_f(i0,r0,r1)         swf_bff(__aeabi_fcmpge,ARM_CC_NE,i0,r0,r1)
+#  define swf_bgei_f(i0,r0,i1)         swf_bff_(__aeabi_fcmpge,ARM_CC_NE,i0,r0,i1)
+#  define swf_bger_d(i0,r0,r1)         swf_bdd(__aeabi_dcmpge,ARM_CC_NE,i0,r0,r1)
+#  define swf_bgei_d(i0,r0,i1)         swf_bdd_(__aeabi_dcmpge,ARM_CC_NE,i0,r0,i1)
+#  define swf_bgtr_f(i0,r0,r1)         swf_bff(__aeabi_fcmpgt,ARM_CC_NE,i0,r0,r1)
+#  define swf_bgti_f(i0,r0,i1)         swf_bff_(__aeabi_fcmpgt,ARM_CC_NE,i0,r0,i1)
+#  define swf_bgtr_d(i0,r0,r1)         swf_bdd(__aeabi_dcmpgt,ARM_CC_NE,i0,r0,r1)
+#  define swf_bgti_d(i0,r0,i1)         swf_bdd_(__aeabi_dcmpgt,ARM_CC_NE,i0,r0,i1)
+#  define swf_bner_f(i0,r0,r1)         swf_bff(__aeabi_fcmpeq,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bnei_f(i0,r0,i1)         swf_bff_(__aeabi_fcmpeq,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bner_d(i0,r0,r1)         swf_bdd(__aeabi_dcmpeq,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bnei_d(i0,r0,i1)         swf_bdd_(__aeabi_dcmpeq,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bunltr_f(i0,r0,r1)       swf_bff(__aeabi_fcmpge,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bunlti_f(i0,r0,i1)       swf_bff_(__aeabi_fcmpge,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bunltr_d(i0,r0,r1)       swf_bdd(__aeabi_dcmpge,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bunlti_d(i0,r0,i1)       swf_bdd_(__aeabi_dcmpge,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bunler_f(i0,r0,r1)       swf_bff(__aeabi_fcmpgt,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bunlei_f(i0,r0,i1)       swf_bff_(__aeabi_fcmpgt,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bunler_d(i0,r0,r1)       swf_bdd(__aeabi_dcmpgt,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bunlei_d(i0,r0,i1)       swf_bdd_(__aeabi_dcmpgt,ARM_CC_EQ,i0,r0,i1)
+#  define swf_buneqr_f(i0,r0,r1)       swf_bunff(1,i0,r0,r1)
+#  define swf_buneqi_f(i0,r0,i1)       swf_bunff_(1,i0,r0,i1)
+#  define swf_buneqr_d(i0,r0,r1)       swf_bundd(1,i0,r0,r1)
+#  define swf_buneqi_d(i0,r0,i1)       swf_bundd_(1,i0,r0,i1)
+#  define swf_bunger_f(i0,r0,r1)       swf_bff(__aeabi_fcmplt,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bungei_f(i0,r0,i1)       swf_bff_(__aeabi_fcmplt,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bunger_d(i0,r0,r1)       swf_bdd(__aeabi_dcmplt,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bungei_d(i0,r0,i1)       swf_bdd_(__aeabi_dcmplt,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bungtr_f(i0,r0,r1)       swf_bff(__aeabi_fcmple,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bungti_f(i0,r0,i1)       swf_bff_(__aeabi_fcmple,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bungtr_d(i0,r0,r1)       swf_bdd(__aeabi_dcmple,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bungti_d(i0,r0,i1)       swf_bdd_(__aeabi_dcmple,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bltgtr_f(i0,r0,r1)       swf_bunff(0,i0,r0,r1)
+#  define swf_bltgti_f(i0,r0,i1)       swf_bunff_(0,i0,r0,i1)
+#  define swf_bltgtr_d(i0,r0,r1)       swf_bundd(0,i0,r0,r1)
+#  define swf_bltgti_d(i0,r0,i1)       swf_bundd_(0,i0,r0,i1)
+#  define swf_bordr_f(i0,r0,r1)                swf_bff(__aeabi_fcmpun,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bordi_f(i0,r0,i1)                swf_bff_(__aeabi_fcmpun,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bordr_d(i0,r0,r1)                swf_bdd(__aeabi_dcmpun,ARM_CC_EQ,i0,r0,r1)
+#  define swf_bordi_d(i0,r0,i1)                swf_bdd_(__aeabi_dcmpun,ARM_CC_EQ,i0,r0,i1)
+#  define swf_bunordr_f(i0,r0,r1)      swf_bff(__aeabi_fcmpun,ARM_CC_NE,i0,r0,r1)
+#  define swf_bunordi_f(i0,r0,i1)      swf_bff_(__aeabi_fcmpun,ARM_CC_NE,i0,r0,i1)
+#  define swf_bunordr_d(i0,r0,r1)      swf_bdd(__aeabi_dcmpun,ARM_CC_NE,i0,r0,r1)
+#  define swf_bunordi_d(i0,r0,i1)      swf_bdd_(__aeabi_dcmpun,ARM_CC_NE,i0,r0,i1)
+#  define swf_ldr_f(r0,r1)             _swf_ldr_f(_jit,r0,r1)
+static void _swf_ldr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_ldr_d(r0,r1)             _swf_ldr_d(_jit,r0,r1)
+static void _swf_ldr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_ldi_f(r0,i0)             _swf_ldi_f(_jit,r0,i0)
+static void _swf_ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#  define swf_ldi_d(r0,i0)             _swf_ldi_d(_jit,r0,i0)
+static void _swf_ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#  define swf_ldxr_f(r0,r1,r2)         _swf_ldxr_f(_jit,r0,r1,r2)
+static void _swf_ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_ldxr_d(r0,r1,r2)         _swf_ldxr_d(_jit,r0,r1,r2)
+static void _swf_ldxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_ldxi_f(r0,r1,i0)         _swf_ldxi_f(_jit,r0,r1,i0)
+static void _swf_ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define swf_ldxi_d(r0,r1,i0)         _swf_ldxi_d(_jit,r0,r1,i0)
+static void _swf_ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define swf_str_f(r0,r1)             _swf_str_f(_jit,r0,r1)
+static void _swf_str_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_str_d(r0,r1)             _swf_str_d(_jit,r0,r1)
+static void _swf_str_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define swf_sti_f(r0,i0)             _swf_sti_f(_jit,r0,i0)
+static void _swf_sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#  define swf_sti_d(r0,i0)             _swf_sti_d(_jit,r0,i0)
+static void _swf_sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#  define swf_stxr_f(r0,r1,r2)         _swf_stxr_f(_jit,r0,r1,r2)
+static void _swf_stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_stxr_d(r0,r1,r2)         _swf_stxr_d(_jit,r0,r1,r2)
+static void _swf_stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define swf_stxi_f(r0,r1,i0)         _swf_stxi_f(_jit,r0,r1,i0)
+static void _swf_stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define swf_stxi_d(r0,r1,i0)         _swf_stxi_d(_jit,r0,r1,i0)
+static void _swf_stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define swf_vaarg_d(r0, r1)          _swf_vaarg_d(_jit, r0, r1)
+static void _swf_vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif
+
+#if CODE
+#define swf_off(rn)                    ((rn - 16) << 2)
+
+#define swf_call(function, label, regno)                               \
+    do {                                                               \
+       jit_word_t      d;                                              \
+       if (!jit_exchange_p()) {                                        \
+           if (jit_thumb_p())                                          \
+               d = (((jit_word_t)function - _jit->pc.w) >> 1) - 2;     \
+           else                                                        \
+               d = (((jit_word_t)function - _jit->pc.w) >> 2) - 2;     \
+           if (_s24P(d)) {                                             \
+               if (jit_thumb_p())                                      \
+                   T2_BLI(encode_thumb_jump(d));                       \
+               else                                                    \
+                   BLI(d & 0x00ffffff);                                \
+           }                                                           \
+           else                                                        \
+               goto label;                                             \
+       }                                                               \
+       else {                                                          \
+       label:                                                          \
+           movi(regno, (jit_word_t)function);                          \
+           if (jit_thumb_p())                                          \
+               T1_BLX(regno);                                          \
+           else                                                        \
+               BLX(regno);                                             \
+       }                                                               \
+    } while (0)
+#define swf_call_with_get_reg(function, label)                         \
+    do {                                                               \
+       jit_word_t      d;                                              \
+       jit_int32_t     reg;                                            \
+       if (!jit_exchange_p()) {                                        \
+           if (jit_thumb_p())                                          \
+               d = (((jit_word_t)function - _jit->pc.w) >> 1) - 2;     \
+           else                                                        \
+               d = (((jit_word_t)function - _jit->pc.w) >> 2) - 2;     \
+           if (_s24P(d)) {                                             \
+               if (jit_thumb_p())                                      \
+                   T2_BLI(encode_thumb_jump(d));                       \
+               else                                                    \
+                   BLI(d & 0x00ffffff);                                \
+           }                                                           \
+           else                                                        \
+               goto label;                                             \
+       }                                                               \
+       else {                                                          \
+       label:                                                          \
+           reg = jit_get_reg(jit_class_gpr);                           \
+           movi(rn(reg), (jit_word_t)function);                        \
+           if (jit_thumb_p())                                          \
+               T1_BLX(rn(reg));                                        \
+           else                                                        \
+               BLX(rn(reg));                                           \
+           jit_unget_reg(reg);                                         \
+       }                                                               \
+    } while (0)
+#define swf_ldrin(rt, rn, im)                                          \
+    do {                                                               \
+       if (jit_thumb_p())      T2_LDRIN(rt, rn, im);                   \
+       else                    LDRIN(rt, rn, im);                      \
+    } while (0)
+#define swf_strin(rt, rn, im)                                          \
+    do {                                                               \
+       if (jit_thumb_p())      T2_STRIN(rt, rn, im);                   \
+       else                    STRIN(rt, rn, im);                      \
+    } while (0)
+#define swf_bici(rt, rn, im)                                           \
+    do {                                                               \
+       if (jit_thumb_p())                                              \
+           T2_BICI(rt, rn, encode_thumb_immediate(im));                \
+       else                                                            \
+           BICI(rt, rn, encode_arm_immediate(im));                     \
+    } while (0)
+
+#if !defined(__GNUC__)
+float __addsf3(float u, float v)
+{
+    return (u + v);
+}
+
+double
+__adddf3(double u, double v)
+{
+    return (u + v);
+}
+
+float
+__aeabi_fsub(float u, float v)
+{
+    return (u - v);
+}
+
+double
+__aeabi_dsub(double u, double v)
+{
+    return (u - v);
+}
+
+float
+__aeabi_fmul(float u, float v)
+{
+    return (u * v);
+}
+
+double
+__aeabi_dmul(double u, double v)
+{
+    return (u * v);
+}
+
+float
+__aeabi_fdiv(float u, float v)
+{
+    return (u / v);
+}
+
+double
+__aeabi_ddiv(double u, double v)
+{
+    return (u / v);
+}
+
+float
+__aeabi_i2f(int u)
+{
+    return (u);
+}
+
+double
+__aeabi_i2d(int u)
+{
+    return (u);
+}
+
+float
+__aeabi_d2f(double u)
+{
+    return (u);
+}
+
+double
+__aeabi_f2d(float u)
+{
+    return (u);
+}
+
+extern int
+__aeabi_f2iz(float u)
+{
+    return (u);
+}
+
+int
+__aeabi_d2iz(double u)
+{
+    return (u);
+}
+
+int
+__aeabi_fcmplt(float u, float v)
+{
+    return (u < v);
+}
+
+int
+__aeabi_dcmplt(double u, double v)
+{
+    return (u < v);
+}
+
+int
+__aeabi_fcmple(float u, float v)
+{
+    return (u <= v);
+}
+
+int
+__aeabi_dcmple(double u, double v)
+{
+    return (u <= v);
+}
+
+int
+__aeabi_fcmpeq(float u, float v)
+{
+    return (u == v);
+}
+
+int
+__aeabi_dcmpeq(double u, double v)
+{
+    return (u == v);
+}
+
+int
+__aeabi_fcmpge(float u, float v)
+{
+    return (u >= v);
+}
+
+int
+__aeabi_dcmpge(double u, double v)
+{
+    return (u >= v);
+}
+
+int
+__aeabi_fcmpgt(float u, float v)
+{
+    return (u > v);
+}
+
+int
+__aeabi_dcmpgt(double u, double v)
+{
+    return (u > v);
+}
+
+int
+__aeabi_fcmpun(float u, float v)
+{
+    return ((u != u) || (v != v));
+}
+
+int
+__aeabi_dcmpun(double u, double v)
+{
+    return ((u != u) || (v != v));
+}
+#endif
+
+static void
+_swf_ff(jit_state_t *_jit, float(*i0)(float),
+       jit_int32_t r0, jit_int32_t r1)
+{
+    jit_get_reg_args();
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    swf_call(i0, fallback, _R1_REGNO);
+    if (jit_fpr_p(r0))
+       swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_dd(jit_state_t *_jit, double (*i0)(double),
+       jit_int32_t r0, jit_int32_t r1)
+{
+    jit_get_reg_args();
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    swf_call(i0, fallback, _R2_REGNO);
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           STRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_strin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(r0, _R0_REGNO);
+       movr(r0 + 1, _R1_REGNO);
+    }
+    jit_unget_reg_args();
+}
+
+static void
+_swf_fff(jit_state_t *_jit, float (*i0)(float, float),
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_get_reg_args();
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    if (jit_fpr_p(r2))
+       swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r2) + 8);
+    else
+       movr(_R1_REGNO, r1);
+    swf_call(i0, fallback, _R3_REGNO);
+    if (jit_fpr_p(r0))
+       swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_ddd(jit_state_t *_jit, double (*i0)(double, double),
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_get_reg_args();
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    if (jit_fpr_p(r2)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R2_REGNO, _FP_REGNO, swf_off(r2) + 8);
+       else {
+           swf_ldrin(_R2_REGNO, _FP_REGNO, swf_off(r2) + 8);
+           swf_ldrin(_R3_REGNO, _FP_REGNO, swf_off(r2) + 4);
+       }
+    }
+    else {
+       movr(_R2_REGNO, r2);
+       movr(_R3_REGNO, r2 + 1);
+    }
+    swf_call_with_get_reg(i0, fallback);
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           STRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_strin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(r0, _R0_REGNO);
+       movr(r0 + 1, _R1_REGNO);
+    }
+    jit_unget_reg_args();
+}
+
+static void
+_swf_fff_(jit_state_t *_jit, float (*i0)(float, float),
+         jit_int32_t r0, jit_int32_t r1, jit_float32_t i1)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+    jit_get_reg_args();
+    data.f = i1;
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    movi(_R1_REGNO, data.i);
+    swf_call(i0, fallback, _R3_REGNO);
+    if (jit_fpr_p(r0))
+       swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_rsbi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_float32_t i0)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+    jit_get_reg_args();
+    data.f = i0;
+    movi(_R0_REGNO, data.i);
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R1_REGNO, r1);
+    swf_call(__aeabi_fsub, fallback, _R3_REGNO);
+    if (jit_fpr_p(r0))
+       swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_ddd_(jit_state_t *_jit, double (*i0)(double, double),
+         jit_int32_t r0, jit_int32_t r1, jit_float64_t i1)
+{
+    union {
+       jit_int32_t     i[2];
+       jit_float64_t   d;
+    } data;
+    jit_get_reg_args();
+
+    data.d = i1;
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    movi(_R2_REGNO, data.i[0]);
+    movi(_R3_REGNO, data.i[1]);
+    swf_call_with_get_reg(i0, fallback);
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           STRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_strin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(r0, _R0_REGNO);
+       movr(r0 + 1, _R1_REGNO);
+    }
+    jit_unget_reg_args();
+}
+
+static void
+_swf_rsbi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_float64_t i0)
+{
+    union {
+       jit_int32_t     i[2];
+       jit_float64_t   d;
+    } data;
+    jit_get_reg_args();
+    data.d = i0;
+    movi(_R0_REGNO, data.i[0]);
+    movi(_R1_REGNO, data.i[1]);
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R2_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R2_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R3_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R2_REGNO, r1);
+       movr(_R3_REGNO, r1 + 1);
+    }
+    swf_call_with_get_reg(__aeabi_dsub, fallback);
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           STRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_strin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(r0, _R0_REGNO);
+       movr(r0 + 1, _R1_REGNO);
+    }
+    jit_unget_reg_args();
+}
+
+static void
+_swf_iff(jit_state_t *_jit, int (*i0)(float, float),
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_get_reg_args();
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    if (jit_fpr_p(r2))
+       swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r2) + 8);
+    else
+       movr(_R1_REGNO, r2);
+    swf_call(i0, fallback, _R2_REGNO);
+    movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_idd(jit_state_t *_jit, int (*i0)(double, double),
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_get_reg_args();
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    if (jit_fpr_p(r2)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R2_REGNO, _FP_REGNO, swf_off(r2) + 8);
+       else {
+           swf_ldrin(_R2_REGNO, _FP_REGNO, swf_off(r2) + 8);
+           swf_ldrin(_R3_REGNO, _FP_REGNO, swf_off(r2) + 4);
+       }
+    }
+    else {
+       movr(_R2_REGNO, r2);
+       movr(_R3_REGNO, r2 + 1);
+    }
+    swf_call_with_get_reg(i0, fallback);
+    movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_iff_(jit_state_t *_jit, int (*i0)(float, float),
+         jit_int32_t r0, jit_int32_t r1, jit_float32_t i1)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+    jit_get_reg_args();
+    data.f = i1;
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    movi(_R1_REGNO, data.i);
+    swf_call(i0, fallback, _R2_REGNO);
+    movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_idd_(jit_state_t *_jit, int (*i0)(double, double),
+         jit_int32_t r0, jit_int32_t r1, jit_float64_t i1)
+{
+    union {
+       jit_int32_t     i[2];
+       jit_float64_t   d;
+    } data;
+    jit_get_reg_args();
+    data.d = i1;
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    movi(_R2_REGNO, data.i[0]);
+    movi(_R3_REGNO, data.i[1]);
+    swf_call_with_get_reg(i0, fallback);
+    movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_iunff(jit_state_t *_jit, int (*i0)(float, float),
+          jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         instr;
+    jit_get_reg_args();
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    if (jit_fpr_p(r2))
+       swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r2) + 8);
+    else
+       movr(_R1_REGNO, r2);
+    swf_call(__aeabi_fcmpun, fcmpun, _R2_REGNO);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       IT(ARM_CC_NE);
+       if (r0 < 8)
+           T1_MOVI(r0, 1);
+       else
+           T2_MOVI(r0, 1);
+       instr = _jit->pc.w;
+       T2_CC_B(ARM_CC_NE, 0);
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       CC_MOVI(ARM_CC_NE, r0, 1);
+       instr = _jit->pc.w;
+       CC_B(ARM_CC_NE, 0);
+    }
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    if (jit_fpr_p(r2))
+       swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r2) + 8);
+    else
+       movr(_R1_REGNO, r2);
+    swf_call(i0, fallback, _R2_REGNO);
+    movr(r0, _R0_REGNO);
+    patch_at(arm_patch_jump, instr, _jit->pc.w);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_iundd(jit_state_t *_jit, int (*i0)(double, double),
+          jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         instr;
+    jit_get_reg_args();
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    if (jit_fpr_p(r2)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R2_REGNO, _FP_REGNO, swf_off(r2) + 8);
+       else {
+           swf_ldrin(_R2_REGNO, _FP_REGNO, swf_off(r2) + 8);
+           swf_ldrin(_R3_REGNO, _FP_REGNO, swf_off(r2) + 4);
+       }
+    }
+    else {
+       movr(_R2_REGNO, r2);
+       movr(_R3_REGNO, r2 + 1);
+    }
+    swf_call_with_get_reg(__aeabi_dcmpun, dcmpun);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       IT(ARM_CC_NE);
+       if (r0 < 8)
+           T1_MOVI(r0, 1);
+       else
+           T2_MOVI(r0, 1);
+       instr = _jit->pc.w;
+       T2_CC_B(ARM_CC_NE, 0);
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       CC_MOVI(ARM_CC_NE, r0, 1);
+       instr = _jit->pc.w;
+       CC_B(ARM_CC_NE, 0);
+    }
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    if (jit_fpr_p(r2)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R2_REGNO, _FP_REGNO, swf_off(r2) + 8);
+       else {
+           swf_ldrin(_R2_REGNO, _FP_REGNO, swf_off(r2) + 8);
+           swf_ldrin(_R3_REGNO, _FP_REGNO, swf_off(r2) + 4);
+       }
+    }
+    else {
+       movr(_R2_REGNO, r2);
+       movr(_R3_REGNO, r2 + 1);
+    }
+    swf_call_with_get_reg(i0, fallback);
+    movr(r0, _R0_REGNO);
+    patch_at(arm_patch_jump, instr, _jit->pc.w);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_iunff_(jit_state_t *_jit, int (*i0)(float, float),
+           jit_int32_t r0, jit_int32_t r1, jit_float32_t i1)
+{
+    jit_word_t         instr;
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+    jit_get_reg_args();
+    data.f = i1;
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    movi(_R1_REGNO, data.i);
+    swf_call(__aeabi_fcmpun, fcmpun, _R2_REGNO);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       IT(ARM_CC_NE);
+       if (r0 < 8)
+           T1_MOVI(r0, 1);
+       else
+           T2_MOVI(r0, 1);
+       instr = _jit->pc.w;
+       T2_CC_B(ARM_CC_NE, 0);
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       CC_MOVI(ARM_CC_NE, r0, 1);
+       instr = _jit->pc.w;
+       CC_B(ARM_CC_NE, 0);
+    }
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    movi(_R1_REGNO, data.i);
+    swf_call(i0, fallback, _R2_REGNO);
+    movr(r0, _R0_REGNO);
+    patch_at(arm_patch_jump, instr, _jit->pc.w);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_iundd_(jit_state_t *_jit, int (*i0)(double, double),
+           jit_int32_t r0, jit_int32_t r1, jit_float64_t i1)
+{
+    jit_word_t         instr;
+    union {
+       jit_int32_t     i[2];
+       jit_float64_t   d;
+    } data;
+    jit_get_reg_args();
+    data.d = i1;
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    movi(_R2_REGNO, data.i[0]);
+    movi(_R3_REGNO, data.i[1]);
+    swf_call_with_get_reg(__aeabi_dcmpun, dcmpun);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       IT(ARM_CC_NE);
+       if (r0 < 8)
+           T1_MOVI(r0, 1);
+       else
+           T2_MOVI(r0, 1);
+       instr = _jit->pc.w;
+       T2_CC_B(ARM_CC_NE, 0);
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       CC_MOVI(ARM_CC_NE, r0, 1);
+       instr = _jit->pc.w;
+       CC_B(ARM_CC_NE, 0);
+    }
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    movi(_R2_REGNO, data.i[0]);
+    movi(_R3_REGNO, data.i[1]);
+    swf_call_with_get_reg(i0, fallback);
+    movr(r0, _R0_REGNO);
+    patch_at(arm_patch_jump, instr, _jit->pc.w);
+    jit_unget_reg_args();
+}
+
+static jit_word_t
+_swf_bff(jit_state_t *_jit, int (*i0)(float, float), int cc,
+        jit_word_t i1, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, d;
+    jit_get_reg_args();
+    if (jit_fpr_p(r0))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(_R0_REGNO, r0);
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R1_REGNO, r1);
+    swf_call(i0, fallback, _R2_REGNO);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       w = _jit->pc.w;
+       d = ((i1 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       w = _jit->pc.w;
+       d = ((i1 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    jit_unget_reg_args();
+    return (w);
+}
+
+static jit_word_t
+_swf_bdd(jit_state_t *_jit, int (*i0)(double, double), int cc,
+        jit_word_t i1, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, d;
+    jit_get_reg_args();
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r0);
+       movr(_R1_REGNO, r0 + 1);
+    }
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R2_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R2_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R3_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R2_REGNO, r1);
+       movr(_R3_REGNO, r1 + 1);
+    }
+    swf_call_with_get_reg(i0, fallback);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       w = _jit->pc.w;
+       d = ((i1 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       w = _jit->pc.w;
+       d = ((i1 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    jit_unget_reg_args();
+    return (w);
+}
+
+static jit_word_t
+_swf_bff_(jit_state_t *_jit, int (*i0)(float, float), int cc,
+         jit_word_t i1, jit_int32_t r0, jit_float32_t i2)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+    jit_word_t         w, d;
+    jit_get_reg_args();
+    data.f = i2;
+    if (jit_fpr_p(r0))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(_R0_REGNO, r0);
+    movi(_R1_REGNO, data.i);
+    swf_call(i0, fallback, _R2_REGNO);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       w = _jit->pc.w;
+       d = ((i1 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       w = _jit->pc.w;
+       d = ((i1 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    jit_unget_reg_args();
+    return (w);
+}
+
+static jit_word_t
+_swf_bdd_(jit_state_t *_jit, int (*i0)(double, double), int cc,
+         jit_word_t i1, jit_int32_t r0, jit_float64_t i2)
+{
+    jit_word_t         w, d;
+    union {
+       jit_int32_t     i[2];
+       jit_float64_t   d;
+    } data;
+    jit_get_reg_args();
+    data.d = i2;
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r0);
+       movr(_R1_REGNO, r0 + 1);
+    }
+    movi(_R2_REGNO, data.i[0]);
+    movi(_R3_REGNO, data.i[1]);
+    swf_call_with_get_reg(i0, fallback);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       w = _jit->pc.w;
+       d = ((i1 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       w = _jit->pc.w;
+       d = ((i1 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    jit_unget_reg_args();
+    return (w);
+}
+
+static jit_word_t
+_swf_bunff(jit_state_t *_jit, int eq,
+          jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, d, j0, j1;
+    jit_get_reg_args();
+    if (jit_fpr_p(r0))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(_R0_REGNO, r0);
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R1_REGNO, r1);
+    swf_call(__aeabi_fcmpun, fcmpun, _R2_REGNO);
+    /* if unordered */
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       j0 = _jit->pc.w;
+       T2_CC_B(ARM_CC_NE, 0);
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       j0 = _jit->pc.w;
+       CC_B(ARM_CC_NE, 0);
+    }
+    if (jit_fpr_p(r0))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(_R0_REGNO, r0);
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R1_REGNO, r1);
+    swf_call(__aeabi_fcmpeq, fcmpeq, _R2_REGNO);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       j1 = _jit->pc.w;
+       if (eq) {
+           T2_CC_B(ARM_CC_EQ, 0);
+           patch_at(arm_patch_jump, j0, _jit->pc.w);
+       }
+       else
+           T2_CC_B(ARM_CC_NE, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s24P(d));
+       T2_B(encode_thumb_jump(d));
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       j1 = _jit->pc.w;
+       if (eq) {
+           CC_B(ARM_CC_EQ, 0);
+           patch_at(arm_patch_jump, j0, _jit->pc.w);
+       }
+       else
+           CC_B(ARM_CC_NE, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       B(d & 0x00ffffff);
+    }
+    if (!eq)
+       patch_at(arm_patch_jump, j0, _jit->pc.w);
+    patch_at(arm_patch_jump, j1, _jit->pc.w);
+    jit_unget_reg_args();
+    return (w);
+}
+
+static jit_word_t
+_swf_bundd(jit_state_t *_jit, int eq,
+          jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, d, j0, j1;
+    jit_get_reg_args();
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r0);
+       movr(_R1_REGNO, r0 + 1);
+    }
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R2_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R2_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R3_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R2_REGNO, r0);
+       movr(_R3_REGNO, r0 + 1);
+    }
+    swf_call_with_get_reg(__aeabi_dcmpun, dcmpun);
+    /* if unordered */
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       j0 = _jit->pc.w;
+       T2_CC_B(ARM_CC_NE, 0);
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       j0 = _jit->pc.w;
+       CC_B(ARM_CC_NE, 0);
+    }
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r0);
+       movr(_R1_REGNO, r0 + 1);
+    }
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R2_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R2_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R3_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R2_REGNO, r0);
+       movr(_R3_REGNO, r0 + 1);
+    }
+    swf_call_with_get_reg(__aeabi_dcmpeq, dcmpeq);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       j1 = _jit->pc.w;
+       if (eq) {
+           T2_CC_B(ARM_CC_EQ, 0);
+           patch_at(arm_patch_jump, j0, _jit->pc.w);
+       }
+       else
+           T2_CC_B(ARM_CC_NE, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s24P(d));
+       T2_B(encode_thumb_jump(d));
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       j1 = _jit->pc.w;
+       if (eq) {
+           CC_B(ARM_CC_EQ, 0);
+           patch_at(arm_patch_jump, j0, _jit->pc.w);
+       }
+       else
+           CC_B(ARM_CC_NE, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       B(d & 0x00ffffff);
+    }
+    if (!eq)
+       patch_at(arm_patch_jump, j0, _jit->pc.w);
+    patch_at(arm_patch_jump, j1, _jit->pc.w);
+    jit_unget_reg_args();
+    return (w);
+}
+
+static jit_word_t
+_swf_bunff_(jit_state_t *_jit, int eq,
+           jit_word_t i0, jit_int32_t r0, jit_float32_t i1)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+    jit_word_t         w, d, j0, j1;
+    data.f = i1;
+    jit_get_reg_args();
+    if (jit_fpr_p(r0))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(_R0_REGNO, r0);
+    movi(_R1_REGNO, data.i);
+    swf_call(__aeabi_fcmpun, fcmpun, _R2_REGNO);
+    /* if unordered */
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       j0 = _jit->pc.w;
+       T2_CC_B(ARM_CC_NE, 0);
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       j0 = _jit->pc.w;
+       CC_B(ARM_CC_NE, 0);
+    }
+    if (jit_fpr_p(r0))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(_R0_REGNO, r0);
+    movi(_R1_REGNO, data.i);
+    swf_call(__aeabi_fcmpeq, fcmpeq, _R2_REGNO);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       j1 = _jit->pc.w;
+       if (eq) {
+           T2_CC_B(ARM_CC_EQ, 0);
+           patch_at(arm_patch_jump, j0, _jit->pc.w);
+       }
+       else
+           T2_CC_B(ARM_CC_NE, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s24P(d));
+       T2_B(encode_thumb_jump(d));
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       j1 = _jit->pc.w;
+       if (eq) {
+           CC_B(ARM_CC_EQ, 0);
+           patch_at(arm_patch_jump, j0, _jit->pc.w);
+       }
+       else
+           CC_B(ARM_CC_NE, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       B(d & 0x00ffffff);
+    }
+    if (!eq)
+       patch_at(arm_patch_jump, j0, _jit->pc.w);
+    patch_at(arm_patch_jump, j1, _jit->pc.w);
+    jit_unget_reg_args();
+    return (w);
+}
+
+static jit_word_t
+_swf_bundd_(jit_state_t *_jit, int eq,
+           jit_word_t i0, jit_int32_t r0, jit_float64_t i1)
+{
+    jit_word_t         w, d, j0, j1;
+    union {
+       jit_int32_t     i[2];
+       jit_float64_t   d;
+    } data;
+    jit_get_reg_args();
+    data.d = i1;
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r0);
+       movr(_R1_REGNO, r0 + 1);
+    }
+    movi(_R2_REGNO, data.i[0]);
+    movi(_R3_REGNO, data.i[1]);
+    swf_call_with_get_reg(__aeabi_dcmpun, fcmpun);
+    /* if unordered */
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       j0 = _jit->pc.w;
+       T2_CC_B(ARM_CC_NE, 0);
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       j0 = _jit->pc.w;
+       CC_B(ARM_CC_NE, 0);
+    }
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r0);
+       movr(_R1_REGNO, r0 + 1);
+    }
+    movi(_R2_REGNO, data.i[0]);
+    movi(_R3_REGNO, data.i[1]);
+    swf_call_with_get_reg(__aeabi_dcmpeq, fcmpeq);
+    if (jit_thumb_p()) {
+       T1_CMPI(_R0_REGNO, 0);
+       j1 = _jit->pc.w;
+       if (eq) {
+           T2_CC_B(ARM_CC_EQ, 0);
+           patch_at(arm_patch_jump, j0, _jit->pc.w);
+       }
+       else
+           T2_CC_B(ARM_CC_NE, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s24P(d));
+       T2_B(encode_thumb_jump(d));
+    }
+    else {
+       CMPI(_R0_REGNO, 0);
+       j1 = _jit->pc.w;
+       if (eq) {
+           CC_B(ARM_CC_EQ, 0);
+           patch_at(arm_patch_jump, j0, _jit->pc.w);
+       }
+       else
+           CC_B(ARM_CC_NE, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       B(d & 0x00ffffff);
+    }
+    if (!eq)
+       patch_at(arm_patch_jump, j0, _jit->pc.w);
+    patch_at(arm_patch_jump, j1, _jit->pc.w);
+    jit_unget_reg_args();
+    return (w);
+}
+
+static void
+_swf_extr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_get_reg_args();
+    movr(_R0_REGNO, r1);
+    swf_call(__aeabi_i2f, i2f, _R1_REGNO);
+    if (jit_fpr_p(r0))
+       swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_extr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_get_reg_args();
+    movr(_R0_REGNO, r1);
+    swf_call(__aeabi_i2d, i2d, _R2_REGNO);
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           STRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_strin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(r0, _R0_REGNO);
+       movr(r0 + 1, _R1_REGNO);
+    }
+    jit_unget_reg_args();
+}
+
+static void
+_swf_extr_d_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_get_reg_args();
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+    swf_call(__aeabi_d2f, d2f, _R2_REGNO);
+    if (jit_fpr_p(r0))
+       swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+    else
+       movr(r0, _R0_REGNO);
+    jit_unget_reg_args();
+}
+
+static void
+_swf_extr_f_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_get_reg_args();
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+    swf_call(__aeabi_f2d, f2d, _R1_REGNO);
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           STRDIN(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+       else {
+           swf_strin(_R0_REGNO, _FP_REGNO, swf_off(r0) + 8);
+           swf_strin(_R1_REGNO, _FP_REGNO, swf_off(r0) + 4);
+       }
+    }
+    else {
+       movr(r0, _R0_REGNO);
+       movr(r0 + 1, _R1_REGNO);
+    }
+    jit_unget_reg_args();
+}
+
+static void
+_swf_truncr_f_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#if !NAN_TO_INT_IS_ZERO
+    jit_word_t         is_nan;
+    jit_word_t         fast_not_nan;
+    jit_word_t         slow_not_nan;
+#endif
+    jit_get_reg_args();
+    if (jit_fpr_p(r1))
+       swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+    else
+       movr(_R0_REGNO, r1);
+#if !NAN_TO_INT_IS_ZERO
+    /* >> based on fragment of __aeabi_fcmpun */
+    lshi(_R2_REGNO, _R0_REGNO, 1);
+    if (jit_thumb_p())
+       torrrs(THUMB2_MVN|ARM_S, _R0_REGNO, _R3_REGNO, _R2_REGNO,
+              encode_thumb_shift(24, ARM_ASR));
+    else
+       corrrs(ARM_CC_AL, ARM_MVN|ARM_S|ARM_ASR,
+              _R0_REGNO, _R3_REGNO, _R2_REGNO, 24);
+    fast_not_nan = _jit->pc.w;
+    if (jit_thumb_p()) {
+       T2_CC_B(ARM_CC_NE, 0);
+       tshift(THUMB2_LSLI|ARM_S, _R0_REGNO, _R3_REGNO, 9);
+    }
+    else {
+       CC_B(ARM_CC_NE, 0);
+       cshift(ARM_CC_AL, ARM_S|ARM_LSL, _R0_REGNO, _R3_REGNO, _R0_REGNO, 9);
+    }
+    slow_not_nan = _jit->pc.w;
+    if (jit_thumb_p())
+       T2_CC_B(ARM_CC_EQ, 0);
+    else
+       CC_B(ARM_CC_EQ, 0);
+    movi(r0, 0x80000000);
+    is_nan = _jit->pc.w;
+    if (jit_thumb_p())
+       T2_B(0);
+    else
+       B(0);
+    patch_at(arm_patch_jump, fast_not_nan, _jit->pc.w);
+    patch_at(arm_patch_jump, slow_not_nan, _jit->pc.w);
+    /* << based on fragment of __aeabi_fcmpun */
+#endif
+    swf_call(__aeabi_f2iz, f2iz, _R2_REGNO);
+    movr(r0, _R0_REGNO);
+#if !NAN_TO_INT_IS_ZERO
+    patch_at(arm_patch_jump, is_nan, _jit->pc.w);
+#endif
+    jit_unget_reg_args();
+}
+
+static void
+_swf_truncr_d_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#if !NAN_TO_INT_IS_ZERO
+    jit_word_t         is_nan;
+    jit_word_t         fast_not_nan;
+    jit_word_t         slow_not_nan;
+#endif
+    jit_get_reg_args();
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p())
+           LDRDIN(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+       else {
+           swf_ldrin(_R0_REGNO, _FP_REGNO, swf_off(r1) + 8);
+           swf_ldrin(_R1_REGNO, _FP_REGNO, swf_off(r1) + 4);
+       }
+    }
+    else {
+       movr(_R0_REGNO, r1);
+       movr(_R1_REGNO, r1 + 1);
+    }
+#if !NAN_TO_INT_IS_ZERO
+    /* >> based on fragment of __aeabi_dcmpun */
+    lshi(_R3_REGNO, _R1_REGNO, 1);
+    if (jit_thumb_p())
+       torrrs(THUMB2_MVN|ARM_S, _R0_REGNO, _R3_REGNO, _R3_REGNO,
+              encode_thumb_shift(21, ARM_ASR));
+    else
+       corrrs(ARM_CC_AL, ARM_MVN|ARM_S|ARM_ASR,
+              _R0_REGNO, _R3_REGNO, _R3_REGNO, 21);
+    fast_not_nan = _jit->pc.w;
+    if (jit_thumb_p()) {
+       T2_CC_B(ARM_CC_NE, 0);
+       torrrs(THUMB2_ORR|ARM_S, _R0_REGNO, _R3_REGNO, _R1_REGNO,
+              encode_thumb_shift(12, ARM_LSL));
+    }
+    else {
+       CC_B(ARM_CC_NE, 0);
+       corrrs(ARM_CC_AL, ARM_ORR|ARM_S|ARM_LSL,
+              _R0_REGNO, _R3_REGNO, _R1_REGNO, 12);
+    }
+    slow_not_nan = _jit->pc.w;
+    if (jit_thumb_p())
+       T2_CC_B(ARM_CC_EQ, 0);
+    else
+       CC_B(ARM_CC_EQ, 0);
+    movi(r0, 0x80000000);
+    is_nan = _jit->pc.w;
+    if (jit_thumb_p())
+       T2_B(0);
+    else
+       B(0);
+    patch_at(arm_patch_jump, fast_not_nan, _jit->pc.w);
+    patch_at(arm_patch_jump, slow_not_nan, _jit->pc.w);
+    /* << based on fragment of __aeabi_dcmpun */
+#endif
+    swf_call(__aeabi_d2iz, d2iz, _R3_REGNO);
+    movr(r0, _R0_REGNO);
+#if !NAN_TO_INT_IS_ZERO
+    patch_at(arm_patch_jump, is_nan, _jit->pc.w);
+#endif
+    jit_unget_reg_args();
+}
+
+static void
+_swf_movr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (r0 != r1) {
+       if (jit_fpr_p(r1)) {
+           reg = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+           if (jit_fpr_p(r0))
+               swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+           else
+               movr(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       else if (jit_fpr_p(r0))
+           swf_strin(r1, _FP_REGNO, swf_off(r0) + 8);
+       else
+           movr(r0, r1);
+    }
+}
+
+static void
+_swf_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (r0 != r1) {
+       if (jit_fpr_p(r1)) {
+           if (!jit_thumb_p() && jit_armv5e_p() &&
+               (reg = jit_get_reg_pair()) != JIT_NOREG) {
+               LDRDIN(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+               if (jit_fpr_p(r0))
+                   STRDIN(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+               else {
+                   movr(r0, rn(reg));
+                   movr(r0 + 1, rn(reg) + 1);
+               }
+               jit_unget_reg_pair(reg);
+           }
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+               if (jit_fpr_p(r0))
+                   swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+               else
+                   movr(r0, rn(reg));
+               swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 4);
+               if (jit_fpr_p(r0))
+                   swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 4);
+               else
+                   movr(r0 + 1, rn(reg));
+               jit_unget_reg(reg);
+           }
+       }
+       else if (jit_fpr_p(r0)) {
+           if (!jit_thumb_p() && jit_armv5e_p() && !(r1 & 1))
+               STRDIN(r1, _FP_REGNO, swf_off(r0) + 8);
+           else {
+               swf_strin(r1, _FP_REGNO, swf_off(r0) + 8);
+               swf_strin(r1 + 1, _FP_REGNO, swf_off(r0) + 4);
+           }
+       }
+       else {
+           movr(r0, r1);
+           movr(r0 + 1, r1 + 1);
+       }
+    }
+}
+
+static void
+_swf_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t i0)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+    jit_int32_t                reg;
+    data.f = i0;
+    if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.i);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg(reg);
+    }
+    else
+       movi(r0, data.i);
+}
+
+static void
+_swf_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t i0)
+{
+    jit_int32_t                reg;
+    union {
+       jit_int32_t     i[2];
+       jit_float64_t   d;
+    } data;
+    data.d = i0;
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           (reg = jit_get_reg_pair()) != JIT_NOREG) {
+           movi(rn(reg), data.i[0]);
+           movi(rn(reg) + 1, data.i[1]);
+           STRDIN(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+           jit_unget_reg_pair(reg);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), data.i[0]);
+           swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+           movi(rn(reg), data.i[1]);
+           swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 4);
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       movi(r0, data.i[0]);
+       movi(r0 + 1, data.i[1]);
+    }
+}
+
+static void
+_swf_absr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       reg = jit_get_reg(jit_class_gpr);
+       swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+       swf_bici(rn(reg), rn(reg), 0x80000000);
+       if (jit_fpr_p(r0))
+           swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       else
+           movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r1);
+       swf_bici(rn(reg), rn(reg), 0x80000000);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg(reg);
+    }
+    else
+       swf_bici(r0, r1, 0x80000000);
+}
+
+static void
+_swf_absr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       if (jit_fpr_p(r0) && !jit_thumb_p() && jit_armv5e_p() &&
+           r0 != r1 && (reg = jit_get_reg_pair()) != JIT_NOREG) {
+           LDRDIN(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+           swf_bici(rn(reg) + 1, rn(reg) + 1, 0x80000000);
+           STRDIN(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+           jit_unget_reg_pair(reg);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 4);
+           swf_bici(rn(reg), rn(reg), 0x80000000);
+           if (jit_fpr_p(r0)) {
+               swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 4);
+               if (r0 != r1) {
+                   swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+                   swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+               }
+           }
+           else {
+               movr(r0, rn(reg));
+               swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+               movr(r0 + 1, rn(reg));
+           }
+           jit_unget_reg(reg);
+       }
+    }
+    else if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r1);
+       swf_bici(rn(reg), rn(reg), 0x80000000);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 4);
+       movr(rn(reg), r1 + 1);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg(reg);
+    }
+    else {
+       swf_bici(r0, r1, 0x80000000);
+       if (r0 != r1)
+           movr(r0 + 1, r1 + 1);
+    }
+}
+
+static void
+_swf_negr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       reg = jit_get_reg(jit_class_gpr);
+       swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+       xori(rn(reg), rn(reg), 0x80000000);
+       if (jit_fpr_p(r0))
+           swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       else
+           movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r1);
+       xori(rn(reg), rn(reg), 0x80000000);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg(reg);
+    }
+    else
+       xori(r0, r1, 0x80000000);
+}
+
+static void
+_swf_negr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       if (jit_fpr_p(r0) && !jit_thumb_p() && jit_armv5e_p() &&
+           r0 != r1 && (reg = jit_get_reg_pair()) != JIT_NOREG) {
+           LDRDIN(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+           EORI(rn(reg) + 1, rn(reg) + 1, encode_arm_immediate(0x80000000));
+           STRDIN(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+           jit_unget_reg_pair(reg);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 4);
+           xori(rn(reg), rn(reg), 0x80000000);
+           if (jit_fpr_p(r0)) {
+               swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 4);
+               if (r0 != r1) {
+                   swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+                   swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+               }
+           }
+           else {
+               movr(r0, rn(reg));
+               swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+               movr(r0 + 1, rn(reg));
+           }
+           jit_unget_reg(reg);
+       }
+    }
+    else if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r1);
+       xori(rn(reg), rn(reg), 0x80000000);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 4);
+       movr(rn(reg), r1 + 1);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg(reg);
+    }
+    else {
+       xori(r0, r1, 0x80000000);
+       if (r0 != r1)
+           movr(r0 + 1, r1 + 1);
+    }
+}
+
+static void
+_swf_ner_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    swf_iff(__aeabi_fcmpeq, r0, r1, r2);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_nei_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_float32_t i0)
+{
+    swf_iff_(__aeabi_fcmpeq, r0, r1, i0);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ner_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    swf_idd(__aeabi_dcmpeq, r0, r1, r2);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_nei_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_float64_t i0)
+{
+    swf_idd_(__aeabi_dcmpeq, r0, r1, i0);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ltgtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    swf_iunff(__aeabi_fcmpeq, r0, r1, r2);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ltgti_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_float32_t i0)
+{
+    swf_iunff_(__aeabi_fcmpeq, r0, r1, i0);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    swf_iundd(__aeabi_dcmpeq, r0, r1, r2);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ltgti_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_float64_t i0)
+{
+    swf_iundd_(__aeabi_dcmpeq, r0, r1, i0);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ordr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    swf_iff(__aeabi_fcmpun, r0, r1, r2);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ordi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_float32_t i0)
+{
+    swf_iff_(__aeabi_fcmpun, r0, r1, i0);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    swf_idd(__aeabi_dcmpun, r0, r1, r2);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ordi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_float64_t i0)
+{
+    swf_idd_(__aeabi_dcmpun, r0, r1, i0);
+    xori(r0, r0, 1);
+}
+
+static void
+_swf_ldr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       ldxi_i(rn(reg), r1, 0);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg(reg);
+    }
+    else
+       ldxi_i(r0, r1, 0);
+}
+
+static void
+_swf_ldr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           (reg = jit_get_reg_pair()) != JIT_NOREG) {
+           LDRDI(rn(reg), r1, 0);
+           STRDIN(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+           jit_unget_reg_pair(reg);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           ldxi_i(rn(reg), r1, 0);
+           swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+           ldxi_i(rn(reg), r1, 4);
+           swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 4);
+           jit_unget_reg(reg);
+       }
+    }
+    else if (!jit_thumb_p() && jit_armv5e_p() && !(r0 & 1))
+       LDRDI(r0, r1, 0);
+    else {
+       ldxi_i(r0, r1, 0);
+       ldxi_i(r0 + 1, r1, 4);
+    }
+}
+
+static void
+_swf_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       ldi_i(rn(reg), i0);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg(reg);
+    }
+    else
+       ldi_i(r0, i0);
+}
+
+static void
+_swf_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                rg0, rg1;
+    if (jit_fpr_p(r0) && !jit_thumb_p() && jit_armv5e_p() &&
+       (rg0 = jit_get_reg_pair()) != JIT_NOREG) {
+       movi(rn(rg0), i0);
+       LDRDI(rn(rg0), rn(rg0), 0);
+       STRDIN(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg_pair(rg0);
+    }
+    else {
+       rg1 = jit_get_reg(jit_class_gpr);
+       movi(rn(rg1), i0);
+       if (jit_fpr_p(r0)) {
+           rg0 = jit_get_reg(jit_class_gpr);
+           ldxi_i(rn(rg0), rn(rg1), 0);
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+           ldxi_i(rn(rg0), rn(rg1), 4);
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 4);
+           jit_unget_reg(rg0);
+       }
+       else if (!jit_thumb_p() && jit_armv5e_p() && !(r0 & 1))
+           LDRDI(r0, rn(rg1), 0);
+       else {
+           ldxi_i(r0, rn(rg1), 0);
+           ldxi_i(r0 + 1, rn(rg1), 0);
+       }
+       jit_unget_reg(rg1);
+    }
+}
+
+static void
+_swf_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       ldxr_i(rn(reg), r1, r2);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg(reg);
+    }
+    else
+       ldxr_i(r0, r1, r2);
+}
+
+static void
+_swf_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                rg0, rg1;
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           (rg0 = jit_get_reg_pair()) != JIT_NOREG) {
+           LDRD(rn(rg0), r1, r2);
+           STRDIN(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+           jit_unget_reg_pair(rg0);
+       }
+       else {
+           rg1 = jit_get_reg(jit_class_gpr);
+           addr(rn(rg1), r1, r2);
+           rg0 = jit_get_reg(jit_class_gpr);
+           ldxi_i(rn(rg0), rn(rg1), 0);
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+           ldxi_i(rn(rg0), rn(rg1), 4);
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 4);
+           jit_unget_reg(rg0);
+           jit_unget_reg(rg1);
+       }
+    }
+    else {
+       if (!jit_thumb_p() && jit_armv5e_p() && !(r0 & 1))
+           LDRD(r0, r1, r2);
+       else {
+           rg1 = jit_get_reg(jit_class_gpr);
+           addr(rn(rg1), r1, r2);
+           ldxi_i(r0, rn(rg1), 0);
+           ldxi_i(r0 + 1, rn(rg1), 4);
+           jit_unget_reg(rg1);
+       }
+    }
+}
+
+static void
+_swf_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       ldxi_i(rn(reg), r1, i0);
+       swf_strin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       jit_unget_reg(reg);
+    }
+    else
+       ldxi_i(r0, r1, i0);
+}
+
+static void
+_swf_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                rg0, rg1;
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           ((i0 >= 0 && i0 <= 255) || (i0 < 0 && i0 >= -255)) &&
+           (rg0 = jit_get_reg_pair()) != JIT_NOREG) {
+           if (i0 >= 0)
+               LDRDI(rn(rg0), r1, i0);
+           else
+               LDRDIN(rn(rg0), r1, -i0);
+           STRDIN(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+           jit_unget_reg_pair(rg0);
+       }
+       else if (i0 >= 0 && i0 + 4 <= 4095) {
+           rg0 = jit_get_reg(jit_class_gpr);
+           ldxi_i(rn(rg0), r1, i0);
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+           ldxi_i(rn(rg0), r1, i0 + 4);
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 4);
+           jit_unget_reg(rg0);
+       }
+       else if (i0 < 0 && ((jit_thumb_p() && i0 >= -255) ||
+                           (!jit_thumb_p() && i0 >= -4095))) {
+           rg0 = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(rg0), r1, -i0);
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+           swf_ldrin(rn(rg0), r1, -(i0 + 4));
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 4);
+           jit_unget_reg(rg0);
+       }
+       else {
+           rg0 = jit_get_reg(jit_class_gpr);
+           rg1 = jit_get_reg(jit_class_gpr);
+           addi(rn(rg1), r1, i0);
+           ldxi_i(rn(rg0), rn(rg1), 0);
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+           ldxi_i(rn(rg0), rn(rg1), 4);
+           swf_strin(rn(rg0), _FP_REGNO, swf_off(r0) + 4);
+           jit_unget_reg(rg1);
+           jit_unget_reg(rg0);
+       }
+    }
+    else {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           i0 >= 0 && i0 <= 255 && !(r0 & 1))
+           LDRDI(r0, r1, i0);
+       else if (!jit_thumb_p() && jit_armv5e_p() &&
+                i0 < 0 && i0 >= -255 && !(r0 & 1))
+           LDRDIN(r0, r1, -i0);
+       else if (i0 >= 0 && i0 + 4 <= 4095) {
+           ldxi_i(r0, r1, i0);
+           ldxi_i(r0 + 1, r1, i0 + 4);
+       }
+       else if (i0 < 0 && i0 >= -4095) {
+           swf_ldrin(r0, r1, -i0);
+           swf_ldrin(r0 + 1, r1, -(i0 + 4));
+       }
+       else {
+           rg0 = jit_get_reg(jit_class_gpr);
+           addi(rn(rg0), r1, i0);
+           ldxi_i(r0, rn(rg0), 0);
+           ldxi_i(r0 + 1, rn(rg0), 4);
+           jit_unget_reg(rg0);
+       }
+    }
+}
+
+static void
+_swf_str_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       reg = jit_get_reg(jit_class_gpr);
+       swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+       stxi_i(0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       str_i(r0, r1);
+}
+
+static void
+_swf_str_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           (reg = jit_get_reg_pair()) != JIT_NOREG) {
+           LDRDIN(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+           STRDI(rn(reg), r0, 0);
+           jit_unget_reg_pair(reg);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+           stxi_i(0, r0, rn(reg));
+           swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 4);
+           stxi_i(4, r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       if (!jit_thumb_p() && jit_armv5e_p() && !(r1 & 1))
+           STRDI(r1, r0, 0);
+       else {
+           stxi_i(0, r0, r1);
+           stxi_i(4, r0, r1 + 1);
+       }
+    }
+}
+
+static void
+_swf_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       swf_ldrin(rn(reg), _FP_REGNO, swf_off(r0) + 8);
+       sti_i(i0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       sti_i(i0, r0);
+}
+
+static void
+_swf_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                rg0, rg1;
+    if (jit_fpr_p(r0)) {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           (rg0 = jit_get_reg_pair()) != JIT_NOREG) {
+           rg1 = jit_get_reg(jit_class_gpr);
+           movi(rn(rg1), i0);
+           LDRDIN(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+           STRDI(rn(rg0), rn(rg1), 0);
+           jit_unget_reg(rg1);
+           jit_unget_reg_pair(rg0);
+       }
+       else {
+           rg1 = jit_get_reg(jit_class_gpr);
+           movi(rn(rg1), i0);
+           rg0 = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r0) + 8);
+           stxi_i(0, rn(rg1), rn(rg0));
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r0) + 4);
+           stxi_i(4, rn(rg1), rn(rg0));
+           jit_unget_reg(rg1);
+           jit_unget_reg(rg0);
+       }
+    }
+    else {
+       rg1 = jit_get_reg(jit_class_gpr);
+       movi(rn(rg1), i0);
+       if (!jit_thumb_p() && jit_armv5e_p() && !(r0 & 1))
+           STRDI(r0, rn(rg1), 0);
+       else {
+           stxi_i(0, rn(rg1), r0);
+           stxi_i(4, rn(rg1), r0 + 1);
+       }
+       jit_unget_reg(rg1);
+    }
+}
+
+static void
+_swf_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r2)) {
+       reg = jit_get_reg(jit_class_gpr);
+       swf_ldrin(rn(reg), _FP_REGNO, swf_off(r2) + 8);
+       stxr_i(r1, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       stxr_i(r0, r1, r2);
+}
+
+static void
+_swf_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                rg0, rg1;
+    if (jit_fpr_p(r2)) {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           (rg0 = jit_get_reg_pair()) != JIT_NOREG) {
+           LDRDIN(rn(rg0), _FP_REGNO, swf_off(r2) + 8);
+           STRD(rn(rg0), r0, r1);
+           jit_unget_reg_pair(rg0);
+       }
+       else {
+           rg1 = jit_get_reg(jit_class_gpr);
+           addr(rn(rg1), r0, r1);
+           rg0 = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r2) + 8);
+           stxi_i(0, rn(rg1), rn(rg0));
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r2) + 4);
+           stxi_i(4, rn(rg1), rn(rg0));
+           jit_unget_reg(rg0);
+           jit_unget_reg(rg1);
+       }
+    }
+    else {
+       if (!jit_thumb_p() && jit_armv5e_p() && !(r2 & 1))
+           STRD(r0, r1, r2);
+       else {
+           rg1 = jit_get_reg(jit_class_gpr);
+           addr(rn(rg1), r0, r1);
+           stxi_i(0, rn(rg1), r2);
+           stxi_i(4, rn(rg1), r2 + 1);
+           jit_unget_reg(rg1);
+       }
+    }
+}
+
+static void
+_swf_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       reg = jit_get_reg(jit_class_gpr);
+       swf_ldrin(rn(reg), _FP_REGNO, swf_off(r1) + 8);
+       stxi_i(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       stxi_i(i0, r0, r1);
+}
+
+static void
+_swf_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                rg0, rg1;
+    if (jit_fpr_p(r1)) {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           ((i0 >= 0 && i0 <= 255) || (i0 < 0 && i0 >= -255)) &&
+           (rg0 = jit_get_reg_pair()) != JIT_NOREG) {
+           LDRDIN(rn(rg0), _FP_REGNO, swf_off(r1) + 8);
+           if (i0 >= 0 && i0 <= 255)
+               STRDI(rn(rg0), r0, i0);
+           else
+               STRDIN(rn(rg0), r0, -i0);
+           jit_unget_reg_pair(rg0);
+       }
+       else if (i0 >= 0 && i0 + 4 <= 4095) {
+           rg0 = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r1) + 8);
+           stxi_i(i0, r0, rn(rg0));
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r1) + 4);
+           stxi_i(i0 + 4, r0, rn(rg0));
+           jit_unget_reg(rg0);
+       }
+       else if (i0 < 0 && ((jit_thumb_p() && i0 >= -255) ||
+                           (!jit_thumb_p() && i0 >= -4095))) {
+           rg0 = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r1) + 8);
+           swf_strin(rn(rg0), r0, -i0);
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r1) + 4);
+           swf_strin(rn(rg0), r0, -(i0 + 4));
+           jit_unget_reg(rg0);
+       }
+       else {
+           rg1 = jit_get_reg(jit_class_gpr);
+           addi(rn(rg1), r0, i0);
+           rg0 = jit_get_reg(jit_class_gpr);
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r1) + 8);
+           stxi_i(0, rn(rg1), rn(rg0));
+           swf_ldrin(rn(rg0), _FP_REGNO, swf_off(r1) + 4);
+           stxi_i(4, rn(rg1), rn(rg0));
+           jit_unget_reg(rg0);
+           jit_unget_reg(rg1);
+       }
+    }
+    else {
+       if (!jit_thumb_p() && jit_armv5e_p() &&
+           i0 >= 0 && i0 <= 255 && !(r1 & 1))
+           STRDI(r1, r0, i0);
+       else if (!jit_thumb_p() && jit_armv5e_p() &&
+                i0 < 0 && i0 >= -255 && !(r1 & 1))
+           STRDIN(r1, r0, -i0);
+       else if (i0 >= 0 && i0 + 4 <= 4095) {
+           stxi_i(i0, r0, r1);
+           stxi_i(i0 + 4, r0, r1 + 1);
+       }
+       else if (i0 < 0 && ((jit_thumb_p() && i0 >= 255) ||
+                           (!jit_thumb_p() && i0 >= -4095))) {
+           swf_strin(r1, r0, -i0);
+           swf_strin(r1 + 1, r0, -(i0 + 4));
+       }
+       else {
+           rg1 = jit_get_reg(jit_class_gpr);
+           addi(rn(rg1), r0, i0);
+           stxi_i(0, rn(rg1), r1);
+           stxi_i(4, rn(rg1), r1 + 1);
+           jit_unget_reg(rg1);
+       }
+    }
+}
+
+static void
+_swf_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Adjust pointer. */
+    reg = jit_get_reg(jit_class_gpr);
+    andi(rn(reg), r1, 7);
+    addr(r1, r1, rn(reg));
+    jit_unget_reg(reg);
+
+    /* Load argument. */
+    swf_ldr_d(r0, r1);
+
+    /* Update stack pointer. */
+    addi(r1, r1, sizeof(jit_float64_t));
+}
+
+#endif
diff --git a/deps/lightning/lib/jit_arm-sz.c b/deps/lightning/lib/jit_arm-sz.c
new file mode 100644 (file)
index 0000000..9f0d012
--- /dev/null
@@ -0,0 +1,808 @@
+
+#if __WORDSIZE == 32
+#if defined(__ARM_PCS_VFP)
+#define JIT_INSTR_MAX 48
+    0, /* data */
+    0, /* live */
+    2, /* align */
+    0, /* save */
+    0, /* load */
+    2, /* #name */
+    0, /* #note */
+    0, /* label */
+    34,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    4, /* va_start */
+    8, /* va_arg */
+    16,        /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    12,        /* addi */
+    4, /* addcr */
+    8, /* addci */
+    4, /* addxr */
+    4, /* addxi */
+    4, /* subr */
+    12,        /* subi */
+    4, /* subcr */
+    8, /* subci */
+    4, /* subxr */
+    4, /* subxi */
+    16,        /* rsbi */
+    4, /* mulr */
+    12,        /* muli */
+    4, /* qmulr */
+    12,        /* qmuli */
+    4, /* qmulr_u */
+    8, /* qmuli_u */
+    40,        /* divr */
+    48,        /* divi */
+    40,        /* divr_u */
+    44,        /* divi_u */
+    34,        /* qdivr */
+    38,        /* qdivi */
+    34,        /* qdivr_u */
+    38,        /* qdivi_u */
+    40,        /* remr */
+    48,        /* remi */
+    40,        /* remr_u */
+    44,        /* remi_u */
+    4, /* andr */
+    12,        /* andi */
+    4, /* orr */
+    12,        /* ori */
+    4, /* xorr */
+    12,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    14,        /* ltr */
+    14,        /* lti */
+    14,        /* ltr_u */
+    14,        /* lti_u */
+    14,        /* ler */
+    14,        /* lei */
+    14,        /* ler_u */
+    14,        /* lei_u */
+    14,        /* eqr */
+    14,        /* eqi */
+    14,        /* ger */
+    14,        /* gei */
+    14,        /* ger_u */
+    14,        /* gei_u */
+    14,        /* gtr */
+    14,        /* gti */
+    14,        /* gtr_u */
+    14,        /* gti_u */
+    14,        /* ner */
+    14,        /* nei */
+    4, /* movr */
+    8, /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    8, /* htonr_us */
+    4, /* htonr_ui */
+    0, /* htonr_ul */
+    4, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    12,        /* ldi_uc */
+    4, /* ldr_s */
+    12,        /* ldi_s */
+    4, /* ldr_us */
+    12,        /* ldi_us */
+    4, /* ldr_i */
+    12,        /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    4, /* ldxr_c */
+    12,        /* ldxi_c */
+    4, /* ldxr_uc */
+    12,        /* ldxi_uc */
+    4, /* ldxr_s */
+    12,        /* ldxi_s */
+    4, /* ldxr_us */
+    12,        /* ldxi_us */
+    4, /* ldxr_i */
+    12,        /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    4, /* str_c */
+    12,        /* sti_c */
+    4, /* str_s */
+    12,        /* sti_s */
+    4, /* str_i */
+    12,        /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    4, /* stxr_c */
+    12,        /* stxi_c */
+    4, /* stxr_s */
+    12,        /* stxi_s */
+    4, /* stxr_i */
+    12,        /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    8, /* bltr */
+    8, /* blti */
+    8, /* bltr_u */
+    8, /* blti_u */
+    8, /* bler */
+    8, /* blei */
+    8, /* bler_u */
+    8, /* blei_u */
+    8, /* beqr */
+    16,        /* beqi */
+    8, /* bger */
+    8, /* bgei */
+    8, /* bger_u */
+    8, /* bgei_u */
+    8, /* bgtr */
+    8, /* bgti */
+    8, /* bgtr_u */
+    8, /* bgti_u */
+    8, /* bner */
+    16,        /* bnei */
+    8, /* bmsr */
+    8, /* bmsi */
+    8, /* bmcr */
+    8, /* bmci */
+    8, /* boaddr */
+    8, /* boaddi */
+    8, /* boaddr_u */
+    8, /* boaddi_u */
+    8, /* bxaddr */
+    8, /* bxaddi */
+    8, /* bxaddr_u */
+    8, /* bxaddi_u */
+    8, /* bosubr */
+    8, /* bosubi */
+    8, /* bosubr_u */
+    8, /* bosubi_u */
+    8, /* bxsubr */
+    8, /* bxsubi */
+    8, /* bxsubr_u */
+    8, /* bxsubi_u */
+    4, /* jmpr */
+    8, /* jmpi */
+    4, /* callr */
+    20,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    24,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    8, /* addi_f */
+    4, /* subr_f */
+    8, /* subi_f */
+    8, /* rsbi_f */
+    4, /* mulr_f */
+    8, /* muli_f */
+    4, /* divr_f */
+    8, /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    18,        /* ltr_f */
+    30,        /* lti_f */
+    20,        /* ler_f */
+    32,        /* lei_f */
+    18,        /* eqr_f */
+    30,        /* eqi_f */
+    18,        /* ger_f */
+    30,        /* gei_f */
+    18,        /* gtr_f */
+    30,        /* gti_f */
+    18,        /* ner_f */
+    30,        /* nei_f */
+    18,        /* unltr_f */
+    30,        /* unlti_f */
+    18,        /* unler_f */
+    30,        /* unlei_f */
+    24,        /* uneqr_f */
+    36,        /* uneqi_f */
+    18,        /* unger_f */
+    30,        /* ungei_f */
+    18,        /* ungtr_f */
+    30,        /* ungti_f */
+    24,        /* ltgtr_f */
+    36,        /* ltgti_f */
+    18,        /* ordr_f */
+    30,        /* ordi_f */
+    18,        /* unordr_f */
+    30,        /* unordi_f */
+    8, /* truncr_f_i */
+    0, /* truncr_f_l */
+    8, /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    12,        /* movi_f */
+    4, /* ldr_f */
+    12,        /* ldi_f */
+    8, /* ldxr_f */
+    16,        /* ldxi_f */
+    4, /* str_f */
+    12,        /* sti_f */
+    8, /* stxr_f */
+    16,        /* stxi_f */
+    12,        /* bltr_f */
+    24,        /* blti_f */
+    12,        /* bler_f */
+    24,        /* blei_f */
+    12,        /* beqr_f */
+    24,        /* beqi_f */
+    12,        /* bger_f */
+    24,        /* bgei_f */
+    12,        /* bgtr_f */
+    24,        /* bgti_f */
+    12,        /* bner_f */
+    24,        /* bnei_f */
+    16,        /* bunltr_f */
+    28,        /* bunlti_f */
+    16,        /* bunler_f */
+    28,        /* bunlei_f */
+    20,        /* buneqr_f */
+    32,        /* buneqi_f */
+    16,        /* bunger_f */
+    28,        /* bungei_f */
+    12,        /* bungtr_f */
+    24,        /* bungti_f */
+    20,        /* bltgtr_f */
+    32,        /* bltgti_f */
+    12,        /* bordr_f */
+    24,        /* bordi_f */
+    12,        /* bunordr_f */
+    24,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    20,        /* addi_d */
+    4, /* subr_d */
+    20,        /* subi_d */
+    20,        /* rsbi_d */
+    4, /* mulr_d */
+    20,        /* muli_d */
+    4, /* divr_d */
+    20,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    18,        /* ltr_d */
+    34,        /* lti_d */
+    20,        /* ler_d */
+    36,        /* lei_d */
+    18,        /* eqr_d */
+    34,        /* eqi_d */
+    18,        /* ger_d */
+    34,        /* gei_d */
+    18,        /* gtr_d */
+    34,        /* gti_d */
+    18,        /* ner_d */
+    34,        /* nei_d */
+    18,        /* unltr_d */
+    34,        /* unlti_d */
+    18,        /* unler_d */
+    34,        /* unlei_d */
+    24,        /* uneqr_d */
+    40,        /* uneqi_d */
+    18,        /* unger_d */
+    34,        /* ungei_d */
+    18,        /* ungtr_d */
+    34,        /* ungti_d */
+    24,        /* ltgtr_d */
+    40,        /* ltgti_d */
+    18,        /* ordr_d */
+    34,        /* ordi_d */
+    18,        /* unordr_d */
+    34,        /* unordi_d */
+    8, /* truncr_d_i */
+    0, /* truncr_d_l */
+    8, /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    16,        /* movi_d */
+    4, /* ldr_d */
+    12,        /* ldi_d */
+    8, /* ldxr_d */
+    16,        /* ldxi_d */
+    4, /* str_d */
+    12,        /* sti_d */
+    8, /* stxr_d */
+    16,        /* stxi_d */
+    12,        /* bltr_d */
+    28,        /* blti_d */
+    12,        /* bler_d */
+    28,        /* blei_d */
+    12,        /* beqr_d */
+    28,        /* beqi_d */
+    12,        /* bger_d */
+    28,        /* bgei_d */
+    12,        /* bgtr_d */
+    28,        /* bgti_d */
+    12,        /* bner_d */
+    28,        /* bnei_d */
+    16,        /* bunltr_d */
+    32,        /* bunlti_d */
+    16,        /* bunler_d */
+    32,        /* bunlei_d */
+    20,        /* buneqr_d */
+    36,        /* buneqi_d */
+    16,        /* bunger_d */
+    32,        /* bungei_d */
+    12,        /* bungtr_d */
+    28,        /* bungti_d */
+    20,        /* bltgtr_d */
+    36,        /* bltgti_d */
+    12,        /* bordr_d */
+    28,        /* bordi_d */
+    12,        /* bunordr_d */
+    28,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    4, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    4, /* movr_d_ww */
+    12,        /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __ARM_PCS_VFP */
+#endif /* __WORDSIZE */
+
+#if __WORDSIZE == 32
+#if !defined(__ARM_PCS_VFP)
+#define JIT_INSTR_MAX 160
+    0, /* data */
+    0, /* live */
+    2, /* align */
+    0, /* save */
+    0, /* load */
+    2, /* #name */
+    0, /* #note */
+    0, /* label */
+    30,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    4, /* va_start */
+    8, /* va_arg */
+    28,        /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    12,        /* addi */
+    4, /* addcr */
+    8, /* addci */
+    4, /* addxr */
+    4, /* addxi */
+    4, /* subr */
+    12,        /* subi */
+    4, /* subcr */
+    8, /* subci */
+    4, /* subxr */
+    4, /* subxi */
+    16,        /* rsbi */
+    8, /* mulr */
+    12,        /* muli */
+    4, /* qmulr */
+    12,        /* qmuli */
+    4, /* qmulr_u */
+    8, /* qmuli_u */
+    40,        /* divr */
+    48,        /* divi */
+    40,        /* divr_u */
+    44,        /* divi_u */
+    34,        /* qdivr */
+    38,        /* qdivi */
+    34,        /* qdivr_u */
+    38,        /* qdivi_u */
+    40,        /* remr */
+    48,        /* remi */
+    40,        /* remr_u */
+    44,        /* remi_u */
+    4, /* andr */
+    12,        /* andi */
+    4, /* orr */
+    12,        /* ori */
+    4, /* xorr */
+    12,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    14,        /* ltr */
+    14,        /* lti */
+    14,        /* ltr_u */
+    14,        /* lti_u */
+    14,        /* ler */
+    14,        /* lei */
+    14,        /* ler_u */
+    14,        /* lei_u */
+    14,        /* eqr */
+    14,        /* eqi */
+    14,        /* ger */
+    14,        /* gei */
+    14,        /* ger_u */
+    14,        /* gei_u */
+    14,        /* gtr */
+    14,        /* gti */
+    14,        /* gtr_u */
+    14,        /* gti_u */
+    14,        /* ner */
+    14,        /* nei */
+    4, /* movr */
+    8, /* movi */
+    8, /* extr_c */
+    4, /* extr_uc */
+    8, /* extr_s */
+    8, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    20,        /* htonr_us */
+    16,        /* htonr_ui */
+    0, /* htonr_ul */
+    4, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    12,        /* ldi_uc */
+    4, /* ldr_s */
+    12,        /* ldi_s */
+    4, /* ldr_us */
+    12,        /* ldi_us */
+    4, /* ldr_i */
+    12,        /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    4, /* ldxr_c */
+    12,        /* ldxi_c */
+    4, /* ldxr_uc */
+    12,        /* ldxi_uc */
+    4, /* ldxr_s */
+    12,        /* ldxi_s */
+    4, /* ldxr_us */
+    12,        /* ldxi_us */
+    4, /* ldxr_i */
+    12,        /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    4, /* str_c */
+    12,        /* sti_c */
+    4, /* str_s */
+    12,        /* sti_s */
+    4, /* str_i */
+    12,        /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    4, /* stxr_c */
+    12,        /* stxi_c */
+    4, /* stxr_s */
+    12,        /* stxi_s */
+    4, /* stxr_i */
+    12,        /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    8, /* bltr */
+    8, /* blti */
+    8, /* bltr_u */
+    8, /* blti_u */
+    8, /* bler */
+    8, /* blei */
+    8, /* bler_u */
+    8, /* blei_u */
+    8, /* beqr */
+    16,        /* beqi */
+    8, /* bger */
+    8, /* bgei */
+    8, /* bger_u */
+    8, /* bgei_u */
+    8, /* bgtr */
+    8, /* bgti */
+    8, /* bgtr_u */
+    8, /* bgti_u */
+    8, /* bner */
+    16,        /* bnei */
+    8, /* bmsr */
+    8, /* bmsi */
+    8, /* bmcr */
+    8, /* bmci */
+    8, /* boaddr */
+    8, /* boaddi */
+    8, /* boaddr_u */
+    8, /* boaddi_u */
+    8, /* bxaddr */
+    8, /* bxaddi */
+    8, /* bxaddr_u */
+    8, /* bxaddi_u */
+    8, /* bosubr */
+    8, /* bosubi */
+    8, /* bosubr_u */
+    8, /* bosubi_u */
+    8, /* bxsubr */
+    8, /* bxsubi */
+    8, /* bxsubr_u */
+    8, /* bxsubi_u */
+    12,        /* jmpr */
+    72,        /* jmpi */
+    4, /* callr */
+    20,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    160,       /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    40,        /* addr_f */
+    40,        /* addi_f */
+    40,        /* subr_f */
+    40,        /* subi_f */
+    40,        /* rsbi_f */
+    40,        /* mulr_f */
+    40,        /* muli_f */
+    40,        /* divr_f */
+    40,        /* divi_f */
+    12,        /* negr_f */
+    12,        /* absr_f */
+    36,        /* sqrtr_f */
+    40,        /* ltr_f */
+    44,        /* lti_f */
+    40,        /* ler_f */
+    44,        /* lei_f */
+    40,        /* eqr_f */
+    44,        /* eqi_f */
+    40,        /* ger_f */
+    44,        /* gei_f */
+    40,        /* gtr_f */
+    44,        /* gti_f */
+    44,        /* ner_f */
+    48,        /* nei_f */
+    72,        /* unltr_f */
+    80,        /* unlti_f */
+    72,        /* unler_f */
+    80,        /* unlei_f */
+    72,        /* uneqr_f */
+    80,        /* uneqi_f */
+    72,        /* unger_f */
+    80,        /* ungei_f */
+    72,        /* ungtr_f */
+    80,        /* ungti_f */
+    76,        /* ltgtr_f */
+    84,        /* ltgti_f */
+    44,        /* ordr_f */
+    48,        /* ordi_f */
+    72,        /* unordr_f */
+    80,        /* unordi_f */
+    36,        /* truncr_f_i */
+    0, /* truncr_f_l */
+    36,        /* extr_f */
+    38,        /* extr_d_f */
+    8, /* movr_f */
+    12,        /* movi_f */
+    8, /* ldr_f */
+    16,        /* ldi_f */
+    8, /* ldxr_f */
+    16,        /* ldxi_f */
+    8, /* str_f */
+    16,        /* sti_f */
+    8, /* stxr_f */
+    16,        /* stxi_f */
+    44,        /* bltr_f */
+    48,        /* blti_f */
+    44,        /* bler_f */
+    48,        /* blei_f */
+    44,        /* beqr_f */
+    52,        /* beqi_f */
+    44,        /* bger_f */
+    48,        /* bgei_f */
+    44,        /* bgtr_f */
+    48,        /* bgti_f */
+    44,        /* bner_f */
+    48,        /* bnei_f */
+    44,        /* bunltr_f */
+    48,        /* bunlti_f */
+    44,        /* bunler_f */
+    48,        /* bunlei_f */
+    76,        /* buneqr_f */
+    84,        /* buneqi_f */
+    44,        /* bunger_f */
+    48,        /* bungei_f */
+    44,        /* bungtr_f */
+    48,        /* bungti_f */
+    76,        /* bltgtr_f */
+    84,        /* bltgti_f */
+    44,        /* bordr_f */
+    48,        /* bordi_f */
+    44,        /* bunordr_f */
+    48,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    50,        /* addr_d */
+    52,        /* addi_d */
+    50,        /* subr_d */
+    52,        /* subi_d */
+    52,        /* rsbi_d */
+    50,        /* mulr_d */
+    52,        /* muli_d */
+    50,        /* divr_d */
+    52,        /* divi_d */
+    20,        /* negr_d */
+    20,        /* absr_d */
+    42,        /* sqrtr_d */
+    44,        /* ltr_d */
+    48,        /* lti_d */
+    44,        /* ler_d */
+    48,        /* lei_d */
+    44,        /* eqr_d */
+    48,        /* eqi_d */
+    44,        /* ger_d */
+    48,        /* gei_d */
+    44,        /* gtr_d */
+    48,        /* gti_d */
+    48,        /* ner_d */
+    52,        /* nei_d */
+    82,        /* unltr_d */
+    88,        /* unlti_d */
+    82,        /* unler_d */
+    88,        /* unlei_d */
+    82,        /* uneqr_d */
+    88,        /* uneqi_d */
+    82,        /* unger_d */
+    88,        /* ungei_d */
+    82,        /* ungtr_d */
+    88,        /* ungti_d */
+    86,        /* ltgtr_d */
+    92,        /* ltgti_d */
+    48,        /* ordr_d */
+    52,        /* ordi_d */
+    82,        /* unordr_d */
+    88,        /* unordi_d */
+    36,        /* truncr_d_i */
+    0, /* truncr_d_l */
+    36,        /* extr_d */
+    38,        /* extr_f_d */
+    16,        /* movr_d */
+    20,        /* movi_d */
+    16,        /* ldr_d */
+    24,        /* ldi_d */
+    20,        /* ldxr_d */
+    28,        /* ldxi_d */
+    16,        /* str_d */
+    24,        /* sti_d */
+    20,        /* stxr_d */
+    28,        /* stxi_d */
+    48,        /* bltr_d */
+    52,        /* blti_d */
+    48,        /* bler_d */
+    52,        /* blei_d */
+    48,        /* beqr_d */
+    60,        /* beqi_d */
+    48,        /* bger_d */
+    52,        /* bgei_d */
+    48,        /* bgtr_d */
+    52,        /* bgti_d */
+    48,        /* bner_d */
+    52,        /* bnei_d */
+    48,        /* bunltr_d */
+    52,        /* bunlti_d */
+    48,        /* bunler_d */
+    52,        /* bunlei_d */
+    84,        /* buneqr_d */
+    92,        /* buneqi_d */
+    48,        /* bunger_d */
+    52,        /* bungei_d */
+    48,        /* bungtr_d */
+    52,        /* bungti_d */
+    84,        /* bltgtr_d */
+    92,        /* bltgti_d */
+    48,        /* bordr_d */
+    52,        /* bordi_d */
+    48,        /* bunordr_d */
+    52,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    4, /* movr_w_f */
+    8, /* movr_ww_d */
+    0, /* movr_w_d */
+    8, /* movr_f_w */
+    8, /* movi_f_w */
+    16,        /* movr_d_ww */
+    12,        /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __ARM_PCS_VFP */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_arm-vfp.c b/deps/lightning/lib/jit_arm-vfp.c
new file mode 100644 (file)
index 0000000..743a3ef
--- /dev/null
@@ -0,0 +1,2330 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+/* as per vfp_regno macro, required due to "support" to soft float registers
+ * or using integer registers as arguments to float operations */
+#  define _D8_REGNO                    32
+#  define ARM_V_Q                      0x00000040
+#  define FPSCR_N                      0x80000000 /* Negative flag */
+#  define FPSCR_Z                      0x40000000 /* Zero flag */
+#  define FPSCR_C                      0x20000000 /* Carry flag */
+#  define FPSCR_V                      0x10000000 /* Overflow flag */
+#  define FPSCR_QC                     0x08000000 /* Cumulative saturation */
+#  define FPSCR_AHP                    0x04000000 /* Alt. half-precision */
+#  define FPSCR_DN                     0x02000000 /* Default NaN mode */
+#  define FPSCR_FZ                     0x01000000 /* Flush to zero */
+#  define FPSCR_RMASK                  0x00c00000
+#    define FPSCR_RN                   0x00000000 /* Round to Nearest */
+#    define FPSCR_RP                   0x00400000 /* Round to Plus Infinity */
+#    define FPSCR_RM                   0x00800000 /* Round to Minus Infinity */
+#    define FPSCR_RZ                   0x00c00000 /* Round towards Zero */
+#  define FPSCR_STRIDE                 0x00300000
+#  define FPSCR_RES1                   0x00080000 /* Reserved, UNK/SBZP */
+#  define FPSCR_LEN                    0x00070000
+#  define FPSCR_IDE                    0x00008000 /* Input Denormal trap */
+#  define FPSCR_IXE                    0x00001000 /* Inexact trap */
+#  define FPSCR_UFE                    0x00000800 /* Underflow trap */
+#  define FPSCR_OFE                    0x00000400 /* Overflow trap */
+#  define FPSCR_DZE                    0x00000200 /* Division by zero trap */
+#  define FPSCR_IOE                    0x00000100 /* Invalid Operation trap */
+#  define FPSCR_IDC                    0x00000080 /* Input Denormal flag */
+#  define FPSCR_RES0                   0x00000060 /* Reserved, UNK/SBZP */
+#  define FPSCR_IXC                    0x00000010 /* Inexact flag */
+#  define FPSCR_UFC                    0x00000008 /* Underflow flag */
+#  define FPSCR_OFC                    0x00000004 /* Overflow flag */
+#  define FPSCR_DZC                    0x00000002 /* Division by zero flag */
+#  define FPSCR_IOC                    0x00000001 /* Invalid Operation flag */
+#  define ARM_V_E                      0x00000080 /* ARM_VCMP except if NaN */
+#  define ARM_V_Z                      0x00010000 /* ARM_VCMP with zero */
+#  define ARM_V_F64                    0x00000100
+#  define ARM_VADD_F                   0x0e300a00
+#  define ARM_VSUB_F                   0x0e300a40
+#  define ARM_VMUL_F                   0x0e200a00
+#  define ARM_VDIV_F                   0x0e800a00
+#  define ARM_VABS_F                   0x0eb00ac0
+#  define ARM_VNEG_F                   0x0eb10a40
+#  define ARM_VSQRT_F                  0x0eb10ac0
+#  define ARM_VMOV_F                   0x0eb00a40
+#  define ARM_VMOV_A_S                 0x0e100a10 /* vmov rn, sn */
+#  define ARM_VMOV_S_A                 0x0e000a10 /* vmov sn, rn */
+#  define ARM_VMOV_AA_D                        0x0c500b10 /* vmov rn,rn, dn */
+#  define ARM_VMOV_D_AA                        0x0c400b10 /* vmov dn, rn,rn */
+#  define ARM_VCMP                     0x0eb40a40
+#  define ARM_VMRS                     0x0ef10a10
+#  define ARM_VMSR                     0x0ee10a10
+#  define ARM_VCVT_2I                  0x00040000 /* to integer */
+#  define ARM_VCVT_2S                  0x00010000 /* to signed */
+#  define ARM_VCVT_RS                  0x00000080 /* round to zero or signed */
+#  define ARM_VCVT                     0x0eb80a40
+#  define ARM_VCVT_S32_F32             ARM_VCVT|ARM_VCVT_2I|ARM_VCVT_2S|ARM_VCVT_RS
+#  define ARM_VCVT_U32_F32             ARM_VCVT|ARM_VCVT_2I|ARM_VCVT_RS
+#  define ARM_VCVT_S32_F64             ARM_VCVT|ARM_VCVT_2I|ARM_VCVT_2S|ARM_VCVT_RS|ARM_V_F64
+#  define ARM_VCVT_U32_F64             ARM_VCVT|ARM_VCVT_2I|ARM_VCVT_RS|ARM_V_F64
+#  define ARM_VCVT_F32_S32             ARM_VCVT|ARM_VCVT_RS
+#  define ARM_VCVT_F32_U32             ARM_VCVT
+#  define ARM_VCVT_F64_S32             ARM_VCVT|ARM_VCVT_RS|ARM_V_F64
+#  define ARM_VCVT_F64_U32             ARM_VCVT|ARM_V_F64
+#  define ARM_VCVT_F                   0x0eb70ac0
+#  define ARM_VCVT_F32_F64             ARM_VCVT_F
+#  define ARM_VCVT_F64_F32             ARM_VCVT_F|ARM_V_F64
+#  define ARM_VCVTR_S32_F32            ARM_VCVT|ARM_VCVT_2I|ARM_VCVT_2S
+#  define ARM_VCVTR_U32_F32            ARM_VCVT|ARM_VCVT_2I
+#  define ARM_VCVTR_S32_F64            ARM_VCVT|ARM_VCVT_2I|ARM_VCVT_2S|ARM_V_F64
+#  define ARM_VCVTR_U32_F64            ARM_VCVT|ARM_VCVT_2I|ARM_V_F64
+#  define ARM_V_D                      0x00400000
+#  define ARM_V_N                      0x00000080
+#  define ARM_V_Q                      0x00000040
+#  define ARM_V_M                      0x00000020
+#  define ARM_V_U                      0x01000000
+#  define ARM_V_I16                    0x00100000
+#  define ARM_V_I32                    0x00200000
+#  define ARM_V_I64                    0x00300000
+#  define ARM_V_S16                    0x00040000
+#  define ARM_V_S32                    0x00080000
+#  define ARM_VADD_I                   0x02000800
+#  define ARM_VQADD_I                  0x02000010 /* set flag on over/carry */
+#  define ARM_VADDL_I                  0x02800000 /* q=d+d */
+#  define ARM_VADDW_I                  0x02800100 /* q=q+d */
+#  define ARM_VSUB_I                   0x03000800
+#  define ARM_VQSUB_I                  0x02000210 /* set flag on over/carry */
+#  define ARM_VSUBL_I                  0x02800200
+#  define ARM_VSUBW_I                  0x02800300
+#  define ARM_VMUL_I                   0x02000910
+#  define ARM_VMULL_I                  0x02800c00
+#  define ARM_VABS_I                   0x03b10300
+#  define ARM_VQABS_I                  0x03b00700 /* sets flag on overflow */
+#  define ARM_VNEG_I                   0x03b10380
+#  define ARM_VQNEG_I                  0x03b00780 /* sets flag on overflow */
+#  define ARM_VAND                     0x02000110
+#  define ARM_VBIC                     0x02100110
+#  define ARM_VORR                     0x02200110
+#  define ARM_VORN                     0x02300110
+#  define ARM_VEOR                     0x03000110
+#  define ARM_VMOVL_S8                 0x00080000
+#  define ARM_VMOVL_S16                        0x00100000
+#  define ARM_VMOVL_S32                        0x00200000
+#  define ARM_VMOVL_I                  0x02800a10
+#  define ARM_VMOVI                    0x02800010
+#  define ARM_VMVNI                    0x02800030
+#  define ARM_VLDR                     0x0d100a00
+#  define ARM_VSTR                     0x0d000a00
+#  define ARM_VM                       0x0c000a00
+#  define ARM_VMOV_ADV_U               0x00800000 /* zero extend */
+#  define ARM_VMOV_ADV_8               0x00400000
+#  define ARM_VMOV_ADV_16              0x00000020
+#  define ARM_VMOV_A_D                 0x0e100b10
+#  define ARM_VMOV_D_A                 0x0e000b10
+
+#  define vodi(oi,r0)                  _vodi(_jit,oi,r0)
+static void _vodi(jit_state_t*,int,int) maybe_unused;
+#  define voqi(oi,r0)                  _voqi(_jit,oi,r0)
+static void _voqi(jit_state_t*,int,int) maybe_unused;
+#  define vo_ss(o,r0,r1)               _cc_vo_ss(_jit,ARM_CC_NV,o,r0,r1)
+#  define cc_vo_ss(cc,o,r0,r1)         _cc_vo_ss(_jit,cc,o,r0,r1)
+static void _cc_vo_ss(jit_state_t*,int,int,int,int);
+#  define vo_dd(o,r0,r1)               _cc_vo_dd(_jit,ARM_CC_NV,o,r0,r1)
+#  define cc_vo_dd(cc,o,r0,r1)         _cc_vo_dd(_jit,cc,o,r0,r1)
+static void _cc_vo_dd(jit_state_t*,int,int,int,int);
+#  define vo_qd(o,r0,r1)               _cc_vo_qd(_jit,ARM_CC_NV,o,r0,r1)
+#  define cc_vo_qd(cc,o,r0,r1)         _cc_vo_qd(_jit,cc,o,r0,r1)
+static void _cc_vo_qd(jit_state_t*,int,int,int,int) maybe_unused;
+#  define vo_qq(o,r0,r1)               _cc_vo_qq(_jit,ARM_CC_NV,o,r0,r1)
+#  define cc_vo_qq(cc,o,r0,r1)         _cc_vo_qq(_jit,cc,o,r0,r1)
+static void _cc_vo_qq(jit_state_t*,int,int,int,int) maybe_unused;
+#  define vorr_(o,r0,r1)               _cc_vorr_(_jit,ARM_CC_NV,o,r0,r1)
+#  define cc_vorr_(cc,o,r0,r1)         _cc_vorr_(_jit,cc,o,r0,r1)
+static void _cc_vorr_(jit_state_t*,int,int,int,int);
+#  define vors_(o,r0,r1)               _cc_vors_(_jit,ARM_CC_NV,o,r0,r1)
+#  define cc_vors_(cc,o,r0,r1)         _cc_vors_(_jit,cc,o,r0,r1)
+static void _cc_vors_(jit_state_t*,int,int,int,int);
+#  define vorv_(o,r0,r1)               _cc_vorv_(_jit,ARM_CC_NV,o,r0,r1)
+#  define cc_vorv_(cc,o,r0,r1)         _cc_vorv_(_jit,cc,o,r0,r1)
+static void _cc_vorv_(jit_state_t*,int,int,int,int) maybe_unused;
+#  define vori_(o,r0,r1)               _cc_vori_(_jit,ARM_CC_NV,o,r0,r1)
+#  define cc_vori_(cc,o,r0,r1)         _cc_vori_(_jit,cc,o,r0,r1)
+static void _cc_vori_(jit_state_t*,int,int,int,int);
+#  define vorrd(o,r0,r1,r2)            _cc_vorrd(_jit,ARM_CC_NV,o,r0,r1,r2)
+#  define cc_vorrd(cc,o,r0,r1,r2)      _cc_vorrd(_jit,cc,o,r0,r1,r2)
+static void _cc_vorrd(jit_state_t*,int,int,int,int,int);
+#  define vosss(o,r0,r1,r2)            _cc_vosss(_jit,ARM_CC_NV,o,r0,r1,r2)
+#  define cc_vosss(cc,o,r0,r1,r2)      _cc_vosss(_jit,cc,o,r0,r1,r2)
+static void _cc_vosss(jit_state_t*,int,int,int,int,int);
+#  define voddd(o,r0,r1,r2)            _cc_voddd(_jit,ARM_CC_NV,o,r0,r1,r2)
+#  define cc_voddd(cc,o,r0,r1,r2)      _cc_voddd(_jit,cc,o,r0,r1,r2)
+static void _cc_voddd(jit_state_t*,int,int,int,int,int);
+#  define voqdd(o,r0,r1,r2)            _cc_voqdd(_jit,ARM_CC_NV,o,r0,r1,r2)
+#  define cc_voqdd(cc,o,r0,r1,r2)      _cc_voqdd(_jit,cc,o,r0,r1,r2)
+static void _cc_voqdd(jit_state_t*,int,int,int,int,int) maybe_unused;
+#  define voqqd(o,r0,r1,r2)            _cc_voqqd(_jit,ARM_CC_NV,o,r0,r1,r2)
+#  define cc_voqqd(cc,o,r0,r1,r2)      _cc_voqqd(_jit,cc,o,r0,r1,r2)
+static void _cc_voqqd(jit_state_t*,int,int,int,int,int) maybe_unused;
+#  define voqqq(o,r0,r1,r2)            _cc_voqqq(_jit,ARM_CC_NV,o,r0,r1,r2)
+#  define cc_voqqq(cc,o,r0,r1,r2)      _cc_voqqq(_jit,cc,o,r0,r1,r2)
+static void _cc_voqqq(jit_state_t*,int,int,int,int,int) maybe_unused;
+#  define cc_vldst(cc,o,r0,r1,i0)      _cc_vldst(_jit,cc,o,r0,r1,i0)
+static void _cc_vldst(jit_state_t*,int,int,int,int,int);
+#  define cc_vorsl(cc,o,r0,r1,i0)      _cc_vorsl(_jit,cc,o,r0,r1,i0)
+static void _cc_vorsl(jit_state_t*,int,int,int,int,int);
+#  define CC_VADD_F32(cc,r0,r1,r2)     cc_vosss(cc,ARM_VADD_F,r0,r1,r2)
+#  define VADD_F32(r0,r1,r2)           CC_VADD_F32(ARM_CC_AL,r0,r1,r2)
+#  define CC_VADD_F64(cc,r0,r1,r2)     cc_voddd(cc,ARM_VADD_F|ARM_V_F64,r0,r1,r2)
+#  define VADD_F64(r0,r1,r2)           CC_VADD_F64(ARM_CC_AL,r0,r1,r2)
+#  define CC_VSUB_F32(cc,r0,r1,r2)     cc_vosss(cc,ARM_VSUB_F,r0,r1,r2)
+#  define VSUB_F32(r0,r1,r2)           CC_VSUB_F32(ARM_CC_AL,r0,r1,r2)
+#  define CC_VSUB_F64(cc,r0,r1,r2)     cc_voddd(cc,ARM_VSUB_F|ARM_V_F64,r0,r1,r2)
+#  define VSUB_F64(r0,r1,r2)           CC_VSUB_F64(ARM_CC_AL,r0,r1,r2)
+#  define CC_VMUL_F32(cc,r0,r1,r2)     cc_vosss(cc,ARM_VMUL_F,r0,r1,r2)
+#  define VMUL_F32(r0,r1,r2)           CC_VMUL_F32(ARM_CC_AL,r0,r1,r2)
+#  define CC_VMUL_F64(cc,r0,r1,r2)     cc_voddd(cc,ARM_VMUL_F|ARM_V_F64,r0,r1,r2)
+#  define VMUL_F64(r0,r1,r2)           CC_VMUL_F64(ARM_CC_AL,r0,r1,r2)
+#  define CC_VDIV_F32(cc,r0,r1,r2)     cc_vosss(cc,ARM_VDIV_F,r0,r1,r2)
+#  define VDIV_F32(r0,r1,r2)           CC_VDIV_F32(ARM_CC_AL,r0,r1,r2)
+#  define CC_VDIV_F64(cc,r0,r1,r2)     cc_voddd(cc,ARM_VDIV_F|ARM_V_F64,r0,r1,r2)
+#  define VDIV_F64(r0,r1,r2)           CC_VDIV_F64(ARM_CC_AL,r0,r1,r2)
+#  define CC_VABS_F32(cc,r0,r1)                cc_vo_ss(cc,ARM_VABS_F,r0,r1)
+#  define VABS_F32(r0,r1)              CC_VABS_F32(ARM_CC_AL,r0,r1)
+#  define CC_VABS_F64(cc,r0,r1)                cc_vo_dd(cc,ARM_VABS_F|ARM_V_F64,r0,r1)
+#  define VABS_F64(r0,r1)              CC_VABS_F64(ARM_CC_AL,r0,r1)
+#  define CC_VNEG_F32(cc,r0,r1)                cc_vo_ss(cc,ARM_VNEG_F,r0,r1)
+#  define VNEG_F32(r0,r1)              CC_VNEG_F32(ARM_CC_AL,r0,r1)
+#  define CC_VNEG_F64(cc,r0,r1)                cc_vo_dd(cc,ARM_VNEG_F|ARM_V_F64,r0,r1)
+#  define VNEG_F64(r0,r1)              CC_VNEG_F64(ARM_CC_AL,r0,r1)
+#  define CC_VSQRT_F32(cc,r0,r1)       cc_vo_ss(cc,ARM_VSQRT_F,r0,r1)
+#  define VSQRT_F32(r0,r1)             CC_VSQRT_F32(ARM_CC_AL,r0,r1)
+#  define CC_VSQRT_F64(cc,r0,r1)       cc_vo_dd(cc,ARM_VSQRT_F|ARM_V_F64,r0,r1)
+#  define VSQRT_F64(r0,r1)             CC_VSQRT_F64(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_F32(cc,r0,r1)                cc_vo_ss(cc,ARM_VMOV_F,r0,r1)
+#  define VMOV_F32(r0,r1)              CC_VMOV_F32(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_F64(cc,r0,r1)                cc_vo_dd(cc,ARM_VMOV_F|ARM_V_F64,r0,r1)
+#  define VMOV_F64(r0,r1)              CC_VMOV_F64(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_AA_D(cc,r0,r1,r2)    cc_vorrd(cc,ARM_VMOV_AA_D,r0,r1,r2)
+#  define VMOV_AA_D(r0,r1,r2)          CC_VMOV_AA_D(ARM_CC_AL,r0,r1,r2)
+#  define CC_VMOV_D_AA(cc,r0,r1,r2)    cc_vorrd(cc,ARM_VMOV_D_AA,r1,r2,r0)
+#  define VMOV_D_AA(r0,r1,r2)          CC_VMOV_D_AA(ARM_CC_AL,r0,r1,r2)
+#  define CC_VMOV_A_S(cc,r0,r1)                cc_vors_(cc,ARM_VMOV_A_S,r0,r1)
+#  define VMOV_A_S(r0,r1)              CC_VMOV_A_S(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_S_A(cc,r0,r1)                cc_vors_(cc,ARM_VMOV_S_A,r1,r0)
+#  define VMOV_S_A(r0,r1)              CC_VMOV_S_A(ARM_CC_AL,r0,r1)
+#  define CC_VCMP_F32(cc,r0,r1)                cc_vo_ss(cc,ARM_VCMP,r0,r1)
+#  define VCMP_F32(r0,r1)              CC_VCMP_F32(ARM_CC_AL,r0,r1)
+#  define CC_VCMP_F64(cc,r0,r1)                cc_vo_dd(cc,ARM_VCMP|ARM_V_F64,r0,r1)
+#  define VCMP_F64(r0,r1)              CC_VCMP_F64(ARM_CC_AL,r0,r1)
+#  define CC_VCMPE_F32(cc,r0,r1)       cc_vo_ss(cc,ARM_VCMP|ARM_V_E,r0,r1)
+#  define VCMPE_F32(r0,r1)             CC_VCMPE_F32(ARM_CC_AL,r0,r1)
+#  define CC_VCMPE_F64(cc,r0,r1)       cc_vo_dd(cc,ARM_VCMP|ARM_V_E|ARM_V_F64,r0,r1)
+#  define VCMPE_F64(r0,r1)             CC_VCMPE_F64(ARM_CC_AL,r0,r1)
+#  define CC_VCMPZ_F32(cc,r0)          cc_vo_ss(cc,ARM_VCMP|ARM_V_Z,r0,0)
+#  define VCMPZ_F32(r0)                        CC_VCMPZ_F32(ARM_CC_AL,r0)
+#  define CC_VCMPZ_F64(cc,r0)          cc_vo_dd(cc,ARM_VCMP|ARM_V_Z|ARM_V_F64,r0,0)
+#  define VCMPZ_F64(r0)                        CC_VCMPZ_F64(ARM_CC_AL,r0)
+#  define CC_VCMPEZ_F32(cc,r0)         cc_vo_ss(cc,ARM_VCMP|ARM_V_Z|ARM_V_E,r0,0)
+#  define VCMPEZ_F32(r0)               CC_VCMPEZ_F32(ARM_CC_AL,r0)
+#  define CC_VCMPEZ_F64(cc,r0)         cc_vo_dd(cc,ARM_VCMP|ARM_V_Z|ARM_V_E|ARM_V_F64,r0,0)
+#  define VCMPEZ_F64(r0)               CC_VCMPEZ_F64(ARM_CC_AL,r0)
+#  define CC_VMRS(cc,r0)               cc_vorr_(cc,ARM_VMRS,r0,0)
+#  define VMRS(r0)                     CC_VMRS(ARM_CC_AL,r0)
+#  define CC_VMSR(cc,r0)               cc_vorr_(cc,ARM_VMSR,r0,0)
+#  define VMSR(r0)                     CC_VMSR(ARM_CC_AL,r0)
+#  define CC_VCVT_S32_F32(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_S32_F32,r0,r1)
+#  define VCVT_S32_F32(r0,r1)          CC_VCVT_S32_F32(ARM_CC_AL,r0,r1)
+#  define CC_VCVT_U32_F32(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_U32_F32,r0,r1)
+#  define VCVT_U32_F32(r0,r1)          CC_VCVT_U32_F32(ARM_CC_AL,r0,r1)
+#  define CC_VCVT_S32_F64(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_S32_F64,r0,r1)
+#  define VCVT_S32_F64(r0,r1)          CC_VCVT_S32_F64(ARM_CC_AL,r0,r1)
+#  define CC_VCVT_U32_F64(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_U32_F64,r0,r1)
+#  define VCVT_U32_F64(r0,r1)          CC_VCVT_U32_F64(ARM_CC_AL,r0,r1)
+#  define CC_VCVT_F32_S32(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_F32_S32,r0,r1)
+#  define VCVT_F32_S32(r0,r1)          CC_VCVT_F32_S32(ARM_CC_AL,r0,r1)
+#  define CC_VCVT_F32_U32(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_F32_U32,r0,r1)
+#  define VCVT_F32_U32(r0,r1)          CC_VCVT_F32_U32(ARM_CC_AL,r0,r1)
+#  define CC_VCVT_F64_S32(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_F64_S32,r0,r1)
+#  define VCVT_F64_S32(r0,r1)          CC_VCVT_F64_S32(ARM_CC_AL,r0,r1)
+#  define CC_VCVT_F64_U32(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_F64_U32,r0,r1)
+#  define VCVT_F64_U32(r0,r1)          CC_VCVT_F64_U32(ARM_CC_AL,r0,r1)
+#  define CC_VCVT_F32_F64(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_F32_F64,r0,r1)
+#  define VCVT_F32_F64(r0,r1)          CC_VCVT_F32_F64(ARM_CC_AL,r0,r1)
+#  define CC_VCVT_F64_F32(cc,r0,r1)    cc_vo_ss(cc,ARM_VCVT_F64_F32,r0,r1)
+#  define VCVT_F64_F32(r0,r1)          CC_VCVT_F64_F32(ARM_CC_AL,r0,r1)
+#  define CC_VCVTR_S32_F32(cc,r0,r1)   cc_vo_ss(cc,ARM_VCVTR_S32_F32,r0,r1)
+#  define VCVTR_S32_F32(r0,r1)         CC_VCVTR_S32_F32(ARM_CC_AL,r0,r1)
+#  define CC_VCVTR_U32_F32(cc,r0,r1)   cc_vo_ss(cc,ARM_VCVTR_U32_F32,r0,r1)
+#  define VCVTR_U32_F32(r0,r1)         CC_VCVTR_U32_F32(ARM_CC_AL,r0,r1)
+#  define CC_VCVTR_S32_F64(cc,r0,r1)   cc_vo_ss(cc,ARM_VCVTR_S32_F64,r0,r1)
+#  define VCVTR_S32_F64(r0,r1)         CC_VCVTR_S32_F64(ARM_CC_AL,r0,r1)
+#  define CC_VCVTR_U32_F64(cc,r0,r1)   cc_vo_ss(cc,ARM_VCVTR_U32_F64,r0,r1)
+#  define VCVTR_U32_F64(r0,r1)         CC_VCVTR_U32_F64(ARM_CC_AL,r0,r1)
+#  define CC_VLDMIA_F32(cc,r0,r1,i0)   cc_vorsl(cc,ARM_VM|ARM_M_L|ARM_M_I,r0,r1,i0)
+#  define VLDMIA_F32(r0,r1,i0)         CC_VLDMIA_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VLDMIA_F64(cc,r0,r1,i0)   cc_vorsl(cc,ARM_VM|ARM_M_L|ARM_M_I|ARM_V_F64,r0,r1,i0)
+#  define VLDMIA_F64(r0,r1,i0)         CC_VLDMIA_F64(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTMIA_F32(cc,r0,r1,i0)   cc_vorsl(cc,ARM_VM|ARM_M_I,r0,r1,i0)
+#  define VSTMIA_F32(r0,r1,i0)         CC_VSTMIA_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTMIA_F64(cc,r0,r1,i0)   cc_vorsl(cc,ARM_VM|ARM_M_I|ARM_V_F64,r0,r1,i0)
+#  define VSTMIA_F64(r0,r1,i0)         CC_VSTMIA_F64(ARM_CC_AL,r0,r1,i0)
+#  define CC_VLDMIA_U_F32(cc,r0,r1,i0) cc_vorsl(cc,ARM_VM|ARM_M_L|ARM_M_I|ARM_M_U,r0,r1,i0)
+#  define VLDMIA_U_F32(r0,r1,i0)       CC_VLDMIA_U_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VLDMIA_U_F64(cc,r0,r1,i0) cc_vorsl(cc,ARM_VM|ARM_M_L|ARM_M_I|ARM_M_U|ARM_V_F64,r0,r1,i0)
+#  define VLDMIA_U_F64(r0,r1,i0)       CC_VLDMIA_U_F64(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTMIA_U_F32(cc,r0,r1,i0) cc_vorsl(cc,ARM_VM|ARM_M_I|ARM_M_U,r0,r1,i0)
+#  define VSTMIA_U_F32(r0,r1,i0)       CC_VSTMIA_U_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTMIA_U_F64(cc,r0,r1,i0) cc_vorsl(cc,ARM_VM|ARM_M_I|ARM_M_U|ARM_V_F64,r0,r1,i0)
+#  define VSTMIA_U_F64(r0,r1,i0)       CC_VSTMIA_U_F64(ARM_CC_AL,r0,r1,i0)
+#  define CC_VLDMDB_U_F32(cc,r0,r1,i0) cc_vorsl(cc,ARM_VM|ARM_M_L|ARM_M_B|ARM_M_U,r0,r1,i0)
+#  define VLDMDB_U_F32(r0,r1,i0)       CC_VLDMDB_U_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VLDMDB_U_F64(cc,r0,r1,i0) cc_vorsl(cc,ARM_VM|ARM_M_L|ARM_M_B|ARM_M_U|ARM_V_F64,r0,r1,i0)
+#  define VLDMDB_U_F64(r0,r1,i0)       CC_VLDMDB_U_F64(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTMDB_U_F32(cc,r0,r1,i0) cc_vorsl(cc,ARM_VM|ARM_M_B|ARM_M_U,r0,r1,i0)
+#  define VSTMDB_U_F32(r0,r1,i0)       CC_VSTMDB_U_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTMDB_U_F64(cc,r0,r1,i0) cc_vorsl(cc,ARM_VM|ARM_M_B|ARM_M_U|ARM_V_F64,r0,r1,i0)
+#  define VSTMDB_U_F64(r0,r1,i0)       CC_VSTMDB_U_F64(ARM_CC_AL,r0,r1,i0)
+#  define CC_VPUSH_F32(cc,r0,i0)       CC_VSTMDB_U_F32(cc,_SP_REGNO,r0,i0)
+#  define VPUSH_F32(r0,i0)             CC_VPUSH_F32(ARM_CC_AL,r0,i0)
+#  define CC_VPUSH_F64(cc,r0,i0)       CC_VSTMDB_U_F64(cc,_SP_REGNO,r0,i0)
+#  define VPUSH_F64(r0,i0)             CC_VPUSH_F64(ARM_CC_AL,r0,i0)
+#  define CC_VPOP_F32(cc,r0,i0)                CC_VLDMIA_U_F32(cc,_SP_REGNO,r0,i0)
+#  define VPOP_F32(r0,i0)              CC_VPOP_F32(ARM_CC_AL,r0,i0)
+#  define CC_VPOP_F64(cc,r0,i0)                CC_VLDMIA_U_F64(cc,_SP_REGNO,r0,i0)
+#  define VPOP_F64(r0,i0)              CC_VPOP_F64(ARM_CC_AL,r0,i0)
+#  define CC_VMOV_A_S8(cc,r0,r1)       cc_vorv_(cc,ARM_VMOV_A_D|ARM_VMOV_ADV_8,r0,r1)
+#  define VMOV_A_S8(r0,r1)             CC_VMOV_A_S8(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_A_U8(cc,r0,r1)       cc_vorv_(cc,ARM_VMOV_A_D|ARM_VMOV_ADV_8|ARM_VMOV_ADV_U,r0,r1)
+#  define VMOV_A_U8(r0,r1)             CC_VMOV_A_U8(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_A_S16(cc,r0,r1)      cc_vorv_(cc,ARM_VMOV_A_D|ARM_VMOV_ADV_16,r0,r1)
+#  define VMOV_A_S16(r0,r1)            CC_VMOV_A_S16(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_A_U16(cc,r0,r1)      cc_vorv_(cc,ARM_VMOV_A_D|ARM_VMOV_ADV_16|ARM_VMOV_ADV_U,r0,r1)
+#  define VMOV_A_U16(r0,r1)            CC_VMOV_A_U16(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_A_S32(cc,r0,r1)      cc_vori_(cc,ARM_VMOV_A_D,r0,r1)
+#  define VMOV_A_S32(r0,r1)            CC_VMOV_A_S32(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_A_U32(cc,r0,r1)      cc_vori_(cc,ARM_VMOV_A_D|ARM_VMOV_ADV_U,r0,r1)
+#  define VMOV_A_U32(r0,r1)            CC_VMOV_A_U32(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_V_I8(cc,r0,r1)       cc_vorv_(cc,ARM_VMOV_D_A|ARM_VMOV_ADV_8,r1,r0)
+#  define VMOV_V_I8(r0,r1)             CC_VMOV_V_I8(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_V_I16(cc,r0,r1)      cc_vorv_(cc,ARM_VMOV_D_A|ARM_VMOV_ADV_16,r1,r0)
+#  define VMOV_V_I16(r0,r1)            CC_VMOV_V_I16(ARM_CC_AL,r0,r1)
+#  define CC_VMOV_V_I32(cc,r0,r1)      cc_vori_(cc,ARM_VMOV_D_A,r1,r0)
+#  define VMOV_V_I32(r0,r1)            CC_VMOV_V_I32(ARM_CC_AL,r0,r1)
+#  define VADD_I8(r0,r1,r2)            voddd(ARM_VADD_I,r0,r1,r2)
+#  define VADDQ_I8(r0,r1,r2)           voqqq(ARM_VADD_I|ARM_V_Q,r0,r1,r2)
+#  define VADD_I16(r0,r1,r2)           voddd(ARM_VADD_I|ARM_V_I16,r0,r1,r2)
+#  define VADDQ_I16(r0,r1,r2)          voqqq(ARM_VADD_I|ARM_V_I16|ARM_V_Q,r0,r1,r2)
+#  define VADD_I32(r0,r1,r2)           voddd(ARM_VADD_I|ARM_V_I32,r0,r1,r2)
+#  define VADDQ_I32(r0,r1,r2)          voqqq(ARM_VADD_I|ARM_V_I32|ARM_V_Q,r0,r1,r2)
+#  define VADD_I64(r0,r1,r2)           voddd(ARM_VADD_I|ARM_V_I64,r0,r1,r2)
+#  define VADDQ_I64(r0,r1,r2)          voqqq(ARM_VADD_I|ARM_V_I64|ARM_V_Q,r0,r1,r2)
+#  define VQADD_S8(r0,r1,r2)           voddd(ARM_VQADD_I,r0,r1,r2)
+#  define VQADDQ_S8(r0,r1,r2)          voqqq(ARM_VQADD_I|ARM_V_Q,r0,r1,r2)
+#  define VQADD_U8(r0,r1,r2)           voddd(ARM_VQADD_I|ARM_V_U,r0,r1,r2)
+#  define VQADDQ_U8(r0,r1,r2)          voqqq(ARM_VQADD_I|ARM_V_U|ARM_V_Q,r0,r1,r2)
+#  define VQADD_S16(r0,r1,r2)          voddd(ARM_VQADD_I|ARM_V_I16,r0,r1,r2)
+#  define VQADDQ_S16(r0,r1,r2)         voqqq(ARM_VQADD_I|ARM_V_I16|ARM_V_Q,r0,r1,r2)
+#  define VQADD_U16(r0,r1,r2)          voddd(ARM_VQADD_I|ARM_V_I16|ARM_V_U,r0,r1,r2)
+#  define VQADDQ_U16(r0,r1,r2)         voqqq(ARM_VQADD_I|ARM_V_I16|ARM_V_U|ARM_V_Q,r0,r1,r2)
+#  define VQADD_S32(r0,r1,r2)          voddd(ARM_VQADD_I|ARM_V_I32,r0,r1,r2)
+#  define VQADDQ_S32(r0,r1,r2)         voqqq(ARM_VQADD_I|ARM_V_I32|ARM_V_Q,r0,r1,r2)
+#  define VQADD_U32(r0,r1,r2)          voddd(ARM_VQADD_I|ARM_V_I32|ARM_V_U,r0,r1,r2)
+#  define VQADDQ_U32(r0,r1,r2)         voqqq(ARM_VQADD_I|ARM_V_I32|ARM_V_U|ARM_V_Q,r0,r1,r2)
+#  define VQADD_S64(r0,r1,r2)          voddd(ARM_VQADD_I|ARM_V_I64,r0,r1,r2)
+#  define VQADDQ_S64(r0,r1,r2)         voqqq(ARM_VQADD_I|ARM_V_I64|ARM_V_Q,r0,r1,r2)
+#  define VQADD_U64(r0,r1,r2)          voddd(ARM_VQADD_I|ARM_V_I64|ARM_V_U,r0,r1,r2)
+#  define VQADDQ_U64(r0,r1,r2)         voqqq(ARM_VQADD_I|ARM_V_I64|ARM_V_U|ARM_V_Q,r0,r1,r2)
+#  define VADDL_S8(r0,r1,r2)           voqdd(ARM_VADDL_I,r0,r1,r2)
+#  define VADDL_U8(r0,r1,r2)           voqdd(ARM_VADDL_I|ARM_V_U,r0,r1,r2)
+#  define VADDL_S16(r0,r1,r2)          voqdd(ARM_VADDL_I|ARM_V_I16,r0,r1,r2)
+#  define VADDL_U16(r0,r1,r2)          voqdd(ARM_VADDL_I|ARM_V_I16|ARM_V_U,r0,r1,r2)
+#  define VADDL_S32(r0,r1,r2)          voqdd(ARM_VADDL_I|ARM_V_I32,r0,r1,r2)
+#  define VADDL_U32(r0,r1,r2)          voqdd(ARM_VADDL_I|ARM_V_I32|ARM_V_U,r0,r1,r2)
+#  define VADDW_S8(r0,r1,r2)           voqqd(ARM_VADDW_I,r0,r1,r2)
+#  define VADDW_U8(r0,r1,r2)           voqqd(ARM_VADDW_I|ARM_V_U,r0,r1,r2)
+#  define VADDW_S16(r0,r1,r2)          voqqd(ARM_VADDW_I|ARM_V_I16,r0,r1,r2)
+#  define VADDW_U16(r0,r1,r2)          voqqd(ARM_VADDW_I|ARM_V_I16|ARM_V_U,r0,r1,r2)
+#  define VADDW_S32(r0,r1,r2)          voqqd(ARM_VADDW_I|ARM_V_I32,r0,r1,r2)
+#  define VADDW_U32(r0,r1,r2)          voqqd(ARM_VADDW_I|ARM_V_I32|ARM_V_U,r0,r1,r2)
+#  define VSUB_I8(r0,r1,r2)            voddd(ARM_VSUB_I,r0,r1,r2)
+#  define VSUBQ_I8(r0,r1,r2)           voqqq(ARM_VSUB_I|ARM_V_Q,r0,r1,r2)
+#  define VSUB_I16(r0,r1,r2)           voddd(ARM_VSUB_I|ARM_V_I16,r0,r1,r2)
+#  define VSUBQ_I16(r0,r1,r2)          voqqq(ARM_VSUB_I|ARM_V_I16|ARM_V_Q,r0,r1,r2)
+#  define VSUB_I32(r0,r1,r2)           voddd(ARM_VSUB_I|ARM_V_I32,r0,r1,r2)
+#  define VSUBQ_I32(r0,r1,r2)          voqqq(ARM_VSUB_I|ARM_V_I32|ARM_V_Q,r0,r1,r2)
+#  define VSUB_I64(r0,r1,r2)           voddd(ARM_VSUB_I|ARM_V_I64,r0,r1,r2)
+#  define VSUBQ_I64(r0,r1,r2)          voqqq(ARM_VSUB_I|ARM_V_I64|ARM_V_Q,r0,r1,r2)
+#  define VQSUB_S8(r0,r1,r2)           voddd(ARM_VQSUB_I,r0,r1,r2)
+#  define VQSUBQ_S8(r0,r1,r2)          voqqq(ARM_VQSUB_I|ARM_V_Q,r0,r1,r2)
+#  define VQSUB_U8(r0,r1,r2)           voddd(ARM_VQSUB_I|ARM_V_U,r0,r1,r2)
+#  define VQSUBQ_U8(r0,r1,r2)          voqqq(ARM_VQSUB_I|ARM_V_U|ARM_V_Q,r0,r1,r2)
+#  define VQSUB_S16(r0,r1,r2)          voddd(ARM_VQSUB_I|ARM_V_I16,r0,r1,r2)
+#  define VQSUBQ_S16(r0,r1,r2)         voqqq(ARM_VQSUB_I|ARM_V_I16|ARM_V_Q,r0,r1,r2)
+#  define VQSUB_U16(r0,r1,r2)          voddd(ARM_VQSUB_I|ARM_V_I16|ARM_V_U,r0,r1,r2)
+#  define VQSUBQ_U16(r0,r1,r2)         voqqq(ARM_VQSUB_I|ARM_V_I16|ARM_V_U|ARM_V_Q,r0,r1,r2)
+#  define VQSUB_S32(r0,r1,r2)          voddd(ARM_VQSUB_I|ARM_V_I32,r0,r1,r2)
+#  define VQSUBQ_S32(r0,r1,r2)         voqqq(ARM_VQSUB_I|ARM_V_I32|ARM_V_Q,r0,r1,r2)
+#  define VQSUB_U32(r0,r1,r2)          voddd(ARM_VQSUB_I|ARM_V_I32|ARM_V_U,r0,r1,r2)
+#  define VQSUBQ_U32(r0,r1,r2)         voqqq(ARM_VQSUB_I|ARM_V_I32|ARM_V_U|ARM_V_Q,r0,r1,r2)
+#  define VQSUB_S64(r0,r1,r2)          voddd(ARM_VQSUB_I|ARM_V_I64,r0,r1,r2)
+#  define VQSUBQ_S64(r0,r1,r2)         voqqq(ARM_VQSUB_I|ARM_V_I64|ARM_V_Q,r0,r1,r2)
+#  define VQSUB_U64(r0,r1,r2)          voddd(ARM_VQSUB_I|ARM_V_I64|ARM_V_U,r0,r1,r2)
+#  define VQSUBQ_U64(r0,r1,r2)         voqqq(ARM_VQSUB_I|ARM_V_I64|ARM_V_U|ARM_V_Q,r0,r1,r2)
+#  define VSUBL_S8(r0,r1,r2)           voqdd(ARM_VSUBL_I,r0,r1,r2)
+#  define VSUBL_U8(r0,r1,r2)           voqdd(ARM_VSUBL_I|ARM_V_U,r0,r1,r2)
+#  define VSUBL_S16(r0,r1,r2)          voqdd(ARM_VSUBL_I|ARM_V_I16,r0,r1,r2)
+#  define VSUBL_U16(r0,r1,r2)          voqdd(ARM_VSUBL_I|ARM_V_I16|ARM_V_U,r0,r1,r2)
+#  define VSUBL_S32(r0,r1,r2)          voqdd(ARM_VSUBL_I|ARM_V_I32,r0,r1,r2)
+#  define VSUBL_U32(r0,r1,r2)          voqdd(ARM_VSUBL_I|ARM_V_I32|ARM_V_U,r0,r1,r2)
+#  define VSUBW_S8(r0,r1,r2)           voqqd(ARM_VSUBW_I,r0,r1,r2)
+#  define VSUBW_U8(r0,r1,r2)           voqqd(ARM_VSUBW_I|ARM_V_U,r0,r1,r2)
+#  define VSUBW_S16(r0,r1,r2)          voqqd(ARM_VSUBW_I|ARM_V_I16,r0,r1,r2)
+#  define VSUBW_U16(r0,r1,r2)          voqqd(ARM_VSUBW_I|ARM_V_I16|ARM_V_U,r0,r1,r2)
+#  define VSUBW_S32(r0,r1,r2)          voqqd(ARM_VSUBW_I|ARM_V_I32,r0,r1,r2)
+#  define VSUBW_U32(r0,r1,r2)          voqqd(ARM_VSUBW_I|ARM_V_I32|ARM_V_U,r0,r1,r2)
+#  define VMUL_I8(r0,r1,r2)            voddd(ARM_VMUL_I,r0,r1,r2)
+#  define VMULQ_I8(r0,r1,r2)           voqqq(ARM_VMUL_I|ARM_V_Q,r0,r1,r2)
+#  define VMUL_I16(r0,r1,r2)           voddd(ARM_VMUL_I|ARM_V_I16,r0,r1,r2)
+#  define VMULQ_I16(r0,r1,r2)          voqqq(ARM_VMUL_I|ARM_V_Q|ARM_V_I16,r0,r1,r2)
+#  define VMUL_I32(r0,r1,r2)           voddd(ARM_VMUL_I|ARM_V_I32,r0,r1,r2)
+#  define VMULQ_I32(r0,r1,r2)          voqqq(ARM_VMUL_I|ARM_V_Q|ARM_V_I32,r0,r1,r2)
+#  define VMULL_S8(r0,r1,r2)           voddd(ARM_VMULL_I,r0,r1,r2)
+#  define VMULL_U8(r0,r1,r2)           voqqq(ARM_VMULL_I|ARM_V_U,r0,r1,r2)
+#  define VMULL_S16(r0,r1,r2)          voddd(ARM_VMULL_I|ARM_V_I16,r0,r1,r2)
+#  define VMULL_U16(r0,r1,r2)          voqqq(ARM_VMULL_I|ARM_V_U|ARM_V_I16,r0,r1,r2)
+#  define VMULL_S32(r0,r1,r2)          voddd(ARM_VMULL_I|ARM_V_I32,r0,r1,r2)
+#  define VMULL_U32(r0,r1,r2)          voqqq(ARM_VMULL_I|ARM_V_U|ARM_V_I32,r0,r1,r2)
+#  define VABS_S8(r0,r1)               vo_dd(ARM_VABS_I,r0,r1)
+#  define VABSQ_S8(r0,r1)              vo_qq(ARM_VABS_I|ARM_V_Q,r0,r1)
+#  define VABS_S16(r0,r1)              vo_dd(ARM_VABS_I|ARM_V_S16,r0,r1)
+#  define VABSQ_S16(r0,r1)             vo_qq(ARM_VABS_I|ARM_V_S16|ARM_V_Q,r0,r1)
+#  define VABS_S32(r0,r1)              vo_dd(ARM_VABS_I|ARM_V_S32,r0,r1)
+#  define VABSQ_S32(r0,r1)             vo_qq(ARM_VABS_I|ARM_V_S32|ARM_V_Q,r0,r1)
+#  define VQABS_S8(r0,r1)              vo_dd(ARM_VQABS_I,r0,r1)
+#  define VQABSQ_S8(r0,r1)             vo_qq(ARM_VQABS_I|ARM_V_Q,r0,r1)
+#  define VQABS_S16(r0,r1)             vo_dd(ARM_VQABS_I|ARM_V_S16,r0,r1)
+#  define VQABSQ_S16(r0,r1)            vo_qq(ARM_VQABS_I|ARM_V_S16|ARM_V_Q,r0,r1)
+#  define VQABS_S32(r0,r1)             vo_dd(ARM_VQABS_I|ARM_V_S32,r0,r1)
+#  define VQABSQ_S32(r0,r1)            vo_qq(ARM_VQABS_I|ARM_V_S32|ARM_V_Q,r0,r1)
+#  define VNEG_S8(r0,r1)               vo_dd(ARM_VNEG_I,r0,r1)
+#  define VNEGQ_S8(r0,r1)              vo_qq(ARM_VNEG_I|ARM_V_Q,r0,r1)
+#  define VNEG_S16(r0,r1)              vo_dd(ARM_VNEG_I|ARM_V_S16,r0,r1)
+#  define VNEGQ_S16(r0,r1)             vo_qq(ARM_VNEG_I|ARM_V_S16|ARM_V_Q,r0,r1)
+#  define VNEG_S32(r0,r1)              vo_dd(ARM_VNEG_I|ARM_V_S32,r0,r1)
+#  define VNEGQ_S32(r0,r1)             vo_qq(ARM_VNEG_I|ARM_V_S32|ARM_V_Q,r0,r1)
+#  define VQNEG_S8(r0,r1)              vo_dd(ARM_VQNEG_I,r0,r1)
+#  define VQNEGQ_S8(r0,r1)             vo_qq(ARM_VQNEG_I|ARM_V_Q,r0,r1)
+#  define VQNEG_S16(r0,r1)             vo_dd(ARM_VQNEG_I|ARM_V_S16,r0,r1)
+#  define VQNEGQ_S16(r0,r1)            vo_qq(ARM_VQNEG_I|ARM_V_S16|ARM_V_Q,r0,r1)
+#  define VQNEG_S32(r0,r1)             vo_dd(ARM_VQNEG_I|ARM_V_S32,r0,r1)
+#  define VQNEGQ_S32(r0,r1)            vo_qq(ARM_VQNEG_I|ARM_V_S32|ARM_V_Q,r0,r1)
+#  define VAND(r0,r1,r2)               voddd(ARM_VAND,r0,r1,r2)
+#  define VANDQ(r0,r1,r2)              voqqq(ARM_VAND|ARM_V_Q,r0,r1,r2)
+#  define VBIC(r0,r1,r2)               voddd(ARM_VBIC,r0,r1,r2)
+#  define VBICQ(r0,r1,r2)              voqqq(ARM_VBIC|ARM_V_Q,r0,r1,r2)
+#  define VORR(r0,r1,r2)               voddd(ARM_VORR,r0,r1,r2)
+#  define VORRQ(r0,r1,r2)              voqqq(ARM_VORR|ARM_V_Q,r0,r1,r2)
+#  define VORN(r0,r1,r2)               voddd(ARM_VORN,r0,r1,r2)
+#  define VORNQ(r0,r1,r2)              voqqq(ARM_VORN|ARM_V_Q,r0,r1,r2)
+#  define VEOR(r0,r1,r2)               voddd(ARM_VEOR,r0,r1,r2)
+#  define VEORQ(r0,r1,r2)              voqqq(ARM_VEOR|ARM_V_Q,r0,r1,r2)
+#  define VMOV(r0,r1)                  VORR(r0,r1,r1)
+#  define VMOVQ(r0,r1)                 VORRQ(r0,r1,r1)
+#  define VMOVL_S8(r0,r1)              vo_qd(ARM_VMOVL_I|ARM_VMOVL_S8,r0,r1)
+#  define VMOVL_U8(r0,r1)              vo_qd(ARM_VMOVL_I|ARM_V_U|ARM_VMOVL_S8,r0,r1)
+#  define VMOVL_S16(r0,r1)             vo_qd(ARM_VMOVL_I|ARM_VMOVL_S16,r0,r1)
+#  define VMOVL_U16(r0,r1)             vo_qd(ARM_VMOVL_I|ARM_V_U|ARM_VMOVL_S16,r0,r1)
+#  define VMOVL_S32(r0,r1)             vo_qd(ARM_VMOVL_I|ARM_VMOVL_S32,r0,r1)
+#  define VMOVL_U32(r0,r1)             vo_qd(ARM_VMOVL_I|ARM_V_U|ARM_VMOVL_S32,r0,r1)
+/* "oi" should be the result of encode_vfp_double */
+#  define VIMM(oi,r0)                  vodi(oi,r0)
+#  define VIMMQ(oi,r0)                 voqi(oi|ARM_V_Q,r0)
+/* index is multipled by four */
+#  define CC_VLDRN_F32(cc,r0,r1,i0)    cc_vldst(cc,ARM_VLDR,r0,r1,i0)
+#  define VLDRN_F32(r0,r1,i0)          CC_VLDRN_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VLDR_F32(cc,r0,r1,i0)     cc_vldst(cc,ARM_VLDR|ARM_P,r0,r1,i0)
+#  define VLDR_F32(r0,r1,i0)           CC_VLDR_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VLDRN_F64(cc,r0,r1,i0)    cc_vldst(cc,ARM_VLDR|ARM_V_F64,r0,r1,i0)
+#  define VLDRN_F64(r0,r1,i0)          CC_VLDRN_F64(ARM_CC_AL,r0,r1,i0)
+#  define CC_VLDR_F64(cc,r0,r1,i0)     cc_vldst(cc,ARM_VLDR|ARM_V_F64|ARM_P,r0,r1,i0)
+#  define VLDR_F64(r0,r1,i0)           CC_VLDR_F64(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTRN_F32(cc,r0,r1,i0)    cc_vldst(cc,ARM_VSTR,r0,r1,i0)
+#  define VSTRN_F32(r0,r1,i0)          CC_VSTRN_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTR_F32(cc,r0,r1,i0)     cc_vldst(cc,ARM_VSTR|ARM_P,r0,r1,i0)
+#  define VSTR_F32(r0,r1,i0)           CC_VSTR_F32(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTRN_F64(cc,r0,r1,i0)    cc_vldst(cc,ARM_VSTR|ARM_V_F64,r0,r1,i0)
+#  define VSTRN_F64(r0,r1,i0)          CC_VSTRN_F64(ARM_CC_AL,r0,r1,i0)
+#  define CC_VSTR_F64(cc,r0,r1,i0)     cc_vldst(cc,ARM_VSTR|ARM_V_F64|ARM_P,r0,r1,i0)
+#  define VSTR_F64(r0,r1,i0)           CC_VSTR_F64(ARM_CC_AL,r0,r1,i0)
+#  define vfp_movr_f(r0,r1)            _vfp_movr_f(_jit,r0,r1)
+static void _vfp_movr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vfp_movr_d(r0,r1)            _vfp_movr_d(_jit,r0,r1)
+static void _vfp_movr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vfp_movi_f(r0,i0)            _vfp_movi_f(_jit,r0,i0)
+static void _vfp_movi_f(jit_state_t*,jit_int32_t,jit_float32_t);
+#  define vfp_movi_d(r0,i0)            _vfp_movi_d(_jit,r0,i0)
+static void _vfp_movi_d(jit_state_t*,jit_int32_t,jit_float64_t);
+#  define vfp_extr_f(r0,r1)            _vfp_extr_f(_jit,r0,r1)
+static void _vfp_extr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vfp_extr_d(r0,r1)            _vfp_extr_d(_jit,r0,r1)
+static void _vfp_extr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vfp_extr_d_f(r0,r1)          _vfp_extr_d_f(_jit,r0,r1)
+static void _vfp_extr_d_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vfp_extr_f_d(r0,r1)          _vfp_extr_f_d(_jit,r0,r1)
+static void _vfp_extr_f_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vfp_truncr_f_i(r0,r1)                _vfp_truncr_f_i(_jit,r0,r1)
+static void _vfp_truncr_f_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vfp_truncr_d_i(r0,r1)                _vfp_truncr_d_i(_jit,r0,r1)
+static void _vfp_truncr_d_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vfp_absr_f(r0,r1)            VABS_F32(r0,r1)
+#  define vfp_absr_d(r0,r1)            VABS_F64(r0,r1)
+#  define vfp_negr_f(r0,r1)            VNEG_F32(r0,r1)
+#  define vfp_negr_d(r0,r1)            VNEG_F64(r0,r1)
+#  define vfp_sqrtr_f(r0,r1)           VSQRT_F32(r0,r1)
+#  define vfp_sqrtr_d(r0,r1)           VSQRT_F64(r0,r1)
+#  define vfp_addr_f(r0,r1,r2)         VADD_F32(r0,r1,r2)
+#  define vfp_addi_f(r0,r1,i0)         _vfp_addi_f(_jit,r0,r1,i0)
+static void _vfp_addi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_addr_d(r0,r1,r2)         VADD_F64(r0,r1,r2)
+#  define vfp_addi_d(r0,r1,i0)         _vfp_addi_d(_jit,r0,r1,i0)
+static void _vfp_addi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_subr_f(r0,r1,r2)         VSUB_F32(r0,r1,r2)
+#  define vfp_subi_f(r0,r1,i0)         _vfp_subi_f(_jit,r0,r1,i0)
+static void _vfp_subi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_subr_d(r0,r1,r2)         VSUB_F64(r0,r1,r2)
+#  define vfp_subi_d(r0,r1,i0)         _vfp_subi_d(_jit,r0,r1,i0)
+static void _vfp_subi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_rsbr_f(r0,r1,r2)         vfp_subr_f(r0,r2,r1)
+#  define vfp_rsbi_f(r0,r1,i0)         _vfp_rsbi_f(_jit,r0,r1,i0)
+static void _vfp_rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_rsbr_d(r0,r1,r2)         vfp_subr_d(r0,r2,r1)
+#  define vfp_rsbi_d(r0,r1,i0)         _vfp_rsbi_d(_jit,r0,r1,i0)
+static void _vfp_rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_mulr_f(r0,r1,r2)         VMUL_F32(r0,r1,r2)
+#  define vfp_muli_f(r0,r1,i0)         _vfp_muli_f(_jit,r0,r1,i0)
+static void _vfp_muli_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_mulr_d(r0,r1,r2)         VMUL_F64(r0,r1,r2)
+#  define vfp_muli_d(r0,r1,i0)         _vfp_muli_d(_jit,r0,r1,i0)
+static void _vfp_muli_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_divr_f(r0,r1,r2)         VDIV_F32(r0,r1,r2)
+#  define vfp_divi_f(r0,r1,i0)         _vfp_divi_f(_jit,r0,r1,i0)
+static void _vfp_divi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_divr_d(r0,r1,r2)         VDIV_F64(r0,r1,r2)
+#  define vfp_divi_d(r0,r1,i0)         _vfp_divi_d(_jit,r0,r1,i0)
+static void _vfp_divi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_cmp_f(r0,r1)             _vfp_cmp_f(_jit,r0,r1)
+static void _vfp_cmp_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vfp_cmp_d(r0,r1)             _vfp_cmp_d(_jit,r0,r1)
+static void _vfp_cmp_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define vcmp01_x(c0,c1,r0)           _vcmp01_x(_jit,c0,c1,r0)
+static void _vcmp01_x(jit_state_t*,int,int,jit_int32_t);
+#  define vcmp01_f(c0,c1,r0,r1,r2)     _vcmp01_f(_jit,c0,c1,r0,r1,r2)
+static void _vcmp01_f(jit_state_t*,int,int,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vcmp01_d(c0,c1,r0,r1,r2)     _vcmp01_d(_jit,c0,c1,r0,r1,r2)
+static void _vcmp01_d(jit_state_t*,int,int,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_ltr_f(r0,r1,r2)          vcmp01_f(ARM_CC_PL,ARM_CC_MI,r0,r1,r2)
+#  define vfp_lti_f(r0,r1,i0)          _vfp_lti_f(_jit,r0,r1,i0)
+static void _vfp_lti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_ltr_d(r0,r1,r2)          vcmp01_d(ARM_CC_PL,ARM_CC_MI,r0,r1,r2)
+#  define vfp_lti_d(r0,r1,i0)          _vfp_lti_d(_jit,r0,r1,i0)
+static void _vfp_lti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_ler_f(r0,r1,r2)          vcmp01_f(ARM_CC_HS,ARM_CC_LS,r0,r1,r2)
+#  define vfp_lei_f(r0,r1,i0)          _vfp_lei_f(_jit,r0,r1,i0)
+static void _vfp_lei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_ler_d(r0,r1,r2)          vcmp01_d(ARM_CC_HS,ARM_CC_LS,r0,r1,r2)
+#  define vfp_lei_d(r0,r1,i0)          _vfp_lei_d(_jit,r0,r1,i0)
+static void _vfp_lei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_eqr_f(r0,r1,r2)          vcmp01_f(ARM_CC_NE,ARM_CC_EQ,r0,r1,r2)
+#  define vfp_eqi_f(r0,r1,i0)          _vfp_eqi_f(_jit,r0,r1,i0)
+static void _vfp_eqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_eqr_d(r0,r1,r2)          vcmp01_d(ARM_CC_NE,ARM_CC_EQ,r0,r1,r2)
+#  define vfp_eqi_d(r0,r1,i0)          _vfp_eqi_d(_jit,r0,r1,i0)
+static void _vfp_eqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_ger_f(r0,r1,r2)          vcmp01_f(ARM_CC_LT,ARM_CC_GE,r0,r1,r2)
+#  define vfp_gei_f(r0,r1,i0)          _vfp_gei_f(_jit,r0,r1,i0)
+static void _vfp_gei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_ger_d(r0,r1,r2)          vcmp01_d(ARM_CC_LT,ARM_CC_GE,r0,r1,r2)
+#  define vfp_gei_d(r0,r1,i0)          _vfp_gei_d(_jit,r0,r1,i0)
+static void _vfp_gei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_gtr_f(r0,r1,r2)          vcmp01_f(ARM_CC_LE,ARM_CC_GT,r0,r1,r2)
+#  define vfp_gti_f(r0,r1,i0)          _vfp_gti_f(_jit,r0,r1,i0)
+static void _vfp_gti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_gtr_d(r0,r1,r2)          vcmp01_d(ARM_CC_LE,ARM_CC_GT,r0,r1,r2)
+#  define vfp_gti_d(r0,r1,i0)          _vfp_gti_d(_jit,r0,r1,i0)
+static void _vfp_gti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_ner_f(r0,r1,r2)          vcmp01_f(ARM_CC_EQ,ARM_CC_NE,r0,r1,r2)
+#  define vfp_nei_f(r0,r1,i0)          _vfp_nei_f(_jit,r0,r1,i0)
+static void _vfp_nei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_ner_d(r0,r1,r2)          vcmp01_d(ARM_CC_EQ,ARM_CC_NE,r0,r1,r2)
+#  define vfp_nei_d(r0,r1,i0)          _vfp_nei_d(_jit,r0,r1,i0)
+static void _vfp_nei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vcmp10_x(c0,r0)              _vcmp10_x(_jit,c0,r0)
+static void _vcmp10_x(jit_state_t*,int,jit_int32_t);
+#  define vcmp_10_f(c0,r0,r1,r2)       _vcmp_10_f(_jit,c0,r0,r1,r2)
+static void _vcmp_10_f(jit_state_t*,int,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vcmp_10_d(c0,r0,r1,r2)       _vcmp_10_d(_jit,c0,r0,r1,r2)
+static void _vcmp_10_d(jit_state_t*,int,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_unltr_f(r0,r1,r2)                vcmp_10_f(ARM_CC_GE,r0,r1,r2)
+#  define vfp_unlti_f(r0,r1,i0)                _vfp_unlti_f(_jit,r0,r1,i0)
+static void _vfp_unlti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_unltr_d(r0,r1,r2)                vcmp_10_d(ARM_CC_GE,r0,r1,r2)
+#  define vfp_unlti_d(r0,r1,i0)                _vfp_unlti_d(_jit,r0,r1,i0)
+static void _vfp_unlti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_unler_f(r0,r1,r2)                vcmp_10_f(ARM_CC_GT,r0,r1,r2)
+#  define vfp_unlei_f(r0,r1,i0)                _vfp_unlei_f(_jit,r0,r1,i0)
+static void _vfp_unlei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_unler_d(r0,r1,r2)                vcmp_10_d(ARM_CC_GT,r0,r1,r2)
+#  define vfp_unlei_d(r0,r1,i0)                _vfp_unlei_d(_jit,r0,r1,i0)
+static void _vfp_unlei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_uneqr_x(r0)              _vfp_uneqr_x(_jit,r0)
+static void _vfp_uneqr_x(jit_state_t*,jit_int32_t);
+#  define vfp_uneqr_f(r0,r1,r2)                _vfp_uneqr_f(_jit,r0,r1,r2)
+static void _vfp_uneqr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_uneqi_f(r0,r1,i0)                _vfp_uneqi_f(_jit,r0,r1,i0)
+static void _vfp_uneqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_uneqr_d(r0,r1,r2)                _vfp_uneqr_d(_jit,r0,r1,r2)
+static void _vfp_uneqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_uneqi_d(r0,r1,i0)                _vfp_uneqi_d(_jit,r0,r1,i0)
+static void _vfp_uneqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vcmp_01_x(c0,r0)             _vcmp_01_x(_jit,c0,r0)
+static void _vcmp_01_x(jit_state_t*,int,jit_int32_t);
+#  define vcmp_01_f(c0,r0,r1,r2)       _vcmp_01_f(_jit,c0,r0,r1,r2)
+static void _vcmp_01_f(jit_state_t*,int,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vcmp_01_d(c0,r0,r1,r2)       _vcmp_01_d(_jit,c0,r0,r1,r2)
+static void _vcmp_01_d(jit_state_t*,int,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_unger_f(r0,r1,r2)                vcmp_01_f(ARM_CC_CS,r0,r1,r2)
+#  define vfp_ungei_f(r0,r1,i0)                _vfp_ungei_f(_jit,r0,r1,i0)
+static void _vfp_ungei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_unger_d(r0,r1,r2)                vcmp_01_d(ARM_CC_CS,r0,r1,r2)
+#  define vfp_ungei_d(r0,r1,i0)                _vfp_ungei_d(_jit,r0,r1,i0)
+static void _vfp_ungei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_ungtr_f(r0,r1,r2)                vcmp_01_f(ARM_CC_HI,r0,r1,r2)
+#  define vfp_ungti_f(r0,r1,i0)                _vfp_ungti_f(_jit,r0,r1,i0)
+static void _vfp_ungti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_ungtr_d(r0,r1,r2)                vcmp_01_d(ARM_CC_HI,r0,r1,r2)
+#  define vfp_ungti_d(r0,r1,i0)                _vfp_ungti_d(_jit,r0,r1,i0)
+static void _vfp_ungti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_ltgtr_x(r0)              _vfp_ltgtr_x(_jit,r0)
+static void _vfp_ltgtr_x(jit_state_t*,jit_int32_t);
+#  define vfp_ltgtr_f(r0,r1,r2)                _vfp_ltgtr_f(_jit,r0,r1,r2)
+static void _vfp_ltgtr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_ltgti_f(r0,r1,i0)                _vfp_ltgti_f(_jit,r0,r1,i0)
+static void _vfp_ltgti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_ltgtr_d(r0,r1,r2)                _vfp_ltgtr_d(_jit,r0,r1,r2)
+static void _vfp_ltgtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_ltgti_d(r0,r1,i0)                _vfp_ltgti_d(_jit,r0,r1,i0)
+static void _vfp_ltgti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_ordr_f(r0,r1,r2)         _vfp_ordr_f(_jit,r0,r1,r2)
+static void _vfp_ordr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_ordi_f(r0,r1,i0)         _vfp_ordi_f(_jit,r0,r1,i0)
+static void _vfp_ordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_ordr_d(r0,r1,r2)         _vfp_ordr_d(_jit,r0,r1,r2)
+static void _vfp_ordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_ordi_d(r0,r1,i0)         _vfp_ordi_d(_jit,r0,r1,i0)
+static void _vfp_ordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vfp_unordr_f(r0,r1,r2)       _vfp_unordr_f(_jit,r0,r1,r2)
+static void _vfp_unordr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_unordi_f(r0,r1,i0)       _vfp_unordi_f(_jit,r0,r1,i0)
+static void _vfp_unordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define vfp_unordr_d(r0,r1,r2)       _vfp_unordr_d(_jit,r0,r1,r2)
+static void _vfp_unordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_unordi_d(r0,r1,i0)       _vfp_unordi_d(_jit,r0,r1,i0)
+static void _vfp_unordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define vbcmp_x(cc,i0)               _vbcmp_x(_jit,cc,i0)
+static jit_word_t _vbcmp_x(jit_state_t*,int,jit_word_t);
+#  define vbcmp_f(cc,i0,r0,r1)         _vbcmp_f(_jit,cc,i0,r0,r1)
+static jit_word_t
+_vbcmp_f(jit_state_t*,int,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vbcmp_x(cc,i0)               _vbcmp_x(_jit,cc,i0)
+static jit_word_t _vbcmp_x(jit_state_t*,int,jit_word_t);
+#  define vbcmp_d(cc,i0,r0,r1)         _vbcmp_d(_jit,cc,i0,r0,r1)
+static jit_word_t
+_vbcmp_d(jit_state_t*,int,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_bltr_f(i0,r0,r1)         vbcmp_f(ARM_CC_MI,i0,r0,r1)
+#  define vfp_blti_f(i0,r0,i1)         _vfp_blti_f(_jit,i0,r0,i1)
+static jit_word_t _vfp_blti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bltr_d(i0,r0,r1)         vbcmp_d(ARM_CC_MI,i0,r0,r1)
+static jit_word_t _vfp_blti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_blti_d(i0,r0,i1)         _vfp_blti_d(_jit,i0,r0,i1)
+#  define vfp_bler_f(i0,r0,r1)         vbcmp_f(ARM_CC_LS,i0,r0,r1)
+#  define vfp_blei_f(i0,r0,i1)         _vfp_blei_f(_jit,i0,r0,i1)
+static jit_word_t _vfp_blei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bler_d(i0,r0,r1)         vbcmp_d(ARM_CC_LS,i0,r0,r1)
+#  define vfp_blei_d(i0,r0,i1)         _vfp_blei_d(_jit,i0,r0,i1)
+static jit_word_t _vfp_blei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_beqr_f(i0,r0,r1)         vbcmp_f(ARM_CC_EQ,i0,r0,r1)
+#  define vfp_beqi_f(i0,r0,i1)         _vfp_beqi_f(_jit,i0,r0,i1)
+static jit_word_t _vfp_beqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_beqr_d(i0,r0,r1)         vbcmp_d(ARM_CC_EQ,i0,r0,r1)
+#  define vfp_beqi_d(i0,r0,i1)         _vfp_beqi_d(_jit,i0,r0,i1)
+static jit_word_t _vfp_beqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_bger_f(i0,r0,r1)         vbcmp_f(ARM_CC_GE,i0,r0,r1)
+#  define vfp_bgei_f(i0,r0,i1)         _vfp_bgei_f(_jit,i0,r0,i1)
+static jit_word_t _vfp_bgei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bger_d(i0,r0,r1)         vbcmp_d(ARM_CC_GE,i0,r0,r1)
+#  define vfp_bgei_d(i0,r0,i1)         _vfp_bgei_d(_jit,i0,r0,i1)
+static jit_word_t _vfp_bgei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_bgtr_f(i0,r0,r1)         vbcmp_f(ARM_CC_GT,i0,r0,r1)
+#  define vfp_bgti_f(i0,r0,i1)         _vfp_bgti_f(_jit,i0,r0,i1)
+static jit_word_t _vfp_bgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bgtr_d(i0,r0,r1)         vbcmp_d(ARM_CC_GT,i0,r0,r1)
+#  define vfp_bgti_d(i0,r0,i1)         _vfp_bgti_d(_jit,i0,r0,i1)
+static jit_word_t _vfp_bgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_bner_f(i0,r0,r1)         vbcmp_f(ARM_CC_NE,i0,r0,r1)
+#  define vfp_bnei_f(i0,r0,i1)         _vfp_bnei_f(_jit,i0,r0,i1)
+static jit_word_t _vfp_bnei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bner_d(i0,r0,r1)         vbcmp_d(ARM_CC_NE,i0,r0,r1)
+#  define vfp_bnei_d(i0,r0,i1)         _vfp_bnei_d(_jit,i0,r0,i1)
+static jit_word_t _vfp_bnei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vbncmp_x(cc,i0)              _vbncmp_x(_jit,cc,i0)
+static jit_word_t _vbncmp_x(jit_state_t*,int,jit_word_t);
+#  define vbncmp_f(cc,i0,r0,r1)                _vbncmp_f(_jit,cc,i0,r0,r1)
+static jit_word_t
+_vbncmp_f(jit_state_t*,int,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vbncmp_d(cc,i0,r0,r1)                _vbncmp_d(_jit,cc,i0,r0,r1)
+static jit_word_t
+_vbncmp_d(jit_state_t*,int,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_bunltr_f(i0,r0,r1)       vbncmp_f(ARM_CC_GE,i0,r0,r1)
+#  define vfp_bunlti_f(i0,r0,i1)       _vfp_bunlti_f(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bunlti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bunltr_d(i0,r0,r1)       vbncmp_d(ARM_CC_GE,i0,r0,r1)
+#  define vfp_bunlti_d(i0,r0,i1)       _vfp_bunlti_d(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bunlti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_bunler_f(i0,r0,r1)       vbncmp_f(ARM_CC_GT,i0,r0,r1)
+#  define vfp_bunlei_f(i0,r0,i1)       _vfp_bunlei_f(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bunlei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bunler_d(i0,r0,r1)       vbncmp_d(ARM_CC_GT,i0,r0,r1)
+#  define vfp_bunlei_d(i0,r0,i1)       _vfp_bunlei_d(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bunlei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_buneqr_x(i0)             _vfp_buneqr_x(_jit,i0)
+static jit_word_t _vfp_buneqr_x(jit_state_t*,jit_word_t);
+#  define vfp_buneqr_f(i0,r0,r1)       _vfp_buneqr_f(_jit,i0,r0,r1)
+static jit_word_t
+_vfp_buneqr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_buneqi_f(i0,r0,i1)       _vfp_buneqi_f(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_buneqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_buneqr_d(i0,r0,r1)       _vfp_buneqr_d(_jit,i0,r0,r1)
+static jit_word_t
+_vfp_buneqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_buneqi_d(i0,r0,i1)       _vfp_buneqi_d(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_buneqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_bunger_x(i0)             _vfp_bunger_x(_jit,i0)
+static jit_word_t _vfp_bunger_x(jit_state_t*,jit_word_t);
+#  define vfp_bunger_f(i0,r0,r1)       _vfp_bunger_f(_jit,i0,r0,r1)
+static jit_word_t
+_vfp_bunger_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_bungei_f(i0,r0,i1)       _vfp_bungei_f(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bungei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bunger_d(i0,r0,r1)       _vfp_bunger_d(_jit,i0,r0,r1)
+static jit_word_t
+_vfp_bunger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_bungei_d(i0,r0,i1)       _vfp_bungei_d(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bungei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_bungtr_f(i0,r0,r1)       vbcmp_f(ARM_CC_HI,i0,r0,r1)
+#  define vfp_bungti_f(i0,r0,i1)       _vfp_bungti_f(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bungti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bungtr_d(i0,r0,r1)       vbcmp_d(ARM_CC_HI,i0,r0,r1)
+#  define vfp_bungti_d(i0,r0,i1)       _vfp_bungti_d(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bungti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_bltgtr_x(i0)             _vfp_bltgtr_x(_jit,i0)
+static jit_word_t _vfp_bltgtr_x(jit_state_t*,jit_word_t);
+#  define vfp_bltgtr_f(i0,r0,r1)       _vfp_bltgtr_f(_jit,i0,r0,r1)
+static jit_word_t
+_vfp_bltgtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_bltgti_f(i0,r0,i1)       _vfp_bltgti_f(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bltgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bltgtr_d(i0,r0,r1)       _vfp_bltgtr_d(_jit,i0,r0,r1)
+static jit_word_t
+_vfp_bltgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_bltgti_d(i0,r0,i1)       _vfp_bltgti_d(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bltgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_bordr_f(i0,r0,r1)                vbcmp_f(ARM_CC_VC,i0,r0,r1)
+#  define vfp_bordi_f(i0,r0,i1)                _vfp_bordi_f(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bordr_d(i0,r0,r1)                vbcmp_d(ARM_CC_VC,i0,r0,r1)
+#  define vfp_bordi_d(i0,r0,i1)                _vfp_bordi_d(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_bunordr_f(i0,r0,r1)      vbcmp_f(ARM_CC_VS,i0,r0,r1)
+#  define vfp_bunordi_f(i0,r0,i1)      _vfp_bunordi_f(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bunordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define vfp_bunordr_d(i0,r0,r1)      vbcmp_d(ARM_CC_VS,i0,r0,r1)
+#  define vfp_bunordi_d(i0,r0,i1)      _vfp_bunordi_d(_jit,i0,r0,i1)
+static jit_word_t
+_vfp_bunordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vfp_ldr_f(r0,r1)             VLDR_F32(r0,r1,0)
+#  define vfp_ldr_d(r0,r1)             VLDR_F64(r0,r1,0)
+#  define vfp_ldi_f(r0,i0)             _vfp_ldi_f(_jit,r0,i0)
+static void _vfp_ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#  define vfp_ldi_d(r0,i0)             _vfp_ldi_d(_jit,r0,i0)
+static void _vfp_ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#  define vfp_ldxr_f(r0,r1,r2)         _vfp_ldxr_f(_jit,r0,r1,r2)
+static void _vfp_ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_ldxr_d(r0,r1,r2)         _vfp_ldxr_d(_jit,r0,r1,r2)
+static void _vfp_ldxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_ldxi_f(r0,r1,i0)         _vfp_ldxi_f(_jit,r0,r1,i0)
+static void _vfp_ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define vfp_ldxi_d(r0,r1,i0)         _vfp_ldxi_d(_jit,r0,r1,i0)
+static void _vfp_ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define vfp_str_f(r0,r1)             VSTR_F32(r1,r0,0)
+#  define vfp_str_d(r0,r1)             VSTR_F64(r1,r0,0)
+#  define vfp_sti_f(i0,r0)             _vfp_sti_f(_jit,i0,r0)
+static void _vfp_sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#  define vfp_sti_d(i0,r0)             _vfp_sti_d(_jit,i0,r0)
+static void _vfp_sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#  define vfp_stxr_f(r0,r1,r2)         _vfp_stxr_f(_jit,r0,r1,r2)
+static void _vfp_stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_stxr_d(r0,r1,r2)         _vfp_stxr_d(_jit,r0,r1,r2)
+static void _vfp_stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define vfp_stxi_f(i0,r0,r1)         _vfp_stxi_f(_jit,i0,r0,r1)
+static void _vfp_stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_stxi_d(i0,r0,r1)         _vfp_stxi_d(_jit,i0,r0,r1)
+static void _vfp_stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define vfp_vaarg_d(r0, r1)          _vfp_vaarg_d(_jit, r0, r1)
+static void _vfp_vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif
+
+#if CODE
+#  define vfp_regno(rn)                (((rn) - 16) >> 1)
+
+static int
+encode_vfp_double(int mov, int inv, unsigned lo, unsigned hi)
+{
+    int                code, mode, imm, mask;
+
+    if (hi != lo) {
+       if (mov && !inv) {
+           /* (I64)
+            *  aaaaaaaabbbbbbbbccccccccddddddddeeeeeeeeffffffffgggggggghhhhhhhh
+            */
+           for (mode = 0, mask = 0xff; mode < 4; mask <<= 8, mode++) {
+               imm = lo & mask;
+               if (imm != mask && imm != 0)
+                   goto fail;
+               imm = hi & mask;
+               if (imm != mask && imm != 0)
+                   goto fail;
+           }
+           mode = 0xe20;
+           imm = (((hi & 0x80000000) >> 24) | ((hi & 0x00800000) >> 17) |
+                  ((hi & 0x00008000) >> 10) | ((hi & 0x00000080) >>  3) |
+                  ((lo & 0x80000000) >> 28) | ((lo & 0x00800000) >> 21) |
+                  ((lo & 0x00008000) >> 14) | ((lo & 0x00000080) >>  7));
+           goto success;
+       }
+       goto fail;
+    }
+    /*  (I32)
+     *  00000000 00000000 00000000 abcdefgh
+     *  00000000 00000000 abcdefgh 00000000
+     *  00000000 abcdefgh 00000000 00000000
+     *  abcdefgh 00000000 00000000 00000000 */
+    for (mode = 0, mask = 0xff; mode < 4; mask <<= 8, mode++) {
+       if ((lo & mask) == lo) {
+           imm = lo >> (mode << 3);
+           mode <<= 9;
+           goto success;
+       }
+    }
+    /*  (I16)
+     *  00000000 abcdefgh 00000000 abcdefgh
+     *  abcdefgh 00000000 abcdefgh 00000000 */
+    for (mode = 0, mask = 0xff; mode < 2; mask <<= 8, mode++) {
+       if ((lo & mask) && ((lo & (mask << 16)) >> 16) == (lo & mask)) {
+           imm = lo >> (mode << 3);
+           mode = 0x800 | (mode << 9);
+           goto success;
+       }
+    }
+    if (mov) {
+       /*  (I32)
+        *  00000000 00000000 abcdefgh 11111111
+        *  00000000 abcdefgh 11111111 11111111 */
+       for (mode = 0, mask = 0xff; mode < 2;
+            mask = (mask << 8) | 0xff, mode++) {
+           if ((lo & mask) == mask &&
+               !((lo & ~mask) >> 8) &&
+               (imm = lo >> (8 + (mode << 8)))) {
+               mode = 0xc00 | (mode << 8);
+               goto success;
+           }
+       }
+       if (!inv) {
+           /* (F32)
+            *  aBbbbbbc defgh000 00000000 00000000
+            *  from the ARM Architecture Reference Manual:
+            *  In this entry, B = NOT(b). The bit pattern represents the
+            *  floating-point number (-1)^s* 2^exp * mantissa, where
+            *  S = UInt(a),
+            *  exp = UInt(NOT(b):c:d)-3 and
+            *  mantissa = (16+UInt(e:f:g:h))/16. */
+           if ((lo & 0x7ffff) == 0 &&
+               (((lo & 0x7e000000) == 0x3e000000) ||
+                ((lo & 0x7e000000) == 0x40000000))) {
+               mode = 0xf00;
+               imm = ((lo >> 24) & 0x80) | ((lo >> 19) & 0x7f);
+               goto success;
+           }
+       }
+    }
+
+fail:
+    /* need another approach (load from memory, move from arm register, etc) */
+    return (-1);
+
+success:
+    code = inv ? ARM_VMVNI : ARM_VMOVI;
+    switch ((mode & 0xf00) >> 8) {
+       case 0x0:       case 0x2:       case 0x4:       case 0x6:
+       case 0x8:       case 0xa:
+           if (inv)    mode |= 0x20;
+           if (!mov)   mode |= 0x100;
+           break;
+       case 0x1:       case 0x3:       case 0x5:       case 0x7:
+           /* should actually not reach here */
+           assert(!inv);
+       case 0x9:       case 0xb:
+           assert(!mov);
+           break;
+       case 0xc:       case 0xd:
+           /* should actually not reach here */
+           assert(inv);
+       case 0xe:
+           assert(mode & 0x20);
+           assert(mov && !inv);
+           break;
+       default:
+           assert(!(mode & 0x20));
+           break;
+    }
+    imm = ((imm & 0x80) << 17) | ((imm & 0x70) << 12) | (imm & 0x0f);
+    code |= mode | imm;
+    if (jit_thumb_p()) {
+       if (code & 0x1000000)
+           code |= 0xff000000;
+       else
+           code |= 0xef000000;
+    }
+    else
+       code |= ARM_CC_NV;
+    return (code);
+}
+
+static void
+_vodi(jit_state_t *_jit, int oi, int r0)
+{
+    jit_thumb_t        thumb;
+    assert(!(oi  & 0x0000f000));
+    assert(!(r0 & 1)); r0 = vfp_regno(r0);
+    thumb.i = oi|(_u4(r0)<<12);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_voqi(jit_state_t *_jit, int oi, int r0)
+{
+    jit_thumb_t        thumb;
+    assert(!(oi  & 0x0000f000));
+    assert(!(r0 & 3)); r0 = vfp_regno(r0);
+    thumb.i = oi|(_u4(r0)<<12);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vo_ss(jit_state_t *_jit, int cc, int o, int r0, int r1)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000f00f));
+    if (r0 & 1)        o |= ARM_V_D;   r0 = vfp_regno(r0);
+    if (r1 & 1)        o |= ARM_V_M;   r1 = vfp_regno(r1);
+    thumb.i = cc|o|(_u4(r0)<<12)|_u4(r1);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vo_dd(jit_state_t *_jit, int cc, int o, int r0, int r1)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000f00f));
+    assert(!(r0 & 1) && !(r1 & 1));
+    r0 = vfp_regno(r0);        r1 = vfp_regno(r1);
+    thumb.i = cc|o|(_u4(r0)<<12)|_u4(r1);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vo_qd(jit_state_t *_jit, int cc, int o, int r0, int r1)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000f00f));
+    assert(!(r0 & 3) && !(r1 & 1));
+    r0 = vfp_regno(r0);        r1 = vfp_regno(r1);
+    thumb.i = cc|o|(_u4(r0)<<12)|_u4(r1);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vo_qq(jit_state_t *_jit, int cc, int o, int r0, int r1)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000f00f));
+    assert(!(r0 & 3) && !(r1 & 3));
+    r0 = vfp_regno(r0);        r1 = vfp_regno(r1);
+    thumb.i = cc|o|(_u4(r0)<<12)|_u4(r1);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vorr_(jit_state_t *_jit, int cc, int o, int r0, int r1)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000f00f));
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vors_(jit_state_t *_jit, int cc, int o, int r0, int r1)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000f00f));
+    if (r1 & 1)        o |= ARM_V_N;   r1 = vfp_regno(r1);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vorv_(jit_state_t *_jit, int cc, int o, int r0, int r1)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000f00f));
+    if (r1 & 1)        o |= ARM_V_M;   r1 = vfp_regno(r1);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vori_(jit_state_t *_jit, int cc, int o, int r0, int r1)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf000f00f));
+    /* use same bit pattern, to set opc1... */
+    if (r1 & 1)        o |= ARM_V_I32; r1 = vfp_regno(r1);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vorrd(jit_state_t *_jit, int cc, int o, int r0, int r1, int r2)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00ff00f));
+    assert(!(r2 & 1));
+    r2 = vfp_regno(r2);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12)|_u4(r2);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vosss(jit_state_t *_jit, int cc, int o, int r0, int r1, int r2)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00ff00f));
+    if (r0 & 1)        o |= ARM_V_D;   r0 = vfp_regno(r0);
+    if (r1 & 1)        o |= ARM_V_N;   r1 = vfp_regno(r1);
+    if (r2 & 1)        o |= ARM_V_M;   r2 = vfp_regno(r2);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12)|_u4(r2);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_voddd(jit_state_t *_jit, int cc, int o, int r0, int r1, int r2)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00ff00f));
+    assert(!(r0 & 1) && !(r1 & 1) && !(r2 & 1));
+    r0 = vfp_regno(r0);        r1 = vfp_regno(r1);     r2 = vfp_regno(r2);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12)|_u4(r2);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_voqdd(jit_state_t *_jit, int cc, int o, int r0, int r1, int r2)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00ff00f));
+    assert(!(r0 & 3) && !(r1 & 1) && !(r2 & 1));
+    r0 = vfp_regno(r0);        r1 = vfp_regno(r1);     r2 = vfp_regno(r2);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12)|_u4(r2);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_voqqd(jit_state_t *_jit, int cc, int o, int r0, int r1, int r2)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00ff00f));
+    assert(!(r0 & 3) && !(r1 & 3) && !(r2 & 1));
+    r0 = vfp_regno(r0);        r1 = vfp_regno(r1);     r2 = vfp_regno(r2);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12)|_u4(r2);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_voqqq(jit_state_t *_jit, int cc, int o, int r0, int r1, int r2)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00ff00f));
+    assert(!(r0 & 3) && !(r1 & 3) && !(r2 & 3));
+    r0 = vfp_regno(r0);        r1 = vfp_regno(r1);     r2 = vfp_regno(r2);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12)|_u4(r2);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vldst(jit_state_t *_jit, int cc, int o, int r0, int r1, int i0)
+{
+    jit_thumb_t        thumb;
+    /* i0 << 2 is byte offset */
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00ff0ff));
+    if (r0 & 1) {
+       assert(!(o & ARM_V_F64));
+       o |= ARM_V_D;
+    }
+    r0 = vfp_regno(r0);
+    thumb.i = cc|o|(_u4(r1)<<16)|(_u4(r0)<<12)|_u8(i0);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_cc_vorsl(jit_state_t *_jit, int cc, int o, int r0, int r1, int i0)
+{
+    jit_thumb_t        thumb;
+    assert(!(cc & 0x0fffffff));
+    assert(!(o  & 0xf00ff0ff));
+    /* save i0 double precision registers */
+    if (o & ARM_V_F64)         i0 <<= 1;
+    /* if (r1 & 1) cc & ARM_V_F64 must be false */
+    if (r1 & 1)        o |= ARM_V_D;   r1 = vfp_regno(r1);
+    assert(i0 && !(i0 & 1) && r1 + i0 <= 32);
+    thumb.i = cc|o|(_u4(r0)<<16)|(_u4(r1)<<12)|_u8(i0);
+    if (jit_thumb_p())
+       iss(thumb.s[0], thumb.s[1]);
+    else
+       ii(thumb.i);
+}
+
+static void
+_vfp_movr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1) {
+       if (jit_fpr_p(r1)) {
+           if (jit_fpr_p(r0))
+               VMOV_F32(r0, r1);
+           else
+               VMOV_A_S(r0, r1);
+       }
+       else if (jit_fpr_p(r0))
+           VMOV_S_A(r0, r1);
+       else
+           movr(r0, r1);
+    }
+}
+
+static void
+_vfp_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1) {
+       if (jit_fpr_p(r1)) {
+           if (jit_fpr_p(r0))
+               VMOV_F64(r0, r1);
+           else
+               VMOV_AA_D(r0, r0 + 1, r1);
+       }
+       else if (jit_fpr_p(r0))
+           VMOV_D_AA(r0, r1, r1 + 1);
+       else {
+           /* minor consistency check */
+           assert(r0 + 1 != r1 && r0 -1 != r1);
+           movr(r0, r1);
+           movr(r0 + 1, r1 + 1);
+       }
+    }
+}
+
+static void
+_vfp_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t i0)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } u;
+    jit_int32_t                reg;
+    jit_int32_t                code;
+    u.f = i0;
+    if (jit_fpr_p(r0)) {
+       /* float arguments are packed, for others,
+        * lightning only address even registers */
+       if (!(r0 & 1) && (r0 - 16) >= 0 &&
+           ((code = encode_vfp_double(1, 0, u.i, u.i)) != -1 ||
+            (code = encode_vfp_double(1, 1, ~u.i, ~u.i)) != -1))
+           VIMM(code, r0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), u.i);
+           VMOV_S_A(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       movi(r0, u.i);
+}
+
+static void
+_vfp_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t i0)
+{
+    union {
+       jit_int32_t     i[2];
+       jit_float64_t   d;
+    } u;
+    jit_int32_t                code;
+    jit_int32_t                rg0, rg1;
+    u.d = i0;
+    if (jit_fpr_p(r0)) {
+       if ((code = encode_vfp_double(1, 0, u.i[0], u.i[1])) != -1 ||
+           (code = encode_vfp_double(1, 1, ~u.i[0], ~u.i[1])) != -1)
+           VIMM(code, r0);
+       else {
+           rg0 = jit_get_reg(jit_class_gpr);
+           rg1 = jit_get_reg(jit_class_gpr);
+           movi(rn(rg0), u.i[0]);
+           movi(rn(rg1), u.i[1]);
+           VMOV_D_AA(r0, rn(rg0), rn(rg1));
+           jit_unget_reg(rg1);
+           jit_unget_reg(rg0);
+       }
+    }
+    else {
+       movi(r0, u.i[0]);
+       movi(r0 + 1, u.i[1]);
+    }
+}
+
+static void
+_vfp_extr_d_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       if (jit_fpr_p(r0))
+           VCVT_F64_F32(r0, r1);
+       else {
+           reg = jit_get_reg(jit_class_fpr);
+           VCVT_F64_F32(rn(reg), r1);
+           VMOV_A_S(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_fpr);
+       VMOV_S_A(rn(reg), r1);
+       VCVT_F64_F32(rn(reg), rn(reg));
+       if (jit_fpr_p(r0))
+           VMOV_F32(r0, rn(reg));
+       else
+           VMOV_A_S(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_vfp_extr_f_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       if (jit_fpr_p(r0))
+           VCVT_F32_F64(r0, r1);
+       else {
+           reg = jit_get_reg(jit_class_fpr);
+           VCVT_F32_F64(rn(reg), r1);
+           VMOV_AA_D(r0, r0 + 1, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_fpr);
+       VMOV_D_AA(rn(reg), r1, r1 + 1);
+       VCVT_F32_F64(rn(reg), rn(reg));
+       if (jit_fpr_p(r0))
+           VMOV_F64(r0, rn(reg));
+       else
+           VMOV_AA_D(r0, r0 + 1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_vfp_extr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       VMOV_V_I32(r0, r1);
+       VCVT_F32_S32(r0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_fpr);
+       VMOV_V_I32(rn(reg), r1);
+       VCVT_F32_S32(rn(reg), rn(reg));
+       VMOV_F32(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_vfp_extr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       VMOV_V_I32(r0, r1);
+       VCVT_F64_S32(r0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_fpr);
+       VMOV_V_I32(rn(reg), r1);
+       VCVT_F64_S32(rn(reg), rn(reg));
+       VMOV_F64(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_vfp_truncr_f_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    if (jit_fpr_p(r1))
+       VCVT_S32_F32(rn(reg), r1);
+    else {
+       VMOV_V_I32(rn(reg), r1);
+       VCVT_S32_F32(rn(reg), rn(reg));
+    }
+    VMOV_A_S32(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_vfp_truncr_d_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    if (jit_fpr_p(r1))
+       VCVT_S32_F64(rn(reg), r1);
+    else {
+       VMOV_V_I32(rn(reg), r1);
+       VCVT_S32_F64(rn(reg), rn(reg));
+    }
+    VMOV_A_S32(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+#  define fopi(name)                                                   \
+static void                                                            \
+_vfp_##name##i_f(jit_state_t *_jit,                                    \
+                jit_int32_t r0, jit_int32_t r1, jit_float32_t i0)      \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    vfp_movi_f(rn(reg), i0);                                           \
+    vfp_##name##r_f(r0, r1, rn(reg));                                  \
+    jit_unget_reg(reg);                                                        \
+}
+#  define dopi(name)                                                   \
+static void                                                            \
+_vfp_##name##i_d(jit_state_t *_jit,                                    \
+                jit_int32_t r0, jit_int32_t r1, jit_float64_t i0)      \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    vfp_movi_d(rn(reg), i0);                                           \
+    vfp_##name##r_d(r0, r1, rn(reg));                                  \
+    jit_unget_reg(reg);                                                        \
+}
+#  define fbopi(name)                                                  \
+static jit_word_t                                                      \
+_vfp_b##name##i_f(jit_state_t *_jit,                                   \
+                 jit_int32_t r0, jit_int32_t r1, jit_float32_t i0)     \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|                \
+                                         jit_class_nospill);           \
+    vfp_movi_f(rn(reg), i0);                                           \
+    word = vfp_b##name##r_f(r0, r1, rn(reg));                          \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+#  define dbopi(name)                                                  \
+static jit_word_t                                                      \
+_vfp_b##name##i_d(jit_state_t *_jit,                                   \
+                 jit_int32_t r0, jit_int32_t r1, jit_float64_t i0)     \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|                \
+                                         jit_class_nospill);           \
+    vfp_movi_d(rn(reg), i0);                                           \
+    word = vfp_b##name##r_d(r0, r1, rn(reg));                          \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+
+fopi(add)
+dopi(add)
+fopi(sub)
+fopi(rsb)
+dopi(rsb)
+dopi(sub)
+fopi(mul)
+dopi(mul)
+fopi(div)
+dopi(div)
+
+static void
+_vfp_cmp_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                rg0, rg1;
+    if (jit_fpr_p(r0)) {
+       if (jit_fpr_p(r1))
+           VCMP_F32(r0, r1);
+       else {
+           rg1 = jit_get_reg(jit_class_fpr);
+           VMOV_S_A(rn(rg1), r1);
+           VCMP_F32(r0, rn(rg1));
+           jit_unget_reg(rg1);
+       }
+    }
+    else {
+       rg0 = jit_get_reg(jit_class_fpr);
+       VMOV_S_A(rn(rg0), r0);
+       if (jit_fpr_p(r1))
+           VCMP_F32(rn(rg0), r1);
+       else {
+           rg1 = jit_get_reg(jit_class_fpr);
+           VMOV_S_A(rn(rg1), r1);
+           VCMP_F32(rn(rg0), rn(rg1));
+           jit_unget_reg(rg1);
+       }
+       jit_unget_reg(rg0);
+    }
+}
+
+static void
+_vfp_cmp_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                rg0, rg1;
+    if (jit_fpr_p(r0)) {
+       if (jit_fpr_p(r1))
+           VCMP_F64(r0, r1);
+       else {
+           rg1 = jit_get_reg(jit_class_fpr);
+           VMOV_D_AA(rn(rg1), r1, r1 + 1);
+           VCMP_F64(r0, rn(rg1));
+           jit_unget_reg(rg1);
+       }
+    }
+    else {
+       rg0 = jit_get_reg(jit_class_fpr);
+       VMOV_D_AA(rn(rg0), r0, r0 + 1);
+       if (jit_fpr_p(r1))
+           VCMP_F64(rn(rg0), r1);
+       else {
+           rg1 = jit_get_reg(jit_class_fpr);
+           VMOV_D_AA(rn(rg1), r1, r1 + 1);
+           VCMP_F64(rn(rg0), rn(rg1));
+           jit_unget_reg(rg1);
+       }
+       jit_unget_reg(rg0);
+    }
+}
+
+static void
+_vcmp01_x(jit_state_t *_jit, int c0, int c1, jit_int32_t r0)
+{
+    VMRS(_R15_REGNO);
+    if (jit_thumb_p()) {
+       if ((c0 ^ c1) >> 28 == 1) {
+           ITE(c0);
+           if (r0 < 8) {
+               T1_MOVI(r0, 0);
+               T1_MOVI(r0, 1);
+           }
+           else {
+               T2_MOVI(r0, 0);
+               T2_MOVI(r0, 1);
+           }
+       }
+       else {
+           if (r0 < 8) {
+               IT(c0);
+               T1_MOVI(r0, 0);
+               IT(c1);
+               T1_MOVI(r0, 1);
+           }
+           else {
+               IT(c0);
+               T2_MOVI(r0, 0);
+               IT(c1);
+               T2_MOVI(r0, 1);
+           }
+       }
+    }
+    else {
+       CC_MOVI(c0, r0, 0);
+       CC_MOVI(c1, r0, 1);
+    }
+}
+
+static void
+_vcmp01_f(jit_state_t *_jit, int c0, int c1,
+         jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_f(r1, r2);
+    vcmp01_x(c0, c1, r0);
+}
+
+static void
+_vcmp01_d(jit_state_t *_jit, int c0, int c1,
+         jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_d(r1, r2);
+    vcmp01_x(c0, c1, r0);
+}
+
+static void
+_vcmp10_x(jit_state_t *_jit, int cc, jit_int32_t r0)
+{
+    if (jit_thumb_p()) {
+       if (r0 < 8) {
+           T1_MOVI(r0, 1);
+           VMRS(_R15_REGNO);
+           IT(cc);
+           T1_MOVI(r0, 0);
+       }
+       else {
+           T2_MOVI(r0, 1);
+           VMRS(_R15_REGNO);
+           IT(cc);
+           T2_MOVI(r0, 0);
+       }
+    }
+    else {
+       VMRS(_R15_REGNO);
+       MOVI(r0, 1);
+       CC_MOVI(cc, r0, 0);
+    }
+}
+static void
+_vcmp_10_f(jit_state_t *_jit, int cc,
+          jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_f(r1, r2);
+    vcmp10_x(cc, r0);
+}
+
+static void
+_vcmp_10_d(jit_state_t *_jit, int cc,
+          jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_d(r1, r2);
+    vcmp10_x(cc, r0);
+}
+
+fopi(lt)
+dopi(lt)
+fopi(le)
+dopi(le)
+fopi(eq)
+dopi(eq)
+fopi(ge)
+dopi(ge)
+fopi(gt)
+dopi(gt)
+fopi(ne)
+dopi(ne)
+fopi(unlt)
+dopi(unlt)
+fopi(unle)
+dopi(unle)
+
+static void
+_vfp_uneqr_x(jit_state_t *_jit, jit_int32_t r0)
+{
+    VMRS(_R15_REGNO);
+    if (jit_thumb_p()) {
+       ITE(ARM_CC_NE);
+       if (r0 < 8) {
+           T1_MOVI(r0, 0);
+           T1_MOVI(r0, 1);
+           IT(ARM_CC_VS);
+           T1_MOVI(r0, 1);
+       }
+       else {
+           T2_MOVI(r0, 0);
+           T2_MOVI(r0, 1);
+           IT(ARM_CC_VS);
+           T2_MOVI(r0, 1);
+       }
+    }
+    else {
+       CC_MOVI(ARM_CC_NE, r0, 0);
+       CC_MOVI(ARM_CC_EQ, r0, 1);
+       CC_MOVI(ARM_CC_VS, r0, 1);
+    }
+}
+
+static void
+_vfp_uneqr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_f(r1, r2);
+    vfp_uneqr_x(r0);
+}
+
+fopi(uneq)
+
+static void
+_vfp_uneqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_d(r1, r2);
+    vfp_uneqr_x(r0);
+}
+
+dopi(uneq)
+
+static void
+_vcmp_01_x(jit_state_t *_jit, int cc, jit_int32_t r0)
+{
+    if (jit_thumb_p()) {
+       if (r0 < 8) {
+           T1_MOVI(r0, 0);
+           VMRS(_R15_REGNO);
+           IT(cc);
+           T1_MOVI(r0, 1);
+       }
+       else {
+           T2_MOVI(r0, 0);
+           VMRS(_R15_REGNO);
+           IT(cc);
+           T2_MOVI(r0, 1);
+       }
+    }
+    else {
+       MOVI(r0, 0);
+       VMRS(_R15_REGNO);
+       CC_MOVI(cc, r0, 1);
+    }
+}
+
+static void
+_vcmp_01_f(jit_state_t *_jit, int cc,
+          jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_f(r1, r2);
+    vcmp_01_x(cc, r0);
+}
+
+static void
+_vcmp_01_d(jit_state_t *_jit, int cc,
+          jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_d(r1, r2);
+    vcmp_01_x(cc, r0);
+}
+
+fopi(unge)
+dopi(unge)
+fopi(ungt)
+dopi(ungt)
+
+static void
+_vfp_ltgtr_x(jit_state_t *_jit, jit_int32_t r0)
+{
+    VMRS(_R15_REGNO);
+    if (jit_thumb_p()) {
+       ITE(ARM_CC_NE);
+       if (r0 < 8) {
+           T1_MOVI(r0, 1);
+           T1_MOVI(r0, 0);
+           IT(ARM_CC_VS);
+           T1_MOVI(r0, 0);
+       }
+       else {
+           T2_MOVI(r0, 1);
+           T2_MOVI(r0, 0);
+           IT(ARM_CC_VS);
+           T2_MOVI(r0, 0);
+       }
+    }
+    else {
+       CC_MOVI(ARM_CC_NE, r0, 1);
+       CC_MOVI(ARM_CC_EQ, r0, 0);
+       CC_MOVI(ARM_CC_VS, r0, 0);
+    }
+}
+
+static void
+_vfp_ltgtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_f(r1, r2);
+    vfp_ltgtr_x(r0);
+}
+
+fopi(ltgt)
+
+static void
+_vfp_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_d(r1, r2);
+    vfp_ltgtr_x(r0);
+}
+
+dopi(ltgt)
+
+static void
+_vfp_ordr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_f(r1, r2);
+    vcmp10_x(ARM_CC_VS, r0);
+}
+
+fopi(ord)
+
+static void
+_vfp_ordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_d(r1, r2);
+    vcmp10_x(ARM_CC_VS, r0);
+}
+
+dopi(ord)
+
+static void
+_vfp_unordr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_f(r1, r2);
+    vcmp_01_x(ARM_CC_VS, r0);
+}
+
+fopi(unord)
+
+static void
+_vfp_unordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    vfp_cmp_d(r1, r2);
+    vcmp_01_x(ARM_CC_VS, r0);
+}
+
+dopi(unord)
+
+static jit_word_t
+_vbcmp_x(jit_state_t *_jit, int cc, jit_word_t i0)
+{
+    jit_word_t         d, w;
+    VMRS(_R15_REGNO);
+    w = _jit->pc.w;
+    if (jit_thumb_p()) {
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(cc, encode_thumb_cc_jump(d));
+    }
+    else {
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(cc, d & 0x00ffffff);
+    }
+    return (w);
+}
+
+
+static jit_word_t
+_vbcmp_f(jit_state_t *_jit, int cc,
+        jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_f(r0, r1);
+    return (vbcmp_x(cc, i0));
+}
+
+static jit_word_t
+_vbcmp_d(jit_state_t *_jit, int cc,
+        jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_d(r0, r1);
+    return (vbcmp_x(cc, i0));
+}
+
+static jit_word_t
+_vbncmp_x(jit_state_t *_jit, int cc, jit_word_t i0)
+{
+    jit_word_t         d, p, w;
+    VMRS(_R15_REGNO);
+    p = _jit->pc.w;
+    if (jit_thumb_p()) {
+       T2_CC_B(cc, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_B(encode_thumb_jump(d));
+    }
+    else {
+       CC_B(cc, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       B(d & 0x00ffffff);
+    }
+    patch_at(arm_patch_jump, p, _jit->pc.w);
+    return (w);
+}
+
+static jit_word_t
+_vbncmp_f(jit_state_t *_jit, int cc,
+         jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_f(r0, r1);
+    return (vbncmp_x(cc, i0));
+}
+
+static jit_word_t
+_vbncmp_d(jit_state_t *_jit, int cc,
+         jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_d(r0, r1);
+    return (vbncmp_x(cc, i0));
+}
+
+fbopi(lt)
+dbopi(lt)
+fbopi(le)
+dbopi(le)
+fbopi(eq)
+dbopi(eq)
+fbopi(ge)
+dbopi(ge)
+fbopi(gt)
+dbopi(gt)
+fbopi(ne)
+dbopi(ne)
+fbopi(unlt)
+dbopi(unlt)
+fbopi(unle)
+dbopi(unle)
+
+static jit_word_t
+_vfp_buneqr_x(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         d, p, q, w;
+    VMRS(_R15_REGNO);
+    p = _jit->pc.w;
+    if (jit_thumb_p()) {
+       T2_CC_B(ARM_CC_VS, 0);
+       q = _jit->pc.w;
+       T2_CC_B(ARM_CC_NE, 0);
+       patch_at(arm_patch_jump, p, _jit->pc.w);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_B(encode_thumb_jump(d));
+    }
+    else {
+       CC_B(ARM_CC_VS, 0);
+       q = _jit->pc.w;
+       CC_B(ARM_CC_NE, 0);
+       patch_at(arm_patch_jump, p, _jit->pc.w);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       B(d & 0x00ffffff);
+    }
+    patch_at(arm_patch_jump, q, _jit->pc.w);
+    return (w);
+}
+
+static jit_word_t
+_vfp_buneqr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_f(r0, r1);
+    return (vfp_buneqr_x(i0));
+}
+
+fbopi(uneq)
+
+static jit_word_t
+_vfp_buneqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_d(r0, r1);
+    return (vfp_buneqr_x(i0));
+}
+
+dbopi(uneq)
+
+static jit_word_t
+_vfp_bunger_x(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         d, p, w;
+    VMRS(_R15_REGNO);
+    p = _jit->pc.w;
+    if (jit_thumb_p()) {
+       T2_CC_B(ARM_CC_MI, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_CC_B(ARM_CC_HS, encode_thumb_cc_jump(d));
+    }
+    else {
+       CC_B(ARM_CC_MI, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       CC_B(ARM_CC_HS, d & 0x00ffffff);
+    }
+    patch_at(arm_patch_jump, p, _jit->pc.w);
+    return (w);
+}
+
+static jit_word_t
+_vfp_bunger_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_f(r0, r1);
+    return (vfp_bunger_x(i0));
+}
+
+fbopi(unge)
+
+static jit_word_t
+_vfp_bunger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_d(r0, r1);
+    return (vfp_bunger_x(i0));
+}
+
+dbopi(unge)
+
+static jit_word_t
+_vfp_bltgtr_x(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         d, p, q, w;
+    VMRS(_R15_REGNO);
+    p = _jit->pc.w;
+    if (jit_thumb_p()) {
+       T2_CC_B(ARM_CC_VS, 0);
+       q = _jit->pc.w;
+       T2_CC_B(ARM_CC_EQ, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 1) - 2;
+       assert(_s20P(d));
+       T2_B(encode_thumb_jump(d));
+    }
+    else {
+       CC_B(ARM_CC_VS, 0);
+       q = _jit->pc.w;
+       CC_B(ARM_CC_EQ, 0);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 2;
+       assert(_s24P(d));
+       B(d & 0x00ffffff);
+    }
+    patch_at(arm_patch_jump, p, _jit->pc.w);
+    patch_at(arm_patch_jump, q, _jit->pc.w);
+    return (w);
+}
+
+static jit_word_t
+_vfp_bltgtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_f(r0, r1);
+    return (vfp_bltgtr_x(i0));
+}
+
+fbopi(ungt)
+dbopi(ungt)
+fbopi(ltgt)
+
+static jit_word_t
+_vfp_bltgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    vfp_cmp_d(r0, r1);
+    return (vfp_bltgtr_x(i0));
+}
+
+dbopi(ltgt)
+fbopi(ord)
+dbopi(ord)
+fbopi(unord)
+dbopi(unord)
+
+static void
+_vfp_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                gpr;
+    if (jit_fpr_p(r0)) {
+       gpr = jit_get_reg(jit_class_gpr);
+       movi(rn(gpr), i0);
+       VLDR_F32(r0, rn(gpr), 0);
+       jit_unget_reg(gpr);
+    }
+    else
+       ldi_i(r0, i0);
+}
+
+static void
+_vfp_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_fpr_p(r0))
+       VLDR_F64(r0, rn(reg), 0);
+    else {
+       ldr_i(r0, rn(reg));
+       ldxi_i(r0 + 1, rn(reg), 4);
+    }
+    jit_unget_reg(reg);
+}
+
+static void
+_vfp_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       addr(rn(reg), r1, r2);
+       VLDR_F32(r0, rn(reg), 0);
+       jit_unget_reg(reg);
+    }
+    else
+       ldxr_i(r0, r1, r2);
+}
+
+static void
+_vfp_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    if (jit_fpr_p(r0))
+       VLDR_F64(r0, rn(reg), 0);
+    else {
+       ldr_i(r0, rn(reg));
+       ldxi_i(r0 + 1, rn(reg), 4);
+    }
+    jit_unget_reg(reg);
+}
+
+static void
+_vfp_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       if (i0 >= 0) {
+           assert(!(i0 & 3));
+           if (i0 < 1024)
+               VLDR_F32(r0, r1, i0 >> 2);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               addi(rn(reg), r1, i0);
+               VLDR_F32(r0, rn(reg), 0);
+               jit_unget_reg(reg);
+           }
+       }
+       else {
+           i0 = -i0;
+           assert(!(i0 & 3));
+           if (i0 < 1024)
+               VLDRN_F32(r0, r1, i0 >> 2);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               subi(rn(reg), r1, i0);
+               VLDR_F32(r0, rn(reg), 0);
+               jit_unget_reg(reg);
+           }
+       }
+    }
+    else
+       ldxi_i(r0, r1, i0);
+}
+
+static void
+_vfp_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       if (i0 >= 0) {
+           assert(!(i0 & 3));
+           if (i0 < 1024)
+               VLDR_F64(r0, r1, i0 >> 2);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               addi(rn(reg), r1, i0);
+               VLDR_F64(r0, rn(reg), 0);
+               jit_unget_reg(reg);
+           }
+       }
+       else {
+           i0 = -i0;
+           assert(!(i0 & 3));
+           if (i0 < 1024)
+               VLDRN_F64(r0, r1, i0 >> 2);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               subi(rn(reg), r1, i0);
+               VLDR_F64(r0, rn(reg), 0);
+               jit_unget_reg(reg);
+           }
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_i(r0, rn(reg));
+       ldxi_i(r0 + 1, rn(reg), 4);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_vfp_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       VSTR_F32(r0, rn(reg), 0);
+       jit_unget_reg(reg);
+    }
+    else
+       sti_i(i0, r0);
+}
+
+static void
+_vfp_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (jit_fpr_p(r0))
+       VSTR_F64(r0, rn(reg), 0);
+    else {
+       str_i(rn(reg), r0);
+       stxi_i(4, rn(reg), r0 + 1);
+    }
+    jit_unget_reg(reg);
+}
+
+static void
+_vfp_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r2)) {
+       reg = jit_get_reg(jit_class_gpr);
+       addr(rn(reg), r0, r1);
+       VSTR_F32(r2, rn(reg), 0);
+       jit_unget_reg(reg);
+    }
+    else
+       stxr_i(r0, r1, r2);
+}
+
+static void
+_vfp_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    if (jit_fpr_p(r2))
+       VSTR_F64(r2, rn(reg), 0);
+    else {
+       str_i(rn(reg), r2);
+       stxi_i(4, rn(reg), r2 + 1);
+    }
+    jit_unget_reg(reg);
+}
+
+static void
+_vfp_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       if (i0 >= 0) {
+           assert(!(i0 & 3));
+           if (i0 < 1024)
+               VSTR_F32(r1, r0, i0 >> 2);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               addi(rn(reg), r0, i0);
+               VSTR_F32(r1, rn(reg), 0);
+               jit_unget_reg(reg);
+           }
+       }
+       else {
+           i0 = -i0;
+           assert(!(i0 & 3));
+           if (i0 < 1024)
+               VSTRN_F32(r1, r0, i0 >> 2);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               subi(rn(reg), r0, i0);
+               VSTR_F32(r1, rn(reg), 0);
+               jit_unget_reg(reg);
+           }
+       }
+    }
+    else
+       stxi_i(i0, r0, r1);
+}
+
+static void
+_vfp_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (jit_fpr_p(r1)) {
+       if (i0 >= 0) {
+           assert(!(i0 & 3));
+           if (i0 < 0124)
+               VSTR_F64(r1, r0, i0 >> 2);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               addi(rn(reg), r0, i0);
+               VSTR_F64(r1, rn(reg), 0);
+               jit_unget_reg(reg);
+           }
+       }
+       else {
+           i0 = -i0;
+           assert(!(i0 & 3));
+           if (i0 < 1024)
+               VSTRN_F64(r1, r0, i0 >> 2);
+           else {
+               reg = jit_get_reg(jit_class_gpr);
+               subi(rn(reg), r0, i0);
+               VSTR_F64(r1, rn(reg), 0);
+               jit_unget_reg(reg);
+           }
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_i(rn(reg), r1);
+       stxi_i(4, rn(reg), r1 + 1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_vfp_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Adjust pointer. */
+    reg = jit_get_reg(jit_class_gpr);
+    andi(rn(reg), r1, 7);
+    addr(r1, r1, rn(reg));
+    jit_unget_reg(reg);
+
+    /* Load argument. */
+    vfp_ldr_d(r0, r1);
+
+    /* Update stack pointer. */
+    addi(r1, r1, sizeof(jit_float64_t));
+}
+#  undef dbopi
+#  undef fbopi
+#  undef dopi
+#  undef fopi
+#endif
diff --git a/deps/lightning/lib/jit_arm.c b/deps/lightning/lib/jit_arm.c
new file mode 100644 (file)
index 0000000..783fa90
--- /dev/null
@@ -0,0 +1,2274 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if defined(__linux__)
+#  include <stdio.h>
+#endif
+
+#define jit_arg_reg_p(i)               ((i) >= 0 && (i) < 4)
+#define jit_arg_f_reg_p(i)             ((i) >= 0 && (i) < 16)
+#define jit_arg_d_reg_p(i)             ((i) >= 0 && (i) < 15)
+
+#define arm_patch_node                 0x80000000
+#define arm_patch_word                 0x40000000
+#define arm_patch_jump                 0x20000000
+#define arm_patch_load                 0x00000000
+
+#define jit_fpr_p(rn)                  ((rn) > 15)
+
+#define arg_base()                                                     \
+    (stack_framesize - 16 + (jit_cpu.abi ? 64 : 0))
+#define arg_offset(n)                                                  \
+    ((n) < 4 ? arg_base() + ((n) << 2) : (n))
+
+/* Assume functions called never match jit instruction set, that is
+ * libc, gmp, mpfr, etc functions are in thumb mode and jit is in
+ * arm mode, what may cause a crash upon return of that function
+ * if generating jit for a relative jump.
+ */
+#define jit_exchange_p()               1
+
+/* FIXME is it really required to not touch _R10? */
+
+/*
+ * Types
+ */
+typedef union _jit_thumb_t {
+    jit_int32_t                i;
+    jit_int16_t                s[2];
+} jit_thumb_t;
+
+typedef jit_pointer_t  jit_va_list;
+
+/*
+ * Prototypes
+ */
+#define jit_make_arg(node)             _jit_make_arg(_jit,node)
+static jit_node_t *_jit_make_arg(jit_state_t*,jit_node_t*);
+#define jit_make_arg_f(node)           _jit_make_arg_f(_jit,node)
+static jit_node_t *_jit_make_arg_f(jit_state_t*,jit_node_t*);
+#define jit_make_arg_d(node)           _jit_make_arg_d(_jit,node)
+static jit_node_t *_jit_make_arg_d(jit_state_t*,jit_node_t*);
+#define jit_get_reg_pair()             _jit_get_reg_pair(_jit)
+static jit_int32_t _jit_get_reg_pair(jit_state_t*);
+#define jit_unget_reg_pair(rn)         _jit_unget_reg_pair(_jit,rn)
+static void _jit_unget_reg_pair(jit_state_t*,jit_int32_t);
+# define must_align_p(node)            _must_align_p(_jit, node)
+static jit_bool_t _must_align_p(jit_state_t*,jit_node_t*);
+#define load_const(uniq,r0,i0)         _load_const(_jit,uniq,r0,i0)
+static void _load_const(jit_state_t*,jit_bool_t,jit_int32_t,jit_word_t);
+#define flush_consts()                 _flush_consts(_jit)
+static void _flush_consts(jit_state_t*);
+#define invalidate_consts()            _invalidate_consts(_jit)
+static void _invalidate_consts(jit_state_t*);
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+#if defined(__GNUC__)
+/* libgcc */
+extern void __clear_cache(void *, void *);
+#endif
+
+#define PROTO                          1
+#  include "jit_rewind.c"
+#  include "jit_arm-cpu.c"
+#  include "jit_arm-swf.c"
+#  include "jit_arm-vfp.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_cpu_t              jit_cpu;
+jit_register_t         _rvs[] = {
+    { rc(gpr) | 0x0c,                  "ip" },
+    { rc(sav) | rc(gpr) | 0x04,                "r4" },
+    { rc(sav) | rc(gpr) | 0x05,                "r5" },
+    { rc(sav) | rc(gpr) | 0x06,                "r6" },
+    { rc(sav) | rc(gpr) | 0x07,                "r7" },
+    { rc(sav) | rc(gpr) | 0x08,                "r8" },
+    { rc(sav) | rc(gpr) | 0x09,                "r9" },
+    { rc(sav) | 0x0a,                  "sl" },
+    { rc(sav) | 0x0b,                  "fp" },
+    { rc(sav) | 0x0d,                  "sp" },
+    { rc(sav) | 0x0e,                  "lr" },
+    { 0x0f,                            "pc" },
+    { rc(arg) | rc(gpr) | 0x03,                "r3" },
+    { rc(arg) | rc(gpr) | 0x02,                "r2" },
+    { rc(arg) | rc(gpr) | 0x01,                "r1" },
+    { rc(arg) | rc(gpr) | 0x00,                "r0" },
+    { rc(fpr) | 0x20,                  "d8" },
+    { 0x21,                            "s17" },
+    { rc(fpr) | 0x22,                  "d9" },
+    { 0x23,                            "s19" },
+    { rc(fpr) | 0x24,                  "d10" },
+    { 0x25,                            "s21" },
+    { rc(fpr) | 0x26,                  "d11" },
+    { 0x27,                            "s23" },
+    { rc(fpr) | 0x28,                  "d12" },
+    { 0x29,                            "s25" },
+    { rc(fpr) | 0x2a,                  "d13" },
+    { 0x2b,                            "s27" },
+    { rc(fpr) | 0x2c,                  "d14" },
+    { 0x2d,                            "s29" },
+    { rc(fpr) | 0x2e,                  "d15" },
+    { 0x2f,                            "s31" },
+    { rc(arg) | 0x1f,                  "s15" },
+    { rc(arg)|rc(sft)|rc(fpr)|0x1e,    "d7" },
+    { rc(arg) | 0x1d,                  "s13" },
+    { rc(arg)|rc(sft)|rc(fpr)|0x1c,    "d6" },
+    { rc(arg) | 0x1b,                  "s11" },
+    { rc(arg)|rc(sft)|rc(fpr)|0x1a,    "d5" },
+    { rc(arg) | 0x19,                  "s9" },
+    { rc(arg)|rc(sft)|rc(fpr)|0x18,    "d4" },
+    { rc(arg) | 0x17,                  "s7" },
+    { rc(arg)|rc(sft)|rc(fpr)|0x16,    "d3" },
+    { rc(arg) | 0x15,                  "s5" },
+    { rc(arg)|rc(sft)|rc(fpr)|0x14,    "d2" },
+    { rc(arg) | 0x13,                  "s3" },
+    { rc(arg)|rc(sft)|rc(fpr)|0x12,    "d1" },
+    { rc(arg) | 0x11,                  "s1" },
+    { rc(arg)|rc(sft)|rc(fpr)|0x10,    "d0" },
+    { _NOREG,                          "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+#if defined(__linux__)
+    FILE       *fp;
+    char       *ptr;
+    char        buf[128];
+
+    if ((fp = fopen("/proc/cpuinfo", "r")) != NULL) {
+       while (fgets(buf, sizeof(buf), fp)) {
+           if (strncmp(buf, "CPU architecture:", 17) == 0) {
+               jit_cpu.version = strtol(buf + 17, &ptr, 10);
+               while (*ptr) {
+                   if (*ptr == 'T' || *ptr == 't') {
+                       ++ptr;
+                       jit_cpu.thumb = 1;
+                   }
+                   else if (*ptr == 'E' || *ptr == 'e') {
+                       jit_cpu.extend = 1;
+                       ++ptr;
+                   }
+                   else
+                       ++ptr;
+               }
+           }
+           else if (strncmp(buf, "Features\t:", 10) == 0) {
+               if ((ptr = strstr(buf + 10, "vfpv")))
+                   jit_cpu.vfp = strtol(ptr + 4, NULL, 0);
+               if ((ptr = strstr(buf + 10, "neon")))
+                   jit_cpu.neon = 1;
+               if ((ptr = strstr(buf + 10, "thumb")))
+                   jit_cpu.thumb = 1;
+           }
+       }
+       fclose(fp);
+    }
+#endif
+#if defined(__ARM_PCS_VFP)
+    if (!jit_cpu.vfp)
+       jit_cpu.vfp = 3;
+    if (!jit_cpu.version)
+       jit_cpu.version = 7;
+    jit_cpu.abi = 1;
+#endif
+#if defined(__thumb2__)
+    jit_cpu.thumb = 1;
+#endif
+    /* armv6t2 todo (software float and thumb2) */
+    if (!jit_cpu.vfp && jit_cpu.thumb)
+       jit_cpu.thumb = 0;
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    jit_int32_t                regno;
+    static jit_bool_t  first = 1;
+
+    _jitc->reglen = jit_size(_rvs) - 1;
+    if (first) {
+       /* jit_get_cpu() should have been already called, and only once */
+       if (!jit_cpu.vfp) {
+           /* cause register to never be allocated, because simple
+            * software float only allocates stack space for 8 slots  */
+           for (regno = _D8; regno < _D7; regno++)
+               _rvs[regno].spec = 0;
+       }
+       if (!jit_cpu.abi) {
+           for (regno = _S15; regno <= _D0; regno++)
+               _rvs[regno].spec &= ~rc(arg);
+       }
+       first = 0;
+    }
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                 offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = stack_framesize;
+    if (jit_cpu.abi)
+       _jitc->function->self.size += 64;
+    _jitc->function->self.argi = _jitc->function->self.argf =
+       _jitc->function->self.alen = 0;
+    if (jit_swf_p())
+       /* 8 soft float registers */
+       _jitc->function->self.aoff = -64;
+    else
+       _jitc->function->self.aoff = 0;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    return (_jitc->function->self.aoff);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 reg;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    jit_negr(reg, v);
+    jit_andi(reg, reg, -8);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, reg);
+    jit_addr(JIT_SP, JIT_SP, reg);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(reg);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    if (JIT_RET != u)
+       jit_movr(JIT_RET, u);
+    jit_live(JIT_RET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    if (jit_cpu.abi) {
+       if (u != JIT_FRET)
+           jit_movr_f(JIT_FRET, u);
+       else
+           jit_live(JIT_FRET);
+    }
+    else {
+       if (u != JIT_RET)
+           jit_movr_f_w(JIT_RET, u);
+       else
+           jit_live(JIT_RET);
+    }
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    if (jit_cpu.abi)
+       jit_movi_f(JIT_FRET, u);
+    else
+       jit_movi_f_w(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    if (jit_cpu.abi) {
+       if (u != JIT_FRET)
+           jit_movr_d(JIT_FRET, u);
+       else
+           jit_live(JIT_FRET);
+    }
+    else {
+       if (u != JIT_RET)
+           jit_movr_d_ww(JIT_RET, _R1, u);
+       else
+           jit_live(JIT_RET);
+    }
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    if (jit_cpu.abi)
+       jit_movi_d(JIT_FRET, u);
+    else
+       jit_movi_d_ww(JIT_RET, _R1, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    if (u->code != jit_code_arg) {
+       if (u->code == jit_code_arg_f) {
+           if (jit_cpu.abi)
+               return (jit_arg_f_reg_p(u->u.w));
+       }
+       else {
+           assert(u->code == jit_code_arg_d);
+           if (jit_cpu.abi)
+               return (jit_arg_d_reg_p(u->u.w));
+       }
+    }
+    return (jit_arg_reg_p(u->u.w));
+}
+
+static jit_node_t *
+_jit_make_arg(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                 offset;
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    if (node == (jit_node_t *)0)
+       node = jit_new_node(jit_code_arg);
+    else
+       link_node(node);
+    node->u.w = offset;
+    node->v.w = ++_jitc->function->self.argn;
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_make_arg_f(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                 offset;
+    if (jit_cpu.abi && !(_jitc->function->self.call & jit_call_varargs)) {
+       if (jit_arg_f_reg_p(_jitc->function->self.argf)) {
+           offset = _jitc->function->self.argf++;
+           goto done;
+       }
+    }
+    else {
+       if (jit_arg_reg_p(_jitc->function->self.argi)) {
+           offset = _jitc->function->self.argi++;
+           goto done;
+       }
+    }
+    offset = _jitc->function->self.size;
+    _jitc->function->self.size += sizeof(jit_float32_t);
+done:
+    if (node == (jit_node_t *)0)
+       node = jit_new_node(jit_code_arg_f);
+    else
+       link_node(node);
+    node->u.w = offset;
+    node->v.w = ++_jitc->function->self.argn;
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_make_arg_d(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                 offset;
+    if (jit_cpu.abi && !(_jitc->function->self.call & jit_call_varargs)) {
+       if (jit_arg_d_reg_p(_jitc->function->self.argf)) {
+           if (_jitc->function->self.argf & 1)
+               ++_jitc->function->self.argf;
+           offset = _jitc->function->self.argf;
+           _jitc->function->self.argf += 2;
+           goto done;
+       }
+    }
+    else {
+       if (_jitc->function->self.argi & 1)
+           ++_jitc->function->self.argi;
+       if (jit_arg_reg_p(_jitc->function->self.argi)) {
+           offset = _jitc->function->self.argi;
+           _jitc->function->self.argi += 2;
+           goto done;
+       }
+    }
+    if (_jitc->function->self.size & 7)
+       _jitc->function->self.size += 4;
+    offset = _jitc->function->self.size;
+    _jitc->function->self.size += sizeof(jit_float64_t);
+done:
+    if (node == (jit_node_t *)0)
+       node = jit_new_node(jit_code_arg_d);
+    else
+       link_node(node);
+    node->u.w = offset;
+    node->v.w = ++_jitc->function->self.argn;
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    if (_jitc->prepare) {
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+       if (jit_cpu.abi && _jitc->function->call.argf)
+           rewind_prepare();
+    }
+    else {
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+       if (jit_cpu.abi &&  _jitc->function->self.argf)
+           rewind_prolog();
+       /* First 4 stack addresses are always spilled r0-r3 */
+       if (jit_arg_reg_p(_jitc->function->self.argi))
+           _jitc->function->vagp = _jitc->function->self.argi * 4;
+       else
+           _jitc->function->vagp = 16;
+    }
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare)
+       jit_link_prepare();
+    else
+       jit_link_prolog();
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    return (jit_make_arg((jit_node_t*)0));
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    return (jit_make_arg_f((jit_node_t*)0));
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    return (jit_make_arg_d((jit_node_t*)0));
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (jit_swf_p())
+       jit_ldxi_c(u, JIT_FP, arg_offset(v->u.w));
+    else if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_c(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (jit_swf_p())
+       jit_ldxi_uc(u, JIT_FP, arg_offset(v->u.w));
+    else if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_uc(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (jit_swf_p())
+       jit_ldxi_s(u, JIT_FP, arg_offset(v->u.w));
+    else if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_s(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (jit_swf_p())
+       jit_ldxi_us(u, JIT_FP, arg_offset(v->u.w));
+    else if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_us(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_swf_p())
+       jit_ldxi_i(u, JIT_FP, arg_offset(v->u.w));
+    else if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_i(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+    if (jit_swf_p())
+       jit_stxi(arg_offset(v->u.w), JIT_FP, u);
+    else if (jit_arg_reg_p(v->u.w))
+       jit_movr(JIT_RA0 - v->u.w, u);
+    else
+       jit_stxi(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+    if (jit_swf_p()) {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(arg_offset(v->u.w), JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    else if (jit_arg_reg_p(v->u.w))
+       jit_movi(JIT_RA0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+    if (jit_cpu.abi && !(_jitc->function->self.call & jit_call_varargs)) {
+       if (jit_arg_f_reg_p(v->u.w))
+           jit_movr_f(u, JIT_FA0 - v->u.w);
+       else
+           jit_ldxi_f(u, JIT_FP, v->u.w);
+    }
+    else if (jit_swf_p())
+       jit_ldxi_f(u, JIT_FP, arg_offset(v->u.w));
+    else {
+       if (jit_arg_reg_p(v->u.w))
+           jit_movr_w_f(u, JIT_RA0 - v->u.w);
+       else
+           jit_ldxi_f(u, JIT_FP, v->u.w);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+    if (jit_cpu.abi) {
+       if (jit_arg_f_reg_p(v->u.w))
+           jit_movr_f(JIT_FA0 - v->u.w, u);
+       else
+           jit_stxi_f(v->u.w, JIT_FP, u);
+    }
+    else if (jit_swf_p())
+       jit_stxi_f(arg_offset(v->u.w), JIT_FP, u);
+    else {
+       if (jit_arg_reg_p(v->u.w))
+           jit_movr_f_w(JIT_RA0 - v->u.w, u);
+       else
+           jit_stxi_f(v->u.w, JIT_FP, u);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+    if (jit_cpu.abi) {
+       if (jit_arg_f_reg_p(v->u.w))
+           jit_movi_f(JIT_FA0 - v->u.w, u);
+       else {
+           regno = jit_get_reg(jit_class_fpr);
+           jit_movi_f(regno, u);
+           jit_stxi_f(v->u.w, JIT_FP, regno);
+           jit_unget_reg(regno);
+       }
+    }
+    else if (jit_swf_p()) {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(arg_offset(v->u.w), JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       if (jit_arg_reg_p(v->u.w))
+           jit_movr_f_w(JIT_RA0 - v->u.w, regno);
+       else
+           jit_stxi_f(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+    if (jit_cpu.abi && !(_jitc->function->self.call & jit_call_varargs)) {
+       if (jit_arg_f_reg_p(v->u.w))
+           jit_movr_d(u, JIT_FA0 - v->u.w);
+       else
+           jit_ldxi_d(u, JIT_FP, v->u.w);
+    }
+    else if (jit_swf_p())
+       jit_ldxi_d(u, JIT_FP, arg_offset(v->u.w));
+    else {
+       if (jit_arg_reg_p(v->u.w))
+           jit_movr_ww_d(u, JIT_RA0 - v->u.w, JIT_RA0 - (v->u.w + 1));
+       else
+           jit_ldxi_d(u, JIT_FP, v->u.w);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+    if (jit_cpu.abi) {
+       if (jit_arg_f_reg_p(v->u.w))
+           jit_movr_d(JIT_FA0 - v->u.w, u);
+       else
+           jit_stxi_d(v->u.w, JIT_FP, u);
+    }
+    else if (jit_swf_p())
+       jit_stxi_d(arg_offset(v->u.w), JIT_FP, u);
+    else {
+       if (jit_arg_reg_p(v->u.w))
+           jit_movr_d_ww(JIT_RA0 - v->u.w, JIT_RA0 - (v->u.w + 1), u);
+       else
+           jit_stxi_d(v->u.w, JIT_FP, u);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+    if (jit_cpu.abi) {
+       if (jit_arg_f_reg_p(v->u.w))
+           jit_movi_d(JIT_FA0 - v->u.w, u);
+       else {
+           regno = jit_get_reg(jit_class_fpr);
+           jit_movi_d(regno, u);
+           jit_stxi_d(v->u.w, JIT_FP, regno);
+           jit_unget_reg(regno);
+       }
+    }
+    else if (jit_swf_p()) {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(arg_offset(v->u.w), JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       if (jit_arg_reg_p(v->u.w))
+           jit_movr_d_ww(JIT_RA0 - v->u.w, JIT_RA0 - (v->u.w + 1), regno);
+       else
+           jit_stxi_d(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+    if (jit_cpu.abi && !(_jitc->function->call.call & jit_call_varargs)) {
+       if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+           jit_movr_f(JIT_FA0 - _jitc->function->call.argf, u);
+           ++_jitc->function->call.argf;
+           goto done;
+       }
+    }
+    else {
+       if (jit_arg_reg_p(_jitc->function->call.argi)) {
+           jit_movr_f_w(JIT_RA0 - _jitc->function->call.argi, u);
+           ++_jitc->function->call.argi;
+           goto done;
+       }
+    }
+    jit_stxi_f(_jitc->function->call.size, JIT_SP, u);
+    _jitc->function->call.size += sizeof(jit_word_t);
+done:
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+    if (jit_cpu.abi && !(_jitc->function->call.call & jit_call_varargs)) {
+       if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+           /* cannot jit_movi_f in the argument register because
+            * float arguments are packed, and that would cause
+            * either an assertion in debug mode, or overwritting
+            * two registers */
+           regno = jit_get_reg(jit_class_fpr);
+           jit_movi_f(regno, u);
+           jit_movr_f(JIT_FA0 - _jitc->function->call.argf, regno);
+           jit_unget_reg(regno);
+           ++_jitc->function->call.argf;
+           goto done;
+       }
+    }
+    else {
+       if (jit_arg_reg_p(_jitc->function->call.argi)) {
+           jit_movi_f_w(JIT_RA0 - _jitc->function->call.argi, u);
+           ++_jitc->function->call.argi;
+           goto done;
+       }
+    }
+    regno = jit_get_reg(jit_class_fpr);
+    jit_movi_f(regno, u);
+    jit_stxi_f(_jitc->function->call.size, JIT_SP, regno);
+    jit_unget_reg(regno);
+    _jitc->function->call.size += sizeof(jit_word_t);
+done:
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+    if (jit_cpu.abi && !(_jitc->function->call.call & jit_call_varargs)) {
+       if (jit_arg_d_reg_p(_jitc->function->call.argf)) {
+           if (_jitc->function->call.argf & 1)
+               ++_jitc->function->call.argf;
+           jit_movr_d(JIT_FA0 - _jitc->function->call.argf, u);
+           _jitc->function->call.argf += 2;
+           goto done;
+       }
+    }
+    else {
+       if (_jitc->function->call.argi & 1)
+           ++_jitc->function->call.argi;
+       if (jit_arg_reg_p(_jitc->function->call.argi)) {
+           jit_movr_d_ww(JIT_RA0 - _jitc->function->call.argi,
+                         JIT_RA0 - (_jitc->function->call.argi + 1),
+                         u);
+           _jitc->function->call.argi += 2;
+           goto done;
+       }
+    }
+    if (_jitc->function->call.size & 7)
+       _jitc->function->call.size += 4;
+    jit_stxi_d(_jitc->function->call.size, JIT_SP, u);
+    _jitc->function->call.size += sizeof(jit_float64_t);
+done:
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+    if (jit_cpu.abi && !(_jitc->function->call.call & jit_call_varargs)) {
+       if (jit_arg_d_reg_p(_jitc->function->call.argf)) {
+           if (_jitc->function->call.argf & 1)
+               ++_jitc->function->call.argf;
+           jit_movi_d(JIT_FA0 - _jitc->function->call.argf, u);
+           _jitc->function->call.argf += 2;
+           goto done;
+       }
+    }
+    else {
+       if (_jitc->function->call.argi & 1)
+           ++_jitc->function->call.argi;
+       if (jit_arg_reg_p(_jitc->function->call.argi)) {
+           jit_movi_d_ww(JIT_RA0 - _jitc->function->call.argi,
+                         JIT_RA0 - (_jitc->function->call.argi + 1),
+                         u);
+           _jitc->function->call.argi += 2;
+           goto done;
+       }
+    }
+    if (_jitc->function->call.size & 7)
+       _jitc->function->call.size += 4;
+    regno = jit_get_reg(jit_class_fpr);
+    jit_movi_d(regno, u);
+    jit_stxi_d(_jitc->function->call.size, JIT_SP, regno);
+    jit_unget_reg(regno);
+    _jitc->function->call.size += sizeof(jit_float64_t);
+done:
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_int32_t                spec;
+    spec = jit_class(_rvs[regno].spec);
+    if (spec & jit_class_arg) {
+       regno = JIT_RA0 - regno;
+       if (regno >= 0 && regno < node->v.w)
+           return (1);
+       if (jit_cpu.abi && spec & jit_class_fpr) {
+           regno = JIT_FA0 - regno;
+           if (regno >= 0 && regno < node->w.w)
+               return (1);
+       }
+    }
+
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_callr(r0);
+    node->v.w = _jitc->function->self.argi;
+    node->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_calli(i0);
+    node->v.w = _jitc->function->call.argi;
+    node->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_c, r0);
+    jit_extr_c(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_uc, r0);
+    jit_extr_uc(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_s, r0);
+    jit_extr_s(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_us, r0);
+    jit_extr_us(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_f, r0);
+    if (jit_cpu.abi) {
+       if (r0 != JIT_FRET)
+           jit_movr_f(r0, JIT_FRET);
+    }
+    else if (r0 != JIT_RET)
+       jit_movr_w_f(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_d, r0);
+    if (jit_cpu.abi) {
+       if (r0 != JIT_FRET)
+           jit_movr_d(r0, JIT_FRET);
+    }
+    else if (r0 != JIT_RET)
+       jit_movr_ww_d(r0, JIT_RET, _R1);
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_int32_t                 value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_uint8_t     *data;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_uword_t      thumb;
+#if DISASSEMBLER
+       jit_int32_t      info_offset;
+#endif
+       jit_int32_t      const_offset;
+       jit_int32_t      patch_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+    _jitc->thumb = 0;
+
+    jit_reglive_setup();
+
+    _jitc->consts.data = NULL;
+    _jitc->consts.offset = _jitc->consts.length = 0;
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.data = NULL;
+    undo.thumb = 0;
+#if DISASSEMBLER
+    undo.info_offset =
+#endif
+       undo.const_offset = undo.patch_offset = 0;
+#  define assert_data(node)            /**/
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_vv(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               if (jit_swf_p())                                        \
+                   swf_##name##r##type(rn(node->u.w), rn(node->v.w));  \
+               else                                                    \
+                   vfp_##name##r##type(rn(node->u.w), rn(node->v.w));  \
+               break
+#define case_vw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               if (jit_swf_p())                                        \
+                   swf_##name##i##type(rn(node->u.w), node->v.w);      \
+               else                                                    \
+                   vfp_##name##i##type(rn(node->u.w), node->v.w);      \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_wv(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               if (jit_swf_p())                                        \
+                   swf_##name##i##type(node->u.w, rn(node->v.w));      \
+               else                                                    \
+                   vfp_##name##i##type(node->u.w, rn(node->v.w));      \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_vvv(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               if (jit_swf_p())                                        \
+                   swf_##name##r##type(rn(node->u.w),                  \
+                                       rn(node->v.w), rn(node->w.w));  \
+               else                                                    \
+                   vfp_##name##r##type(rn(node->u.w),                  \
+                                       rn(node->v.w), rn(node->w.w));  \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_vvw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               if (jit_swf_p())                                        \
+                   swf_##name##i##type(rn(node->u.w),                  \
+                                       rn(node->v.w), node->w.w);      \
+               else                                                    \
+                   vfp_##name##i##type(rn(node->u.w),                  \
+                                       rn(node->v.w), node->w.w);      \
+               break
+#define case_vvf(name)                                                 \
+           case jit_code_##name##i_f:                                  \
+               assert_data(node);                                      \
+               if (jit_swf_p())                                        \
+                   swf_##name##i_f(rn(node->u.w), rn(node->v.w),       \
+                                   node->w.f);                         \
+               else                                                    \
+                   vfp_##name##i_f(rn(node->u.w), rn(node->v.w),       \
+                                   node->w.f);                         \
+               break
+#define case_vvd(name)                                                 \
+           case jit_code_##name##i_d:                                  \
+               assert_data(node);                                      \
+               if (jit_swf_p())                                        \
+                   swf_##name##i_d(rn(node->u.w), rn(node->v.w),       \
+                                   node->w.d);                         \
+               else                                                    \
+                   vfp_##name##i_d(rn(node->u.w), rn(node->v.w),       \
+                                   node->w.d);                         \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_wvv(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               if (jit_swf_p())                                        \
+                   swf_##name##i##type(node->u.w,                      \
+                                       rn(node->v.w), rn(node->w.w));  \
+               else                                                    \
+                   vfp_##name##i##type(node->u.w,                      \
+                                       rn(node->v.w), rn(node->w.w));  \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_bvv(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch) {                      \
+                   if (jit_swf_p())                                    \
+                       swf_##name##r##type(temp->u.w, rn(node->v.w),   \
+                                           rn(node->w.w));             \
+                   else                                                \
+                       vfp_##name##r##type(temp->u.w, rn(node->v.w),   \
+                                           rn(node->w.w));             \
+               }                                                       \
+               else {                                                  \
+                   if (jit_swf_p())                                    \
+                       word = swf_##name##r##type(_jit->pc.w,          \
+                                                  rn(node->v.w),       \
+                                                  rn(node->w.w));      \
+                   else                                                \
+                       word = vfp_##name##r##type(_jit->pc.w,          \
+                                                  rn(node->v.w),       \
+                                                  rn(node->w.w));      \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break;
+#define case_bvf(name)                                                 \
+           case jit_code_##name##i_f:                                  \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch) {                      \
+                   if (jit_swf_p())                                    \
+                       swf_##name##i_f(temp->u.w, rn(node->v.w),       \
+                                       node->w.f);                     \
+                   else                                                \
+                       vfp_##name##i_f(temp->u.w, rn(node->v.w),       \
+                                       node->w.f);                     \
+               }                                                       \
+               else {                                                  \
+                   if (jit_swf_p())                                    \
+                       word = swf_##name##i_f(_jit->pc.w,              \
+                                              rn(node->v.w),           \
+                                              node->w.f);              \
+                   else                                                \
+                       word = vfp_##name##i_f(_jit->pc.w,              \
+                                              rn(node->v.w),           \
+                                              node->w.f);              \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_bvd(name)                                                 \
+           case jit_code_##name##i_d:                                  \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch) {                      \
+                   if (jit_swf_p())                                    \
+                       swf_##name##i_d(temp->u.w, rn(node->v.w),       \
+                                       node->w.d);                     \
+                   else                                                \
+                       vfp_##name##i_d(temp->u.w, rn(node->v.w),       \
+                                       node->w.d);                     \
+               }                                                       \
+               else {                                                  \
+                   if (jit_swf_p())                                    \
+                       word = swf_##name##i_d(_jit->pc.w,              \
+                                              rn(node->v.w),           \
+                                              node->w.d);              \
+                   else                                                \
+                       word = vfp_##name##i_d(_jit->pc.w,              \
+                                              rn(node->v.w),           \
+                                              node->w.d);              \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if (node->u.w == sizeof(jit_word_t) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               if (must_align_p(node->next))
+                   nop(2);
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               if (must_align_p(node->next))
+                   nop(2);
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rr(neg,);
+               case_rr(com,);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_vv(trunc, _f_i);
+               case_vv(trunc, _d_i);
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), temp->u.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_vvv(add, _f);
+               case_vvf(add);
+               case_vvv(sub, _f);
+               case_vvf(sub);
+               case_vvf(rsb);
+               case_vvv(mul, _f);
+               case_vvf(mul);
+               case_vvv(div, _f);
+               case_vvf(div);
+               case_vv(abs, _f);
+               case_vv(neg, _f);
+               case_vv(sqrt, _f);
+               case_vv(ext, _f);
+               case_vv(ld, _f);
+               case_vw(ld, _f);
+               case_vvv(ldx, _f);
+               case_vvw(ldx, _f);
+               case_vv(st, _f);
+               case_wv(st, _f);
+               case_vvv(stx, _f);
+               case_wvv(stx, _f);
+               case_vv(mov, _f);
+           case jit_code_movi_f:
+               assert_data(node);
+               if (jit_swf_p())
+                   swf_movi_f(rn(node->u.w), node->v.f);
+               else
+                   vfp_movi_f(rn(node->u.w), node->v.f);
+               break;
+               case_vv(ext, _d_f);
+               case_vvv(lt, _f);
+               case_vvf(lt);
+               case_vvv(le, _f);
+               case_vvf(le);
+               case_vvv(eq, _f);
+               case_vvf(eq);
+               case_vvv(ge, _f);
+               case_vvf(ge);
+               case_vvv(gt, _f);
+               case_vvf(gt);
+               case_vvv(ne, _f);
+               case_vvf(ne);
+               case_vvv(unlt, _f);
+               case_vvf(unlt);
+               case_vvv(unle, _f);
+               case_vvf(unle);
+               case_vvv(uneq, _f);
+               case_vvf(uneq);
+               case_vvv(unge, _f);
+               case_vvf(unge);
+               case_vvv(ungt, _f);
+               case_vvf(ungt);
+               case_vvv(ltgt, _f);
+               case_vvf(ltgt);
+               case_vvv(ord, _f);
+               case_vvf(ord);
+               case_vvv(unord, _f);
+               case_vvf(unord);
+               case_bvv(blt, _f);
+               case_bvf(blt);
+               case_bvv(ble, _f);
+               case_bvf(ble);
+               case_bvv(beq, _f);
+               case_bvf(beq);
+               case_bvv(bge, _f);
+               case_bvf(bge);
+               case_bvv(bgt, _f);
+               case_bvf(bgt);
+               case_bvv(bne, _f);
+               case_bvf(bne);
+               case_bvv(bunlt, _f);
+               case_bvf(bunlt);
+               case_bvv(bunle, _f);
+               case_bvf(bunle);
+               case_bvv(buneq, _f);
+               case_bvf(buneq);
+               case_bvv(bunge, _f);
+               case_bvf(bunge);
+               case_bvv(bungt, _f);
+               case_bvf(bungt);
+               case_bvv(bltgt, _f);
+               case_bvf(bltgt);
+               case_bvv(bord, _f);
+               case_bvf(bord);
+               case_bvv(bunord, _f);
+               case_bvf(bunord);
+               case_vvv(add, _d);
+               case_vvd(add);
+               case_vvv(sub, _d);
+               case_vvd(sub);
+               case_vvd(rsb);
+               case_vvv(mul, _d);
+               case_vvd(mul);
+               case_vvv(div, _d);
+               case_vvd(div);
+               case_vv(abs, _d);
+               case_vv(neg, _d);
+               case_vv(sqrt, _d);
+               case_vv(ext, _d);
+               case_vv(ld, _d);
+               case_vw(ld, _d);
+               case_vvv(ldx, _d);
+               case_vvw(ldx, _d);
+               case_vv(st, _d);
+               case_wv(st, _d);
+               case_vvv(stx, _d);
+               case_wvv(stx, _d);
+               case_vv(mov, _d);
+           case jit_code_movi_d:
+               assert_data(node);
+               if (jit_swf_p())
+                   swf_movi_d(rn(node->u.w), node->v.d);
+               else
+                   vfp_movi_d(rn(node->u.w), node->v.d);
+               break;
+               case_vv(ext, _f_d);
+               case_vvv(lt, _d);
+               case_vvd(lt);
+               case_vvv(le, _d);
+               case_vvd(le);
+               case_vvv(eq, _d);
+               case_vvd(eq);
+               case_vvv(ge, _d);
+               case_vvd(ge);
+               case_vvv(gt, _d);
+               case_vvd(gt);
+               case_vvv(ne, _d);
+               case_vvd(ne);
+               case_vvv(unlt, _d);
+               case_vvd(unlt);
+               case_vvv(unle, _d);
+               case_vvd(unle);
+               case_vvv(uneq, _d);
+               case_vvd(uneq);
+               case_vvv(unge, _d);
+               case_vvd(unge);
+               case_vvv(ungt, _d);
+               case_vvd(ungt);
+               case_vvv(ltgt, _d);
+               case_vvd(ltgt);
+               case_vvv(ord, _d);
+               case_vvd(ord);
+               case_vvv(unord, _d);
+               case_vvd(unord);
+               case_bvv(blt, _d);
+               case_bvd(blt);
+               case_bvv(ble, _d);
+               case_bvd(ble);
+               case_bvv(beq, _d);
+               case_bvd(beq);
+               case_bvv(bge, _d);
+               case_bvd(bge);
+               case_bvv(bgt, _d);
+               case_bvd(bgt);
+               case_bvv(bne, _d);
+               case_bvd(bne);
+               case_bvv(bunlt, _d);
+               case_bvd(bunlt);
+               case_bvv(bunle, _d);
+               case_bvd(bunle);
+               case_bvv(buneq, _d);
+               case_bvd(buneq);
+               case_bvv(bunge, _d);
+               case_bvd(bunge);
+               case_bvv(bungt, _d);
+               case_bvd(bungt);
+               case_bvv(bltgt, _d);
+               case_bvd(bltgt);
+               case_bvv(bord, _d);
+               case_bvd(bord);
+               case_bvv(bunord, _d);
+               case_bvd(bunord);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               flush_consts();
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi_p(_jit->pc.w, 1);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               flush_consts();
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       calli(temp->u.w);
+                   else {
+                       word = calli_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.data = _jitc->consts.data;
+               undo.thumb = _jitc->thumb;
+               undo.const_offset = _jitc->consts.offset;
+               undo.patch_offset = _jitc->patches.offset;
+#if DISASSEMBLER
+               if (_jitc->data_info.ptr)
+                   undo.info_offset = _jitc->data_info.offset;
+#endif
+           restart_function:
+               _jitc->again = 0;
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   invalidate_consts();
+                   _jitc->consts.data = undo.data;
+                   _jitc->thumb = undo.thumb;
+                   _jitc->consts.offset = undo.const_offset;
+                   _jitc->patches.offset = undo.patch_offset;
+#if DISASSEMBLER
+                   if (_jitc->data_info.ptr)
+                       _jitc->data_info.offset = undo.info_offset;
+#endif
+                   goto restart_function;
+               }
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               flush_consts();
+               break;
+           case jit_code_movr_w_f:
+               if (jit_swf_p())
+                   swf_movr_f(rn(node->u.w), rn(node->v.w));
+               else
+                   vfp_movr_f(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movr_f_w:
+               if (jit_swf_p())
+                   swf_movr_f(rn(node->u.w), rn(node->v.w));
+               else
+                   vfp_movr_f(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movi_f_w:
+               assert_data(node);
+               if (jit_swf_p())
+                   swf_movi_f(rn(node->u.w), node->v.f);
+               else
+                   vfp_movi_f(rn(node->u.w), node->v.f);
+               break;
+           case jit_code_movr_ww_d:
+               if (jit_swf_p())
+                   swf_movr_d(rn(node->u.w), rn(node->v.w));
+               else
+                   vfp_movr_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movr_d_ww:
+               if (jit_swf_p())
+                   swf_movr_d(rn(node->u.w), rn(node->w.w));
+               else
+                   vfp_movr_d(rn(node->u.w), rn(node->w.w));
+               break;
+           case jit_code_movi_d_ww:
+               assert_data(node);
+               if (jit_swf_p())
+                   swf_movi_d(rn(node->u.w), node->w.d);
+               else
+                   vfp_movi_d(rn(node->u.w), node->w.d);
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               if (jit_swf_p())
+                   swf_vaarg_d(rn(node->u.w), rn(node->v.w));
+               else
+                   vfp_vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:                 case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           default:
+               abort();
+       }
+       jit_regarg_clr(node, value);
+       assert(_jitc->regarg == 0 && _jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+
+       if (_jitc->consts.length &&
+           (_jit->pc.uc - _jitc->consts.data >= 3968 ||
+            (jit_uword_t)_jit->pc.uc -
+            (jit_uword_t)_jitc->consts.patches[0] >= 3968)) {
+           /* longest sequence should be 64 bytes, but preventively
+            * do not let it go past 128 remaining bytes before a flush */
+           if (node->next &&
+               node->next->code != jit_code_jmpi &&
+               node->next->code != jit_code_jmpr &&
+               node->next->code != jit_code_epilog) {
+               /* insert a jump, flush constants and continue */
+               word = _jit->pc.w;
+               assert(!jit_thumb_p());
+               B(0);
+               flush_consts();
+               patch_at(arm_patch_jump, word, _jit->pc.w);
+           }
+       }
+    }
+#undef case_bvd
+#undef case_bvf
+#undef case_brw
+#undef case_bvv
+#undef case_brr
+#undef case_wvv
+#undef case_wrr
+#undef case_vvd
+#undef case_vvf
+#undef case_vvw
+#undef case_rrw
+#undef case_vvv
+#undef case_rrr
+#undef case_wv
+#undef case_wr
+#undef case_vw
+#undef case_vv
+#undef case_rw
+#undef case_rr
+
+    flush_consts();
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       assert(_jitc->patches.ptr[offset].kind & arm_patch_node);
+       node = _jitc->patches.ptr[offset].node;
+       word = _jitc->patches.ptr[offset].inst;
+       if (!jit_thumb_p() &&
+           (node->code == jit_code_movi || node->code == jit_code_calli)) {
+           /* calculate where to patch word */
+           value = *(jit_int32_t *)word;
+           assert((value & 0x0f700000) == ARM_LDRI);
+           /* offset may become negative (-4) if last instruction
+            * before unconditional branch and data following
+            * FIXME can this cause issues in the preprocessor prefetch
+            * or something else? should not, as the constants are after
+            * an unconditional jump */
+           if (value & ARM_P)  value =   value & 0x00000fff;
+           else                value = -(value & 0x00000fff);
+           word = word + 8 + value;
+       }
+       value = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(_jitc->patches.ptr[offset].kind & ~arm_patch_node, word, value);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_rewind.c"
+#  include "jit_arm-cpu.c"
+#  include "jit_arm-swf.c"
+#  include "jit_arm-vfp.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+#if defined(__GNUC__)
+    jit_uword_t                i, f, t, s;
+
+    s = sysconf(_SC_PAGE_SIZE);
+    f = (jit_uword_t)fptr & -s;
+    t = (((jit_uword_t)tptr) + s - 1) & -s;
+    for (i = f; i < t; i += s)
+       __clear_cache((void *)i, (void *)(i + s));
+#endif
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi_i(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi_i(i0, rn(r0), rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (jit_swf_p())
+       swf_ldxi_d(rn(r0), rn(r1), i0);
+    else
+       vfp_ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_swf_p())
+       swf_stxi_d(i0, rn(r0), rn(r1));
+    else
+       vfp_stxi_d(i0, rn(r0), rn(r1));
+}
+
+static jit_int32_t
+_jit_get_reg_pair(jit_state_t *_jit)
+{
+    /*   bypass jit_get_reg() with argument or'ed with jit_class_chk
+     * and try to find an consecutive, even free register pair, or
+     * return JIT_NOREG if fail, as the cost of spills is greater
+     * than splitting a double load/store in two operations. */
+    if (jit_reg_free_p(_R0) && jit_reg_free_p(_R1)) {
+       jit_regset_setbit(&_jitc->regarg, _R0);
+       jit_regset_setbit(&_jitc->regarg, _R1);
+       return (_R0);
+    }
+    if (jit_reg_free_p(_R2) && jit_reg_free_p(_R3)) {
+       jit_regset_setbit(&_jitc->regarg, _R2);
+       jit_regset_setbit(&_jitc->regarg, _R3);
+       return (_R2);
+    }
+    if (jit_reg_free_p(_R4) && jit_reg_free_p(_R5)) {
+       jit_regset_setbit(&_jitc->regarg, _R4);
+       jit_regset_setbit(&_jitc->regarg, _R5);
+       return (_R4);
+    }
+    if (jit_reg_free_p(_R6) && jit_reg_free_p(_R7)) {
+       jit_regset_setbit(&_jitc->regarg, _R6);
+       jit_regset_setbit(&_jitc->regarg, _R7);
+       return (_R6);
+    }
+    if (jit_reg_free_p(_R8) && jit_reg_free_p(_R9)) {
+       jit_regset_setbit(&_jitc->regarg, _R8);
+       jit_regset_setbit(&_jitc->regarg, _R9);
+       return (_R8);
+    }
+    return (JIT_NOREG);
+}
+
+static void
+_jit_unget_reg_pair(jit_state_t *_jit, jit_int32_t reg)
+{
+    jit_unget_reg(reg);
+    switch (reg) {
+       case _R0:       jit_unget_reg(_R1);     break;
+       case _R2:       jit_unget_reg(_R3);     break;
+       case _R4:       jit_unget_reg(_R5);     break;
+       case _R6:       jit_unget_reg(_R7);     break;
+       case _R8:       jit_unget_reg(_R9);     break;
+       default:        abort();
+    }
+}
+
+/*   A prolog must be aligned at mod 4 bytes boundary.
+ *   This condition was not being required to be tested by
+ * accident previously, but with the jit_frame and jit_tramp
+ * code it is required */
+static jit_bool_t
+_must_align_p(jit_state_t *_jit, jit_node_t *node)
+{
+    if (jit_thumb_p() && (_jit->pc.w & 3)) {
+       for (; node; node = node->next) {
+           switch (node->code) {
+               case jit_code_note:
+               case jit_code_name:
+               case jit_code_label:
+                   break;
+               case jit_code_prolog:
+                   return (1);
+               default:
+                   return (0);
+           }
+       }
+    }
+    return (0);
+}
+
+static void
+_load_const(jit_state_t *_jit, jit_bool_t uniq, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t          w;
+    jit_word_t          d;
+    jit_word_t          base;
+    jit_int32_t                *data;
+    jit_int32_t                 size;
+    jit_int32_t                 offset;
+
+    assert(!jit_thumb_p());
+    if (!uniq) {
+       /* use zero, a valid directly encoded immediate, to avoid the
+        * need of a bitmask to know what offsets will be patched, so
+        * that comparison will always fail for constants that cannot
+        * be encoded */
+       assert(i0 != 0);
+
+       /* Actually, code is (currently at least) not self modifying,
+        * so, any value reachable backwards is valid as a constant. */
+
+       /* FIXME a quickly updateable/mutable hash table could be
+        * better here, but most times only a few comparisons
+        * should be done
+        */
+
+       /* search in previous constant pool */
+       if ((data = (jit_int32_t *)_jitc->consts.data)) {
+           w = (jit_word_t)data;
+           /* maximum backwards offset */
+           base = (_jit->pc.w + 8) - 4092;
+           if (base <= w)
+               /* can scan all possible available backward constants */
+               base = 0;
+           else
+               base = (base - w) >> 2;
+           size = _jitc->consts.size >> 2;
+           for (offset = size - 1; offset >= base; offset--) {
+               if (data[offset] == i0) {
+                   w = (jit_word_t)(data + offset);
+                   d = (_jit->pc.w + 8) - w;
+                   LDRIN(r0, _R15_REGNO, d);
+                   return;
+               }
+           }
+       }
+    }
+    else
+       assert(i0 == 0);
+
+    _jitc->consts.patches[_jitc->consts.offset++] = _jit->pc.w;
+    /* (probably) positive forward offset */
+    LDRI(r0, _R15_REGNO, 0);
+
+    if (!uniq) {
+       /* search already requested values */
+       for (offset = 0; offset < _jitc->consts.length; offset++) {
+           if (_jitc->consts.values[offset] == i0) {
+               _jitc->consts.patches[_jitc->consts.offset++] = offset;
+               return;
+           }
+       }
+    }
+
+#if DEBUG
+    /* cannot run out of space because of limited range
+     * but assert anyway to catch logic errors */
+    assert(_jitc->consts.length < 1024);
+    assert(_jitc->consts.offset < 2048);
+#endif
+    _jitc->consts.patches[_jitc->consts.offset++] = _jitc->consts.length;
+    _jitc->consts.values[_jitc->consts.length++] = i0;
+}
+
+static void
+_flush_consts(jit_state_t *_jit)
+{
+    jit_word_t          word;
+    jit_int32_t                 offset;
+
+    /* if no forward constants */
+    if (!_jitc->consts.length)
+       return;
+    assert(!jit_thumb_p());
+    word = _jit->pc.w;
+    _jitc->consts.data = _jit->pc.uc;
+    _jitc->consts.size = _jitc->consts.length << 2;
+    /* FIXME check will not overrun, otherwise, need to reallocate
+     * code buffer and start over */
+    jit_memcpy(_jitc->consts.data, _jitc->consts.values, _jitc->consts.size);
+    _jit->pc.w += _jitc->consts.size;
+
+#if DISASSEMBLER
+    if (_jitc->data_info.ptr) {
+       if (_jitc->data_info.offset >= _jitc->data_info.length) {
+           jit_realloc((jit_pointer_t *)&_jitc->data_info.ptr,
+                       _jitc->data_info.length * sizeof(jit_data_info_t),
+                       (_jitc->data_info.length + 1024) *
+                       sizeof(jit_data_info_t));
+           _jitc->data_info.length += 1024;
+       }
+       _jitc->data_info.ptr[_jitc->data_info.offset].code = word;
+       _jitc->data_info.ptr[_jitc->data_info.offset].length = _jitc->consts.size;
+       ++_jitc->data_info.offset;
+    }
+#endif
+
+    for (offset = 0; offset < _jitc->consts.offset; offset += 2)
+       patch_at(arm_patch_load, _jitc->consts.patches[offset],
+                word + (_jitc->consts.patches[offset + 1] << 2));
+    _jitc->consts.length = _jitc->consts.offset = 0;
+}
+
+/* to be called if needing to start over a function */
+static void
+_invalidate_consts(jit_state_t *_jit)
+{
+    /* if no forward constants */
+    if (_jitc->consts.length)
+       _jitc->consts.length = _jitc->consts.offset = 0;
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                 flag;
+    jit_int32_t                 kind;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi) {
+       flag = node->v.n->flag;
+       kind = arm_patch_word;
+    }
+    else {
+       flag = node->u.n->flag;
+       if (node->code == jit_code_calli ||
+           (node->code == jit_code_jmpi && !(node->flag & jit_flag_node)))
+           kind = arm_patch_word;
+       else
+           kind = arm_patch_jump;
+    }
+    assert(!(flag & jit_flag_patch));
+    kind |= arm_patch_node;
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].kind = kind;
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_disasm.c b/deps/lightning/lib/jit_disasm.c
new file mode 100644 (file)
index 0000000..15b91b9
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+#if DISASSEMBLER
+#  include <dis-asm.h>
+#endif
+
+/*
+ * Prototypes
+ */
+#if DISASSEMBLER
+static int
+disasm_compare_symbols(const void *ap, const void *bp);
+
+static void
+disasm_print_address(bfd_vma addr, struct disassemble_info *info);
+
+#define disassemble(u, v)      _disassemble(_jit, u, v)
+static void
+_disassemble(jit_state_t *_jit, jit_pointer_t code, jit_int32_t length);
+#endif
+
+/*
+ * Initialization
+ */
+#if DISASSEMBLER
+static bfd                      *disasm_bfd;
+static disassemble_info                  disasm_info;
+static disassembler_ftype        disasm_print;
+static asymbol                 **disasm_symbols;
+static asymbol                  *disasm_synthetic;
+static long                      disasm_num_symbols;
+static long                      disasm_num_synthetic;
+static jit_state_t              *disasm_jit;
+#define disasm_stream            stdout
+#endif
+
+/*
+ * Implementation
+ */
+void
+jit_init_debug(const char *progname)
+{
+#if DISASSEMBLER
+    bfd_init();
+
+    if (progname)
+       disasm_bfd = bfd_openr(progname, NULL);
+    if (disasm_bfd == NULL) {
+#if defined(__linux__)
+       disasm_bfd = bfd_openr("/proc/self/exe", NULL);
+       if (disasm_bfd == NULL)
+#endif
+           return;
+    }
+    bfd_check_format(disasm_bfd, bfd_object);
+    bfd_check_format(disasm_bfd, bfd_archive);
+    INIT_DISASSEMBLE_INFO(disasm_info, disasm_stream, fprintf);
+#  if defined(__i386__) || defined(__x86_64__)
+    disasm_info.arch = bfd_arch_i386;
+#    if defined(__x86_64__)
+#      if __WORDSIZE == 32
+    disasm_info.mach = bfd_mach_x64_32;
+#      else
+    disasm_info.mach = bfd_mach_x86_64;
+#      endif
+#    else
+    disasm_info.mach = bfd_mach_i386_i386;
+#    endif
+#  endif
+#  if defined(__powerpc__)
+    disasm_info.arch = bfd_arch_powerpc;
+    disasm_info.mach = bfd_mach_ppc64;
+#    if HAVE_DISASSEMBLE_INIT_FOR_TARGET
+    disassemble_init_for_target(&disasm_info);
+#    elif HAVE_DISASSEMBLE_INIT_POWERPC
+    disassemble_init_powerpc(&disasm_info);
+#    endif
+#    if defined(__powerpc64__)
+    disasm_info.disassembler_options = "64";
+#    endif
+#    if HAVE_DISASSEMBLE_INIT_FOR_TARGET
+    disassemble_init_for_target(&disasm_info);
+#    elif HAVE_DISASSEMBLE_INIT_POWERPC
+    disassemble_init_powerpc(&disasm_info);
+#    endif
+#  endif
+#  if defined(__sparc__)
+    disasm_info.endian = disasm_info.display_endian = BFD_ENDIAN_BIG;
+#  endif
+#  if defined(__s390__) || defined(__s390x__)
+    disasm_info.arch = bfd_arch_s390;
+#    if __WORDSIZE == 32
+    disasm_info.mach = bfd_mach_s390_31;
+#    else
+    disasm_info.mach = bfd_mach_s390_64;
+#    endif
+    disasm_info.endian = disasm_info.display_endian = BFD_ENDIAN_BIG;
+    disasm_info.disassembler_options = "zarch";
+#  endif
+#  if defined(__alpha__)
+    disasm_info.arch = bfd_arch_alpha;
+    disasm_info.mach = bfd_mach_alpha_ev6;
+#  endif
+#  if defined(__hppa__)
+    disasm_info.arch = bfd_arch_hppa;
+    disasm_info.mach = bfd_mach_hppa10;
+#  endif
+#  if defined(__riscv)
+    disasm_info.arch = bfd_arch_riscv;
+#  if __WORDSIZE == 32
+    disasm_info.mach = bfd_mach_riscv32;
+#  else
+    disasm_info.mach = bfd_mach_riscv64;
+#  endif
+#  endif
+    disasm_info.print_address_func = disasm_print_address;
+
+# if BINUTILS_2_29
+    disasm_print = disassembler(disasm_info.arch, __BYTE_ORDER == __BIG_ENDIAN,
+                               disasm_info.mach, disasm_bfd);
+#  else
+    disasm_print = disassembler(disasm_bfd);
+#  endif
+    assert(disasm_print);
+
+    if (bfd_get_file_flags(disasm_bfd) & HAS_SYMS) {
+       asymbol         **in;
+       asymbol         **out;
+       asymbol          *symbol;
+       long              offset;
+       long              sym_count;
+       long              dyn_count;
+       long              sym_storage;
+       long              dyn_storage;
+
+       if ((sym_storage = bfd_get_symtab_upper_bound(disasm_bfd)) >= 0) {
+
+           if (bfd_get_file_flags(disasm_bfd) & DYNAMIC) {
+               dyn_storage = bfd_get_dynamic_symtab_upper_bound(disasm_bfd);
+#  if defined(__alpha__)
+               /* XXX */
+               if (dyn_storage < 0)
+                   dyn_storage = 0;
+#  else
+               assert(dyn_storage >= 0);
+#  endif
+           }
+           else
+               dyn_storage = 0;
+
+           jit_alloc((jit_pointer_t *)&disasm_symbols,
+                     (sym_storage + dyn_storage) * sizeof(asymbol *));
+           sym_count = bfd_canonicalize_symtab(disasm_bfd, disasm_symbols);
+           assert(sym_count >= 0);
+           if (dyn_storage) {
+               dyn_count = bfd_canonicalize_dynamic_symtab(disasm_bfd,
+                                                           disasm_symbols +
+                                                           sym_count);
+               assert(dyn_count >= 0);
+           }
+           else
+               dyn_count = 0;
+           disasm_num_symbols = sym_count + dyn_count;
+
+           disasm_num_synthetic = bfd_get_synthetic_symtab(disasm_bfd,
+                                                           sym_count,
+                                                           disasm_symbols,
+                                                           dyn_count,
+                                                           disasm_symbols +
+                                                           sym_count,
+                                                           &disasm_synthetic);
+           if (disasm_num_synthetic > 0) {
+               jit_realloc((jit_pointer_t *)&disasm_symbols,
+                           (sym_storage + dyn_storage) * sizeof(asymbol *),
+                           (sym_storage + dyn_storage + disasm_num_synthetic) *
+                           sizeof(asymbol *));
+               for (offset = 0; offset < disasm_num_synthetic; offset++)
+                   disasm_symbols[disasm_num_symbols++] =
+                       disasm_synthetic + offset;
+           }
+
+           /* remove symbols not useful for disassemble */
+           in = out = disasm_symbols;
+           for (offset = 0; offset < disasm_num_symbols; offset++) {
+               symbol = *in++;
+               if (symbol->name &&
+                   symbol->name[0] != '\0' &&
+                   !(symbol->flags & (BSF_DEBUGGING | BSF_SECTION_SYM)) &&
+                   !bfd_is_und_section(symbol->section) &&
+                   !bfd_is_com_section(symbol->section))
+                   *out++ = symbol;
+           }
+           disasm_num_symbols = out - disasm_symbols;
+           qsort(disasm_symbols, disasm_num_symbols,
+                 sizeof(asymbol *), disasm_compare_symbols);
+       }
+    }
+#endif
+}
+
+void
+jit_finish_debug(void)
+{
+#if DISASSEMBLER
+    if (disasm_synthetic)
+       jit_free((jit_pointer_t *)&disasm_synthetic);
+    if (disasm_symbols)
+       jit_free((jit_pointer_t *)&disasm_symbols);
+    if (disasm_bfd)
+       bfd_close (disasm_bfd);
+#endif
+}
+
+void
+_jit_disassemble(jit_state_t *_jit)
+{
+#if DISASSEMBLER
+    if (disasm_bfd) {
+#  if defined(__arm__)
+       /* FIXME add mapping for prolog switching to arm and possible jump
+        * before first prolog also in arm mode */
+       disasm_info.disassembler_options = jit_cpu.thumb ? "force-thumb" : "";
+#  endif
+
+       disassemble(_jit->code.ptr, _jit->pc.uc - _jit->code.ptr);
+    }
+#endif
+}
+
+#if DISASSEMBLER
+/* Based on objdump source */
+static int
+disasm_compare_symbols(const void *ap, const void *bp)
+{
+    const asymbol      *a = *(const asymbol **)ap;
+    const asymbol      *b = *(const asymbol **)bp;
+
+    if (bfd_asymbol_value(a) > bfd_asymbol_value(b))
+       return (1);
+    if (bfd_asymbol_value(a) < bfd_asymbol_value(b))
+       return (-1);
+    return (0);
+}
+
+#if __WORDSIZE == 32
+#  define address_buffer_length                16
+#  define address_buffer_format                "%llx"
+#else
+#  define address_buffer_length                32
+#  define address_buffer_format                "%lx"
+#endif
+static void
+disasm_print_address(bfd_vma addr, struct disassemble_info *info)
+{
+    char               *name;
+    char               *file;
+    int                         line;
+    char                buffer[address_buffer_length];
+
+    sprintf(buffer, address_buffer_format, (long long)addr);
+    (*info->fprintf_func)(info->stream, "0x%s", buffer);
+
+#  define _jit                         disasm_jit
+#  undef jit_pointer_p
+#  define jit_pointer_p(u)                                     \
+       ((u) >= _jit->code.ptr && (u) < _jit->pc.uc)
+    if (jit_pointer_p((jit_uint8_t *)(jit_word_t)addr)) {
+       if (jit_get_note((jit_uint8_t *)(jit_word_t)addr, &name, &file, &line))
+           (*info->fprintf_func)(info->stream, " %s:%s:%d",
+                                 name ? name : "",
+                                 file ? file : "",
+                                 line);
+    }
+#  undef jit_pointer_p
+#  undef _jit
+    else if (disasm_num_symbols) {
+       long             low;
+       long             high;
+       long             offset;
+       asymbol         *symbol;
+
+       low = 0;
+       high = disasm_num_symbols;
+       do {
+           offset = (low + high) >> 1;
+           symbol = disasm_symbols[offset];
+           if (bfd_asymbol_value(symbol) > addr)
+               high = offset - 1;
+           else if (bfd_asymbol_value(symbol) < addr)
+               low = offset + 1;
+           else
+               break;
+       } while (low < high);
+
+       if (offset >= 0 && offset < disasm_num_symbols) {
+           if (bfd_asymbol_value(symbol) < addr) {
+               while (++offset < disasm_num_symbols) {
+                   symbol = disasm_symbols[offset];
+                   if (bfd_asymbol_value(symbol) >= addr)
+                       break;
+               }
+           }
+           else if (bfd_asymbol_value(symbol) > addr) {
+               while (offset--) {
+                   if (bfd_asymbol_value(disasm_symbols[offset]) < addr)
+                       break;
+                   symbol = disasm_symbols[offset];
+               }
+           }
+           if (bfd_asymbol_value(symbol) == addr)
+               (*info->fprintf_func)(info->stream, " # %s", symbol->name);
+       }
+    }
+}
+
+static void
+_disassemble(jit_state_t *_jit, jit_pointer_t code, jit_int32_t length)
+{
+    int                         bytes;
+    char               *name, *old_name;
+    char               *file, *old_file;
+    int                         line,  old_line;
+#if __arm__
+    jit_int32_t                 offset;
+    jit_bool_t          data_info;
+    jit_int32_t                 data_offset;
+#endif
+    bfd_vma             pc = (jit_uword_t)code;
+    bfd_vma             end = (jit_uword_t)code + length;
+    char                buffer[address_buffer_length];
+#if DEVEL_DISASSEMBLER
+    jit_node_t         *node;
+    jit_uword_t                 prevw;
+#endif
+
+#if __arm__
+    data_info = _jitc && _jitc->data_info.ptr;
+    data_offset = 0;
+#endif
+    disasm_info.buffer = code;
+    disasm_info.buffer_vma = (jit_uword_t)code;
+    disasm_info.buffer_length = length;
+    old_file = old_name = NULL;
+    old_line = 0;
+    disasm_jit = _jit;
+#if DEVEL_DISASSEMBLER
+    node = _jitc->head;
+    prevw = pc;
+#endif
+    while (pc < end) {
+#if DEVEL_DISASSEMBLER
+       while (node && (jit_uword_t)(prevw + node->offset) < (jit_uword_t)pc) {
+           prevw += node->offset;
+           node = node->next;
+       }
+       while (node && (jit_uword_t)(prevw + node->offset) == (jit_uword_t)pc) {
+           jit_print_node(node);
+           fputc('\n', stdout); 
+           prevw += node->offset;
+           node = node->next;
+       }
+#endif
+#if __arm__
+    again:
+       if (data_info) {
+           while (_jitc->data_info.ptr[data_offset].code < pc) {
+               if (++data_offset >= _jitc->data_info.length) {
+                   data_info = 0;
+                   goto again;
+               }
+           }
+           if (pc == _jitc->data_info.ptr[data_offset].code) {
+               offset = _jitc->data_info.ptr[data_offset].length;
+               for (; offset >= 4; offset -= 4, pc += 4) {
+                   bytes = sprintf(buffer, address_buffer_format, pc);
+                   (*disasm_info.fprintf_func)(disasm_stream,
+                                               "%*c0x%s\t.data\t0x%08x\n",
+                                               16 - bytes, ' ', buffer,
+                                               *(jit_uint32_t *)
+                                               (jit_uint32_t)pc);
+               }
+               /* reset disassemble information instead of attempting
+                * to hack the arm specific backend data structures to
+                * tell it to forward the required number of bytes. */
+               disasm_info.buffer = (jit_pointer_t)(jit_uint32_t)pc;
+               disasm_info.buffer_vma = (jit_uword_t)pc;
+               if ((disasm_info.buffer_length = end - pc) <= 0)
+                   break;
+           }
+       }
+#endif
+       if (jit_get_note((jit_uint8_t *)(jit_word_t)pc, &name, &file, &line) &&
+           (name != old_name || file != old_file || line != old_line)) {
+           (*disasm_info.fprintf_func)(disasm_stream, "# %s:%s:%d\n",
+                                       name ? name : "",
+                                       file ? file : "",
+                                       line);
+           old_name = name;
+           old_file = file;
+           old_line = line;
+       }
+
+       bytes = sprintf(buffer, address_buffer_format, (long long)pc);
+       (*disasm_info.fprintf_func)(disasm_stream, "%*c0x%s\t",
+                                   16 - bytes, ' ', buffer);
+       pc += (*disasm_print)(pc, &disasm_info);
+       putc('\n', disasm_stream);
+    }
+}
+#endif
diff --git a/deps/lightning/lib/jit_hppa-cpu.c b/deps/lightning/lib/jit_hppa-cpu.c
new file mode 100644 (file)
index 0000000..db5a36a
--- /dev/null
@@ -0,0 +1,2796 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+typedef struct idiv {
+    int                        quo;
+    int                        rem;
+} idiv_t;
+
+typedef struct udiv {
+    unsigned int       quo;
+    unsigned int       rem;
+} udiv_t;
+
+/* 16 spill bytes; -52 for first actual stack argument */
+#define params_offset          -32
+/* Assume all callee save registers may need to be spilled */
+#define alloca_offset          192
+#define _R0_REGNO              0
+#define _R1_REGNO              1
+#define _RP_REGNO              2
+#define _FP_REGNO              3
+#define _R19_REGNO             19
+#define _R23_REGNO             23
+#define _R24_REGNO             24
+#define _R25_REGNO             25
+#define _R26_REGNO             26
+#define _R28_REGNO             28
+#define _R29_REGNO             29
+#define _SP_REGNO              30
+#define _R31_REGNO             31
+#define _CR11_REGNO            11
+#define ii(v)                  *_jit->pc.ui++ = v
+#define f1(o,b,t,i)                    _f1(_jit,o,b,t,i)
+static void _f1(jit_state_t*,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t);
+#define f2(o,b,r,i,j)                  _f2(_jit,o,b,r,i,j)
+static void _f2(jit_state_t*,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f3(o,b,t,i,j)                  _f3(_jit,o,b,t,i,j)
+static void _f3(jit_state_t*,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t);
+#define f4(o,b,x,s,u,y,c,z,m,t)                _f4(_jit,o,b,x,s,u,y,c,z,m,t)
+static void _f4(jit_state_t*,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f5(o,b,i,s,a,y,c,z,m,t)                _f5(_jit,o,b,i,s,a,y,c,z,m,t)
+static void _f5(jit_state_t*,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f6(o,b,r,s,a,x,c,y,m,i)                _f6(_jit,o,b,r,s,a,x,c,y,m,i)
+static void _f6(jit_state_t*,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f7(o,r,i)                      _f7(_jit,o,r,i)
+static void _f7(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f8(o,r2,r1,cf,e1,x,e2,y,d,t)   _f8(_jit,o,r2,r1,cf,e1,x,e2,y,d,t)
+static void _f8(jit_state_t*,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t);
+#define f9(o,r,t,cf,e1,im)             _f9(_jit,o,r,t,cf,e1,im)
+static void _f9(jit_state_t*,
+               jit_int32_t,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t);
+#define f10(o,r2,r1,u,v,w,x,sa,y,t)    _f10(_jit,o,r2,r1,u,v,w,x,sa,y,t)
+static void _f10(jit_state_t*,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f11(o,r2,r1,c,x,y,z,u,t)       _f11(_jit,o,r2,r1,c,x,y,z,u,t)
+static void _f11(jit_state_t*,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f12(o,r,t,c,x,se,y,c1,z,clen)  _f12(_jit,o,r,t,c,x,se,y,c1,z,clen)
+static void _f12(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f13(o,t,r,c,x,nz,c1,clen)      _f13(_jit,o,t,r,c,x,nz,c1,clen)
+static void _f13(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t);
+#define f13x(o,t,i,c,x,nz,c1,clen)     _f13x(_jit,o,t,i,c,x,nz,c1,clen)
+static void _f13x(jit_state_t*,jit_int32_t,jit_int32_t,
+                 jit_int32_t,jit_int32_t,jit_int32_t,
+                 jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f14(o,r2,r1,c,x,cp,y,cpos,t)   _f14(_jit,o,r2,r1,c,x,cp,y,cpos,t)
+static void _f14(jit_state_t*,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f15(o,r,t,c,c1,p,se,pos,clen)  _f15(_jit,o,r,t,c,c1,p,se,pos,clen)
+static void _f15(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f16(o,t,r,c,c1,cp,nz,cpos,clen)        _f16(_jit,o,t,r,c,c1,cp,nz,cpos,clen)
+static void _f16(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f16x(o,t,i,c,c1,cp,nz,cpos,clen) _f16x(_jit,o,t,i,c,c1,cp,nz,cpos,clen)
+static void _f16x(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f17(o,r2,r1,c,i,n)             _f17(_jit,o,r2,r1,c,i,n)
+static void _f17(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f17x(o,r2,r1,c,i,n)            _f17x(_jit,o,r2,r1,c,i,n)
+static void _f17x(jit_state_t*,jit_int32_t,jit_int32_t,
+                 jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f18(o,p,r,c,i,n)               _f18(_jit,o,p,r,c,i,n)
+static void _f18(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f19(o,b,s,i,n)                 _f19(_jit,o,b,s,i,n)
+static void _f19(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f20(o,t,i,g,n)                 _f20(_jit,o,t,i,g,n)
+static void _f20(jit_state_t*,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t);
+#define f21(o,t,x,y,n)                 _f21(_jit,o,t,x,y,n)
+static void _f21(jit_state_t*,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t);
+#define f22(o,b,x,r,n,p)               _f22(_jit,o,b,x,r,n,p)
+static void _f22(jit_state_t*,jit_int32_t,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f23(o,a,b,c,d,e,f,g,h)         _f23(_jit,o,a,b,c,d,e,f,g,h)
+static void _f23(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f24(o,b,x,s,y,m,r)             _f24(_jit,o,b,x,s,y,m,r)
+static void _f24(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f25(o,b,i,s,y,m,r)             _f25(_jit,o,b,i,s,y,m,r)
+static void _f25(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f26(o,b,x,s,y,m,r)             _f26(_jit,o,b,x,s,y,m,r)
+static void _f26(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f27(o,i,j)                     _f27(_jit,o,i,j)
+static void _f27(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f28(o,i)                       _f28(_jit,o,i)
+static void _f28(jit_state_t*,jit_int32_t,jit_int32_t) maybe_unused;
+#define f29(o,r,x,s,y,t)               _f29(_jit,o,r,x,s,y,t)
+static void _f29(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f30(o,b,r,s,x,y,t)             _f30(_jit,o,b,r,s,x,y,t)
+static void _f30(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f31(o,t,r,v,x,y)               _f31(_jit,o,t,r,v,x,y)
+static void _f31(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f33(o,x,r,y,z,u)               _f33(_jit,o,x,r,y,z,u)
+static void _f33(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f34(o,o1,x,sf,n,o2)            _f34(_jit,o,o1,x,sf,n,o2)
+static void _f34(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f35(o,op,x,sf,n,t)             _f35(_jit,o,op,x,sf,n,t)
+static void _f35(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f36(o,r,o1,x,sf,n,o2)          _f36(_jit,o,r,o1,x,sf,n,o2)
+static void _f36(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f37(o,r2,r1,o1,x,sf,n,o2)      _f37(_jit,o,r2,r1,o1,x,sf,n,o2)
+static void _f37(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f38(o,s,u,n)                   _f38(_jit,o,s,u,n)
+static void _f38(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+/* nulify next instruction if condition is met with addition */
+#define ADD_CF_NV              0       /* never */
+#define ADD_CF_EQ              2       /* O1 == -O2 (word) */
+#define ADD_CF_LT              4       /* O1 <  -O2 (signed)*/
+#define ADD_CF_LE              6       /* O1 <= -O2 (signed) */
+#define ADD_CF_NUV             8       /* O1 +   O2 does not overflow (unsigned) */
+#define ADD_CF_ZNV             10      /* O1 +   O2 is zero or no overflow (unsigned) */
+#define ADD_CF_SV              12      /* O1 +   O2 overflows (signed) */
+#define ADD_CF_OD              14      /* O1 +   O2 is odd */
+#define ADD_CF_TR              1       /* always */
+#define ADD_CF_NE              3       /* O1 != -O2 */
+#define ADD_CF_GE              5       /* O1 >= -O2 (signed) */
+#define ADD_CF_GT              7       /* O1 >  -O2 (signed) */
+#define ADD_CF_UV              9       /* O1 +   O2 overflows (unsigned) */
+#define ADD_CF_VNZ             11      /* O1 +   O2 is nonzero and overflows (unsigned) */
+#define ADD_CF_NSV             13      /* O1 +   O2 does not overflow (signed) */
+#define ADD_CF_EV              15      /* O1 +   O2 is even */
+#define ADD_EN_NONE            6       /* none */
+#define ADD_EN_C               7       /* with carry */
+#define ADD_EN_L               10      /* logical */
+#define ADD_EN_TSV             12      /* trap on signed overflow */
+#define ADD_EN_C_TSV           13      /* with carry and trap on signed overflow */
+#define ADDI_OE_TC             0       /* trap on condition */
+#define ADDI_OE_TSV_TC         1       /* trap on signed overflow or condition */
+#define ADDI_OE_NONE           2       /* none */
+#define ADDI_OE_TSV            3       /* trap on signed overflow */
+#define ADD_(en,cf,r1,r2,t)    f8(0x2,r2,r1,cf,en>>2,1,en&1,0,0,t)
+#define ADD(r1,r2,t)           ADD_(ADD_EN_NONE,ADD_CF_NV,r1,r2,t)
+#define ADD_C(r1,r2,t)         ADD_(ADD_EN_C,ADD_CF_NV,r1,r2,t)
+#define ADD_L(r1,r2,t)         ADD_(ADD_EN_L,ADD_CF_NV,r1,r2,t)
+#define ADDB_(cc,r1,r2,t)      f17(0x28|((cc&1)<<1),r2,r1,cc>>1,t,0)
+#define ADDB(r1,r2,t)          ADDB_(ADD_CF_NV,r1,r2,t)
+#define ADDB_EQ(r1,r2,t)       ADDB_(ADD_CF_EQ,r1,r2,t)
+#define ADDB_LT(r1,r2,t)       ADDB_(ADD_CF_LT,r1,r2,t)
+#define ADDB_LE(r1,r2,t)       ADDB_(ADD_CF_LE,r1,r2,t)
+#define ADDB_NUV(r1,r2,t)      ADDB_(ADD_CF_NUV,r1,r2,t)
+#define ADDB_ZNV(r1,r2,t)      ADDB_(ADD_CF_ZNV,r1,r2,t)
+#define ADDB_SV(r1,r2,t)       ADDB_(ADD_CF_SV,r1,r2,t)
+#define ADDB_OD(r1,r2,t)       ADDB_(ADD_CF_OD,r1,r2,t)
+#define ADDB_TR(r1,r2,t)       ADDB_(ADD_CF_TR,r1,r2,t)
+#define ADDB_NE(r1,r2,t)       ADDB_(ADD_CF_NE,r1,r2,t)
+#define ADDB_GE(r1,r2,t)       ADDB_(ADD_CF_GE,r1,r2,t)
+#define ADDB_GT(r1,r2,t)       ADDB_(ADD_CF_GT,r1,r2,t)
+#define ADDB_UV(r1,r2,t)       ADDB_(ADD_CF_UV,r1,r2,t)
+#define ADDB_VNZ(r1,r2,t)      ADDB_(ADD_CF_VNZ,r1,r2,t)
+#define ADDB_NSV(r1,r2,t)      ADDB_(ADD_CF_NSV,r1,r2,t)
+#define ADDB_EV(r1,r2,t)       ADDB_(ADD_CF_EV,r2,r1,t)
+#define ADDB_N_(cc,r1,r2,t)    f17(0x28|((cc&1)<<1),r2,r1,cc>>1,t,1)
+#define ADDB_N(r1,r2,t)                ADDB_N_(ADD_CF_NV,r1,r2,t)
+#define ADDB_N_EQ(r1,r2,t)     ADDB_N_(ADD_CF_EQ,r1,r2,t)
+#define ADDB_N_LT(r1,r2,t)     ADDB_N_(ADD_CF_LT,r1,r2,t)
+#define ADDB_N_LE(r1,r2,t)     ADDB_N_(ADD_CF_LE,r1,r2,t)
+#define ADDB_N_NUV(r1,r2,t)    ADDB_N_(ADD_CF_NUV,r1,r2,t)
+#define ADDB_N_ZNV(r1,r2,t)    ADDB_N_(ADD_CF_ZNV,r1,r2,t)
+#define ADDB_N_SV(r1,r2,t)     ADDB_N_(ADD_CF_SV,r1,r2,t)
+#define ADDB_N_OD(r1,r2,t)     ADDB_N_(ADD_CF_OD,r1,r2,t)
+#define ADDB_N_TR(r1,r2,t)     ADDB_N_(ADD_CF_TR,r1,r2,t)
+#define ADDB_N_NE(r1,r2,t)     ADDB_N_(ADD_CF_NE,r1,r2,t)
+#define ADDB_N_GE(r1,r2,t)     ADDB_N_(ADD_CF_GE,r1,r2,t)
+#define ADDB_N_GT(r1,r2,t)     ADDB_N_(ADD_CF_GT,r1,r2,t)
+#define ADDB_N_UV(r1,r2,t)     ADDB_N_(ADD_CF_UV,r1,r2,t)
+#define ADDB_N_VNZ(r1,r2,t)    ADDB_N_(ADD_CF_VNZ,r1,r2,t)
+#define ADDB_N_NSV(r1,r2,t)    ADDB_N_(ADD_CF_NSV,r1,r2,t)
+#define ADDB_N_EV(r1,r2,t)     ADDB_N_(ADD_CF_EV,r1,r2,t)
+#define ADDI_(ec,cf,i,r,t)     f9(0x2c|(ec>>1),r,t,cf,ec&1,i)
+#define ADDI(i,r,t)            ADDI_(ADDI_OE_NONE,ADD_CF_NV,i,r,t)
+#define ADDIB_(cc,i,r,t)       f17x(0x29|((cc&1)<<1),r,i,cc>>1,t,0)
+#define ADDIB(i,r,t)           ADDIB_(ADD_CF_NV,i,r,t)
+#define ADDIB_EQ(i,r,t)                ADDIB_(ADD_CF_EQ,i,r,t)
+#define ADDIB_LT(i,r,t)                ADDIB_(ADD_CF_LT,i,r,t)
+#define ADDIB_LE(i,r,t)                ADDIB_(ADD_CF_LE,i,r,t)
+#define ADDIB_NUV(i,r,t)       ADDIB_(ADD_CF_NUV,i,r,t)
+#define ADDIB_ZNV(i,r,t)       ADDIB_(ADD_CF_ZNV,i,r,t)
+#define ADDIB_SV(i,r,t)                ADDIB_(ADD_CF_SV,i,r,t)
+#define ADDIB_OD(i,r,t)                ADDIB_(ADD_CF_OD,i,r,t)
+#define ADDIB_TR(i,r,t)                ADDIB_(ADD_CF_TR,i,r,t)
+#define ADDIB_NE(i,r,t)                ADDIB_(ADD_CF_NE,i,r,t)
+#define ADDIB_GE(i,r,t)                ADDIB_(ADD_CF_GE,i,r,t)
+#define ADDIB_GT(i,r,t)                ADDIB_(ADD_CF_GT,i,r,t)
+#define ADDIB_UV(i,r,t)                ADDIB_(ADD_CF_UV,i,r,t)
+#define ADDIB_VNZ(i,r,t)       ADDIB_(ADD_CF_VNZ,i,r,t)
+#define ADDIB_NSV(i,r,t)       ADDIB_(ADD_CF_NSV,i,r,t)
+#define ADDIB_EV(i,r,t)                ADDIB_(ADD_CF_EV,i,r,t)
+#define ADDIB_N_(cc,i,r,t)     f17x(0x29|((cc&1)<<1),r,i,cc>>1,t,1)
+#define ADDIB_N(i,r,t)         ADDIB_N_(ADD_CF_NV,i,r,t)
+#define ADDIB_N_EQ(i,r,t)      ADDIB_N_(ADD_CF_EQ,i,r,t)
+#define ADDIB_N_LT(i,r,t)      ADDIB_N_(ADD_CF_LT,i,r,t)
+#define ADDIB_N_LE(i,r,t)      ADDIB_N_(ADD_CF_LE,i,r,t)
+#define ADDIB_N_NUV(i,r,t)     ADDIB_N_(ADD_CF_NUV,i,r,t)
+#define ADDIB_N_ZNV(i,r,t)     ADDIB_N_(ADD_CF_ZNV,i,r,t)
+#define ADDIB_N_SV(i,r,t)      ADDIB_N_(ADD_CF_SV,i,r,t)
+#define ADDIB_N_OD(i,r,t)      ADDIB_N_(ADD_CF_OD,i,r,t)
+#define ADDIB_N_TR(i,r,t)      ADDIB_N_(ADD_CF_TR,i,r,t)
+#define ADDIB_N_NE(i,r,t)      ADDIB_N_(ADD_CF_NE,i,r,t)
+#define ADDIB_N_GE(i,r,t)      ADDIB_N_(ADD_CF_GE,i,r,t)
+#define ADDIB_N_GT(i,r,t)      ADDIB_N_(ADD_CF_GT,i,r,t)
+#define ADDIB_N_UV(i,r,t)      ADDIB_N_(ADD_CF_UV,i,r,t)
+#define ADDIB_N_VNZ(i,r,t)     ADDIB_N_(ADD_CF_VNZ,i,r,t)
+#define ADDIB_N_NSV(i,r,t)     ADDIB_N_(ADD_CF_NSV,i,r,t)
+#define ADDIB_N_EV(i,r,t)      ADDIB_N_(ADD_CF_EV,0,i,r,t)
+#define ADDIL(i,r)             f7(0xa,r,i)
+#define LOG_CC_NV              0       /* never */
+#define LOG_CC_EQ              1       /* all bits are 0 */
+#define LOG_CC_LT              2       /* leftmost bit is 1 */
+#define LOG_CC_LE              3       /* leftmost bit is 1 or all bits are 0 */
+#define LOG_CC_OD              7       /* rightmost bit is 1 */
+#define LOG_CC_TR              8       /* always */
+#define LOG_CC_NE              9       /* some bits are 1 */
+#define LOG_CC_GE              10      /* leftmost bit is 0 */
+#define LOG_CC_GT              11      /* leftmost bit is 0 or some bits are 1 */
+#define LOG_CC_EV              15      /* rightmost bit is 0 */
+#define AND_(cc,r1,r2,t)       f8(0x2,r2,r1,cc,0,1,0,0,0,t)
+#define AND(r1,r2,t)           AND_(LOG_CC_NV,r1,r2,t)
+#define ANDCM_(cc,r1,r2,t)     f8(0x2,r2,r1,cc,0,0,0,0,0,t)
+#define ANDCM(r1,r2,t)         ANDCM_(LOG_CC_NV,r1,r2,t)
+#define B_(n,i,t)              f20(0x3a,t,i,0,n)
+#define B(i,t)                 B_(0,i,t)
+#define B_N(i,t)               B_(1,i,t)
+#define B_L(i)                 B_(0,i,_RP_REGNO)
+#define B_L_N(i)               B_(1,i,_RP_REGNO)
+#define BB_CC_LT               0       /* leftmost bit in word is 1 */
+#define BB_CC_GE               1       /* leftmost bit in word is 0 */
+#define BB_(c,r,i)             f18(0x30,0,r,c,i,0)
+#define BB_N_(c,r,i)           f18(0x30,0,r,c,i,1)
+#define BBI_(c,r,p,i)          f18(0x31,p,r,c,i,0)
+#define BBI_N_(c,r,p,i)                f18(0x31,p,r,c,i,1)
+#define BB(c,r,i)              BB_(c,r,i)
+#define BBI_LT(r,p,i)          BBI_(BB_CC_LT,r,p,i)
+#define BBI_GE(r,p,i)          BBI_(BB_CC_GE,r,p,i)
+#define BB_N(c,r,i)            BB_(c,r,i)
+#define BBI_N_LT(r,p,i)                BBI_N_(BB_CC_LT,r,p,i)
+#define BBI_N_GE(r,p,i)                BBI_N_(BB_CC_GE,r,p,i)
+#define BE(i,s,b)              f19(0x38,b,s,i,0)
+#define BE_L(i,s,b)            f19(0x39,b,s,i,0)
+#define BE_L_N(i,s,b)          f19(0x39,b,s,i,1)
+#define BLR(x,t)               f21(0x3a,t,x,2,0)
+#define BLR_N(x,t)             f21(0x3a,t,x,2,1)
+#define BREAK(i,j)             f27(0,j,i)
+#define BV(x,b)                        f21(0x3a,b,x,6,0)
+#define BV_N(x,b)              f21(0x3a,b,x,6,1)
+#define BVE(b)                 f22(0x3a,b,6,0,0,0)
+#define BVE_N(b)               f22(0x3a,b,6,0,1,0)
+#define BVE_L(b)               f22(0x3a,b,7,0,0,0)
+#define BVE_L_N(b)             f22(0x3a,b,7,0,0,1)
+#define II_C_NONE              0
+#define II_C_M                 (1<<5)
+#define II_C_S                 (1<<13)
+#define II_C_SM                        (II_C_S|II_C_M)
+#define II_AU_NONE             0
+#define II_AU_PRE              ((1<<13)|II_C_M)
+#define II_AU_POS              II_C_M
+#define LD_CC_H_NONE           0       /* No hint */
+#define LD_CC_H_SPL            2       /* Spatial Locality */
+#define CLRBTS()               f23(0x3a,0,0,2,0,0,1,0,1)
+#define CS_CC_NV               0       /* never */
+#define CS_CC_EQ               2       /* O1 =  O2 */
+#define CS_CC_LT               4       /* O1 <  O2 (signed) */
+#define CS_CC_LE               6       /* O1 <= O2 (signed) */
+#define CS_CC_ULT              8       /* O1 <  O2 (unsigned) */
+#define CS_CC_ULE              10      /* O1 <= O2 (unsigned) */
+#define CS_CC_SV               12      /* O1 -  O2 overflows (signed) */
+#define CS_CC_OD               14      /* O1 -  O2 is odd */
+#define CS_CC_TR               1       /* always */
+#define CS_CC_NE               3       /* O1 != O2 */
+#define CS_CC_GE               5       /* O1 >= O2 (signed) */
+#define CS_CC_GT               7       /* O1 >  O2 (signed) */
+#define CS_CC_UGE              9       /* O1 >= O2 (unsigned) */
+#define CS_CC_UGT              11      /* O1 >  O2 (unsigned) */
+#define CS_CC_NSV              13      /* O1 -  O2 does not overflows (signed) */
+#define CS_CC_EV               15      /* O1 -  O2 is even */
+#define CMPB_(c,r1,r2,i)       f17((c)&1?0x22:0x20,r2,r1,(c)>>1,i,0)
+#define CMPB(r1,r2,i)          CMPB_(CS_CC_NV,r1,r2,i)
+#define CMPB_EQ(r1,r2,i)       CMPB_(CS_CC_EQ,r1,r2,i)
+#define CMPB_LT(r1,r2,i)       CMPB_(CS_CC_LT,r1,r2,i)
+#define CMPB_LE(r1,r2,i)       CMPB_(CS_CC_LE,r1,r2,i)
+#define CMPB_ULT(r1,r2,i)      CMPB_(CS_CC_ULT,r1,r2,i)
+#define CMPB_ULE(r1,r2,i)      CMPB_(CS_CC_ULE,r1,r2,i)
+#define CMPB_SV(r1,r2,i)       CMPB_(CS_CC_SV,r1,r2,i)
+#define CMPB_OD(r1,r2,i)       CMPB_(CS_CC_OD,r1,r2,i)
+#define CMPB_TR(r1,r2,i)       CMPB_(CS_CC_TR,r1,r2,i)
+#define CMPB_NE(r1,r2,i)       CMPB_(CS_CC_NE,r1,r2,i)
+#define CMPB_GE(r1,r2,i)       CMPB_(CS_CC_GE,r1,r2,i)
+#define CMPB_GT(r1,r2,i)       CMPB_(CS_CC_GT,r1,r2,i)
+#define CMPB_UGE(r1,r2,i)      CMPB_(CS_CC_UGE,r1,r2,i)
+#define CMPB_UGT(r1,r2,i)      CMPB_(CS_CC_UGT,r1,r2,i)
+#define CMPB_NSV(r1,r2,i)      CMPB_(CS_CC_NSV,r1,r2,i)
+#define CMPB_EV(r1,r2,i)       CMPB_(CS_CC_EV,r1,r2,i)
+#define CMPB_N_(c,r1,r2,i)     f17((c)&1?0x22:0x20,r2,r1,(c)>>1,i,1)
+#define CMPB_N(r1,r2,i)                CMPB_N_(CS_CC_NV,r1,r2,i)
+#define CMPB_EQ_N(r1,r2,i)     CMPB_N_(CS_CC_EQ,r1,r2,i)
+#define CMPB_LT_N(r1,r2,i)     CMPB_N_(CS_CC_LT,r1,r2,i)
+#define CMPB_LE_N(r1,r2,i)     CMPB_N_(CS_CC_LE,r1,r2,i)
+#define CMPB_ULT_N(r1,r2,i)    CMPB_N_(CS_CC_ULT,r1,r2,i)
+#define CMPB_ULE_N(r1,r2,i)    CMPB_N_(CS_CC_ULE,r1,r2,i)
+#define CMPB_SV_N(r1,r2,i)     CMPB_N_(CS_CC_SV,r1,r2,i)
+#define CMPB_OD_N(r1,r2,i)     CMPB_N_(CS_CC_OD,r1,r2,i)
+#define CMPB_TR_N(r1,r2,i)     CMPB_N_(CS_CC_TR,r1,r2,i)
+#define CMPB_NE_N(r1,r2,i)     CMPB_N_(CS_CC_NE,r1,r2,i)
+#define CMPB_GE_N(r1,r2,i)     CMPB_N_(CS_CC_GE,r1,r2,i)
+#define CMPB_GT_N(r1,r2,i)     CMPB_N_(CS_CC_GT,r1,r2,i)
+#define CMPB_UGE_N(r1,r2,i)    CMPB_N_(CS_CC_UGE,r1,r2,i)
+#define CMPB_UGT_N(r1,r2,i)    CMPB_N_(CS_CC_UGT,r1,r2,i)
+#define CMPB_NSV_N(r1,r2,i)    CMPB_N_(CS_CC_NSV,r1,r2,i)
+#define CMPB_EV_N(r1,r2,i)     CMPB_N_(CS_CC_EV,r1,r2,i)
+#define CMPCLR_(c,r1,r2,i)     f8(0x2,r2,r1,c,2,0,0,2,0,i)
+#define CMPCLR(r1,r2,i)                CMPCLR_(CS_CC_NV,r1,r2,i)
+#define CMPCLR_EQ(r1,r2,i)     CMPCLR_(CS_CC_EQ,r1,r2,i)
+#define CMPCLR_LT(r1,r2,i)     CMPCLR_(CS_CC_LT,r1,r2,i)
+#define CMPCLR_LE(r1,r2,i)     CMPCLR_(CS_CC_LE,r1,r2,i)
+#define CMPCLR_ULT(r1,r2,i)    CMPCLR_(CS_CC_ULT,r1,r2,i)
+#define CMPCLR_ULE(r1,r2,i)    CMPCLR_(CS_CC_ULE,r1,r2,i)
+#define CMPCLR_SV(r1,r2,i)     CMPCLR_(CS_CC_SV,r1,r2,i)
+#define CMPCLR_OD(r1,r2,i)     CMPCLR_(CS_CC_OD,r1,r2,i)
+#define CMPCLR_TR(r1,r2,i)     CMPCLR_(CS_CC_TR,r1,r2,i)
+#define CMPCLR_NE(r1,r2,i)     CMPCLR_(CS_CC_NE,r1,r2,i)
+#define CMPCLR_GE(r1,r2,i)     CMPCLR_(CS_CC_GE,r1,r2,i)
+#define CMPCLR_GT(r1,r2,i)     CMPCLR_(CS_CC_GT,r1,r2,i)
+#define CMPCLR_UGE(r1,r2,i)    CMPCLR_(CS_CC_UGE,r1,r2,i)
+#define CMPCLR_UGT(r1,r2,i)    CMPCLR_(CS_CC_UGT,r1,r2,i)
+#define CMPCLR_NSV(r1,r2,i)    CMPCLR_(CS_CC_NSV,r1,r2,i)
+#define CMPCLR_EV(r1,r2,i)     CMPCLR_(CS_CC_EV,r1,r2,i)
+#define CMPIB_(c,i,r,t)                f17x((c)&1?0x23:0x21,r,i,(c)>>1,t,0)
+#define CMPIB_NONE(i,r,t)      CMPIB_(CS_CC_NV,i,r,t)
+#define CMPIB_EQ(i,r,t)                CMPIB_(CS_CC_EQ,i,r,t)
+#define CMPIB_LT(i,r,t)                CMPIB_(CS_CC_LT,i,r,t)
+#define CMPIB_LE(i,r,t)                CMPIB_(CS_CC_LE,i,r,t)
+#define CMPIB_ULT(i,r,t)       CMPIB_(CS_CC_ULT,i,r,t)
+#define CMPIB_ULE(i,r,t)       CMPIB_(CS_CC_ULE,i,r,t)
+#define CMPIB_SV(i,r,t)                CMPIB_(CS_CC_SV,i,r,t)
+#define CMPIB_OD(i,r,t)                CMPIB_(CS_CC_OD,i,r,t)
+#define CMPIB(i,r,t)           CMPIB_(CS_CC_TR,i,r,t)
+#define CMPIB_NE(i,r,t)                CMPIB_(CS_CC_NE,i,r,t)
+#define CMPIB_GE(i,r,t)                CMPIB_(CS_CC_GE,i,r,t)
+#define CMPIB_GT(i,r,t)                CMPIB_(CS_CC_GT,i,r,t)
+#define CMPIB_UGE(i,r,t)       CMPIB_(CS_CC_UGE,i,r,t)
+#define CMPIB_UGT(i,r,t)       CMPIB_(CS_CC_UGT,i,r,t)
+#define CMPIB_NSV(i,r,t)       CMPIB_(CS_CC_NSV,i,r,t)
+#define CMPIB_EV(i,r,t)                CMPIB_(CS_CC_EV,i,r,t)
+#define CMPIB_N_(c,i,r,t)      f17x((c)&1?0x23:0x21,r,i,(c)>>1,t,1)
+#define CMPIB_NONE_N(i,r,t)    CMPIB_N_(CS_CC_NV,i,r,t)
+#define CMPIB_EQ_N(i,r,t)      CMPIB_N_(CS_CC_EQ,i,r,t)
+#define CMPIB_LT_N(i,r,t)      CMPIB_N_(CS_CC_LT,i,r,t)
+#define CMPIB_LE_N(i,r,t)      CMPIB_N_(CS_CC_LE,i,r,t)
+#define CMPIB_ULT_N(i,r,t)     CMPIB_N_(CS_CC_ULT,i,r,t)
+#define CMPIB_ULE_N(i,r,t)     CMPIB_N_(CS_CC_ULE,i,r,t)
+#define CMPIB_SV_N(i,r,t)      CMPIB_N_(CS_CC_SV,i,r,t)
+#define CMPIB_OD_N(i,r,t)      CMPIB_N_(CS_CC_OD,i,r,t)
+#define CMPIB_N(i,r,t)         CMPIB_N_(CS_CC_TR,i,r,t)
+#define CMPIB_NE_N(i,r,t)      CMPIB_N_(CS_CC_NE,i,r,t)
+#define CMPIB_GE_N(i,r,t)      CMPIB_N_(CS_CC_GE,i,r,t)
+#define CMPIB_GT_N(i,r,t)      CMPIB_N_(CS_CC_GT,i,r,t)
+#define CMPIB_UGE_N(i,r,t)     CMPIB_N_(CS_CC_UGE,i,r,t)
+#define CMPIB_UGT_N(i,r,t)     CMPIB_N_(CS_CC_UGT,i,r,t)
+#define CMPIB_NSV_N(i,r,t)     CMPIB_N_(CS_CC_NSV,i,r,t)
+#define CMPIB_EV_N(i,r,t)      CMPIB_N_(CS_CC_EV,i,r,t)
+#define CMPICLR_(c,i,r,t)      f9(0x24,r,t,c,0,i)
+#define CMPICLR(i,r,t)         CMPICLR_(CS_CC_NV,i,r,t)
+#define CMPICLR_EQ(i,r,t)      CMPICLR_(CS_CC_EQ,i,r,t)
+#define CMPICLR_LT(i,r,t)      CMPICLR_(CS_CC_LT,i,r,t)
+#define CMPICLR_LE(i,r,t)      CMPICLR_(CS_CC_LE,i,r,t)
+#define CMPICLR_ULT(i,r,t)     CMPICLR_(CS_CC_ULT,i,r,t)
+#define CMPICLR_ULE(i,r,t)     CMPICLR_(CS_CC_ULE,i,r,t)
+#define CMPICLR_SV(i,r,t)      CMPICLR_(CS_CC_SV,i,r,t)
+#define CMPICLR_OD(i,r,t)      CMPICLR_(CS_CC_OD,i,r,t)
+#define CMPICLR_TR(i,r,t)      CMPICLR_(CS_CC_TR,i,r,t)
+#define CMPICLR_NE(i,r,t)      CMPICLR_(CS_CC_NE,i,r,t)
+#define CMPICLR_GE(i,r,t)      CMPICLR_(CS_CC_GE,i,r,t)
+#define CMPICLR_GT(i,r,t)      CMPICLR_(CS_CC_GT,i,r,t)
+#define CMPICLR_UGE(i,r,t)     CMPICLR_(CS_CC_UGE,i,r,t)
+#define CMPICLR_UGT(i,r,t)     CMPICLR_(CS_CC_UGT,i,r,t)
+#define CMPICLR_NSV(i,r,t)     CMPICLR_(CS_CC_NSV,i,r,t)
+#define CMPICLR_EV(i,r,t)      CMPICLR_(CS_CC_EV,i,r,t)
+#define COPR(u,s)              f38(0x0c,s,u,0)
+#define UI_CF_NONE             0       /* never */
+#define UI_CF_SBZ              2       /* some byte zero */
+#define UI_CF_SHZ              3       /* some halfword zero */
+#define UI_CF_SDC              4       /* some digit carry */
+#define UI_CF_SBC              6       /* some byte carry */
+#define UI_CF_SHC              7       /* some halfword carry */
+#define UI_TR_SHC              8       /* always */
+#define UI_CF_NBZ              10      /* no byte zero */
+#define UI_CF_NHZ              11      /* no halfword zero */
+#define UI_CF_NDC              12      /* no digit carry */
+#define UI_CF_NBC              14      /* no byte carry */
+#define UI_CF_NHC              15      /* no halfword carry */
+#define DCOR_(e1,cf,r,t)       f8(0x2,r,0,cf,2,1,1,e1,0,t)
+#define DCOR(r,t)              DCOR_(2,UI_CF_NONE,r,t)
+#define DCOR_I(r,t)            DCOR_(3,UI_CF_NONE,r,t)
+#define SED_C_NEVER            0       /* never */
+#define SED_C_EQ               1       /* all bits 0 */
+#define SED_C_LT               2       /* lefmost bits 1 */
+#define SED_C_OD               3       /* rightmost bit 1 */
+#define SED_C_TR               4       /* always */
+#define SED_C_NE               5       /* some bit 1 */
+#define SED_C_GE               6       /* lefmost bits 1 */
+#define SED_C_EV               7       /* rightmost bit 0 */
+#define DEPW(r,len,t)          f13(0x35,t,r,SED_C_NEVER,0,1,0,len)
+#define DEPW_Z(r,len,t)                f13(0x35,t,r,SED_C_NEVER,0,0,0,len)
+#define DEPWR(r,pos,len,t)     f16(0x35,t,r,SED_C_NEVER,0,1,1,31-(pos),len)
+#define DEPWR_Z(r,pos,len,t)   f16(0x35,t,r,SED_C_NEVER,0,1,0,31-(pos),len)
+#define SHLWI(r,sa,t)          DEPWR_Z(r,31-(sa),32-(sa),t)
+#define DEPWI(i,len,t)         f13x(0x35,t,i,SED_C_NEVER,2,1,0,len)
+#define DEPWI_Z(i,len,t)       f13x(0x35,t,i,SED_C_NEVER,2,0,0,len)
+#define DEPWRI(i,pos,len,t)    f16x(0x35,t,i,SED_C_NEVER,1,1,1,31-(pos),len)
+#define DEPWRI_Z(i,pos,len,t)  f16x(0x35,t,i,SED_C_NEVER,1,1,0,31-(pos),len)
+#define DIAG(i)                        f28(0x5,i)
+#define DS(r1,r2,t)            f8(0x2,r2,r1,ADD_CF_NV,1,0,0,1,0,t)
+#define EXTRW(r,len,t)         f12(0x34,r,t,SED_C_NEVER,2,1,0,0,0,len)
+#define EXTRW_U(r,len,t)       f12(0x34,r,t,SED_C_NEVER,2,0,0,0,0,len)
+#define EXTRWR(r,pos,len,t)    f15(0x34,r,t,SED_C_NEVER,1,1,1,pos,len)
+#define SHRWI(r,sa,t)          EXTRWR(r,31-(sa),32-(sa),t)
+#define EXTRWR_U(r,pos,len,t)  f15(0x34,r,t,SED_C_NEVER,1,1,0,pos,len)
+#define SHRWI_U(r,sa,t)                EXTRWR_U(r,31-(sa),32-(sa),t)
+#define FDC(x,s,b)             f24(0x1,b,x,s,0x4a,0,0)
+#define FDC_M(x,s,b)           f24(0x1,b,x,s,0x4a,1,0)
+#define FDCI(i,s,b)            f25(0x1,b,i,s,0xca,0,0)
+#define FDCE(x,s,b)            f24(0x1,b,x,s,0x4b,0,0)
+#define FDCE_M(x,s,b)          f24(0x1,b,x,s,0x4b,1,0)
+#define FIC(x,s,b)             f26(0x1,b,x,s,0xa,0,0)
+#define FIC_M(x,s,b)           f26(0x1,b,x,s,0xa,1,0)
+#define FICI(x,s,b)            f25(0x1,b,x,s,0x4f,0,0)
+#define FICI_M(x,s,b)          f25(0x1,b,x,s,0x4f,1,0)
+#define FICE(x,s,b)            f26(0x1,b,x,s,0xb,0,0)
+#define FICE_M(x,s,b)          f26(0x1,b,x,s,0xb,1,0)
+#define HADD_(c,r1,r2,t)       f8(0x2,r2,r1,0,0,1,1,c,0,t)
+#define HADD(r1,r2,t)          HADD_(3,r1,r2,t)
+#define HADD_SS(r1,r2,t)       HADD_(1,r1,r2,t)
+#define HADD_US(r1,r2,t)       HADD_(0,r1,r2,t)
+#define HAVG(r1,r2,t)          f8(0x2,r2,r1,0,0,1,0,3,0,t)
+#define HSHL(r,sa,t)           f10(0x3e,0,r,1,0,0,2,sa,0,t)
+#define HSHLADD(r1,sa,r2,t)    f8(0x2,r2,r1,0,1,1,1,sa,0,t)
+#define HSHR(r,sa,t)           f10(0x3e,r,0,1,2,0,3,sa,0,t)
+#define HSHR_U(r,sa,t)         f10(0x3e,r,0,1,2,0,2,sa,0,t)
+#define HSHRADD(r1,sa,r2,t)    f8(0x2,r2,r1,0,1,0,1,sa,0,t)
+#define HSUB_(c,r1,r2,t)       f8(0x2,r2,r1,0,0,0,1,c,0,t)
+#define HSUB(r1,r2,t)          HSUB_(3,r1,r2,t)
+#define HSUB_SS(r1,r2,t)       HSUB_(1,r1,r2,t)
+#define HSUB_US(r1,r2,t)       HSUB_(0,r1,r2,t)
+#define IDTLBT(r1,r2)          f26(0x1,r2,r1,0,0x60,0,0)
+#define IITLBT(r1,r2)          f26(0x1,r2,r1,0,0x20,0,0)
+#define LCI(x,s,b,t)           f24(0x1,b,x,s,0x4c,0,t)
+#define LDBL(i,b,t)            f1(0x10,b,t,i)
+#define LDB(x,b,t)             f4(0x3,b,x,0,0,0,LD_CC_H_NONE,0,0,t)
+#define LDBI(i,b,t)            f5(0x3,b,i,0,0,1,LD_CC_H_NONE,0,0,t)
+#define LDCD(x,b,t)            f4(0x3,b,x,0,0,0,LD_CC_H_NONE,5,0,t)
+#define LDCDI(i,b,t)           f5(0x3,b,i,0,0,1,LD_CC_H_NONE,5,0,t)
+#define LDCW(x,b,t)            f4(0x3,b,x,0,0,0,LD_CC_H_NONE,7,0,t)
+#define LDCWI(i,b,t)           f5(0x3,b,i,0,0,1,LD_CC_H_NONE,7,0,t)
+#define LDDL(i,b,t)            f3(0x14,b,t,i,0)
+#define LDD(x,b,t)             f4(0x3,b,x,0,0,0,LD_CC_H_NONE,3,0,t)
+#define LDDI(i,b,t)            f5(0x3,b,i,0,0,1,LD_CC_H_NONE,3,0,t)
+#define LDDA(x,b,t)            f4(0x3,b,x,0,0,0,LD_CC_H_NONE,4,0,t)
+#define LDDAI(i,b,t)           f5(0x3,b,i,0,0,1,LD_CC_H_NONE,4,0,t)
+#define LDHL(i,b,t)            f1(0x11,b,t,i)
+#define LDH(x,b,t)             f4(0x3,b,x,0,0,0,LD_CC_H_NONE,1,0,t)
+#define LDHI(i,b,t)            f5(0x3,b,i,0,0,1,LD_CC_H_NONE,1,0,t)
+#define LDIL(i,t)              f7(0x8,t,i)
+#define LDO(i,b,t)             f1(0xd,b,t,i)
+#define LDI(i,t)               LDO(i,0,t)
+#define LDSID(s,b,t)           f30(0x0,b,0,s,0,0x85,t)
+#define LDWL(i,b,t)            f1(0x12,b,t,i)
+#define LDWL_MB(i,b,t)         f1(0x13,b,t,i)  /* pre-dec or post-inc */
+#define LDWL_MA(i,b,t)         f2(0x17,b,t,i,2)/* post-dec or pre-inc */
+#define LDW(x,b,t)             f4(0x3,b,x,0,0,0,LD_CC_H_NONE,2,0,t)
+#define LDWI(i,b,t)            f5(0x3,b,i,0,0,1,LD_CC_H_NONE,2,0,t)
+#define LDWA(x,b,t)            f4(0x3,b,x,0,0,0,LD_CC_H_NONE,6,0,t)
+#define LDWAI(i,b,t)           f5(0x3,b,i,0,0,1,LD_CC_H_NONE,6,0,t)
+#define LPA(x,s,b,t)           f24(0x1,b,x,s,0x4d,0,t)
+#define MFSP(s,t)              f29(0x0,0,0,s,0x25,t)
+#define MIXH_L(r1,r2,t)                f10(0x3e,r2,r1,1,0,0,1,0,0,t)
+#define MIXH_R(r1,r2,t)                f10(0x3e,r2,r1,1,2,0,1,0,0,t)
+#define MIXW_L(r1,r2,t)                f10(0x3e,r2,r1,1,0,0,0,0,0,t)
+#define MIXW_R(r1,r2,t)                f10(0x3e,r2,r1,1,2,0,0,0,0,t)
+#define MOVB_(c,r1,r2,i)       f17(0x32,r2,r1,c,i,0)
+#define MOVB(r1,r2,i)          MOVB_(SED_C_NEVER,r1,r2,i)
+#define MOVB_EQ(r1,r2,i)       MOVB_(SED_C_EQ,r1,r2,i)
+#define MOVB_LT(r1,r2,i)       MOVB_(SED_C_LT,r1,r2,i)
+#define MOVB_OD(r1,r2,i)       MOVB_(SED_C_OD,r1,r2,i)
+#define MOVB_TR(r1,r2,i)       MOVB_(SED_C_TR,r1,r2,i)
+#define MOVB_NE(r1,r2,i)       MOVB_(SED_C_NE,r1,r2,i)
+#define MOVB_GE(r1,r2,i)       MOVB_(SED_C_GE,r1,r2,i)
+#define MOVB_EV(r1,r2,i)       MOVB_(SED_C_EV,r1,r2,i)
+#define MOVIB_(c,r,i,t)                f17x(0x33,r,i,c,t,0)
+#define MOVIB(i,r,t)           MOVIB_(SED_C_NEVER,i,r,t)
+#define MOVIB_EQ(i,r,t)                MOVIB_(SED_C_EQ,i,r,t)
+#define MOVIB_LT(i,r,t)                MOVIB_(SED_C_LT,i,r,t)
+#define MOVIB_OD(i,r,t)                MOVIB_(SED_C_OD,i,r,t)
+#define MOVIB_TR(i,r,t)                MOVIB_(SED_C_TR,i,r,t)
+#define MOVIB_NE(i,r,t)                MOVIB_(SED_C_NE,i,r,t)
+#define MOVIB_GE(i,r,t)                MOVIB_(SED_C_GE,i,r,t)
+#define MOVIB_EV(i,r,t)                MOVIB_(SED_C_EV,i,r,t)
+#define MTCTL(r,t)             f31(0x0,t,r,0,0xc2,0)
+#define MTSAR(r)               MTCTL(r,_CR11_REGNO)
+#define MTSARCM(r)             f31(0x0,0xb,r,0,0xc6,0)
+#define MTSM(r)                        f33(0x0,0,r,0,0xc3,0)
+#define MTSP(r,s)              f29(0x0,0,r,s,0xc1,0)
+#define OR_(c,r1,r2,t)         f8(0x2,r2,r1,c,0,1,0,1,0,t)
+#define OR(r1,r2,t)            OR_(LOG_CC_NV,r1,r2,t)
+#define NOP()                  OR(_R0_REGNO,_R0_REGNO,_R0_REGNO)
+#define COPY(r,t)              OR(r,0,t)
+#define PDC(x,s,b)             f24(0x1,b,x,s,0x4e,0,0)
+#define PDTLB(x,s,b)           f24(0x1,b,x,s,0x48,0,0)
+#define PDTLB_L(x,s,b)         f24(0x1,b,x,s,0x58,0,0)
+#define PDTLBE(x,s,b)          f24(0x1,b,x,s,0x49,0,0)
+#define PERMH(c,r,t)           f10(0x3e,r,r,0,(c)&3,0,((c)>>2)&3,(((c)>>2)&6)|(((c)>>6)&3),0,t)
+#define PITBL(x,s,b)           f26(0x1,b,x,s,0x08,0,0)
+#define PITBL_L(x,s,b)         f26(0x1,b,x,s,0x18,0,0)
+#define PITBLE(x,s,b)          f26(0x1,b,x,s,0x09,0,0)
+#define POPBTS(i)              f23(0x3a,0,0,2,0,i,1,0,1)
+#define PROBE_R(s,b,r,t)       f24(0x1,b,r,s,0x46,0,t)
+#define PROBE_W(s,b,r,t)       f24(0x1,b,r,s,0x47,0,t)
+#define PROBEI_R(s,b,i,t)      f24(0x1,b,i,s,0x46,0,t)
+#define PROBEI_W(s,b,i,t)      f24(0x1,b,i,s,0x47,0,t)
+#define PUSHBTS(r)             f23(0x3a,0,r,2,0,0,0,0,1)
+#define PUSHNOM()              f23(0x3a,0,0,2,0,0,0,0,1)
+#define RFI()                  f33(0x0,0,0,0,0x60,0)
+#define RFI_R()                        f33(0x0,0,0,0,0x65,0)
+#define RSM(i,t)               f33(0x0,((i)&0x3e0)>>5,(i)&0x1f,0,0x73,t)
+#define SHLADD_(e,cf,r1,sa,r2,t) f8(0x2,r2,r1,cf,e,1,0,sa,0,t)
+#define SHLADD(r1,sa,r2,t)     SHLADD_(1,ADD_CF_NV,r1,sa,r2,t)
+#define SHLADD_L(r1,sa,r2,t)   SHLADD_(2,ADD_CF_NV,r1,sa,r2,t)
+#define SHLADD_TSV(r1,sa,r2,t) SHLADD_(3,ADD_CF_NV,r1,sa,r2,t)
+#define SHRPD(r1,r2,t)         f11(0x34,r2,r1,SED_C_NEVER,0,0,1,0,t)
+#define SHRPDI(r1,r2,sa,t)     f14(0x34,r2,r1,SED_C_NEVER,0,(63-(sa))>>5,1,(63-(sa))&0x1f,t)
+#define SHRPW(r1,r2,t)         f11(0x34,r2,r1,SED_C_NEVER,0,0,0,0,t)
+#define SHRPWI(r1,r2,sa,t)     f14(0x34,r2,r1,SED_C_NEVER,0,1,0,31-(sa),t)
+#define SPOP0(sf,so)           f34(0x4,(so)>>5,0,sf,0,(so)&0x1f)
+#define SPOP1(sf,so,t)         f35(0x4,so,1,sf,0,t)
+#define SPOP2(sf,so,r)         f36(0x4,r,(so)>>5,2,sf,0,(so)&0x1f)
+#define SPOP3(sf,so,r1,r2)     f37(0x4,r2,r1,(so)>>5,3,sf,0,(so)&0x1f)
+#define SSM(i,t)               f33(0x00,(i)>>5,(i)&0x1f,0,0x6b,t)
+#define STBL(r,i,b)            f1(0x18,b,r,i)
+#define STBI(r,i,b)            f6(0x3,b,r,0,0,1,LD_CC_H_NONE,0x8,0,i)
+#define STDL(r,i,b)            f3(0x1c,b,r,i,0)
+#define STDI(r,i,b)            f6(0x3,b,r,0,0,1,LD_CC_H_NONE,0xc,0,i)
+#define STDA(r,i,b)            f6(0x3,b,r,0,0,1,LD_CC_H_NONE,0xf,0,i)
+#define STHL(r,i,b)            f1(0x19,b,r,i)
+#define STHI(r,i,b)            f6(0x3,b,r,0,0,1,LD_CC_H_NONE,0x9,0,i)
+#define STWL(r,i,b)            f1(0x1a,b,r,i)
+#define STWL_MA(r,i,b)         f1(0x1b,b,r,i)  /* pre-dec or post-inc */
+#define STWL_MB(r,i,b)         f2(0x1f,b,r,i,2)/* post-dec or pre-inc */
+#define STWI(r,i,b)            f6(0x3,b,r,0,0,1,LD_CC_H_NONE,0xa,0,i)
+#define STWA(r,i,b)            f6(0x3,b,r,0,0,1,LD_CC_H_NONE,0xe,0,i)
+#define SUB_(e1,e2,cf,r1,r2,t) f8(0x2,r2,r1,cf,e1,0,e2,0,0,t)
+#define SUB(r1,r2,t)           SUB_(1,0,CS_CC_NV,r1,r2,t)
+#define SUB_B(r1,r2,t)         SUB_(1,1,CS_CC_NV,r1,r2,t)
+#define SUB_SV(r1,r2,t)                SUB_(1,0,CS_CC_SV,r1,r2,t)
+#define SUB_NSV(r1,r2,t)       SUB_(1,0,CS_CC_NSV,r1,r2,t)
+/* actually, rsbi */
+#define SUBI_(e1,cf,i,r,t)     f9(0x25,r,t,cf,e1,i)
+#define SUBI(i,r,t)            SUBI_(0,ADD_CF_NV,i,r,t)
+#define SYNC()                 f33(0x0,0,0,0,0x20,0)
+#define SYNCDMA()              f33(0x0,0,1<<4,0,0x20,0)
+#define UADDCM(r1,r2,t)                f8(0x2,r2,r1,ADD_CF_NV,2,0,1,2,0,t)
+#define UXOR(r1,r2,t)          f8(0x2,r2,r1,LOG_CC_NV,0,1,1,2,0,t)
+#define XOR(r1,r2,t)           f8(0x2,r2,r1,LOG_CC_NV,0,1,0,2,0,t)
+#  define nop(c)                       _nop(_jit,c)
+static void _nop(jit_state_t*,jit_int32_t);
+#define movr(r0,r1)            _movr(_jit,r0,r1)
+static void _movr(jit_state_t*,jit_int32_t,jit_int32_t);
+#define movi(r0,i0)            _movi(_jit,r0,i0)
+static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
+#define movi_p(r0,i0)          _movi_p(_jit,r0,i0)
+static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
+#define comr(r0,r1)            UADDCM(_R0_REGNO,r1,r0)
+#define negr(r0,r1)            SUB(_R0_REGNO,r1,r0)
+#define extr_c(r0,r1)          EXTRWR(r1,31,8,r0)
+#define extr_uc(r0,r1)         EXTRWR_U(r1,31,8,r0)
+#define extr_s(r0,r1)          EXTRWR(r1,31,16,r0)
+#define extr_us(r0,r1)         EXTRWR_U(r1,31,16,r0)
+#if __BYTE_ORDER == __BIG_ENDIAN
+#  define htonr_us(r0,r1)      extr_us(r0,r1)
+#  define htonr_ui(r0,r1)      movr(r0,r1)
+#else
+#  error need htonr implementation
+#endif
+#define addr(r0,r1,r2)         ADD(r1,r2,r0)
+#define addi(r0,r1,i0)         _addi(_jit,r0,r1,i0)
+static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define addcr(r0,r1,r2)                addr(r0,r1,r2)
+#define addci(r0,r1,i0)                _addci(_jit,r0,r1,i0)
+static void _addci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define addxr(r0,r1,r2)                ADD_C(r1,r2,r0)
+#define addxi(r0,r1,i0)                _addxi(_jit,r0,r1,i0)
+static void _addxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define subr(r0,r1,r2)         SUB(r1,r2,r0)
+#define subi(r0,r1,i0)         _subi(_jit,r0,r1,i0)
+static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define subcr(r0,r1,r2)                subr(r0,r1,r2)
+#define subci(r0,r1,i0)                _subci(_jit,r0,r1,i0)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define subxr(r0,r1,r2)                SUB_B(r1,r2,r0)
+#define subxi(r0,r1,i0)                _subxi(_jit,r0,r1,i0)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define rsbi(r0, r1, i0)       _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define mulr(r0,r1,r2)         _mulr(_jit,r0,r1,r2)
+static void _mulr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define muli(r0,r1,i0)         _muli(_jit,r0,r1,i0)
+static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+static long long __llmul(int, int);
+#define qmulr(r0,r1,r2,r3)     _qmulr(_jit,r0,r1,r2,r3)
+static void _qmulr(jit_state_t*,
+                  jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define qmuli(r0,r1,r2,i0)     _qmuli(_jit,r0,r1,r2,i0)
+static void _qmuli(jit_state_t*,
+                  jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+#define qmulr_u(r0,r1,r2,r3)   _qmulr_u(_jit,r0,r1,r2,r3)
+static void _qmulr_u(jit_state_t*,
+                    jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define qmuli_u(r0,r1,r2,i0)   _qmuli_u(_jit,r0,r1,r2,i0)
+static void _qmuli_u(jit_state_t*,
+                    jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+static int __idiv(int, int);
+#define divr(r0,r1,r2)         _divr(_jit,r0,r1,r2)
+static void _divr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define divi(r0,r1,i0)         _divi(_jit,r0,r1,i0)
+static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+static unsigned int __udiv(unsigned int, unsigned int);
+#define divr_u(r0,r1,r2)       _divr_u(_jit,r0,r1,r2)
+static void _divr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define divi_u(r0,r1,i0)       _divi_u(_jit,r0,r1,i0)
+static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+static int __irem(int, int);
+#define remr(r0,r1,r2)         _remr(_jit,r0,r1,r2)
+static void _remr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define remi(r0,r1,i0)         _remi(_jit,r0,r1,i0)
+static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+static unsigned int __urem(unsigned int, unsigned int);
+#define remr_u(r0,r1,r2)       _remr_u(_jit,r0,r1,r2)
+static void _remr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define remi_u(r0,r1,i0)       _remi_u(_jit,r0,r1,i0)
+static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+static idiv_t __idivrem(int, int);
+#define qdivr(r0,r1,r2,r3)     _qdivr(_jit,r0,r1,r2,r3)
+static void _qdivr(jit_state_t*,
+                  jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define qdivi(r0,r1,r2,i0)     _qdivi(_jit,r0,r1,r2,i0)
+static void _qdivi(jit_state_t*,
+                  jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+static udiv_t __udivrem(unsigned int, unsigned int);
+#define qdivr_u(r0,r1,r2,r3)   _qdivr_u(_jit,r0,r1,r2,r3)
+static void _qdivr_u(jit_state_t*,
+                    jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define qdivi_u(r0,r1,r2,i0)   _qdivi_u(_jit,r0,r1,r2,i0)
+static void _qdivi_u(jit_state_t*,
+                    jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+#define andr(r0,r1,r2)         AND(r1,r2,r0)
+#define andi(r0,r1,i0)         _andi(_jit,r0,r1,i0)
+static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define orr(r0,r1,r2)          OR(r1,r2,r0)
+#define ori(r0,r1,i0)          _ori(_jit,r0,r1,i0)
+static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define xorr(r0,r1,r2)         XOR(r1,r2,r0)
+#define xori(r0,r1,i0)         _xori(_jit,r0,r1,i0)
+static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define lshr(r0,r1,r2)         _lshr(_jit,r0,r1,r2)
+static void _lshr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define lshi(r0,r1,i0)         SHLWI(r1,i0,r0)
+#define rshr(r0,r1,r2)         _rshr(_jit,r0,r1,r2)
+static void _rshr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define rshi(r0,r1,i0)         SHRWI(r1,i0,r0)
+#define rshr_u(r0,r1,r2)       _rshr_u(_jit,r0,r1,r2)
+static void _rshr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define rshi_u(r0,r1,i0)       SHRWI_U(r1,i0,r0)
+#define cmpr(c,r0,r1,r2)       _cmpr(_jit,c,r0,r1,r2)
+static void _cmpr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define cmpi(c,ci,r0,r1,i0)    _cmpi(_jit,c,ci,r0,r1,i0)
+static void _cmpi(jit_state_t*,jit_word_t,jit_word_t,
+                 jit_int32_t,jit_int32_t,jit_word_t);
+#define ltr(r0,r1,r2)          cmpr(CS_CC_GE,r0,r1,r2)
+#define lti(r0,r1,i0)          cmpi(CS_CC_GE,CS_CC_LE,r0,r1,i0)
+#define ltr_u(r0,r1,r2)                cmpr(CS_CC_UGE,r0,r1,r2)
+#define lti_u(r0,r1,i0)                cmpi(CS_CC_UGE,CS_CC_ULE,r0,r1,i0)
+#define ler(r0,r1,r2)          cmpr(CS_CC_GT,r0,r1,r2)
+#define lei(r0,r1,i0)          cmpi(CS_CC_GT,CS_CC_LT,r0,r1,i0)
+#define ler_u(r0,r1,r2)                cmpr(CS_CC_UGT,r0,r1,r2)
+#define lei_u(r0,r1,i0)                cmpi(CS_CC_UGT,CS_CC_ULT,r0,r1,i0)
+#define eqr(r0,r1,r2)          cmpr(CS_CC_NE,r0,r1,r2)
+#define eqi(r0,r1,i0)          cmpi(CS_CC_NE,CS_CC_NE,r0,r1,i0)
+#define ger(r0,r1,r2)          cmpr(CS_CC_LT,r0,r1,r2)
+#define gei(r0,r1,i0)          cmpi(CS_CC_LT,CS_CC_GT,r0,r1,i0)
+#define ger_u(r0,r1,r2)                cmpr(CS_CC_ULT,r0,r1,r2)
+#define gei_u(r0,r1,i0)                cmpi(CS_CC_ULT,CS_CC_UGT,r0,r1,i0)
+#define gtr(r0,r1,r2)          cmpr(CS_CC_LE,r0,r1,r2)
+#define gti(r0,r1,i0)          cmpi(CS_CC_LE,CS_CC_GE,r0,r1,i0)
+#define gtr_u(r0,r1,r2)                cmpr(CS_CC_ULE,r0,r1,r2)
+#define gti_u(r0,r1,i0)                cmpi(CS_CC_ULE,CS_CC_UGE,r0,r1,i0)
+#define ner(r0,r1,r2)          cmpr(CS_CC_EQ,r0,r1,r2)
+#define nei(r0,r1,i0)          cmpi(CS_CC_EQ,CS_CC_EQ,r0,r1,i0)
+#define ldr_c(r0,r1)           _ldr_c(_jit,r0,r1)
+static void _ldr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#define ldi_c(r0,i0)           _ldi_c(_jit,r0,i0)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldxr_c(r0,r1,r2)       _ldxr_c(_jit,r0,r1,r2)
+static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_c(r0,r1,i0)       _ldxi_c(_jit,r0,r1,i0)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldr_uc(r0,r1)          LDBI(_R0_REGNO,r1,r0)
+#define ldi_uc(r0,i0)          _ldi_uc(_jit,r0,i0)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldxr_uc(r0,r1,r2)      LDB(r2,r1,r0)
+#define ldxi_uc(r0,r1,i0)      _ldxi_uc(_jit,r0,r1,i0)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldr_s(r0,r1)           _ldr_s(_jit,r0,r1)
+static void _ldr_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#define ldi_s(r0,i0)           _ldi_s(_jit,r0,i0)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldxr_s(r0,r1,r2)       _ldxr_s(_jit,r0,r1,r2)
+static void _ldxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_s(r0,r1,i0)       _ldxi_s(_jit,r0,r1,i0)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldr_us(r0,r1)          LDHI(_R0_REGNO,r1,r0)
+#define ldi_us(r0,i0)          _ldi_us(_jit,r0,i0)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldxr_us(r0,r1,r2)      LDH(r2,r1,r0)
+#define ldxi_us(r0,r1,i0)      _ldxi_us(_jit,r0,r1,i0)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldr(r0,r1)             ldr_ui(r0,r1)
+#define ldr_i(r0,r1)           ldr_ui(r0,r1)
+#define ldr_ui(r0,r1)          LDWI(_R0_REGNO,r1,r0)
+#define ldi_i(r0,i0)           ldi_ui(r0,i0)
+#define ldi_ui(r0,i0)          _ldi_ui(_jit,r0,i0)
+static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldxr_i(r0,r1,r2)       ldxr_ui(r0,r1,r2)
+#define ldxr_ui(r0,r1,r2)      LDW(r2,r1,r0)
+#define ldxi(r0,r1,i0)         ldxi_ui(r0,r1,i0)
+#define ldxi_i(r0,r1,i0)       ldxi_ui(r0,r1,i0)
+#define ldxi_ui(r0,r1,i0)      _ldxi_ui(_jit,r0,r1,i0)
+static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define str_c(r0,r1)           STBI(r1,_R0_REGNO,r0)
+#define sti_c(i0,r0)           _sti_c(_jit,i0,r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#define stxr_c(r0,r1,r2)       _stxr_c(_jit,r0,r1,r2)
+static void _stxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define stxi_c(i0,r0,r1)       _stxi_c(_jit,i0,r0,r1)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define str_s(r0,r1)           STHI(r1,_R0_REGNO,r0)
+#define sti_s(i0,r0)           _sti_s(_jit,i0,r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#define stxr_s(r0,r1,r2)       _stxr_s(_jit,r0,r1,r2)
+static void _stxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define stxi_s(i0,r0,r1)       _stxi_s(_jit,i0,r0,r1)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define str_i(r0,r1)           STWI(r1,_R0_REGNO,r0)
+#define sti_i(i0,r0)           _sti_i(_jit,i0,r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#define stxr_i(r0,r1,r2)       _stxr_i(_jit,r0,r1,r2)
+static void _stxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define stxi(i0,r0,r1)         stxi_i(i0,r0,r1)
+#define stxi_i(i0,r0,r1)       _stxi_i(_jit,i0,r0,r1)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bcmpr(c,i0,r0,r1)      _bcmpr(_jit,c,i0,r0,r1)
+static jit_word_t _bcmpr(jit_state_t*,jit_word_t,
+                        jit_word_t,jit_int32_t,jit_int32_t);
+#define bcmpi(c,ci,i0,r0,i1)   _bcmpi(_jit,c,ci,i0,r0,i1)
+static jit_word_t _bcmpi(jit_state_t*,jit_word_t,jit_word_t,
+                        jit_word_t,jit_int32_t,jit_word_t);
+#define bltr(i0,r0,r1)         bcmpr(CS_CC_LT,i0,r0,r1)
+#define blti(i0,r0,r1)         bcmpi(CS_CC_LT,CS_CC_GT,i0,r0,r1)
+#define bltr_u(i0,r0,r1)       bcmpr(CS_CC_ULT,i0,r0,r1)
+#define blti_u(i0,r0,r1)       bcmpi(CS_CC_ULT,CS_CC_UGT,i0,r0,r1)
+#define bler(i0,r0,r1)         bcmpr(CS_CC_LE,i0,r0,r1)
+#define blei(i0,r0,r1)         bcmpi(CS_CC_LE,CS_CC_GE,i0,r0,r1)
+#define bler_u(i0,r0,r1)       bcmpr(CS_CC_ULE,i0,r0,r1)
+#define blei_u(i0,r0,r1)       bcmpi(CS_CC_ULE,CS_CC_UGE,i0,r0,r1)
+#define beqr(i0,r0,r1)         bcmpr(CS_CC_EQ,i0,r0,r1)
+#define beqi(i0,r0,r1)         bcmpi(CS_CC_EQ,CS_CC_EQ,i0,r0,r1)
+#define bger(i0,r0,r1)         bcmpr(CS_CC_GE,i0,r0,r1)
+#define bgei(i0,r0,r1)         bcmpi(CS_CC_GE,CS_CC_LE,i0,r0,r1)
+#define bger_u(i0,r0,r1)       bcmpr(CS_CC_UGE,i0,r0,r1)
+#define bgei_u(i0,r0,r1)       bcmpi(CS_CC_UGE,CS_CC_ULE,i0,r0,r1)
+#define bgtr(i0,r0,r1)         bcmpr(CS_CC_GT,i0,r0,r1)
+#define bgti(i0,r0,r1)         bcmpi(CS_CC_GT,CS_CC_LT,i0,r0,r1)
+#define bgtr_u(i0,r0,r1)       bcmpr(CS_CC_UGT,i0,r0,r1)
+#define bgti_u(i0,r0,r1)       bcmpi(CS_CC_UGT,CS_CC_ULT,i0,r0,r1)
+#define bner(i0,r0,r1)         bcmpr(CS_CC_NE,i0,r0,r1)
+#define bnei(i0,r0,r1)         bcmpi(CS_CC_NE,CS_CC_NE,i0,r0,r1)
+#define bmxr(c,i0,r0,r1)       _bmxr(_jit,c,i0,r0,r1)
+static jit_word_t _bmxr(jit_state_t*,jit_bool_t,
+                       jit_word_t,jit_int32_t,jit_int32_t);
+#define bmxi(c,i0,r0,i1)       _bmxi(_jit,c,i0,r0,i1)
+static jit_word_t _bmxi(jit_state_t*,jit_bool_t,
+                       jit_word_t,jit_int32_t,jit_word_t);
+#define bmcr(r0,r1,r2)         bmxr(0,r0,r1,r2)
+#define bmci(r0,r1,r2)         bmxi(0,r0,r1,r2)
+#define bmsr(r0,r1,r2)         bmxr(1,r0,r1,r2)
+#define bmsi(r0,r1,r2)         bmxi(1,r0,r1,r2)
+#define boaddr(i0,r0,r1)       _boaddr(_jit,i0,r0,r1)
+static jit_word_t _boaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define boaddi(i0,r0,i1)       _boaddi(_jit,i0,r0,i1)
+static jit_word_t _boaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define boaddr_u(i0,r0,r1)     _boaddr_u(_jit,i0,r0,r1)
+static jit_word_t _boaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define boaddi_u(i0,r0,i1)     _boaddi_u(_jit,i0,r0,i1)
+static jit_word_t _boaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bxaddr(i0,r0,r1)       _bxaddr(_jit,i0,r0,r1)
+static jit_word_t _bxaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bxaddi(i0,r0,i1)       _bxaddi(_jit,i0,r0,i1)
+static jit_word_t _bxaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bxaddr_u(i0,r0,r1)     _bxaddr_u(_jit,i0,r0,r1)
+static jit_word_t _bxaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bxaddi_u(i0,r0,i1)     _bxaddi_u(_jit,i0,r0,i1)
+static jit_word_t _bxaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bosubr(i0,r0,r1)       _bosubr(_jit,i0,r0,r1)
+static jit_word_t _bosubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bosubi(i0,r0,i1)       _bosubi(_jit,i0,r0,i1)
+static jit_word_t _bosubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bosubr_u(i0,r0,r1)     _bosubr_u(_jit,i0,r0,r1)
+static jit_word_t _bosubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bosubi_u(i0,r0,i1)     _bosubi_u(_jit,i0,r0,i1)
+static jit_word_t _bosubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bxsubr(i0,r0,r1)       _bxsubr(_jit,i0,r0,r1)
+static jit_word_t _bxsubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bxsubi(i0,r0,i1)       _bxsubi(_jit,i0,r0,i1)
+static jit_word_t _bxsubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bxsubr_u(i0,r0,r1)     _bxsubr_u(_jit,i0,r0,r1)
+static jit_word_t _bxsubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bxsubi_u(i0,r0,i1)     _bxsubi_u(_jit,i0,r0,i1)
+static jit_word_t _bxsubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define jmpr(r0)               _jmpr(_jit,r0)
+static void _jmpr(jit_state_t*,jit_int32_t);
+#define jmpi(i0)               _jmpi(_jit,i0)
+static void _jmpi(jit_state_t*,jit_word_t);
+#define jmpi_p(i0)             _jmpi_p(_jit,i0)
+static jit_word_t _jmpi_p(jit_state_t*,jit_word_t);
+#define callr(r0)              _callr(_jit,r0)
+static void _callr(jit_state_t*,jit_int32_t);
+#define calli(i0)              _calli(_jit,i0)
+static void _calli(jit_state_t*,jit_word_t);
+#define calli_p(i0)            _calli_p(_jit,i0)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t);
+#define prolog(node)           _prolog(_jit, node)
+static void _prolog(jit_state_t*, jit_node_t*);
+#define epilog(node)           _epilog(_jit, node)
+static void _epilog(jit_state_t*, jit_node_t*);
+#define vastart(r0)            _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#define vaarg(r0, r1)          _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#define patch_at(i,l)          _patch_at(_jit,i,l)
+static void _patch_at(jit_state_t*,jit_word_t,jit_word_t);
+#endif
+
+#if CODE
+/* from binutils bfd/libhppa.h */
+static inline int
+sign_extend (int x, int len)
+{
+  int signbit = (1 << (len - 1));
+  int mask = (signbit << 1) - 1;
+  return ((x & mask) ^ signbit) - signbit;
+}
+
+static inline int
+sign_unext (int x, int len)
+{
+  int len_ones;
+
+  len_ones = (1 << len) - 1;
+
+  return x & len_ones;
+}
+
+static inline int
+low_sign_unext (int x, int len)
+{
+  int temp;
+  int sign;
+
+  sign = (x >> (len-1)) & 1;
+
+  temp = sign_unext (x, len-1);
+
+  return (temp << 1) | sign;
+}
+
+static inline int
+re_assemble_3 (int as3)
+{
+  return ((  (as3 & 4) << (13-2))
+         | ((as3 & 3) << (13+1)));
+}
+
+static inline int
+re_assemble_12 (int as12)
+{
+  return ((  (as12 & 0x800) >> 11)
+         | ((as12 & 0x400) >> (10 - 2))
+         | ((as12 & 0x3ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_16 (int as16)
+{
+  int s, t;
+
+  /* Unusual 16-bit encoding, for wide mode only.  */
+  t = (as16 << 1) & 0xffff;
+  s = (as16 & 0x8000);
+  return (t ^ s ^ (s >> 1)) | (s >> 15);
+}
+
+static inline int
+re_assemble_17 (int as17)
+{
+  return ((  (as17 & 0x10000) >> 16)
+         | ((as17 & 0x0f800) << (16 - 11))
+         | ((as17 & 0x00400) >> (10 - 2))
+         | ((as17 & 0x003ff) << (1 + 2)));
+}
+
+static inline int
+re_assemble_21 (int as21)
+{
+  return ((  (as21 & 0x100000) >> 20)
+         | ((as21 & 0x0ffe00) >> 8)
+         | ((as21 & 0x000180) << 7)
+         | ((as21 & 0x00007c) << 14)
+         | ((as21 & 0x000003) << 12));
+}
+
+static inline int
+re_assemble_22 (int as22)
+{
+  return ((  (as22 & 0x200000) >> 21)
+         | ((as22 & 0x1f0000) << (21 - 16))
+         | ((as22 & 0x00f800) << (16 - 11))
+         | ((as22 & 0x000400) >> (10 - 2))
+         | ((as22 & 0x0003ff) << (1 + 2)));
+}
+
+static void
+_f1(jit_state_t *_jit, jit_int32_t o,
+    jit_int32_t b, jit_int32_t t, jit_int32_t i)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(b  & ~0x1f));
+    assert(!(t  & ~0x1f));
+    assert(i >= -8192 && i <= 8191);
+    ii((o<<26)|(b<<21)|(t<<16)|(re_assemble_16(i)));
+}
+
+static void
+_f2(jit_state_t *_jit, jit_int32_t o,
+    jit_int32_t b, jit_int32_t t, jit_int32_t i, jit_int32_t j)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(b  & ~0x1f));
+    assert(!(t  & ~0x1f));
+    assert(i >= -32768 && i <= 32767);
+    assert(!(j  &  ~0x3));
+    ii((o<<26)|(b<<21)|(t<<16)|(j<<1)|(re_assemble_16(i)));
+}
+
+static void
+_f3(jit_state_t *_jit, jit_int32_t o,
+    jit_int32_t b, jit_int32_t t, jit_int32_t i, jit_int32_t j)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(b  & ~0x1f));
+    assert(!(t  & ~0x1f));
+    assert(i >= -32768 && i <= 32767);
+    assert(!(j  &  ~0x1));
+    ii((o<<26)|(b<<21)|(t<<16)|(j<<1)|(re_assemble_16(i)));
+}
+
+static void
+_f4(jit_state_t *_jit, jit_int32_t o, jit_int32_t b,
+    jit_int32_t x, jit_int32_t s, jit_int32_t u, jit_int32_t y,
+    jit_int32_t c, jit_int32_t z, jit_int32_t m, jit_int32_t t)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(b  & ~0x1f));
+    assert(!(x  & ~0x1f));
+    assert(!(s  &  ~0x3));
+    assert(!(u  &  ~0x1));
+    assert(!(y  &  ~0x1));
+    assert(!(c  &  ~0x3));
+    assert(!(z  &  ~0xf));
+    assert(!(m  &  ~0x1));
+    assert(!(t  & ~0x1f));
+    ii((o<<26)|(b<<21)|(x<<16)|(s<<14)|(u<<13)|(y<<12)|(c<<10)|(z<<6)|(m<<5)|t);
+}
+
+static void
+_f5(jit_state_t *_jit, jit_int32_t o, jit_int32_t b,
+    jit_int32_t i, jit_int32_t s, jit_int32_t a, jit_int32_t y,
+    jit_int32_t c, jit_int32_t z, jit_int32_t m, jit_int32_t t)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(b  & ~0x1f));
+    assert(!(s  &  ~0x3));
+    assert(!(a  &  ~0x1));
+    assert(!(y  &  ~0x1));
+    assert(!(c  &  ~0x3));
+    assert(!(z  &  ~0xf));
+    assert(!(m  &  ~0x1));
+    assert(i >= -16 && i <= 15);
+    ii((o<<26)|(b<<21)|(low_sign_unext(i,5)<<16)|
+       (s<<14)|(a<<13)|(y<<12)|(c<<10)|(z<<6)|(m<<5)|t);
+}
+
+static void
+_f6(jit_state_t *_jit, jit_int32_t o, jit_int32_t b,
+    jit_int32_t r, jit_int32_t s, jit_int32_t a, jit_int32_t x,
+    jit_int32_t c, jit_int32_t y, jit_int32_t m, jit_int32_t i)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(b  & ~0x1f));
+    assert(!(s  &  ~0x3));
+    assert(!(a  &  ~0x1));
+    assert(!(x  &  ~0x1));
+    assert(!(c  &  ~0x3));
+    assert(!(y  &  ~0xf));
+    assert(!(m  &  ~0x1));
+    assert(i >= -16 && i <= 15);
+    ii((o<<26)|(b<<21)|(r<<16)|(s<<14)|(a<<13)|
+       (x<<12)|(c<<10)|(y<<6)|(m<<5)|low_sign_unext(i,5));
+}
+
+static void
+_f7(jit_state_t *_jit, jit_int32_t o, jit_int32_t r, jit_int32_t i)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r  & ~0x1f));
+    assert(!(i  &  0x7ff));
+    ii((o<<26)|(r<<21)|re_assemble_21(i>>11));
+}
+
+static void
+_f8(jit_state_t *_jit, jit_int32_t o,
+    jit_int32_t r2, jit_int32_t r1, jit_int32_t cf,
+    jit_int32_t e1, jit_int32_t x, jit_int32_t e2,
+    jit_int32_t e3, jit_int32_t d, jit_int32_t t)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r2 & ~0x1f));
+    assert(!(r1 & ~0x1f));
+    assert(!(cf &  ~0xf));
+    assert(!(e1 &  ~0x3));
+    assert(!(x  &  ~0x1));
+    assert(!(e2 &  ~0x3));
+    assert(!(e3 &  ~0x3));
+    assert(!(d  &  ~0x1));
+    assert(!(t  & ~0x1f));
+    ii((o<<26)|(r2<<21)|(r1<<16)|(cf<<12)|
+       (e1<<10)|(x<<9)|(e2<<8)|(e3<<6)|(d<<5)|t);
+}
+
+static void
+_f9(jit_state_t *_jit,
+    jit_int32_t o, jit_int32_t r, jit_int32_t t,
+    jit_int32_t cf, jit_int32_t e1, jit_int32_t i)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r  & ~0x1f));
+    assert(!(t  & ~0x1f));
+    assert(!(cf &  ~0xf));
+    assert(!(e1 &  ~0x1));
+    assert(i >= -2048 && i <= 2047);
+    ii((o<<26)|(r<<21)|(t<<16)|(cf<<12)|(e1<<11)|low_sign_unext(i,11));
+}
+
+static void
+_f10(jit_state_t *_jit, jit_int32_t o, jit_int32_t r2,
+     jit_int32_t r1, jit_int32_t u, jit_int32_t v, jit_int32_t w,
+     jit_int32_t x, jit_int32_t sa, jit_int32_t y, jit_int32_t t)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r2 & ~0x1f));
+    assert(!(r1 & ~0x1f));
+    assert(!(u  &  ~0x1));
+    assert(!(v  &  ~0x3));
+    assert(!(w  &  ~0x1));
+    assert(!(x  &  ~0x3));
+    assert(!(sa &  ~0xf));
+    assert(!(y  &  ~0x1));
+    assert(!(t  & ~0x1f));
+    ii((o<<26)|(r2<<21)|(r1<<16)|(u<<15)|
+       (v<<13)|(w<<12)|(x<<10)|(sa<<6)|(y<<5)|t);
+}
+
+static void
+_f11(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t r2, jit_int32_t r1, jit_int32_t c, jit_int32_t x,
+     jit_int32_t y, jit_int32_t z, jit_int32_t u, jit_int32_t t)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r1 & ~0x1f));
+    assert(!(r2 & ~0x1f));
+    assert(!(c  &  ~0x7));
+    assert(!(x  &  ~0x3));
+    assert(!(y  &  ~0x1));
+    assert(!(z  &  ~0x1));
+    assert(!(u  &  ~0xf));
+    assert(!(t  & ~0x1f));
+    ii((o<<26)|(r2<<21)|(r1<<16)|(c<<13)|(x<<11)|(y<<10)|(z<<9)|(u<<5)|t);
+}
+
+static void
+_f12(jit_state_t *_jit, jit_int32_t o, jit_int32_t r,
+     jit_int32_t t, jit_int32_t c, jit_int32_t x, jit_int32_t se,
+     jit_int32_t y, jit_int32_t c1, jit_int32_t z, jit_int32_t clen)
+{
+    assert(!(o    & ~0x3f));
+    assert(!(r    & ~0x1f));
+    assert(!(t    & ~0x1f));
+    assert(!(c    &  ~0x7));
+    assert(!(x    &  ~0x3));
+    assert(!(se   &  ~0x1));
+    assert(!(y    &  ~0x1));
+    assert(!(c1   &  ~0x1));
+    assert(!(z    &  ~0x7));
+    assert(!((32-clen) & ~0x1f));
+    ii((o<<26)|(r<<21)|(t<<16)|(c<<13)|(x<<11)|
+       (se<<10)|(y<<9)|(c1<<8)|(z<<5)|(32-clen));
+}
+
+static void
+_f13(jit_state_t *_jit, jit_int32_t o, jit_int32_t t,
+     jit_int32_t r, jit_int32_t c, jit_int32_t x,
+     jit_int32_t nz, jit_int32_t c1, jit_int32_t clen)
+{
+    assert(!(o    & ~0x3f));
+    assert(!(t    & ~0x1f));
+    assert(!(r    & ~0x1f));
+    assert(!(c    &  ~0x7));
+    assert(!(x    &  ~0x3));
+    assert(!(nz   &  ~0x1));
+    assert(!(c1   &  ~0x1));
+    assert(!((32-clen) & ~0x1f));
+    ii((o<<26)|(t<<21)|(r<<16)|(c<<13)|
+       (x<<11)|(nz<<10)|(c1<<8)|(32-clen));
+}
+
+static void
+_f13x(jit_state_t *_jit, jit_int32_t o, jit_int32_t t,
+      jit_int32_t i, jit_int32_t c, jit_int32_t x,
+      jit_int32_t nz, jit_int32_t c1, jit_int32_t clen)
+{
+    assert(!(o    & ~0x3f));
+    assert(!(t    & ~0x1f));
+    assert(i >= -16 && i <= 15);
+    assert(!(c    &  ~0x7));
+    assert(!(x    &  ~0x3));
+    assert(!(nz   &  ~0x1));
+    assert(!((32-clen) & ~0x1f));
+    ii((o<<26)|(t<<21)|(low_sign_unext(i,5)<<16)|
+       (c<<13)|(x<<11)|(nz<<10)|(c1<<8)|(32-clen));
+}
+
+static void
+_f14(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t r2, jit_int32_t r1, jit_int32_t c, jit_int32_t x,
+     jit_int32_t cp, jit_int32_t y, jit_int32_t cpos, jit_int32_t t)
+{
+    assert(!(o    & ~0x3f));
+    assert(!(r1   & ~0x1f));
+    assert(!(r2   & ~0x1f));
+    assert(!(c    &  ~0x7));
+    assert(!(x    &  ~0x3));
+    assert(!(cp   &  ~0x1));
+    assert(!(y    &  ~0x1));
+    assert(!(cpos & ~0x1f));
+    assert(!(t    & ~0x1f));
+    ii((o<<26)|(r2<<21)|(r1<<16)|(c<<13)|(x<<12)|(cp<<11)|(y<<10)|(cpos<<5)|t);
+}
+
+static void
+_f15(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t r, jit_int32_t t, jit_int32_t c, jit_int32_t c1,
+     jit_int32_t p, jit_int32_t se, jit_int32_t pos, jit_int32_t clen)
+{
+    assert(!(o    & ~0x3f));
+    assert(!(r    & ~0x1f));
+    assert(!(t    & ~0x1f));
+    assert(!(c    &  ~0x7));
+    assert(!(c1   &  ~0x1));
+    assert(!(p    &  ~0x1));
+    assert(!(se   &  ~0x1));
+    assert(!(pos  & ~0x1f));
+    assert(!((32-clen) & ~0x1f));
+    ii((o<<26)|(r<<21)|(t<<16)|(c<<13)|(c1<<12)|
+       (p<<11)|(se<<10)|(pos<<5)|(32-clen));
+}
+
+static void
+_f16(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t t, jit_int32_t r, jit_int32_t c, jit_int32_t c1,
+     jit_int32_t cp, jit_int32_t nz, jit_int32_t cpos, jit_int32_t clen)
+{
+    assert(!(o    & ~0x3f));
+    assert(!(t    & ~0x1f));
+    assert(!(r    & ~0x1f));
+    assert(!(c    &  ~0x7));
+    assert(!(c1   &  ~0x1));
+    assert(!(cp   &  ~0x1));
+    assert(!(nz   &  ~0x1));
+    assert(!(cpos & ~0x1f));
+    assert(!((32-clen) & ~0x3f));
+    ii((o<<26)|(t<<21)|(r<<16)|(c<<13)|
+       (c1<<12)|(cp<<11)|(nz<<10)|(cpos<<5)|(32-clen));
+}
+
+static void
+_f16x(jit_state_t *_jit, jit_int32_t o,
+      jit_int32_t t, jit_int32_t i, jit_int32_t c, jit_int32_t c1,
+      jit_int32_t cp, jit_int32_t nz, jit_int32_t cpos, jit_int32_t clen)
+{
+    assert(!(o    & ~0x3f));
+    assert(!(t    & ~0x1f));
+    assert(i >= -16 && i <= 15);
+    assert(!(c    &  ~0x7));
+    assert(!(c1   &  ~0x1));
+    assert(!(cp   &  ~0x1));
+    assert(!(nz   &  ~0x1));
+    assert(!(cpos & ~0x1f));
+    assert(!((32-clen) & ~0x3f));
+    ii((o<<26)|(t<<21)|(low_sign_unext(i,5)<<16)|(c<<13)|
+       (c1<<12)|(cp<<11)|(nz<<10)|(cpos<<5)|(32-clen));
+}
+
+static void
+_f17(jit_state_t *_jit, jit_int32_t o, jit_int32_t r2,
+     jit_int32_t r1, jit_int32_t c, jit_int32_t i, jit_int32_t n)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r2 & ~0x1f));
+    assert(!(r1 & ~0x1f));
+    assert(!(c  &  ~0x7));
+    assert(i >= -2048 && i <= 2047);
+    assert(!(n  &   ~0x1));
+    ii((o<<26)|(r2<<21)|(r1<<16)|(c<<13)|re_assemble_12(i)|(n<<1));
+}
+
+static void
+_f17x(jit_state_t *_jit, jit_int32_t o, jit_int32_t r,
+      jit_int32_t i, jit_int32_t c, jit_int32_t t, jit_int32_t n)
+{
+    assert(!(o & ~0x3f));
+    assert(!(r & ~0x1f));
+    assert(i >= -16 && i <= 15);
+    assert(!(c &  ~0x7));
+    assert(t >= -2048 && t <= 2047);
+    assert(!(n &  ~0x1));
+    ii((o<<26)|(r<<21)|
+       (low_sign_unext(i,5)<<16)|(c<<13)|re_assemble_12(t)|(n<<1));
+}
+
+static void
+_f18(jit_state_t *_jit, jit_int32_t o, jit_int32_t p,
+     jit_int32_t r, jit_int32_t c, jit_int32_t i, jit_int32_t n)
+{
+    assert(!(o & ~0x3f));
+    assert(!(p & ~0x1f));
+    assert(!(r & ~0x1f));
+    assert(!(c &  ~0x1));
+    assert(i >= -2048 && i <= 2047);
+    assert(!(n &  ~0x1));
+    ii((o<<26)|(p<<21)|(r<<16)|(c<<15)|(1<<14)|re_assemble_12(i)|(n<<1));
+}
+
+static void
+_f19(jit_state_t *_jit, jit_int32_t o, jit_int32_t b,
+     jit_int32_t s, jit_int32_t i, jit_int32_t n)
+{
+    assert(!(o & ~0x3f));
+    assert(!(b & ~0x1f));
+    assert(!(s &  ~0x7));
+    assert(i >= -65536 && i <= 65535);
+    assert(!(n &  ~0x1));
+    ii((o<<26)|(b<<21)|re_assemble_3(s)|re_assemble_17(i)|(n<<1));
+}
+
+static void
+_f20(jit_state_t *_jit, jit_int32_t o, jit_int32_t t,
+     jit_int32_t i, jit_int32_t g, jit_int32_t n)
+{
+    assert(!(o & ~0x3f));
+    assert(!(t & ~0x1f));
+    assert(i >= -32768 && i <= 32767);
+    assert(!(g &  ~0x7));
+    assert(!(n &  ~0x1));
+    ii((o<<26)|(t<<21)|(g<<13)|re_assemble_17(i)|(n<<1));
+}
+
+static void
+_f21(jit_state_t *_jit, jit_int32_t o, jit_int32_t t,
+     jit_int32_t x, jit_int32_t y, jit_int32_t n)
+{
+    assert(!(o & ~0x3f));
+    assert(!(t & ~0x1f));
+    assert(!(x & ~0x1f));
+    assert(!(y &  ~0x7));
+    assert(!(n &  ~0x1));
+    ii((o<<26)|(t<<21)|(x<<16)|(y<<13)|(n<<1));
+}
+
+static void
+_f22(jit_state_t *_jit, jit_int32_t o, jit_int32_t b,
+     jit_int32_t x, jit_int32_t r, jit_int32_t n, jit_int32_t p)
+{
+    assert(!(o & ~0x3f));
+    assert(!(b & ~0x1f));
+    assert(!(x &  ~0x7));
+    assert(!(r & ~0x3f));
+    assert(!(n &  ~0x1));
+    assert(!(p &  ~0x1));
+    ii((o<<26)|(b<<21)|(x<<13)|(1<<12)|(r<<2)|(n<<1)|p);
+}
+
+static void
+_f23(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t a, jit_int32_t b, jit_int32_t c, jit_int32_t d,
+     jit_int32_t e, jit_int32_t f, jit_int32_t g, jit_int32_t h)
+{
+    assert(!(o &  ~0x3f));
+    assert(!(a &  ~0x1f));
+    assert(!(b &  ~0x1f));
+    assert(!(c &   ~0x7));
+    assert(!(d &   ~0x1));
+    assert(!(e & ~0x1ff));
+    assert(!(f &   ~0x1));
+    assert(!(g &   ~0x1));
+    assert(!(h &   ~0x1));
+    ii((o<<26)|(a<<21)|(b<<16)|(c<<13)|(d<<12)|(e<<3)|(f<<2)|(g<<1)|h);
+}
+
+static void
+_f24(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t b, jit_int32_t x, jit_int32_t s,
+     jit_int32_t y, jit_int32_t m,jit_int32_t r)
+{
+    assert(!(o &  ~0x3f));
+    assert(!(b &  ~0x1f));
+    assert(!(x &  ~0x1f));
+    assert(!(s &   ~0x3));
+    assert(!(y &  ~0xff));
+    assert(!(m &   ~0x1));
+    assert(!(r &  ~0x1f));
+    ii((o<<26)|(b<<21)|(x<<16)|(s<<14)|(y<<6)|(m<<5)|r);
+}
+
+static void
+_f25(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t b, jit_int32_t i, jit_int32_t s,
+     jit_int32_t y, jit_int32_t m, jit_int32_t r)
+{
+    assert(!(o &  ~0x3f));
+    assert(!(b &  ~0x1f));
+    assert(i >= -16 && i <= 15);
+    assert(!(s &   ~0x3));
+    assert(!(y &  ~0xff));
+    assert(!(m &   ~0x1));
+    assert(!(r &  ~0x1f));
+    ii((o<<26)|(b<<21)|(low_sign_unext(i,5)<<16)|(s<<14)|(y<<6)|(m<<5)|r);
+}
+
+static void
+_f26(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t b, jit_int32_t x, jit_int32_t s,
+     jit_int32_t y, jit_int32_t m,jit_int32_t r)
+{
+    assert(!(o &  ~0x3f));
+    assert(!(b &  ~0x1f));
+    assert(!(x &  ~0x1f));
+    assert(!(s &   ~0x7));
+    assert(!(y &  ~0x7f));
+    assert(!(m &   ~0x1));
+    assert(!(r &  ~0x1f));
+    ii((o<<26)|(b<<21)|(x<<16)|(s<<13)|(y<<6)|(m<<5)|r);
+}
+
+static void
+_f27(jit_state_t *_jit, jit_int32_t o, jit_int32_t i, jit_int32_t j)
+{
+    assert(!(o & ~0x3f));
+    assert(i >= -4096 && i < 4095);
+    assert(j >=   -16 && j <   15);
+    ii((o<<26)|(i<<13)|j);
+}
+
+static void
+_f28(jit_state_t *_jit, jit_int32_t o, jit_int32_t i)
+{
+    assert(!(o &      ~0x3f));
+    assert(!(i & ~0x1ffffff));
+    ii((o<<26)|i);
+}
+
+static void
+_f29(jit_state_t *_jit, jit_int32_t o, jit_int32_t r,
+     jit_int32_t x, jit_int32_t s, jit_int32_t y, jit_int32_t t)
+{
+    assert(!(o & ~0x3f));
+    assert(!(r & ~0x1f));
+    assert(!(x & ~0x1f));
+    assert(!(s &  ~0x7));
+    assert(!(y & ~0xff));
+    assert(!(t & ~0x1f));
+    ii((o<<26)|(r<<21)|(x<<16)|re_assemble_3(s)|(y<<5)|t);
+}
+
+static void
+_f30(jit_state_t *_jit, jit_int32_t o, jit_int32_t b, jit_int32_t r,
+     jit_int32_t s, jit_int32_t x, jit_int32_t y, jit_int32_t t)
+{
+    assert(!(o & ~0x3f));
+    assert(!(b & ~0x1f));
+    assert(!(r & ~0x1f));
+    assert(!(s &  ~0x3));
+    assert(!(x &  ~0x1));
+    assert(!(y & ~0xff));
+    assert(!(t & ~0x1f));
+    ii((o<<26)|(b<<21)|(r<<16)|(s<<14)|(x<<13)|(y<<5)|t);
+}
+
+static void
+_f31(jit_state_t *_jit, jit_int32_t o, jit_int32_t t,
+     jit_int32_t r, jit_int32_t v, jit_int32_t x, jit_int32_t y)
+{
+    assert(!(o & ~0x3f));
+    assert(!(t & ~0x1f));
+    assert(!(r & ~0x1f));
+    assert(!(v & ~0x1f));
+    assert(!(x & ~0xff));
+    assert(!(y & ~0x1f));
+    ii((o<<26)|(t<<21)|(r<<16)|(v<<14)|(x<<5)|y);
+}
+
+static void
+_f33(jit_state_t *_jit, jit_int32_t o, jit_int32_t x,
+     jit_int32_t r, jit_int32_t y, jit_int32_t z, jit_int32_t u)
+{
+    assert(!(o & ~0x3f));
+    assert(!(x & ~0x1f));
+    assert(!(r & ~0x1f));
+    assert(!(y &  ~0x7));
+    assert(!(z & ~0xff));
+    assert(!(u & ~0x1f));
+    ii((o<<26)|(x<<21)|(r<<16)|(y<<13)|(z<<5)|u);
+}
+
+static void
+_f34(jit_state_t *_jit, jit_int32_t o, jit_int32_t o1,
+     jit_int32_t x, jit_int32_t sf, jit_int32_t n, jit_int32_t o2)
+{
+    assert(!(o  &   ~0x3f));
+    assert(!(o1 & ~0x7fff));
+    assert(!(x  &    ~0x3));
+    assert(!(sf &    ~0x7));
+    assert(!(n  &    ~0x1));
+    assert(!(o2 &   ~0x1f));
+    ii((o<<26)|(o1<<11)|(x<<9)|(sf<<6)|(n<<5)|o2);
+}
+
+static void
+_f35(jit_state_t *_jit, jit_int32_t o, jit_int32_t op,
+     jit_int32_t x, jit_int32_t sf, jit_int32_t n, jit_int32_t t)
+{
+    assert(!(o  &   ~0x3f));
+    assert(!(op & ~0x7fff));
+    assert(!(x  &    ~0x3));
+    assert(!(sf &    ~0x7));
+    assert(!(n  &    ~0x1));
+    assert(!(t  &   ~0x1f));
+    ii((o<<26)|(op<<11)|(x<<9)|(sf<<6)|(n<<5)|t);
+}
+
+static void
+_f36(jit_state_t *_jit, jit_int32_t o, jit_int32_t r, jit_int32_t o1,
+     jit_int32_t x, jit_int32_t sf, jit_int32_t n, jit_int32_t o2)
+{
+    assert(!(o  &  ~0x3f));
+    assert(!(r  &  ~0x1f));
+    assert(!(o1 & ~0x3ff));
+    assert(!(x  &   ~0x3));
+    assert(!(sf &   ~0x7));
+    assert(!(n  &   ~0x1));
+    assert(!(o2 &  ~0x1f));
+    ii((o<<26)|(r<<21)|(o1<<11)|(x<<9)|(sf<<6)|(n<<5)|o2);
+}
+
+static void
+_f37(jit_state_t *_jit, jit_int32_t o, jit_int32_t r2,
+     jit_int32_t r1, jit_int32_t o1, jit_int32_t x,
+     jit_int32_t sf, jit_int32_t n, jit_int32_t o2)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r2 & ~0x1f));
+    assert(!(r1 & ~0x1f));
+    assert(!(o1 & ~0x1f));
+    assert(!(x  &  ~0x3));
+    assert(!(sf &  ~0x7));
+    assert(!(n  &  ~0x1));
+    assert(!(o2 & ~0x1f));
+    ii((o<<26)|(r2<<21)|(r1<<16)|(o1<<11)|(x<<9)|(sf<<6)|(n<<5)|o2);
+}
+
+static void
+_f38(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t s, jit_int32_t u, jit_int32_t n)
+{
+    assert(!(o &     ~0x3f));
+    assert(!(s & ~0x3fffff));
+    assert(!(u &      ~0x7));
+    assert(!(n &      ~0x1));
+    ii((o<<26)|((s>>5)<<9)|(u<<6)|(n<<1)|(s&0x1f));
+}
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t i0)
+{
+    for (; i0 > 0; i0 -= 4)
+       NOP();
+    assert(i0 == 0);
+}
+
+static void
+_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       COPY(r1, r0);
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    if (i0 >= -8192 && i0 <= 8191)
+       LDI(i0, r0);
+    else if (!(i0 & 0x7ff))
+       LDIL(i0, r0);
+    else {
+       LDIL(i0 & ~0x7ff, r0);
+       LDO(i0 & 0x7ff, r0, r0);
+    }
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    LDIL(i0 & ~0x7ff, r0);
+    LDO(i0 & 0x7ff, r0, r0);
+    return (w);
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -1024 && i0 <= 1023)
+       ADDI(i0, r1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    addcr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    addxr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -1023 && i0 <= 1024)
+       addi(r0, r1, -i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    subcr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    subxr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -1024 && i0 <= 1023)
+       SUBI(i0, r1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subr(r0, rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_mulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_fpr);
+    t1 = jit_get_reg(jit_class_fpr);
+    stxi(alloca_offset - 8, _FP_REGNO, r1);
+    ldxi_f(rn(t0), _FP_REGNO, alloca_offset - 8);
+    stxi(alloca_offset - 8, _FP_REGNO, r2);
+    ldxi_f(rn(t1), _FP_REGNO, alloca_offset - 8);
+    XMPYU(rn(t0), rn(t1), rn(t0));
+    stxi_d(alloca_offset - 8, _FP_REGNO, rn(t0));
+    ldxi(r0, _FP_REGNO, alloca_offset - 4);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (r0 != r1) {
+       movi(r0, i0);
+       mulr(r0, r1, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       mulr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static long long
+__llmul(int u, int v)
+{
+    return ((long long)u * (long long)v);
+}
+
+static void
+_qmulr(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    movr(_R26_REGNO, r2);
+    movr(_R25_REGNO, r3);
+    calli((jit_word_t)__llmul);
+    movr(r0, _R29_REGNO);
+    movr(r1, _R28_REGNO);
+}
+
+static void
+_qmuli(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    movr(_R26_REGNO, r2);
+    movi(_R25_REGNO, i0);
+    calli((jit_word_t)__llmul);
+    movr(r0, _R29_REGNO);
+    movr(r1, _R28_REGNO);
+}
+
+static void
+_qmulr_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_fpr);
+    t1 = jit_get_reg(jit_class_fpr);
+    stxi(alloca_offset - 8, _FP_REGNO, r2);
+    ldxi_f(rn(t0), _FP_REGNO, alloca_offset - 8);
+    stxi(alloca_offset - 8, _FP_REGNO, r3);
+    ldxi_f(rn(t1), _FP_REGNO, alloca_offset - 8);
+    XMPYU(rn(t0), rn(t1), rn(t0));
+    stxi_d(alloca_offset - 8, _FP_REGNO, rn(t0));
+    ldxi(r0, _FP_REGNO, alloca_offset - 4);
+    ldxi(r1, _FP_REGNO, alloca_offset - 8);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+}
+
+static void
+_qmuli_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    qmulr_u(r0, r1, r2, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static int
+__idiv(int u, int v)
+{
+    return (u / v);
+}
+
+static void
+_divr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    movr(_R26_REGNO, r1);
+    movr(_R25_REGNO, r2);
+    calli((jit_word_t)__idiv);
+    movr(r0, _R28_REGNO);
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(_R26_REGNO, r1);
+    movi(_R25_REGNO, i0);
+    calli((jit_word_t)__idiv);
+    movr(r0, _R28_REGNO);
+}
+
+static unsigned int
+__udiv(unsigned int u, unsigned int v)
+{
+    return (u / v);
+}
+
+static void
+_divr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    movr(_R26_REGNO, r1);
+    movr(_R25_REGNO, r2);
+    calli((jit_word_t)__udiv);
+    movr(r0, _R28_REGNO);
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(_R26_REGNO, r1);
+    movi(_R25_REGNO, i0);
+    calli((jit_word_t)__udiv);
+    movr(r0, _R28_REGNO);
+}
+
+static int
+__irem(int u, int v)
+{
+    return (u % v);
+}
+
+static void
+_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    movr(_R26_REGNO, r1);
+    movr(_R25_REGNO, r2);
+    calli((jit_word_t)__irem);
+    movr(r0, _R28_REGNO);
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(_R26_REGNO, r1);
+    movi(_R25_REGNO, i0);
+    calli((jit_word_t)__irem);
+    movr(r0, _R28_REGNO);
+}
+
+static unsigned int
+__urem(unsigned int u, unsigned int v)
+{
+    return (u % v);
+}
+
+static void
+_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    movr(_R26_REGNO, r1);
+    movr(_R25_REGNO, r2);
+    calli((jit_word_t)__urem);
+    movr(r0, _R28_REGNO);
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(_R26_REGNO, r1);
+    movi(_R25_REGNO, i0);
+    calli((jit_word_t)__urem);
+    movr(r0, _R28_REGNO);
+}
+
+static idiv_t
+__idivrem(int u, int v)
+{
+    idiv_t     div;
+    div.quo = u / v;
+    div.rem = u % v;
+    return (div);
+}
+
+static void
+_qdivr(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    movr(_R26_REGNO, r2);
+    movr(_R25_REGNO, r3);
+    calli((jit_word_t)__idivrem);
+    movr(r0, _R28_REGNO);
+    movr(r1, _R29_REGNO);
+}
+
+static void
+_qdivi(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    movr(_R26_REGNO, r2);
+    movi(_R25_REGNO, i0);
+    calli((jit_word_t)__idivrem);
+    movr(r0, _R28_REGNO);
+    movr(r1, _R29_REGNO);
+}
+
+static udiv_t
+__udivrem(unsigned int u, unsigned int v)
+{
+    udiv_t     div;
+    div.quo = u / v;
+    div.rem = u % v;
+    return (div);
+}
+
+static void
+_qdivr_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    movr(_R26_REGNO, r2);
+    movr(_R25_REGNO, r3);
+    calli((jit_word_t)__udivrem);
+    movr(r0, _R28_REGNO);
+    movr(r1, _R29_REGNO);
+}
+
+static void
+_qdivi_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    movr(_R26_REGNO, r2);
+    movi(_R25_REGNO, i0);
+    calli((jit_word_t)__udivrem);
+    movr(r0, _R28_REGNO);
+    movr(r1, _R29_REGNO);
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    andr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    orr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    xorr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_lshr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    SUBI(0x1f, r2, _R1_REGNO);
+    MTSAR(_R1_REGNO);
+    DEPW_Z(r1, 32, r0);
+}
+
+static void
+_rshr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    SUBI(0x1f, r2, _R1_REGNO);
+    MTSAR(_R1_REGNO);
+    EXTRW(r1, 32, r0);
+}
+
+static void
+_rshr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    SUBI(0x1f, r2, _R1_REGNO);
+    MTSAR(_R1_REGNO);
+    EXTRW_U(r1, 32, r0);
+}
+
+static void
+_cmpr(jit_state_t *_jit, jit_word_t c,
+      jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPCLR_(c, r1, r2, r0);
+    LDI(1, r0);
+}
+
+static void
+_cmpi(jit_state_t *_jit, jit_word_t c, jit_word_t ci,
+      jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       CMPICLR_(ci, i0, r1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPCLR_(c, r1, rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+    LDI(1, r0);
+}
+
+static void
+_ldr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ldr_uc(r0, r1);
+    extr_c(r0, r0);
+}
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    ldi_uc(r0, i0);
+    extr_c(r0, r0);
+}
+
+static void
+_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    ldxr_uc(r0, r1, r2);
+    extr_c(r0, r0);
+}
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi_uc(r0, r1, i0);
+    extr_c(r0, r0);
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -8182 && i0 <= 8191)
+       LDBL(i0, _R0_REGNO, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       LDIL(i0 & ~0x7ff, rn(reg));
+       LDBL(sign_extend(i0, 11), rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       LDBI(i0, r1, r0);
+    else if (i0 >= -8182 && i0 <= 8191)
+       LDBL(i0, r1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_uc(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ldr_us(r0, r1);
+    extr_s(r0, r0);
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    ldi_us(r0, i0);
+    extr_s(r0, r0);
+}
+
+static void
+_ldxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    ldxr_us(r0, r1, r2);
+    extr_s(r0, r0);
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi_us(r0, r1, i0);
+    extr_s(r0, r0);
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -8182 && i0 <= 8191)
+       LDHL(i0, _R0_REGNO, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       LDIL(i0 & ~0x7ff, rn(reg));
+       LDHL(sign_extend(i0, 11), rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       LDHI(i0, r1, r0);
+    else if (i0 >= -8182 && i0 <= 8191)
+       LDHL(i0, r1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_us(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -8182 && i0 <= 8191)
+       LDWL(i0, _R0_REGNO, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       LDIL(i0 & ~0x7ff, rn(reg));
+       LDWL(sign_extend(i0, 11), rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       LDWI(i0, r1, r0);
+    else if (i0 >= -8182 && i0 <= 8191)
+       LDWL(i0, r1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_ui(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -8182 && i0 <= 8191)
+       STBL(r0, i0, _R0_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       LDIL(i0 & ~0x7ff, rn(reg));
+       STBL(r0, sign_extend(i0, 11), rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_c(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       STBI(r1, i0, r0);
+    else if (i0 >= -8182 && i0 <= 8191)
+       STBL(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_c(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -8182 && i0 <= 8191)
+       STHL(r0, i0, _R0_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       LDIL(i0 & ~0x7ff, rn(reg));
+       STHL(r0, sign_extend(i0, 11), rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_s(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       STHI(r1, i0, r0);
+    else if (i0 >= -8182 && i0 <= 8191)
+       STHL(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_s(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -8182 && i0 <= 8191)
+       STWL(r0, i0, _R0_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       LDIL(i0 & ~0x7ff, rn(reg));
+       STWL(r0, sign_extend(i0, 11), rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_i(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       STWI(r1, i0, r0);
+    else if (i0 >= -8182 && i0 <= 8191)
+       STWL(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_i(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_bcmpr(jit_state_t *_jit, jit_word_t c,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    CMPB_N_(c, r0, r1, ((i0 - w) >> 2) - 2);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bcmpi(jit_state_t *_jit, jit_word_t c, jit_word_t ci,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -16 && i1 <= 15) {
+       w = _jit->pc.w;
+       CMPIB_N_(ci, i1, r0, ((i0 - w) >> 2) - 2);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = _jit->pc.w;
+       CMPB_N_(c, r0, rn(reg), ((i0 - w) >> 2) - 2);
+       jit_unget_reg(reg);
+    }
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bmxr(jit_state_t *_jit, jit_bool_t c,
+      jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    andr(rn(reg), r0, r1);
+    w = c ? bnei(i0, rn(reg), 0) : beqi(i0, rn(reg), 0);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bmxi(jit_state_t *_jit, jit_bool_t c,
+      jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    andr(rn(reg), r0, rn(reg));
+    w = c ? bnei(i0, rn(reg), 0) : beqi(i0, rn(reg), 0);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_boaddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    ADDB_N_SV(r1, r0, ((i0 - w) >> 2) - 2);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_boaddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -16 && i1 <= 15) {
+       w = _jit->pc.w;
+       ADDIB_N_SV(i1, r0, ((i0 - w) >> 2) - 2);
+       NOP();
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = boaddr(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_boaddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    ADDB_N_UV(r1, r0, ((i0 - w) >> 2) - 2);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_boaddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -16 && i1 <= 15) {
+       w = _jit->pc.w;
+       ADDIB_N_UV(i1, r0, ((i0 - w) >> 2) - 2);
+       NOP();
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = boaddr_u(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bxaddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    ADDB_N_NSV(r1, r0, ((i0 - w) >> 2) - 2);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bxaddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -16 && i1 <= 15) {
+       w = _jit->pc.w;
+       ADDIB_N_NSV(i1, r0, ((i0 - w) >> 2) - 2);
+       NOP();
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = bxaddr(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bxaddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    ADDB_N_NUV(r1, r0, ((i0 - w) >> 2) - 2);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bxaddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -16 && i1 <= 15) {
+       w = _jit->pc.w;
+       ADDIB_N_NUV(i1, r0, ((i0 - w) >> 2) - 2);
+       NOP();
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = bxaddr_u(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bosubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    SUB_NSV(r0, r1, r0);
+    w = _jit->pc.w;
+    /* null'ed if no signed overflow */
+    B_N(((i0 - w) >> 2) - 2, _R0_REGNO);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bosubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    movi(_R1_REGNO, i1);
+    return (bosubr(i0, r0, _R1_REGNO));
+}
+
+static jit_word_t
+_bosubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    SUB(r0, r1, r0);
+    SUB_B(_R0_REGNO, _R0_REGNO, _R1_REGNO);
+    return (bnei(i0, _R1_REGNO, 0));
+}
+
+static jit_word_t
+_bosubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    movi(_R1_REGNO, i1);
+    SUB(r0, _R1_REGNO, r0);
+    SUB_B(_R0_REGNO, _R0_REGNO, _R1_REGNO);
+    return (bnei(i0, _R1_REGNO, 0));
+}
+
+static jit_word_t
+_bxsubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    SUB_SV(r0, r1, r0);
+    w = _jit->pc.w;
+    /* null'ed if signed overflow */
+    B_N(((i0 - w) >> 2) - 2, _R0_REGNO);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bxsubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    movi(_R1_REGNO, i1);
+    return (bxsubr(i0, r0, _R1_REGNO));
+}
+
+static jit_word_t
+_bxsubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    SUB(r0, r1, r0);
+    SUB_B(_R0_REGNO, _R0_REGNO, _R1_REGNO);
+    return (beqi(i0, _R1_REGNO, 0));
+}
+
+static jit_word_t
+_bxsubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    movi(_R1_REGNO, i1);
+    SUB(r0, _R1_REGNO, r0);
+    SUB_B(_R0_REGNO, _R0_REGNO, _R1_REGNO);
+    return (beqi(i0, _R1_REGNO, 0));
+}
+
+static void
+_jmpr(jit_state_t *_jit, jit_int32_t r0)
+{
+    BV_N(_R0_REGNO, r0);
+}
+
+static void
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    w = ((i0 - _jit->pc.w) >> 2) - 2;
+    if (w >= -32768 && w <= 32767)
+       B_N(w, _R0_REGNO);
+    else {
+       movi(_R1_REGNO, w);
+       BV_N(_R0_REGNO, _R1_REGNO);
+    }
+}
+
+static jit_word_t
+_jmpi_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    w = movi_p(_R1_REGNO, i0);
+    jmpr(_R1_REGNO);
+    return (w);
+}
+
+static void
+_callr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_word_t         dyn;
+    jit_word_t         imm;
+    if (r0 != _R1_REGNO)
+       COPY(r0, _R1_REGNO);
+    /* inline $$dyncall */
+    imm = _jit->pc.w;
+    BBI_N_GE(_R1_REGNO, 30, 0);                /*   if (r1 & 2) {              */
+    DEPWRI(0, 31, 2, _R1_REGNO);       /*      r1 &= ~2;               */
+    LDWI(4, _R1_REGNO, _R19_REGNO);    /*      r19 = r1[1];            */
+    LDWI(0, _R1_REGNO, _R1_REGNO);     /*      r1  = r1[0];            */
+                                       /*   }                          */
+    BVE_L(_R1_REGNO);
+    STWL(_RP_REGNO, -24, _SP_REGNO);
+    dyn = _jit->pc.w;
+    jmpi(_jit->pc.w);
+    patch_at(imm, _jit->pc.w);
+    BVE_L_N(_R1_REGNO);
+    NOP();
+    patch_at(dyn, _jit->pc.w);
+}
+
+static void
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    if (i0 & 2) {
+       i0 &= -4;
+       movi(_R1_REGNO, i0);
+       LDWI(4, _R1_REGNO, _R19_REGNO);
+       LDWI(0, _R1_REGNO, _R1_REGNO);
+       BVE_L(_R1_REGNO);
+       STWL(_RP_REGNO, -24, _SP_REGNO);
+    }
+    else {
+       w = ((i0 - _jit->pc.w) >> 2) - 2;
+       if (w >= -32768 && w <= 32767)
+           B_L_N(w);
+       else {
+           movi(_R1_REGNO, i0);
+           BVE_L_N(_R1_REGNO);
+       }
+       NOP();
+    }
+}
+
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    w = movi_p(_R1_REGNO, i0);
+    callr(_R1_REGNO);
+    return (w);
+}
+
+static jit_int32_t gr[] = {
+     _R4,  _R5,  _R6,  _R7,  _R8,
+     _R9, _R10, _R11, _R12, _R13,
+    _R14, _R15, _R16, _R17, _R18
+};
+
+static jit_int32_t fr[] = {
+    _F12, _F13, _F14, _F15, _F16,
+    _F17, _F18, _F19, _F20, _F21
+};
+
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                regno;
+    jit_word_t         offset;
+
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       /* hppa stack grows up */
+       assert(_jitc->function->self.aoff <= _jitc->function->frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = _jitc->function->frame;
+    }
+    if (_jitc->function->allocar) {
+       _jitc->function->self.aoff += 63;
+       _jitc->function->self.aoff &= -64;
+    }
+    _jitc->function->stack = ((_jitc->function->self.aoff -
+                              _jitc->function->self.alen -
+                              _jitc->function->self.size) + 63) & -64;
+
+    /* Save stack frame (FIXME Only required if non leaf) */
+    STWL(_RP_REGNO, -20, _SP_REGNO);
+
+    /* Create stack frame */
+    COPY(_FP_REGNO, _R1_REGNO);
+    COPY(_SP_REGNO, _FP_REGNO);
+    STWL_MA(_R1_REGNO, _jitc->function->stack, _SP_REGNO);
+
+    /* Save any modified callee save registers */
+    offset = alloca_offset - 140;
+    for (regno = 0; regno < jit_size(gr); regno++, offset += 4) {
+       if (jit_regset_tstbit(&_jitc->function->regset, gr[regno]))
+           stxi(offset, _FP_REGNO, rn(gr[regno]));
+    }
+    for (regno = 0; regno < jit_size(fr); regno++, offset += 8) {
+       if (jit_regset_tstbit(&_jitc->function->regset, fr[regno]))
+           stxi_d(offset, _FP_REGNO, rn(fr[regno]));
+    }
+
+    if (_jitc->function->allocar) {
+       regno = jit_get_reg(jit_class_gpr);
+       movi(rn(regno), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, _FP_REGNO, rn(regno));
+       jit_unget_reg(regno);
+    }
+
+    if (_jitc->function->self.call & jit_call_varargs) {
+       for (regno = 3; regno >= _jitc->function->vagp; --regno)
+           stxi(params_offset - regno * 4 - 4, _FP_REGNO, rn(_R26 - regno));
+    }
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                regno;
+    jit_word_t         offset;
+
+    if (_jitc->function->assume_frame)
+       return;
+    /* Restore any modified callee save registers */
+    offset = alloca_offset - 140;
+    for (regno = 0; regno < jit_size(gr); regno++, offset += 4) {
+       if (jit_regset_tstbit(&_jitc->function->regset, gr[regno]))
+           ldxi(rn(gr[regno]), _FP_REGNO, offset);
+    }
+    for (regno = 0; regno < jit_size(fr); regno++, offset += 8) {
+       if (jit_regset_tstbit(&_jitc->function->regset, fr[regno]))
+           ldxi_d(rn(fr[regno]), _FP_REGNO, offset);
+    }
+
+    /* Restore stack frame (FIXME Only required if non leaf) */
+    LDWL(-20, _FP_REGNO, _RP_REGNO);
+    LDO(_jitc->function->stack, _FP_REGNO, _SP_REGNO);
+    LDWL_MB(-_jitc->function->stack, _SP_REGNO, _FP_REGNO);
+#if defined(__hpux)
+    BVE_N(_RP_REGNO);
+#else
+    BV_N(_R0_REGNO, _RP_REGNO);
+#endif
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+    /* Initialize stack pointer to the first stack argument. */
+    if (jit_arg_reg_p(_jitc->function->vagp))
+       addi(r0, _FP_REGNO, params_offset - _jitc->function->vagp * 4);
+    else
+       addi(r0, _FP_REGNO, _jitc->function->self.size);
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Update vararg stack pointer. */
+    subi(r1, r1, 4);
+
+    /* Load argument. */
+    ldr(r0, r1);
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
+{
+    jit_word_t          w;
+    union {
+       jit_uint32_t    *i;
+       jit_word_t       w;
+    } u;
+    u.w = instr;
+    switch (u.i[0] >> 26) {
+       case 0x8:                               /* LDIL */
+           u.i[0] &= ~0x1fffff;
+           u.i[0] |= re_assemble_21((label & ~0x7ff) >> 11);
+           assert((u.i[1] >> 26) == 0xd);      /* LDO */
+           u.i[1] &= ~0xffff;
+           u.i[1] |= re_assemble_16(label & 0x7ff);
+           break;
+       case 0x20:      case 0x22:              /* CMPB */
+       case 0x21:      case 0x23:              /* CMPIB */
+       case 0x28:      case 0x2a:              /* ADDB */
+       case 0x29:      case 0x2b:              /* ADDIB */
+       case 0x31:                              /* BBI */
+           w = ((label - instr) >> 2) - 2;
+           assert(w >= -2048 && w <= 2047);
+           u.i[0] &= ~0x1ffd;
+           u.i[0] |= re_assemble_12(w);
+           break;
+       case 0x3a:                              /* B */
+           w = ((label - instr) >> 2) - 2;
+           assert(w >= -32768 && w <= 32767);
+           u.i[0] &= ~0x1f1ffd;
+           u.i[0] |= re_assemble_17(w);
+           break;
+       default:
+           abort();
+    }
+}
+#endif
diff --git a/deps/lightning/lib/jit_hppa-fpu.c b/deps/lightning/lib/jit_hppa-fpu.c
new file mode 100644 (file)
index 0000000..5fa6856
--- /dev/null
@@ -0,0 +1,1070 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+
+/* FIXME should actually be hw model/version/etc or other constraint
+ * that causes a SIGSEGV/SIGILL if using these instructions */
+#if 1 //defined(__hpux)
+#  define FSTXR                                0
+#  define FLDXR                                0
+#else
+#  define FSTXR                                1
+#  define FLDXR                                1
+#endif
+
+#define f39(o,b,x,t)                   _f39(_jit,o,b,x,t)
+static void _f39(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f40(o,b,x,r)                   _f40(_jit,o,b,x,r)
+static void _f40(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t)
+    maybe_unused;
+#define f41(o,b,x,t)                   _f41(_jit,o,b,x,t)
+static void _f41(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f42(o,b,i,r)                   _f42(_jit,o,b,i,r)
+static void _f42(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f43(o,b,t,i)                   f1(o,b,t,i)
+#define f45(o,r,a,b,fmt,c,d,e,t)       _f45(_jit,o,r,a,b,fmt,c,d,e,t)
+static void _f45(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f46(o,r,a,s,df,sf,b,c,d,t)     _f46(_jit,o,r,a,s,df,sf,b,c,d,t)
+static void _f46(jit_state_t*,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f47(o,r1,r2,a,fmt,b,c,d,t)     f47_48(o,r1,r2,a,fmt,b,c,d,t)
+#define f48(o,r1,r2,a,fmt,b,c,d,t)     f47_48(o,r1,r2,a,fmt,b,c,d,t)
+#define f47_48(o,r1,r2,y,fmt,b,c,d,t)  _f47_48(_jit,o,r1,r2,y,fmt,b,c,d,t)
+static void _f47_48(jit_state_t*,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f49(o,r,a,b,c,f,d,e,g,h,i,t)   f49_52(o,r,a,b,c,f,d,e,g,h,i,t)
+#define f51(o,r1,r2,y,a,f,b,d,e,g,h,c) f49_52(o,r1,r2,y,a,f,b,d,e,g,h,c)
+#define f52(o,r1,r2,a,b,f,c,d,e,g,h,t) f49_52(o,r1,r2,a,b,f,c,d,e,g,h,t)
+#define f49_52(o,r1,r2,y,v,f,a,b,u,c,d,t) _f49_52(_jit,o,r1,r2,y,v,f,a,b,u,c,d,t)
+static void _f49_52(jit_state_t*,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define f53(o,r1,r2,ta,ra,f,tm)                _f53(_jit,o,r1,r2,ta,ra,f,tm)
+static void _f53(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define f54(o,r1,r2,a,b,f,c,d,e,g,t)   _f54(_jit,o,r1,r2,a,b,f,c,d,e,g,t)
+static void _f54(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t) maybe_unused;
+#define FABS_(f,r,t)                   f49(0xe,r,0,3,0,f,0,0,0,0,0,t)
+#define FABS_S(r,t)                    FABS_(0,r,t)
+#define FABS_D(r,t)                    FABS_(1,r,t)
+#define FABS_Q(r,t)                    f45(0xc,r,0,3,3,0,0,0,t)
+#define FADD_(f,r1,r2,t)               f52(0xe,r1,r2,0,0,f,3,0,0,0,0,t)
+#define FADD_S(r1,r2,t)                        FADD_(0,r1,r2,t)
+#define FADD_D(r1,r2,t)                        FADD_(1,r1,r2,t)
+#define FADD_Q(r1,r2,t)                        f48(0xc,r1,r2,0,3,3,0,0,t)
+#define FPSR_GT                                1
+#define FPSR_LT                                2
+#define FPSR_EQ                                4
+#define FPSR_UN                                8
+/*
+    Actually these are reversed, but easier for the FTEST after the FCMP
+    fcmp,dbl,false? fr4,fr12           0
+    fcmp,dbl,false fr4,fr12            1
+    fcmp,dbl,? fr4,fr12                        2
+    fcmp,dbl,!<=> fr4,fr12             3               ORD
+    fcmp,dbl,= fr4,fr12                        4               NE
+    fcmp,dbl,=t fr4,fr12               5
+    fcmp,dbl,?= fr4,fr12               6
+    fcmp,dbl,!<> fr4,fr12              7               LTGT
+    fcmp,dbl,!?>= fr4,fr12             8
+    fcmp,dbl,< fr4,fr12                        9               UNGE
+    fcmp,dbl,?< fr4,fr12               10
+    fcmp,dbl,!>= fr4,fr12              11              GE
+    fcmp,dbl,!?> fr4,fr12              12
+    fcmp,dbl,<= fr4,fr12               13              UNGT
+    fcmp,dbl,?<= fr4,fr12              14
+    fcmp,dbl,!> fr4,fr12               15              GT
+    fcmp,dbl,!?<= fr4,fr12             16
+    fcmp,dbl,> fr4,fr12                        17              UNLE
+    fcmp,dbl,?> fr4,fr12               18
+    fcmp,dbl,!<= fr4,fr12              19              LE
+    fcmp,dbl,!?< fr4,fr12              20
+    fcmp,dbl,>= fr4,fr12               21              UNLT
+    fcmp,dbl,?>= fr4,fr12              22
+    fcmp,dbl,!< fr4,fr12               23              LT
+    fcmp,dbl,!?= fr4,fr12              24
+    fcmp,dbl,<> fr4,fr12               25              UNEQ
+    fcmp,dbl,!= fr4,fr12               26              EQ
+    fcmp,dbl,!=t fr4,fr12              27
+    fcmp,dbl,!? fr4,fr12               28
+    fcmp,dbl,<=> fr4,fr12              29              UNORD
+    fcmp,dbl,true? fr4,fr12            30
+    fcmp,dbl,true fr4,fr12             31
+ */
+#define FCMP_LT                                23
+#define FCMP_LE                                19
+#define FCMP_EQ                                26
+#define FCMP_GE                                11
+#define FCMP_GT                                15
+#define FCMP_NE                                4
+#define FCMP_UNLT                      21
+#define FCMP_UNLE                      17
+#define FCMP_UNEQ                      25
+#define FCMP_UNGE                      9
+#define FCMP_UNGT                      13
+#define FCMP_LTGT                      7
+#define FCMP_ORD                       3
+#define FCMP_UNORD                     29
+#define FCMP_(f,r1,r2,c)               f51(0xe,r1,r2,0,0,f,2,0,0,0,0,c)
+#define FCMP_S_(r1,r2,c)               FCMP_(0,r1,r2,c)
+#define FCMP_D_(r1,r2,c)               FCMP_(1,r1,r2,c)
+#define FCMP_Q_(r1,r2,c)               f47(0xc,r1,r2,0,3,2,0,0,c)
+#define FCMP_S_LT(r1,r2)               FCMP_S_(r1,r2,FCMP_LT)
+#define FCMP_D_LT(r1,r2)               FCMP_D_(r1,r2,FCMP_LT)
+#define FCMP_Q_LT(r1,r2)               FCMP_Q_(r1,r2,FCMP_LT)
+#define FCMP_S_LE(r1,r2)               FCMP_S_(r1,r2,FCMP_LE)
+#define FCMP_D_LE(r1,r2)               FCMP_D_(r1,r2,FCMP_LE)
+#define FCMP_Q_LE(r1,r2)               FCMP_Q_(r1,r2,FCMP_LE)
+#define FCMP_S_EQ(r1,r2)               FCMP_S_(r1,r2,FCMP_EQ)
+#define FCMP_D_EQ(r1,r2)               FCMP_D_(r1,r2,FCMP_EQ)
+#define FCMP_Q_EQ(r1,r2)               FCMP_Q_(r1,r2,FCMP_EQ)
+#define FCMP_S_GE(r1,r2)               FCMP_S_(r1,r2,FCMP_GE)
+#define FCMP_D_GE(r1,r2)               FCMP_D_(r1,r2,FCMP_GE)
+#define FCMP_Q_GE(r1,r2)               FCMP_Q_(r1,r2,FCMP_GE)
+#define FCMP_S_GT(r1,r2)               FCMP_S_(r1,r2,FCMP_GT)
+#define FCMP_D_GT(r1,r2)               FCMP_D_(r1,r2,FCMP_GT)
+#define FCMP_Q_GT(r1,r2)               FCMP_Q_(r1,r2,FCMP_GT)
+#define FCMP_S_NE(r1,r2)               FCMP_S_(r1,r2,FCMP_NE)
+#define FCMP_D_NE(r1,r2)               FCMP_D_(r1,r2,FCMP_NE)
+#define FCMP_Q_NE(r1,r2)               FCMP_Q_(r1,r2,FCMP_NE)
+#define FCMP_S_UNLT(r1,r2)             FCMP_S_(r1,r2,FCMP_UNLT)
+#define FCMP_D_UNLT(r1,r2)             FCMP_D_(r1,r2,FCMP_UNLT)
+#define FCMP_Q_UNLT(r1,r2)             FCMP_Q_(r1,r2,FCMP_UNLT)
+#define FCMP_S_UNLE(r1,r2)             FCMP_S_(r1,r2,FCMP_UNLE)
+#define FCMP_D_UNLE(r1,r2)             FCMP_D_(r1,r2,FCMP_UNLE)
+#define FCMP_Q_UNLE(r1,r2)             FCMP_Q_(r1,r2,FCMP_UNLE)
+#define FCMP_S_UNEQ(r1,r2)             FCMP_S_(r1,r2,FCMP_UNEQ)
+#define FCMP_D_UNEQ(r1,r2)             FCMP_D_(r1,r2,FCMP_UNEQ)
+#define FCMP_Q_UNEQ(r1,r2)             FCMP_Q_(r1,r2,FCMP_UNEQ)
+#define FCMP_S_UNGE(r1,r2)             FCMP_S_(r1,r2,FCMP_UNGE)
+#define FCMP_D_UNGE(r1,r2)             FCMP_D_(r1,r2,FCMP_UNGE)
+#define FCMP_Q_UNGE(r1,r2)             FCMP_Q_(r1,r2,FCMP_UNGE)
+#define FCMP_S_UNGT(r1,r2)             FCMP_S_(r1,r2,FCMP_UNGT)
+#define FCMP_D_UNGT(r1,r2)             FCMP_D_(r1,r2,FCMP_UNGT)
+#define FCMP_Q_UNGT(r1,r2)             FCMP_Q_(r1,r2,FCMP_UNGT)
+#define FCMP_S_LTGT(r1,r2)             FCMP_S_(r1,r2,FCMP_LTGT)
+#define FCMP_D_LTGT(r1,r2)             FCMP_D_(r1,r2,FCMP_LTGT)
+#define FCMP_Q_LTGT(r1,r2)             FCMP_Q_(r1,r2,FCMP_LTGT)
+#define FCMP_S_ORD(r1,r2)              FCMP_S_(r1,r2,FCMP_ORD)
+#define FCMP_D_ORD(r1,r2)              FCMP_D_(r1,r2,FCMP_ORD)
+#define FCMP_Q_ORD(r1,r2)              FCMP_Q_(r1,r2,FCMP_ORD)
+#define FCMP_S_UNORD(r1,r2)            FCMP_S_(r1,r2,FCMP_UNORD)
+#define FCMP_D_UNORD(r1,r2)            FCMP_D_(r1,r2,FCMP_UNORD)
+#define FCMP_Q_UNORD(r1,r2)            FCMP_Q_(r1,r2,FCMP_UNORD)
+#define XFNVFF(s,d,r,t)                        f46(0xc,r,0,0,d,s,1,0,0,t)
+#define FCNVFF_Q_S(r,t)                        XFNVFF(3,0,r,t)
+#define FCNVFF_Q_D(r,t)                        XFNVFF(3,1,r,t)
+#define FCNVFF_S_Q(r,t)                        XFNVFF(0,3,r,t)
+#define FCNVFF_D_Q(r,t)                        XFNVFF(1,3,r,t)
+#define FCNVFF_(s,d,r,t)               f46(0xc,r,0,0,d,s,1,0,0,t)
+#define FCNVFF_S_D(r,t)                        FCNVFF_(0,1,r,t)
+#define FCNVFF_D_S(r,t)                        FCNVFF_(1,0,r,t)
+#define FCNVXF_(s,d,r,t)               f46(0xc,r,0,1,d,s,1,0,0,t)
+#define FCNVXF_S_S(r,t)                        FCNVXF_(0,0,r,t)
+#define FCNVXF_S_D(r,t)                        FCNVXF_(0,1,r,t)
+#define FCNVXT_(s,d,r,t)               f46(0xc,r,0,3,d,s,1,0,0,t)
+#define FCNVXT_S_S(r,t)                        FCNVXT_(0,0,r,t)
+#define FCNVXT_D_S(r,t)                        FCNVXT_(1,0,r,t)
+#define FCPY_(f,r,t)                   f49(0xe,r,0,2,0,f,0,0,0,0,0,t)
+#define FCPY_S(r,t)                    FCPY_(0,r,t)
+#define FCPY_D(r,t)                    FCPY_(1,r,t)
+#define FCPY_Q(r,t)                    f45(0xc,r,0,2,2,0,0,0,t)
+#define FDIV_(f,r1,r2,t)               f52(0xe,r1,r2,3,0,f,3,0,0,0,0,t)
+#define FDIV_S(r1,r2,t)                        FDIV_(0,r1,r2,t)
+#define FDIV_D(r1,r2,t)                        FDIV_(1,r1,r2,t)
+#define FDIV_Q(r1,r2,t)                        f48(0xc,r1,r2,3,3,3,0,0,t)
+#define FID()                          f45(0xc,0,0,0,2,0,0,0,0)
+#define FLDDL(i,b,t)                   f3(0x14,b,t,i,1)
+#define FLDD(x,b,t)                    f39(0xb,b,x,t)
+#define FLDDI(i,b,t)                   f41(0xb,b,i,t)
+#define FLDWL(i,b,t)                   f43(0x17,b,t,i)
+#define FLDW(x,b,t)                    f39(0x9,b,x,t)
+#define FLDWI(i,b,t)                   f41(0x9,b,i,t)
+#define FMPY_(f,r1,r2,t)               f52(0xe,r1,r2,2,0,f,3,0,0,0,0,t)
+#define FMPY_S(r1,r2,t)                        FMPY_(0,r1,r2,t)
+#define FMPY_D(r1,r2,t)                        FMPY_(1,r1,r2,t)
+#define FMPY_Q(r1,r2,t)                        f48(0xc,r1,r2,2,3,3,0,0,t)
+/* FIXME not disassembled */
+#define FMPYADD_(f,r1,r2,ta,ra,tm)     f53(0x6,r1,r2,ta,ra,f,tm)
+#define FMPYADD_S(r1,r2,ta,ra,tm)      FMPYADD_(0,r1,r2,ta,ra,tm)
+#define FMPYADD_D(r1,r2,ta,ra,tm)      FMPYADD_(1,r1,r2,ta,ra,tm)
+#define FMPYFADD_(f,r1,r2,ra,t)                f54(0x2e,r1,r2,ra>>3,0,f,(ra)&7,0,0,0,t)
+#define FMPYFADD_S(r1,r2,ra,t)         FMPYFADD_(0,r1,r2,ra,t)
+#define FMPYFADD_D(r1,r2,ra,t)         FMPYFADD_(1,r1,r2,ra,t)
+#define FMPYNFADD_(f,r1,r2,ra,t)       f54(0x2e,r1,r2,ra>>3,0,f,(ra)&7,0,0,1,t)
+#define FMPYNFADD_S(r1,r2,ra,t)                FMPYNFADD_(0,r1,r2,ra,t)
+#define FMPYNFADD_D(r1,r2,ra,t)                FMPYNFADD_(1,r1,r2,ra,t)
+#define FMPYSUB_(f,r1,r2,ta,ra,tm)     f53(0x26,r1,r2,ta,ra,f,tm)
+#define FMPYSUB_S(r1,r2,ta,ra,tm)      FMPYSUB_(0,r1,r2,ta,ra,tm)
+#define FMPYSUB_D(r1,r2,ta,ra,tm)      FMPYSUB_(1,r1,r2,ta,ra,tm)
+#define FNEG_(f,r,t)                   f49(0xe,r,0,6,0,f,0,0,0,0,0,t)
+#define FNEG_S(r,t)                    FNEG_(0,r,t)
+#define FNEG_D(r,t)                    FNEG_(1,r,t)
+/* FIXME not disassembled */
+#define FNEG_Q(r,t)                    f45(0xc,r,0,6,3,0,0,0,t)
+#define FNEGABS_(f,r,t)                        f49(0xe,r,0,7,0,f,0,0,0,0,0,t)
+#define FNEGABS_S(r,t)                 FNEGABS_(0,r,t)
+#define FNEGABS_D(r,t)                 FNEGABS_(1,r,t)
+#define FNEGABS_Q(r,t)                 f45(0xc,r,0,7,3,0,0,0,t)
+#define FRND_(f,r,t)                   f49(0xe,r,0,5,0,f,0,0,0,0,0,t)
+#define FRND_S(r,t)                    FRND_(0,r,t)
+#define FRND_D(r,t)                    FRND_(1,r,t)
+#define FRND_Q(r,t)                    f45(0xc,r,0,5,3,0,0,0,t)
+#define FSQRT_(f,r,t)                  f49(0xe,r,0,4,0,f,0,0,0,0,0,t)
+#define FSQRT_S(r,t)                   FSQRT_(0,r,t)
+#define FSQRT_D(r,t)                   FSQRT_(1,r,t)
+#define FSQRT_Q(r,t)                   f45(0xc,r,0,4,3,0,0,0,t)
+#define FSTDL(r,i,b)                   f3(0x1c,b,r,i,1)
+#define FSTD(r,x,b)                    f40(0xb,b,x,r)
+#define FSTDI(r,i,b)                   f42(0xb,b,i,r)
+#define FSTWL(r,i,b)                   f43(0x1f,b,r,i)
+#define FSTW(r,x,b)                    f40(0x9,b,x,r)
+#define FSTWI(r,i,b)                   f42(0x9,b,i,r)
+#define FSUB_(f,r1,r2,t)               f52(0xe,r1,r2,1,0,f,3,0,0,0,0,t)
+#define FSUB_S(r1,r2,t)                        FSUB_(0,r1,r2,t)
+#define FSUB_D(r1,r2,t)                        FSUB_(1,r1,r2,t)
+#define FSUB_Q(r1,r2,t)                        f48(0xc,r1,r2,1,3,3,0,0,t)
+#define FTEST_(c)                      f47(0xc,0,0,0,0,2,0,1,c)
+#define FTEST()                                f47(0xc,0,0,1,0,2,0,1,0)
+#define FTEST_LT()                     FTEST_(FCMP_LT)
+#define FTEST_LE()                     FTEST_(FCMP_LE)
+#define FTEST_EQ()                     FTEST_(FCMP_EQ)
+#define FTEST_GE()                     FTEST_(FCMP_GE)
+#define FTEST_GT()                     FTEST_(FCMP_GT)
+#define FTEST_NE()                     FTEST_(FCMP_NE)
+#define FTEST_UNLT()                   FTEST_(FCMP_UNLT)
+#define FTEST_UNLE()                   FTEST_(FCMP_UNLE)
+#define FTEST_UNEQ()                   FTEST_(FCMP_UNEQ)
+#define FTEST_UNGE()                   FTEST_(FCMP_UNGE)
+#define FTEST_UNGT()                   FTEST_(FCMP_UNGT)
+#define FTEST_LTGT()                   FTEST_(FCMP_LTGT)
+#define FTEST_ORD()                    FTEST_(FCMP_ORD)
+#define FTEST_UNORD()                  FTEST_(FCMP_UNORD)
+#define XMPYU(r1,r2,t)                 f52(0xe,r1,r2,2,0,0,3,1,0,0,0,t)
+#define XMPYU_L_R(r1,r2,t)             f52(0xe,r1,r2,2,1,0,3,1,0,0,0,t)
+#define XMPYU_R_L(r1,r2,t)             f52(0xe,r1,r2,2,0,0,3,1,1,0,0,t)
+#define XMPYU_R_R(r1,r2,t)             f52(0xe,r1,r2,2,1,0,3,1,1,0,0,t)
+#define negr_f(r0,r1)                  FNEG_S(r1,r0)
+#define negr_d(r0,r1)                  FNEG_D(r1,r0)
+#define sqrtr_f(r0,r1)                 FSQRT_S(r1,r0)
+#define sqrtr_d(r0,r1)                 FSQRT_D(r1,r0)
+#define extr_f(r0,r1)                  _extr_f(_jit,r0,r1)
+static void _extr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#define extr_d(r0,r1)                  _extr_d(_jit,r0,r1)
+static void _extr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#define extr_f_d(r0,r1)                        FCNVFF_S_D(r1,r0)
+#define extr_d_f(r0,r1)                        FCNVFF_D_S(r1,r0)
+#define truncr_f(r0,r1)                        truncr_f_i(r0,r1)
+#define truncr_f_i(r0,r1)              _truncr_f_i(_jit,r0,r1)
+static void _truncr_f_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#define truncr_d(r0,r1)                        truncr_d_i(r0,r1)
+#define truncr_d_i(r0,r1)              _truncr_d_i(_jit,r0,r1)
+static void _truncr_d_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#define movr_f(r0,r1)                  FCPY_S(r1,r0)
+#define movi_f(r0,i0)                  _movi_f(_jit,r0,i0)
+static void _movi_f(jit_state_t*,jit_int32_t,jit_float32_t*);
+#define movr_d(r0,r1)                  FCPY_D(r1,r0)
+#define movi_d(r0,i0)                  _movi_d(_jit,r0,i0)
+static void _movi_d(jit_state_t*,jit_int32_t,jit_float64_t*);
+#define absr_f(r0,r1)                  FABS_S(r1,r0)
+#define absr_d(r0,r1)                  FABS_D(r1,r0)
+#define addr_f(r0,r1,r2)               FADD_S(r1,r2,r0)
+#define addi_f(r0,r1,i0)               _addi_f(_jit,r0,r1,i0)
+static void _addi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define addr_d(r0,r1,r2)               FADD_D(r1,r2,r0)
+#define addi_d(r0,r1,i0)               _addi_d(_jit,r0,r1,i0)
+static void _addi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define subr_f(r0,r1,r2)               FSUB_S(r1,r2,r0)
+#define subi_f(r0,r1,i0)               _subi_f(_jit,r0,r1,i0)
+static void _subi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define subr_d(r0,r1,r2)               FSUB_D(r1,r2,r0)
+#define subi_d(r0,r1,i0)               _subi_d(_jit,r0,r1,i0)
+static void _subi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define rsbr_f(r0,r1,r2)               subr_f(r0,r2,r1)
+#define rsbi_f(r0,r1,i0)               _rsbi_f(_jit,r0,r1,i0)
+static void _rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define rsbr_d(r0,r1,r2)               subr_d(r0,r2,r1)
+#define rsbi_d(r0,r1,i0)               _rsbi_d(_jit,r0,r1,i0)
+static void _rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define mulr_f(r0,r1,r2)               FMPY_S(r1,r2,r0)
+#define muli_f(r0,r1,i0)               _muli_f(_jit,r0,r1,i0)
+static void _muli_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define mulr_d(r0,r1,r2)               FMPY_D(r1,r2,r0)
+#define muli_d(r0,r1,i0)               _muli_d(_jit,r0,r1,i0)
+static void _muli_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define divr_f(r0,r1,r2)               FDIV_S(r1,r2,r0)
+#define divi_f(r0,r1,i0)               _divi_f(_jit,r0,r1,i0)
+static void _divi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define divr_d(r0,r1,r2)               FDIV_D(r1,r2,r0)
+#define divi_d(r0,r1,i0)               _divi_d(_jit,r0,r1,i0)
+static void _divi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define cmpr_f(c,r0,r1,r2)             _cmpr_f(_jit,c,r0,r1,r2)
+static void _cmpr_f(jit_state_t*,jit_word_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t);
+#define cmpi_f(c,r0,r1,i0)             _cmpi_f(_jit,c,r0,r1,i0)
+static void _cmpi_f(jit_state_t*,jit_word_t,
+                   jit_int32_t,jit_int32_t,jit_float32_t*);
+#define cmpr_d(c,r0,r1,r2)             _cmpr_d(_jit,c,r0,r1,r2)
+static void _cmpr_d(jit_state_t*,jit_word_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t);
+#define cmpi_d(c,r0,r1,i0)             _cmpi_d(_jit,c,r0,r1,i0)
+static void _cmpi_d(jit_state_t*,jit_word_t,
+                   jit_int32_t,jit_int32_t,jit_float64_t*);
+#define ltr_f(r0,r1,r2)                        cmpr_f(FCMP_LT,r0,r1,r2)
+#define lti_f(r0,r1,i0)                        cmpi_f(FCMP_LT,r0,r1,i0)
+#define ltr_d(r0,r1,r2)                        cmpr_d(FCMP_LT,r0,r1,r2)
+#define lti_d(r0,r1,i0)                        cmpi_d(FCMP_LT,r0,r1,i0)
+#define ler_f(r0,r1,r2)                        cmpr_f(FCMP_LE,r0,r1,r2)
+#define lei_f(r0,r1,i0)                        cmpi_f(FCMP_LE,r0,r1,i0)
+#define ler_d(r0,r1,r2)                        cmpr_d(FCMP_LE,r0,r1,r2)
+#define lei_d(r0,r1,i0)                        cmpi_d(FCMP_LE,r0,r1,i0)
+#define eqr_f(r0,r1,r2)                        cmpr_f(FCMP_EQ,r0,r1,r2)
+#define eqi_f(r0,r1,i0)                        cmpi_f(FCMP_EQ,r0,r1,i0)
+#define eqr_d(r0,r1,r2)                        cmpr_d(FCMP_EQ,r0,r1,r2)
+#define eqi_d(r0,r1,i0)                        cmpi_d(FCMP_EQ,r0,r1,i0)
+#define ger_f(r0,r1,r2)                        cmpr_f(FCMP_GE,r0,r1,r2)
+#define gei_f(r0,r1,i0)                        cmpi_f(FCMP_GE,r0,r1,i0)
+#define ger_d(r0,r1,r2)                        cmpr_d(FCMP_GE,r0,r1,r2)
+#define gei_d(r0,r1,i0)                        cmpi_d(FCMP_GE,r0,r1,i0)
+#define gtr_f(r0,r1,r2)                        cmpr_f(FCMP_GT,r0,r1,r2)
+#define gti_f(r0,r1,i0)                        cmpi_f(FCMP_GT,r0,r1,i0)
+#define gtr_d(r0,r1,r2)                        cmpr_d(FCMP_GT,r0,r1,r2)
+#define gti_d(r0,r1,i0)                        cmpi_d(FCMP_GT,r0,r1,i0)
+#define ner_f(r0,r1,r2)                        cmpr_f(FCMP_NE,r0,r1,r2)
+#define nei_f(r0,r1,i0)                        cmpi_f(FCMP_NE,r0,r1,i0)
+#define ner_d(r0,r1,r2)                        cmpr_d(FCMP_NE,r0,r1,r2)
+#define nei_d(r0,r1,i0)                        cmpi_d(FCMP_NE,r0,r1,i0)
+#define unltr_f(r0,r1,r2)              cmpr_f(FCMP_UNLT,r0,r1,r2)
+#define unlti_f(r0,r1,i0)              cmpi_f(FCMP_UNLT,r0,r1,i0)
+#define unltr_d(r0,r1,r2)              cmpr_d(FCMP_UNLT,r0,r1,r2)
+#define unlti_d(r0,r1,i0)              cmpi_d(FCMP_UNLT,r0,r1,i0)
+#define unler_f(r0,r1,r2)              cmpr_f(FCMP_UNLE,r0,r1,r2)
+#define unlei_f(r0,r1,i0)              cmpi_f(FCMP_UNLE,r0,r1,i0)
+#define unler_d(r0,r1,r2)              cmpr_d(FCMP_UNLE,r0,r1,r2)
+#define unlei_d(r0,r1,i0)              cmpi_d(FCMP_UNLE,r0,r1,i0)
+#define uneqr_f(r0,r1,r2)              cmpr_f(FCMP_UNEQ,r0,r1,r2)
+#define uneqi_f(r0,r1,i0)              cmpi_f(FCMP_UNEQ,r0,r1,i0)
+#define uneqr_d(r0,r1,r2)              cmpr_d(FCMP_UNEQ,r0,r1,r2)
+#define uneqi_d(r0,r1,i0)              cmpi_d(FCMP_UNEQ,r0,r1,i0)
+#define unger_f(r0,r1,r2)              cmpr_f(FCMP_UNGE,r0,r1,r2)
+#define ungei_f(r0,r1,i0)              cmpi_f(FCMP_UNGE,r0,r1,i0)
+#define unger_d(r0,r1,r2)              cmpr_d(FCMP_UNGE,r0,r1,r2)
+#define ungei_d(r0,r1,i0)              cmpi_d(FCMP_UNGE,r0,r1,i0)
+#define ungtr_f(r0,r1,r2)              cmpr_f(FCMP_UNGT,r0,r1,r2)
+#define ungti_f(r0,r1,i0)              cmpi_f(FCMP_UNGT,r0,r1,i0)
+#define ungtr_d(r0,r1,r2)              cmpr_d(FCMP_UNGT,r0,r1,r2)
+#define ungti_d(r0,r1,i0)              cmpi_d(FCMP_UNGT,r0,r1,i0)
+#define ltgtr_f(r0,r1,r2)              cmpr_f(FCMP_LTGT,r0,r1,r2)
+#define ltgti_f(r0,r1,i0)              cmpi_f(FCMP_LTGT,r0,r1,i0)
+#define ltgtr_d(r0,r1,r2)              cmpr_d(FCMP_LTGT,r0,r1,r2)
+#define ltgti_d(r0,r1,i0)              cmpi_d(FCMP_LTGT,r0,r1,i0)
+#define ordr_f(r0,r1,r2)               cmpr_f(FCMP_ORD,r0,r1,r2)
+#define ordi_f(r0,r1,i0)               cmpi_f(FCMP_ORD,r0,r1,i0)
+#define ordr_d(r0,r1,r2)               cmpr_d(FCMP_ORD,r0,r1,r2)
+#define ordi_d(r0,r1,i0)               cmpi_d(FCMP_ORD,r0,r1,i0)
+#define unordr_f(r0,r1,r2)             cmpr_f(FCMP_UNORD,r0,r1,r2)
+#define unordi_f(r0,r1,i0)             cmpi_f(FCMP_UNORD,r0,r1,i0)
+#define unordr_d(r0,r1,r2)             cmpr_d(FCMP_UNORD,r0,r1,r2)
+#define unordi_d(r0,r1,i0)             cmpi_d(FCMP_UNORD,r0,r1,i0)
+#define ldr_f(r0,r1)                   FLDWI(0,r1,r0)
+#define ldi_f(r0,i0)                   _ldi_f(_jit,r0,i0)
+static void _ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#if FLDXR
+#  define ldxr_f(r0,r1,r2)             FLDW(r2,r1,r0)
+#  define ldxr_d(r0,r1,r2)             FLDD(r2,r1,r0)
+#else
+#define ldxr_f(r0,r1,r2)               _ldxr_f(_jit,r0,r1,r2)
+static void _ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxr_d(r0,r1,r2)               _ldxr_d(_jit,r0,r1,r2)
+static void _ldxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#endif
+#define ldxi_f(r0,r1,i0)               _ldxi_f(_jit,r0,r1,i0)
+static void _ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldr_d(r0,r1)                   FLDDI(0,r1,r0)
+#define ldi_d(r0,i0)                   _ldi_d(_jit,r0,i0)
+static void _ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldxi_d(r0,r1,i0)               _ldxi_d(_jit,r0,r1,i0)
+static void _ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define str_f(r0,r1)                   FSTWI(r1,0,r0)
+#define sti_f(i0,r0)                   _sti_f(_jit,i0,r0)
+static void _sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#if FSTXR
+#  define stxr_f(r0,r1,r2)             FSTW(r2,r1,r0)
+#  define stxr_d(r0,r1,r2)             FSTD(r2,r1,r0)
+#else
+#  define stxr_f(r0,r1,r2)             _stxr_f(_jit,r0,r1,r2)
+static void _stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxr_d(r0,r1,r2)             _stxr_d(_jit,r0,r1,r2)
+static void _stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#endif
+#define stxi_f(i0,r0,r1)               _stxi_f(_jit,i0,r0,r1)
+static void _stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define str_d(r0,r1)                   FSTDI(r1,0,r0)
+#define sti_d(i0,r0)                   _sti_d(_jit,i0,r0)
+static void _sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#define stxi_d(i0,r0,r1)               _stxi_d(_jit,i0,r0,r1)
+static void _stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bcmpr_f(c,i0,r0,r1)            _bcmpr_f(_jit,c,i0,r0,r1)
+static jit_word_t _bcmpr_f(jit_state_t*,jit_word_t,
+                          jit_word_t,jit_int32_t,jit_int32_t);
+#define bcmpi_f(c,i0,r0,i1)            _bcmpi_f(_jit,c,i0,r0,i1)
+static jit_word_t _bcmpi_f(jit_state_t*,jit_word_t,
+                          jit_word_t,jit_int32_t,jit_float32_t*);
+#define bcmpr_d(c,i0,r0,r1)            _bcmpr_d(_jit,c,i0,r0,r1)
+static jit_word_t _bcmpr_d(jit_state_t*,jit_word_t,
+                          jit_word_t,jit_int32_t,jit_int32_t);
+#define bcmpi_d(c,i0,r0,i1)            _bcmpi_d(_jit,c,i0,r0,i1)
+static jit_word_t _bcmpi_d(jit_state_t*,jit_word_t,
+                          jit_word_t,jit_int32_t,jit_float64_t*);
+#define bltr_f(i0,r0,r1)               bcmpr_f(FCMP_LT,i0,r0,r1)
+#define blti_f(i0,r0,i1)               bcmpi_f(FCMP_LT,i0,r0,i1)
+#define bltr_d(i0,r0,r1)               bcmpr_d(FCMP_LT,i0,r0,r1)
+#define blti_d(i0,r0,i1)               bcmpi_d(FCMP_LT,i0,r0,i1)
+#define bler_f(i0,r0,r1)               bcmpr_f(FCMP_LE,i0,r0,r1)
+#define blei_f(i0,r0,i1)               bcmpi_f(FCMP_LE,i0,r0,i1)
+#define bler_d(i0,r0,r1)               bcmpr_d(FCMP_LE,i0,r0,r1)
+#define blei_d(i0,r0,i1)               bcmpi_d(FCMP_LE,i0,r0,i1)
+#define beqr_f(i0,r0,r1)               bcmpr_f(FCMP_EQ,i0,r0,r1)
+#define beqi_f(i0,r0,i1)               bcmpi_f(FCMP_EQ,i0,r0,i1)
+#define beqr_d(i0,r0,r1)               bcmpr_d(FCMP_EQ,i0,r0,r1)
+#define beqi_d(i0,r0,i1)               bcmpi_d(FCMP_EQ,i0,r0,i1)
+#define bger_f(i0,r0,r1)               bcmpr_f(FCMP_GE,i0,r0,r1)
+#define bgei_f(i0,r0,i1)               bcmpi_f(FCMP_GE,i0,r0,i1)
+#define bger_d(i0,r0,r1)               bcmpr_d(FCMP_GE,i0,r0,r1)
+#define bgei_d(i0,r0,i1)               bcmpi_d(FCMP_GE,i0,r0,i1)
+#define bgtr_f(i0,r0,r1)               bcmpr_f(FCMP_GT,i0,r0,r1)
+#define bgti_f(i0,r0,i1)               bcmpi_f(FCMP_GT,i0,r0,i1)
+#define bgtr_d(i0,r0,r1)               bcmpr_d(FCMP_GT,i0,r0,r1)
+#define bgti_d(i0,r0,i1)               bcmpi_d(FCMP_GT,i0,r0,i1)
+#define bner_f(i0,r0,r1)               bcmpr_f(FCMP_NE,i0,r0,r1)
+#define bnei_f(i0,r0,i1)               bcmpi_f(FCMP_NE,i0,r0,i1)
+#define bner_d(i0,r0,r1)               bcmpr_d(FCMP_NE,i0,r0,r1)
+#define bnei_d(i0,r0,i1)               bcmpi_d(FCMP_NE,i0,r0,i1)
+#define bunltr_f(i0,r0,r1)             bcmpr_f(FCMP_UNLT,i0,r0,r1)
+#define bunlti_f(i0,r0,i1)             bcmpi_f(FCMP_UNLT,i0,r0,i1)
+#define bunltr_d(i0,r0,r1)             bcmpr_d(FCMP_UNLT,i0,r0,r1)
+#define bunlti_d(i0,r0,i1)             bcmpi_d(FCMP_UNLT,i0,r0,i1)
+#define bunler_f(i0,r0,r1)             bcmpr_f(FCMP_UNLE,i0,r0,r1)
+#define bunlei_f(i0,r0,i1)             bcmpi_f(FCMP_UNLE,i0,r0,i1)
+#define bunler_d(i0,r0,r1)             bcmpr_d(FCMP_UNLE,i0,r0,r1)
+#define bunlei_d(i0,r0,i1)             bcmpi_d(FCMP_UNLE,i0,r0,i1)
+#define buneqr_f(i0,r0,r1)             bcmpr_f(FCMP_UNEQ,i0,r0,r1)
+#define buneqi_f(i0,r0,i1)             bcmpi_f(FCMP_UNEQ,i0,r0,i1)
+#define buneqr_d(i0,r0,r1)             bcmpr_d(FCMP_UNEQ,i0,r0,r1)
+#define buneqi_d(i0,r0,i1)             bcmpi_d(FCMP_UNEQ,i0,r0,i1)
+#define bunger_f(i0,r0,r1)             bcmpr_f(FCMP_UNGE,i0,r0,r1)
+#define bungei_f(i0,r0,i1)             bcmpi_f(FCMP_UNGE,i0,r0,i1)
+#define bunger_d(i0,r0,r1)             bcmpr_d(FCMP_UNGE,i0,r0,r1)
+#define bungei_d(i0,r0,i1)             bcmpi_d(FCMP_UNGE,i0,r0,i1)
+#define bungtr_f(i0,r0,r1)             bcmpr_f(FCMP_UNGT,i0,r0,r1)
+#define bungti_f(i0,r0,i1)             bcmpi_f(FCMP_UNGT,i0,r0,i1)
+#define bungtr_d(i0,r0,r1)             bcmpr_d(FCMP_UNGT,i0,r0,r1)
+#define bungti_d(i0,r0,i1)             bcmpi_d(FCMP_UNGT,i0,r0,i1)
+#define bltgtr_f(i0,r0,r1)             bcmpr_f(FCMP_LTGT,i0,r0,r1)
+#define bltgti_f(i0,r0,i1)             bcmpi_f(FCMP_LTGT,i0,r0,i1)
+#define bltgtr_d(i0,r0,r1)             bcmpr_d(FCMP_LTGT,i0,r0,r1)
+#define bltgti_d(i0,r0,i1)             bcmpi_d(FCMP_LTGT,i0,r0,i1)
+#define bordr_f(i0,r0,r1)              bcmpr_f(FCMP_ORD,i0,r0,r1)
+#define bordi_f(i0,r0,i1)              bcmpi_f(FCMP_ORD,i0,r0,i1)
+#define bordr_d(i0,r0,r1)              bcmpr_d(FCMP_ORD,i0,r0,r1)
+#define bordi_d(i0,r0,i1)              bcmpi_d(FCMP_ORD,i0,r0,i1)
+#define bunordr_f(i0,r0,r1)            bcmpr_f(FCMP_UNORD,i0,r0,r1)
+#define bunordi_f(i0,r0,i1)            bcmpi_f(FCMP_UNORD,i0,r0,i1)
+#define bunordr_d(i0,r0,r1)            bcmpr_d(FCMP_UNORD,i0,r0,r1)
+#define bunordi_d(i0,r0,i1)            bcmpi_d(FCMP_UNORD,i0,r0,i1)
+#define vaarg_d(r0, r1)                        _vaarg_d(_jit, r0, r1)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif
+
+#if CODE
+static void
+_f39(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t b, jit_int32_t x, jit_int32_t t)
+{
+    assert(!(o & ~0x3f));
+    assert(!(b & ~0x1f));
+    assert(!(x & ~0x1f));
+    assert(!(t & ~0x1f));
+    ii((o<<26)|(b<<21)|(x<<16)|t);
+}
+
+static void
+_f40(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t b, jit_int32_t x, jit_int32_t r)
+{
+    assert(!(o & ~0x3f));
+    assert(!(b & ~0x1f));
+    assert(!(x & ~0x1f));
+    assert(!(r & ~0x1f));
+    ii((o<<26)|(b<<21)|(x<<16)|(1<<9)|r);
+}
+
+static void
+_f41(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t b, jit_int32_t x, jit_int32_t t)
+{
+    assert(!(o & ~0x3f));
+    assert(!(b & ~0x1f));
+    assert(x >= -16 && x < 15);
+    assert(!(t & ~0x1f));
+    ii((o<<26)|(b<<21)|(low_sign_unext(x,5)<<16)|(1<<12)|t);
+}
+
+static void
+_f42(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t b, jit_int32_t i, jit_int32_t r)
+{
+    assert(!(o & ~0x3f));
+    assert(!(b & ~0x1f));
+    assert(i >= -16 && i < 15);
+    assert(!(r & ~0x1f));
+    ii((o<<26)|(b<<21)|(low_sign_unext(i,5)<<16)|(1<<12)|(1<<9)|r);
+}
+
+static void
+_f45(jit_state_t *_jit, jit_int32_t o,
+     jit_int32_t r, jit_int32_t a, jit_int32_t b, jit_int32_t fmt,
+     jit_int32_t c, jit_int32_t d, jit_int32_t e, jit_int32_t t)
+{
+    assert(!(o   & ~0x3f));
+    assert(!(r   & ~0x1f));
+    assert(!(a   & ~0x1f));
+    assert(!(b   &  ~0x7));
+    assert(!(fmt &  ~0x3));
+    assert(!(c   &  ~0x3));
+    assert(!(d   &  ~0x7));
+    assert(!(e   &  ~0x1));
+    assert(!(t   & ~0x1f));
+    ii((o<<26)|(r<<21)|(a<<16)|(fmt<<13)|(b<<11)|(c<<9)|(d<<6)|(e<<5)|t);
+}
+
+static void
+_f46(jit_state_t *_jit, jit_int32_t o, jit_int32_t r,
+     jit_int32_t a, jit_int32_t s, jit_int32_t df, jit_int32_t sf,
+     jit_int32_t b, jit_int32_t c, jit_int32_t d, jit_int32_t t)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r  & ~0x1f));
+    assert(!(a  &  ~0x7));
+    assert(!(s  &  ~0x7));
+    assert(!(df &  ~0x3));
+    assert(!(sf &  ~0x3));
+    assert(!(b  &  ~0x3));
+    assert(!(c  &  ~0x7));
+    assert(!(d  &  ~0x1));
+    assert(!(t  & ~0x1f));
+    ii((o<<26)|(r<<21)|(a<<18)|(s<<15)|
+       (df<<13)|(sf<<11)|(b<<9)|(c<<6)|(d<<5)|t);
+}
+
+static void
+_f47_48(jit_state_t *_jit, jit_int32_t o,
+       jit_int32_t r2, jit_int32_t r1, jit_int32_t y, jit_int32_t fmt,
+       jit_int32_t a, jit_int32_t b, jit_int32_t c, jit_int32_t t)
+{
+    assert(!(o   & ~0x3f));
+    assert(!(r2  & ~0x1f));
+    assert(!(r1  & ~0x1f));
+    assert(!(y   &  ~0x7));
+    assert(!(fmt &  ~0x3));
+    assert(!(a   &  ~0x3));
+    assert(!(b   &  ~0x7));
+    assert(!(c   &  ~0x1));
+    assert(!(t   & ~0x1f));
+    ii((o<<26)|(r2<<21)|(r1<<16)|(y<<13)|(fmt<<11)|(a<<9)|(b<<6)|(c<<5)|t);
+}
+
+static void
+_f49_52(jit_state_t *_jit, jit_int32_t o,
+       jit_int32_t r1, jit_int32_t r2, jit_int32_t y,
+       jit_int32_t v, jit_int32_t f, jit_int32_t a, jit_int32_t b,
+       jit_int32_t u, jit_int32_t c, jit_int32_t d, jit_int32_t t)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r1 & ~0x1f));
+    assert(!(r2 & ~0x3f));
+    assert(!(y  &  ~0x7));
+    assert(!(v  &  ~0x1));
+    assert(!(f  &  ~0x1));
+    assert(!(a  &  ~0x3));
+    assert(!(b  &  ~0x1));
+    assert(!(u  &  ~0x1));
+    assert(!(c  &  ~0x1));
+    assert(!(d  &  ~0x1));
+    assert(!(t  & ~0x1f));
+    ii((o<<26)|(r1<<21)|(r2<<16)|(y<<13)|(v<<12)|
+       (f<<11)|(a<<9)|(b<<8)|(u<<7)|(c<<6)|(d<<5)|t);
+}
+
+static void
+_f53(jit_state_t *_jit, jit_int32_t o, jit_int32_t r1, jit_int32_t r2,
+     jit_int32_t ta, jit_int32_t ra, jit_int32_t f, jit_int32_t tm)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r1 & ~0x1f));
+    assert(!(r2 & ~0x1f));
+    assert(!(ta & ~0x1f));
+    assert(!(ra & ~0x1f));
+    assert(!(f  &  ~0x1));
+    assert(!(tm & ~0x1f));
+    assert(ra != tm ||
+          (ta == r1 || ta == r2 || ta == tm) ||
+          (f && ra == 1) || (!f && !ra));
+    ii((o<<26)|(r1<<21)|(r2<<16)|(ta<<11)|(ra<<6)|(f<<5)|tm);
+}
+
+static void
+_f54(jit_state_t *_jit, jit_int32_t o, jit_int32_t r1, jit_int32_t r2,
+     jit_int32_t a, jit_int32_t b, jit_int32_t f, jit_int32_t c,
+     jit_int32_t d, jit_int32_t e, jit_int32_t g, jit_int32_t t)
+{
+    assert(!(o  & ~0x3f));
+    assert(!(r1 & ~0x1f));
+    assert(!(r2 & ~0x1f));
+    assert(!(a  &  ~0x7));
+    assert(!(b  &  ~0x1));
+    assert(!(f  &  ~0x1));
+    assert(!(c  &  ~0x7));
+    assert(!(e  &  ~0x1));
+    assert(!(e  &  ~0x1));
+    assert(!(g  &  ~0x1));
+    assert(!(t  & ~0x1f));
+    ii((o<<26)|(r1<<21)|(r2<<16)|(a<<13)|
+       (b<<12)|(f<11)|(c<<8)|(d<<7)|(e<<6)|(g<<5)|t);
+}
+
+static void
+_extr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi(alloca_offset - 8, _FP_REGNO, r1);
+    ldxi_f(r0, _FP_REGNO, alloca_offset - 8);
+    FCNVXF_S_S(r0, r0);
+}
+
+static void
+_extr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi(alloca_offset - 8, _FP_REGNO, r1);
+    ldxi_f(r0, _FP_REGNO, alloca_offset - 8);
+    FCNVXF_S_D(r0, r0);
+}
+
+static void
+_truncr_f_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    FCNVXT_S_S(r1, rn(reg));
+    stxi_f(alloca_offset - 8, _FP_REGNO, rn(reg));
+    ldxi(r0, _FP_REGNO, alloca_offset - 8);
+    jit_unget_reg(reg);
+}
+
+static void
+_truncr_d_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    FCNVXT_D_S(r1, rn(reg));
+    stxi_d(alloca_offset - 8, _FP_REGNO, rn(reg));
+    ldxi(r0, _FP_REGNO, alloca_offset - 8);
+    jit_unget_reg(reg);
+}
+
+static void
+_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t      i;
+       jit_float32_t    f;
+    } data;
+    jit_int32_t                 reg;
+
+    if (_jitc->no_data) {
+       data.f = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.i);
+       stxi_i(alloca_offset - 8, _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+       ldxi_f(r0, _FP_REGNO, alloca_offset - 8);
+    }
+    else
+       ldi_f(r0, (jit_word_t)i0);
+}
+
+static void
+_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+       jit_int32_t      ii[2];
+       jit_word_t       w;
+       jit_float64_t    d;
+    } data;
+    jit_int32_t                 reg;
+
+    data.d = *i0;
+    if (_jitc->no_data) {
+       data.d = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.ii[0]);
+       stxi_i(alloca_offset - 8, _FP_REGNO, rn(reg));
+       movi(rn(reg), data.ii[1]);
+       stxi_i(alloca_offset - 4, _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+       ldxi_d(r0, _FP_REGNO, alloca_offset - 8);
+    }
+    else
+       ldi_d(r0, (jit_word_t)i0);
+}
+
+#define fpr_opi(name, type, size)                                      \
+static void                                                            \
+_##name##i_##type(jit_state_t *_jit,                                   \
+                 jit_int32_t r0, jit_int32_t r1,                       \
+                 jit_float##size##_t *i0)                              \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    movi_##type(rn(reg), i0);                                          \
+    name##r_##type(r0, r1, rn(reg));                                   \
+    jit_unget_reg(reg);                                                        \
+}
+#define fopi(name)                     fpr_opi(name, f, 32)
+#define dopi(name)                     fpr_opi(name, d, 64)
+
+fopi(add)
+dopi(add)
+fopi(sub)
+dopi(sub)
+fopi(rsb)
+dopi(rsb)
+fopi(mul)
+dopi(mul)
+fopi(div)
+dopi(div)
+
+static void
+_cmpr_f(jit_state_t *_jit, jit_word_t c,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    LDI(0, r0);
+    FCMP_S_(r1, r2, c);
+    FTEST();
+    LDI(1, r0);
+}
+
+static void
+_cmpi_f(jit_state_t *_jit, jit_word_t c,
+       jit_int32_t r0, jit_int32_t r1, jit_float32_t *i0)
+{
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);
+    movi_f(rn(reg), i0);
+    cmpr_f(c, r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_cmpr_d(jit_state_t *_jit, jit_word_t c,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    LDI(0, r0);
+    FCMP_D_(r1, r2, c);
+    FTEST();
+    LDI(1, r0);
+}
+
+static void
+_cmpi_d(jit_state_t *_jit, jit_word_t c,
+       jit_int32_t r0, jit_int32_t r1, jit_float64_t *i0)
+{
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);
+    movi_d(rn(reg), i0);
+    cmpr_d(c, r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 3));
+    if (i0 >= -8192 && i0 <= 8191 && !(re_assemble_16(i0) & 6))
+       FLDWL(i0, _R0_REGNO, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#if !FLDXR
+static void
+_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_f(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_d(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+#endif
+
+static void
+_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       FLDWI(i0, r1, r0);
+    /* |im11a|0|t|i| */
+    else if (FLDXR && i0 >= -8192 && i0 <= 8191 && !(re_assemble_16(i0) & 6))
+       FLDWL(i0, r1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_f(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 7));
+    if (i0 >= -8192 && i0 <= 8191 && !(re_assemble_16(i0) & 14))
+       FLDDL(i0, _R0_REGNO, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       FLDDI(i0, r1, r0);
+    /* |im10a|m|a|1|i| */
+    else if (FLDXR && i0 >= -8192 && i0 <= 8191 && !(re_assemble_16(i0) & 14))
+       FLDDL(i0, r1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_d(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 3));
+    if (i0 >= -8192 && i0 <= 8191 && !(re_assemble_16(i0) & 6))
+       FSTWL(r0, i0, _R0_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_f(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+#if !FSTXR
+static void
+_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_f(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_d(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+#endif
+
+static void
+_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       FSTWI(r1, i0, r0);
+    /* |im11a|0|t|i| */
+    else if (FSTXR && i0 >= -8192 && i0 <= 8191 && !(re_assemble_16(i0) & 6))
+       FSTWL(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+#if FSTXR
+       movi(rn(reg), i0);
+       stxr_f(rn(reg), r0, r1);
+#else
+       addi(rn(reg), r0, i0);
+       str_f(rn(reg), r1);
+#endif
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    assert(!(i0 & 7));
+    if (i0 >= -8192 && i0 <= 8191 && !(re_assemble_16(i0) & 14))
+       FSTDL(r0, i0, _R0_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_d(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 >= -16 && i0 <= 15)
+       FSTDI(r1, i0, r0);
+    /* |im10a|m|a|1|i| */
+    else if (FSTXR && i0 >= -8192 && i0 <= 8191 && !(re_assemble_16(i0) & 14))
+       FSTDL(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+#if FSTXR
+       movi(rn(reg), i0);
+       stxr_d(rn(reg), r0, r1);
+#else
+       addi(rn(reg), r0, i0);
+       str_d(rn(reg), r1);
+#endif
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_bcmpr_f(jit_state_t *_jit, jit_word_t c,
+        jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_S_(r0, r1, c);
+    FTEST();
+    w = _jit->pc.w;
+    B_N(((i0 - w) >> 2) - 2, _R0_REGNO);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bcmpi_f(jit_state_t *_jit, jit_word_t c,
+        jit_word_t i0, jit_int32_t r0, jit_float32_t *i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi_f(rn(reg), i1);
+    FCMP_S_(r0, rn(reg), c);
+    FTEST();
+    w = _jit->pc.w;
+    B_N(((i0 - w) >> 2) - 2, _R0_REGNO);
+    NOP();
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bcmpr_d(jit_state_t *_jit, jit_word_t c,
+        jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_D_(r0, r1, c);
+    FTEST();
+    w = _jit->pc.w;
+    B_N(((i0 - w) >> 2) - 2, _R0_REGNO);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bcmpi_d(jit_state_t *_jit, jit_word_t c,
+        jit_word_t i0, jit_int32_t r0, jit_float64_t *i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi_d(rn(reg), i1);
+    FCMP_D_(r0, rn(reg), c);
+    FTEST();
+    w = _jit->pc.w;
+    B_N(((i0 - w) >> 2) - 2, _R0_REGNO);
+    NOP();
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Align pointer if required. */
+    reg = jit_get_reg(jit_class_gpr);
+    andi(rn(reg), r1, 7);
+    subr(r1, r1, rn(reg));
+    jit_unget_reg(reg);
+
+    /* Adjust vararg stack pointer. */
+    subi(r1, r1, 8);
+
+    /* Load argument. */
+    ldr_d(r0, r1);
+}
+#endif
diff --git a/deps/lightning/lib/jit_hppa-sz.c b/deps/lightning/lib/jit_hppa-sz.c
new file mode 100644 (file)
index 0000000..3c04f63
--- /dev/null
@@ -0,0 +1,402 @@
+
+#if __WORDSIZE == 32
+#define JIT_INSTR_MAX 64
+    0, /* data */
+    0, /* live */
+    0, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    64,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    0, /* va_start */
+    0, /* va_arg */
+    0, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    12,        /* addi */
+    4, /* addcr */
+    12,        /* addci */
+    4, /* addxr */
+    8, /* addxi */
+    4, /* subr */
+    12,        /* subi */
+    4, /* subcr */
+    12,        /* subci */
+    4, /* subxr */
+    8, /* subxi */
+    16,        /* rsbi */
+    28,        /* mulr */
+    36,        /* muli */
+    40,        /* qmulr */
+    44,        /* qmuli */
+    32,        /* qmulr_u */
+    40,        /* qmuli_u */
+    36,        /* divr */
+    40,        /* divi */
+    36,        /* divr_u */
+    40,        /* divi_u */
+    40,        /* qdivr */
+    40,        /* qdivi */
+    40,        /* qdivr_u */
+    40,        /* qdivi_u */
+    36,        /* remr */
+    40,        /* remi */
+    36,        /* remr_u */
+    40,        /* remi_u */
+    4, /* andr */
+    12,        /* andi */
+    4, /* orr */
+    12,        /* ori */
+    4, /* xorr */
+    12,        /* xori */
+    12,        /* lshr */
+    4, /* lshi */
+    12,        /* rshr */
+    4, /* rshi */
+    12,        /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    8, /* ltr */
+    8, /* lti */
+    8, /* ltr_u */
+    8, /* lti_u */
+    8, /* ler */
+    8, /* lei */
+    8, /* ler_u */
+    8, /* lei_u */
+    8, /* eqr */
+    12,        /* eqi */
+    8, /* ger */
+    8, /* gei */
+    8, /* ger_u */
+    8, /* gei_u */
+    8, /* gtr */
+    8, /* gti */
+    8, /* gtr_u */
+    8, /* gti_u */
+    8, /* ner */
+    8, /* nei */
+    4, /* movr */
+    8, /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    4, /* htonr_us */
+    4, /* htonr_ui */
+    0, /* htonr_l */
+    8, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    8, /* ldi_uc */
+    8, /* ldr_s */
+    12,        /* ldi_s */
+    4, /* ldr_us */
+    8, /* ldi_us */
+    4, /* ldr_i */
+    8, /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    8, /* ldxr_c */
+    8, /* ldxi_c */
+    4, /* ldxr_uc */
+    4, /* ldxi_uc */
+    8, /* ldxr_s */
+    8, /* ldxi_s */
+    4, /* ldxr_us */
+    4, /* ldxi_us */
+    4, /* ldxr_i */
+    4, /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    4, /* str_c */
+    8, /* sti_c */
+    4, /* str_s */
+    8, /* sti_s */
+    4, /* str_i */
+    8, /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    8, /* stxr_c */
+    4, /* stxi_c */
+    8, /* stxr_s */
+    4, /* stxi_s */
+    8, /* stxr_i */
+    4, /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    8, /* bltr */
+    8, /* blti */
+    8, /* bltr_u */
+    8, /* blti_u */
+    8, /* bler */
+    12,        /* blei */
+    8, /* bler_u */
+    8, /* blei_u */
+    8, /* beqr */
+    16,        /* beqi */
+    8, /* bger */
+    8, /* bgei */
+    8, /* bger_u */
+    8, /* bgei_u */
+    8, /* bgtr */
+    8, /* bgti */
+    8, /* bgtr_u */
+    8, /* bgti_u */
+    8, /* bner */
+    16,        /* bnei */
+    12,        /* bmsr */
+    16,        /* bmsi */
+    12,        /* bmcr */
+    16,        /* bmci */
+    8, /* boaddr */
+    8, /* boaddi */
+    8, /* boaddr_u */
+    8, /* boaddi_u */
+    8, /* bxaddr */
+    8, /* bxaddi */
+    8, /* bxaddr_u */
+    8, /* bxaddi_u */
+    12,        /* bosubr */
+    16,        /* bosubi */
+    16,        /* bosubr_u */
+    20,        /* bosubi_u */
+    12,        /* bxsubr */
+    16,        /* bxsubi */
+    16,        /* bxsubr_u */
+    20,        /* bxsubi_u */
+    0, /* jmpr */
+    12,        /* jmpi */
+    40,        /* callr */
+    44,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    64,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    16,        /* addi_f */
+    4, /* subr_f */
+    16,        /* subi_f */
+    16,        /* rsbi_f */
+    4, /* mulr_f */
+    16,        /* muli_f */
+    4, /* divr_f */
+    16,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    16,        /* ltr_f */
+    28,        /* lti_f */
+    16,        /* ler_f */
+    28,        /* lei_f */
+    16,        /* eqr_f */
+    28,        /* eqi_f */
+    16,        /* ger_f */
+    28,        /* gei_f */
+    16,        /* gtr_f */
+    28,        /* gti_f */
+    16,        /* ner_f */
+    28,        /* nei_f */
+    16,        /* unltr_f */
+    28,        /* unlti_f */
+    16,        /* unler_f */
+    28,        /* unlei_f */
+    16,        /* uneqr_f */
+    28,        /* uneqi_f */
+    16,        /* unger_f */
+    28,        /* ungei_f */
+    16,        /* ungtr_f */
+    28,        /* ungti_f */
+    16,        /* ltgtr_f */
+    28,        /* ltgti_f */
+    16,        /* ordr_f */
+    28,        /* ordi_f */
+    16,        /* unordr_f */
+    28,        /* unordi_f */
+    12,        /* truncr_f_i */
+    0, /* truncr_f_l */
+    12,        /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    12,        /* movi_f */
+    4, /* ldr_f */
+    12,        /* ldi_f */
+    4, /* ldxr_f */
+    4, /* ldxi_f */
+    4, /* str_f */
+    12,        /* sti_f */
+    8, /* stxr_f */
+    4, /* stxi_f */
+    16,        /* bltr_f */
+    28,        /* blti_f */
+    16,        /* bler_f */
+    28,        /* blei_f */
+    16,        /* beqr_f */
+    28,        /* beqi_f */
+    16,        /* bger_f */
+    28,        /* bgei_f */
+    16,        /* bgtr_f */
+    28,        /* bgti_f */
+    16,        /* bner_f */
+    28,        /* bnei_f */
+    16,        /* bunltr_f */
+    28,        /* bunlti_f */
+    16,        /* bunler_f */
+    28,        /* bunlei_f */
+    16,        /* buneqr_f */
+    28,        /* buneqi_f */
+    16,        /* bunger_f */
+    28,        /* bungei_f */
+    16,        /* bungtr_f */
+    28,        /* bungti_f */
+    16,        /* bltgtr_f */
+    28,        /* bltgti_f */
+    16,        /* bordr_f */
+    28,        /* bordi_f */
+    16,        /* bunordr_f */
+    28,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    24,        /* addi_d */
+    4, /* subr_d */
+    24,        /* subi_d */
+    24,        /* rsbi_d */
+    4, /* mulr_d */
+    24,        /* muli_d */
+    4, /* divr_d */
+    24,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    16,        /* ltr_d */
+    36,        /* lti_d */
+    16,        /* ler_d */
+    36,        /* lei_d */
+    16,        /* eqr_d */
+    36,        /* eqi_d */
+    16,        /* ger_d */
+    36,        /* gei_d */
+    16,        /* gtr_d */
+    36,        /* gti_d */
+    16,        /* ner_d */
+    36,        /* nei_d */
+    16,        /* unltr_d */
+    36,        /* unlti_d */
+    16,        /* unler_d */
+    36,        /* unlei_d */
+    16,        /* uneqr_d */
+    36,        /* uneqi_d */
+    16,        /* unger_d */
+    36,        /* ungei_d */
+    16,        /* ungtr_d */
+    36,        /* ungti_d */
+    16,        /* ltgtr_d */
+    36,        /* ltgti_d */
+    16,        /* ordr_d */
+    36,        /* ordi_d */
+    16,        /* unordr_d */
+    36,        /* unordi_d */
+    12,        /* truncr_d_i */
+    0, /* truncr_d_l */
+    12,        /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    20,        /* movi_d */
+    4, /* ldr_d */
+    12,        /* ldi_d */
+    4, /* ldxr_d */
+    4, /* ldxi_d */
+    4, /* str_d */
+    12,        /* sti_d */
+    8, /* stxr_d */
+    4, /* stxi_d */
+    16,        /* bltr_d */
+    36,        /* blti_d */
+    16,        /* bler_d */
+    36,        /* blei_d */
+    16,        /* beqr_d */
+    36,        /* beqi_d */
+    16,        /* bger_d */
+    36,        /* bgei_d */
+    16,        /* bgtr_d */
+    36,        /* bgti_d */
+    16,        /* bner_d */
+    36,        /* bnei_d */
+    16,        /* bunltr_d */
+    36,        /* bunlti_d */
+    16,        /* bunler_d */
+    36,        /* bunlei_d */
+    16,        /* buneqr_d */
+    36,        /* buneqi_d */
+    16,        /* bunger_d */
+    36,        /* bungei_d */
+    16,        /* bungtr_d */
+    36,        /* bungti_d */
+    16,        /* bltgtr_d */
+    36,        /* bltgti_d */
+    16,        /* bordr_d */
+    36,        /* bordi_d */
+    16,        /* bunordr_d */
+    36,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_hppa.c b/deps/lightning/lib/jit_hppa.c
new file mode 100644 (file)
index 0000000..21fe20c
--- /dev/null
@@ -0,0 +1,1585 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+
+#define jit_arg_reg_p(i)               (i >= 0 && i < 4)
+
+#define PROTO                          1
+#  include "jit_hppa-cpu.c"
+#  include "jit_hppa-fpu.c"
+#undef PROTO
+
+/*
+ * Types
+ */
+typedef jit_pointer_t  jit_va_list;
+
+/*
+ * Prototypes
+ */
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+/* libgcc */
+extern void __clear_cache(void *, void *);
+
+/*
+ * Initialization
+ */
+jit_register_t         _rvs[] = {
+    { 0,                       "r0" },         /* Zero */
+    /* Not register starved, so, avoid allocating r1 and rp
+     * due to being implicit target of ADDIL and B,L */
+    { 1,                       "r1" },         /* Scratch */
+    { 2,                       "rp" },         /* Return Pointer and scratch */
+    { rc(sav) | 3,             "r3" },
+    { 19,                      "r19" },        /* Linkage Table */
+    { rc(gpr) | 20,            "r20" },
+    { rc(gpr) | 21,            "r21" },
+    { rc(gpr) | 22,            "r22" },
+    { rc(gpr) | 29,            "ret1" },
+    { rc(gpr) | 28,            "ret0" },
+    /* JIT_Rx in callee save registers due to need to call
+     * functions to implement some instructions */
+    /* JIT_R0- JIT_R2 */
+    { rc(gpr) | rc(sav) | 4,   "r4" },
+    { rc(gpr) | rc(sav) | 5,   "r5" },
+    { rc(gpr) | rc(sav) | 6,   "r6" },
+    /* JIT_V0- JIT_V2 */
+    { rc(gpr) | rc(sav) | 7,   "r7" },
+    { rc(sav) | rc(sav) | 8,   "r8" },
+    { rc(gpr) | rc(sav) | 9,   "r9" },
+    /* JIT_R3 */
+    { rc(gpr) | rc(sav) | 10,  "r10" },
+    /* JIT_V3+ */
+    { rc(gpr) | rc(sav) | 11,  "r11" },
+    { rc(gpr) | rc(sav) | 12,  "r12" },
+    { rc(gpr) | rc(sav) | 13,  "r13" },
+    { rc(gpr) | rc(sav) | 14,  "r14" },
+    { rc(gpr) | rc(sav) | 15,  "r15" },
+    { rc(gpr) | rc(sav) | 16,  "r16" },
+    { rc(gpr) | rc(sav) | 17,  "r17" },
+    { rc(gpr) | rc(sav) | 18,  "r18" },
+    /* Arguments */
+    { rc(gpr) | rc(arg) | 23,  "r23" },
+    { rc(gpr) | rc(arg) | 24,  "r24" },
+    { rc(gpr) | rc(arg) | 25,  "r25" },
+    { rc(gpr) | rc(arg) | 26,  "r26" },
+    { 27,                      "dp" },         /* Data Pointer */
+    { 30,                      "sp" },
+    { 31,                      "r31" },        /* Link Register */
+    { rc(fpr) | 31,            "fr31" },
+    { rc(fpr) | 30,            "fr30" },
+    { rc(fpr) | 29,            "fr29" },
+    { rc(fpr) | 28,            "fr28" },
+    { rc(fpr) | 27,            "fr27" },
+    { rc(fpr) | 26,            "fr26" },
+    { rc(fpr) | 25,            "fr25" },
+    { rc(fpr) | 24,            "fr24" },
+    { rc(fpr) | 23,            "fr23" },
+    { rc(fpr) | 22,            "fr22" },
+    { rc(fpr) | 11,            "fr11" },
+    { rc(fpr) | 10,            "fr10" },
+    { rc(fpr) | 9,             "fr9" },
+    { rc(fpr) | 8,             "fr8" },
+    /* Arguments */
+    { rc(fpr) | rc(arg) | 7,   "fr7" },
+    { rc(fpr) | rc(arg) | 6,   "fr6" },
+    { rc(fpr) | rc(arg) | 5,   "fr5" },
+    { rc(fpr) | rc(arg) | 4,   "fr4" },
+    /* Callee Saves */
+    { rc(fpr) | rc(sav) | 21,  "fr21" },
+    { rc(fpr) | rc(sav) | 20,  "fr20" },
+    { rc(fpr) | rc(sav) | 19,  "fr19" },
+    { rc(fpr) | rc(sav) | 18,  "fr18" },
+    { rc(fpr) | rc(sav) | 17,  "fr17" },
+    { rc(fpr) | rc(sav) | 16,  "fr16" },
+    { rc(fpr) | rc(sav) | 15,  "fr15" },
+    { rc(fpr) | rc(sav) | 14,  "fr14" },
+    { rc(fpr) | rc(sav) | 13,  "fr13" },
+    { rc(fpr) | rc(sav) | 12,  "fr12" },
+    { 0,                       "fpsr" },
+    { 1,                       "fpe2" },
+    { 2,                       "fpe4" },
+    { 3,                       "fpe6" },
+    { _NOREG,                  "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+    /* FIXME Expecting PARISC 2.0, for PARISC 1.0 should not use fr16-fr31 */
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    _jitc->reglen = jit_size(_rvs) - 1;
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = params_offset;
+    _jitc->function->self.argi = _jitc->function->self.alen = 0;
+    /* float conversion */
+    _jitc->function->self.aoff = alloca_offset;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    jit_int32_t                offset;
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:
+           break;
+       case 2:
+           _jitc->function->self.aoff = (_jitc->function->self.aoff + 1) & -2;
+           break;
+       case 3: case 4:
+           _jitc->function->self.aoff = (_jitc->function->self.aoff + 3) & -4;
+           break;
+       default:
+           _jitc->function->self.aoff = (_jitc->function->self.aoff + 7) & -8;
+           break;
+    }
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    offset = _jitc->function->self.aoff;
+    _jitc->function->self.aoff += length;
+    return (offset);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 reg;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    jit_addi(reg, v, 63);
+    jit_andi(reg, reg, -64);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(JIT_SP, JIT_SP, reg);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(reg);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    jit_movr(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    jit_movr_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    jit_movr_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    assert(u->code == jit_code_arg ||
+          u->code == jit_code_arg_f || u->code == jit_code_arg_d);
+    return (jit_arg_reg_p(u->u.w));
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare) {
+       jit_link_prepare();
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+    }
+    else {
+       jit_link_prolog();
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+
+       _jitc->function->vagp = _jitc->function->self.argi;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    _jitc->function->self.size -= sizeof(jit_word_t);
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else
+       offset = _jitc->function->self.size;
+    node = jit_new_node_ww(jit_code_arg, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    _jitc->function->self.size -= sizeof(jit_word_t);
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else
+       offset = _jitc->function->self.size;
+    node = jit_new_node_ww(jit_code_arg_f, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    if (_jitc->function->self.argi & 1) {
+       ++_jitc->function->self.argi;
+       _jitc->function->self.size -= sizeof(jit_word_t);
+    }
+    _jitc->function->self.size -= sizeof(jit_float64_t);
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi + 1;
+       _jitc->function->self.argi += 2;
+    }
+    else {
+       /* "Standard" initial value (-52) is unaligned */
+       if (_jitc->function->self.size & 7)
+           _jitc->function->self.size -= sizeof(jit_word_t);
+       offset = _jitc->function->self.size;
+    }
+    node = jit_new_node_ww(jit_code_arg_d, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (v->u.w >= 0)
+       jit_extr_c(u, _R26 - v->u.w);
+    else
+       jit_ldxi_c(u, JIT_FP, v->u.w + 3);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (v->u.w >= 0)
+       jit_extr_uc(u, _R26 - v->u.w);
+    else
+       jit_ldxi_uc(u, JIT_FP, v->u.w + 3);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (v->u.w >= 0)
+       jit_extr_s(u, _R26 - v->u.w);
+    else
+       jit_ldxi_s(u, JIT_FP, v->u.w + 2);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (v->u.w >= 0)
+       jit_extr_us(u, _R26 - v->u.w);
+    else
+       jit_ldxi_us(u, JIT_FP, v->u.w + 2);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (v->u.w >= 0)
+       jit_movr(u, _R26 - v->u.w);
+    else
+       jit_ldxi_i(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+    if (v->u.w >= 0)
+       jit_movr(_R26 - v->u.w, u);
+    else
+       jit_stxi(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+    if (v->u.w >= 0)
+       jit_movi(_R26 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+    if (v->u.w >= 0)
+       jit_movr_f(u, _F4 - v->u.w);
+    else
+       jit_ldxi_f(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+    if (v->u.w >= 0)
+       jit_movr_f(_F4 - v->u.w, u);
+    else
+       jit_stxi_f(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+    if (v->u.w >= 0)
+       jit_movi_f(_R26 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+    if (v->u.w >= 0)
+       jit_movr_d(u, _F4 - v->u.w);
+    else
+       jit_ldxi_d(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+    if (v->u.w >= 0)
+       jit_movr_d(_F4 - v->u.w, u);
+    else
+       jit_stxi_d(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+    if (v->u.w >= 0)
+       jit_movi_d(_R26 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+    _jitc->function->call.size -= sizeof(jit_word_t);
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(_R26 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else
+       jit_stxi(_jitc->function->call.size + params_offset, JIT_SP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+    _jitc->function->call.size -= sizeof(jit_word_t);
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(_R26 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size + params_offset, JIT_SP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+    _jitc->function->call.size -= sizeof(jit_word_t);
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr_f(_F4 - _jitc->function->call.argi, u);
+#if !defined(__hpux)
+       /* HP-UX appears to always pass float arguments in gpr registers */
+       if (_jitc->function->call.call & jit_call_varargs)
+#endif
+       {
+           jit_stxi_f(alloca_offset - 8, JIT_FP, u);
+           jit_ldxi(_R26 - _jitc->function->call.argi, JIT_FP,
+                    alloca_offset - 8);
+       }
+       ++_jitc->function->call.argi;
+    }
+    else
+       jit_stxi_f(_jitc->function->call.size + params_offset, JIT_SP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+    _jitc->function->call.size -= sizeof(jit_word_t);
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi_f(_F4 - _jitc->function->call.argi, u);
+#if !defined(__hpux)
+       /* HP-UX appears to always pass float arguments in gpr registers */
+       if (_jitc->function->call.call & jit_call_varargs)
+#endif
+       {
+           jit_stxi_f(alloca_offset - 8, JIT_FP,
+                      _F4 - _jitc->function->call.argi);
+           jit_ldxi(_R26 - _jitc->function->call.argi,
+                    JIT_FP, alloca_offset - 8);
+       }
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(_jitc->function->call.size + params_offset, JIT_SP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+    _jitc->function->call.size -= sizeof(jit_float64_t);
+    if (_jitc->function->call.argi & 1) {
+       ++_jitc->function->call.argi;
+       _jitc->function->call.size -= sizeof(jit_word_t);
+    }
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr_d(_F4 - (_jitc->function->call.argi + 1), u);
+#if !defined(__hpux)
+       /* HP-UX appears to always pass float arguments in gpr registers */
+       if (_jitc->function->call.call & jit_call_varargs)
+#endif
+       {
+           jit_stxi_d(alloca_offset - 8, JIT_FP, u);
+           jit_ldxi(_R26 - _jitc->function->call.argi,
+                    JIT_FP, alloca_offset - 4);
+           jit_ldxi(_R25 - _jitc->function->call.argi,
+                    JIT_FP, alloca_offset - 8);
+       }
+       _jitc->function->call.argi += 2;
+    }
+    else {
+       /* "Standard" initial value (-52) is unaligned */
+       if ((_jitc->function->call.size + params_offset) & 7)
+           _jitc->function->call.size -= sizeof(jit_word_t);
+       jit_stxi_d(_jitc->function->call.size + params_offset, JIT_SP, u);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+    _jitc->function->call.size -= sizeof(jit_float64_t);
+    if (_jitc->function->call.argi & 1) {
+       ++_jitc->function->call.argi;
+       _jitc->function->call.size -= sizeof(jit_word_t);
+    }
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi_d(_F4 - (_jitc->function->call.argi + 1), u);
+#if !defined(__hpux)
+       /* HP-UX appears to always pass float arguments in gpr registers */
+       if (_jitc->function->call.call & jit_call_varargs)
+#endif
+       {
+           jit_stxi_d(alloca_offset - 8, JIT_FP,
+                      _F4 - (_jitc->function->call.argi + 1));
+           jit_ldxi(_R26 - _jitc->function->call.argi,
+                    JIT_FP, alloca_offset - 4);
+           jit_ldxi(_R25 - _jitc->function->call.argi,
+                    JIT_FP, alloca_offset - 8);
+       }
+       _jitc->function->call.argi += 2;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       if ((_jitc->function->call.size + params_offset) & 7)
+           _jitc->function->call.size -= sizeof(jit_word_t);
+       jit_stxi_d(_jitc->function->call.size + params_offset, JIT_SP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_int32_t                spec;
+    spec = jit_class(_rvs[regno].spec);
+    if (spec & jit_class_arg) {
+       if (spec & jit_class_gpr) {
+           regno -= _R23;
+           if (regno >= 0 && regno < node->v.w)
+               return (1);
+       }
+       else if (spec & jit_class_fpr) {
+           regno = _F4 - regno;
+           if (regno >= 0 && regno < node->w.w)
+               return (1);
+       }
+    }
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *call;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen > _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    call = jit_callr(r0);
+    call->v.w = call->w.w = _jitc->function->call.argi;
+    _jitc->function->call.argi = _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen > _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_calli(i0);
+    node->v.w = node->w.w = _jitc->function->call.argi;
+    _jitc->function->call.argi = _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_c, r0);
+    jit_extr_c(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_uc, r0);
+    jit_extr_uc(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_s, r0);
+    jit_extr_s(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_us, r0);
+    jit_extr_us(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+    jit_movr(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_f, r0);
+    jit_movr_f(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_d, r0);
+    jit_movr_d(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_int32_t                 value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_int32_t      patch_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.patch_offset = 0;
+
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w),rn(node->v.w), node->w.w);  \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_rrf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               assert(node->flag & jit_flag_data);                     \
+               name##i##type(rn(node->u.w), rn(node->v.w),             \
+                             (jit_float##size##_t *)node->w.n->u.w);   \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w,rn(node->v.w), rn(node->w.w));  \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w, rn(node->v.w),             \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w, rn(node->v.w),     \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if (node->u.w == sizeof(jit_word_t) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), node->v.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rr(neg,);
+               case_rr(com,);
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_rr(mov, _f);
+           case jit_code_movi_f:
+               assert(node->flag & jit_flag_data);
+               movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               break;
+               case_rr(mov, _d);
+           case jit_code_movi_d:
+               assert(node->flag & jit_flag_data);
+               movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               break;
+               case_rr(trunc, _f_i);
+               case_rr(trunc, _d_i);
+               case_rr(ext, _f);
+               case_rr(ext, _d);
+               case_rr(ext, _d_f);
+               case_rr(ext, _f_d);
+               case_rr(abs, _f);
+               case_rr(abs, _d);
+               case_rr(neg, _f);
+               case_rr(neg, _d);
+               case_rr(sqrt, _f);
+               case_rr(sqrt, _d);
+               case_rrr(add, _f);
+               case_rrf(add, _f, 32);
+               case_rrr(add, _d);
+               case_rrf(add, _d, 64);
+               case_rrr(sub, _f);
+               case_rrf(sub, _f, 32);
+               case_rrf(rsb, _f, 32);
+               case_rrr(sub, _d);
+               case_rrf(sub, _d, 64);
+               case_rrf(rsb, _d, 64);
+               case_rrr(mul, _f);
+               case_rrf(mul, _f, 32);
+               case_rrr(mul, _d);
+               case_rrf(mul, _d, 64);
+               case_rrr(div, _f);
+               case_rrf(div, _f, 32);
+               case_rrr(div, _d);
+               case_rrf(div, _d, 64);
+               case_rrr(lt, _f);
+               case_rrf(lt, _f, 32);
+               case_rrr(lt, _d);
+               case_rrf(lt, _d, 64);
+               case_rrr(le, _f);
+               case_rrf(le, _f, 32);
+               case_rrr(le, _d);
+               case_rrf(le, _d, 64);
+               case_rrr(eq, _f);
+               case_rrf(eq, _f, 32);
+               case_rrr(eq, _d);
+               case_rrf(eq, _d, 64);
+               case_rrr(ge, _f);
+               case_rrf(ge, _f, 32);
+               case_rrr(ge, _d);
+               case_rrf(ge, _d, 64);
+               case_rrr(gt, _f);
+               case_rrf(gt, _f, 32);
+               case_rrr(gt, _d);
+               case_rrf(gt, _d, 64);
+               case_rrr(ne, _f);
+               case_rrf(ne, _f, 32);
+               case_rrr(ne, _d);
+               case_rrf(ne, _d, 64);
+               case_rrr(unlt, _f);
+               case_rrf(unlt, _f, 32);
+               case_rrr(unlt, _d);
+               case_rrf(unlt, _d, 64);
+               case_rrr(unle, _f);
+               case_rrf(unle, _f, 32);
+               case_rrr(unle, _d);
+               case_rrf(unle, _d, 64);
+               case_rrr(uneq, _f);
+               case_rrf(uneq, _f, 32);
+               case_rrr(uneq, _d);
+               case_rrf(uneq, _d, 64);
+               case_rrr(unge, _f);
+               case_rrf(unge, _f, 32);
+               case_rrr(unge, _d);
+               case_rrf(unge, _d, 64);
+               case_rrr(ungt, _f);
+               case_rrf(ungt, _f, 32);
+               case_rrr(ungt, _d);
+               case_rrf(ungt, _d, 64);
+               case_rrr(ltgt, _f);
+               case_rrf(ltgt, _f, 32);
+               case_rrr(ltgt, _d);
+               case_rrf(ltgt, _d, 64);
+               case_rrr(ord, _f);
+               case_rrf(ord, _f, 32);
+               case_rrr(ord, _d);
+               case_rrf(ord, _d, 64);
+               case_rrr(unord, _f);
+               case_rrf(unord, _f, 32);
+               case_rrr(unord, _d);
+               case_rrf(unord, _d, 64);
+               case_rr(ld, _f);
+               case_rw(ld, _f);
+               case_rr(ld, _d);
+               case_rw(ld, _d);
+               case_rrr(ldx, _f);
+               case_rrw(ldx, _f);
+               case_rrr(ldx, _d);
+               case_rrw(ldx, _d);
+               case_rr(st, _f);
+               case_wr(st, _f);
+               case_rr(st, _d);
+               case_wr(st, _d);
+               case_rrr(stx, _f);
+               case_wrr(stx, _f);
+               case_rrr(stx, _d);
+               case_wrr(stx, _d);
+               case_brr(blt, _f);
+               case_brf(blt, _f, 32);
+               case_brr(blt, _d);
+               case_brf(blt, _d, 64);
+               case_brr(ble, _f);
+               case_brf(ble, _f, 32);
+               case_brr(ble, _d);
+               case_brf(ble, _d, 64);
+               case_brr(beq, _f);
+               case_brf(beq, _f, 32);
+               case_brr(beq, _d);
+               case_brf(beq, _d, 64);
+               case_brr(bge, _f);
+               case_brf(bge, _f, 32);
+               case_brr(bge, _d);
+               case_brf(bge, _d, 64);
+               case_brr(bgt, _f);
+               case_brf(bgt, _f, 32);
+               case_brr(bgt, _d);
+               case_brf(bgt, _d, 64);
+               case_brr(bne, _f);
+               case_brf(bne, _f, 32);
+               case_brr(bne, _d);
+               case_brf(bne, _d, 64);
+               case_brr(bunlt, _f);
+               case_brf(bunlt, _f, 32);
+               case_brr(bunlt, _d);
+               case_brf(bunlt, _d, 64);
+               case_brr(bunle, _f);
+               case_brf(bunle, _f, 32);
+               case_brr(bunle, _d);
+               case_brf(bunle, _d, 64);
+               case_brr(buneq, _f);
+               case_brf(buneq, _f, 32);
+               case_brr(buneq, _d);
+               case_brf(buneq, _d, 64);
+               case_brr(bunge, _f);
+               case_brf(bunge, _f, 32);
+               case_brr(bunge, _d);
+               case_brf(bunge, _d, 64);
+               case_brr(bungt, _f);
+               case_brf(bungt, _f, 32);
+               case_brr(bungt, _d);
+               case_brf(bungt, _d, 64);
+               case_brr(bltgt, _f);
+               case_brf(bltgt, _f, 32);
+               case_brr(bltgt, _d);
+               case_brf(bltgt, _d, 64);
+               case_brr(bord, _f);
+               case_brf(bord, _f, 32);
+               case_brr(bord, _d);
+               case_brf(bord, _d, 64);
+               case_brr(bunord, _f);
+               case_brf(bunord, _f, 32);
+               case_brr(bunord, _d);
+               case_brf(bunord, _d, 64);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (!(temp->flag & jit_flag_patch)) {
+                       word = calli_p(temp->u.w);
+                       patch(word, node);
+                   }
+                   else
+                       calli(temp->u.w);
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+           restart_function:
+               _jitc->again = 0;
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+                   goto restart_function;
+               }
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:
+           case jit_code_arg:                  case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           default:
+               abort();
+       }
+       jit_regarg_clr(node, value);
+       assert(_jitc->regarg == 0 && _jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+    }
+#undef case_brf
+#undef case_brw
+#undef case_brr
+#undef case_wrr
+#undef case_rrf
+#undef case_rrrw
+#undef case_rrw
+#undef case_rrrr
+#undef case_rrr
+#undef case_wr
+#undef case_rw
+#undef case_rr
+
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(_jitc->patches.ptr[offset].inst, word);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_hppa-cpu.c"
+#  include "jit_hppa-fpu.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+    jit_word_t         f, t, s;
+    s = sysconf(_SC_PAGE_SIZE);
+    f = (jit_word_t)fptr & -s;
+    t = (((jit_word_t)tptr) + s - 1) & -s;
+#if defined(__hppa)
+/* --- parisc2.0.pdf ---
+               Programming Note
+
+The minimum spacing that is guaranteed to work for "self-modifying code" is
+shown in the code segment below. Since instruction prefetching is permitted,
+any data cache flushes must be separated from any instruction cache flushes
+by a SYNC. This will ensure that the "new" instruction will be written to
+memory prior to any attempts at prefetching it as an instruction.
+
+       LDIL    l%newinstr,rnew
+       LDW     r%newinstr(0,rnew),temp
+       LDIL    l%instr,rinstr
+       STW     temp,r%instr(0,rinstr)
+       FDC     r%instr(0,rinstr)
+       SYNC
+       FIC     r%instr(rinstr)
+       SYNC
+       instr   ...
+       (at least seven instructions)
+
+This sequence assumes a uniprocessor system. In a multiprocessor system,
+software must ensure no processor is executing code which is in the process
+of being modified.
+*/
+
+/*
+  Adapted from ffcall/trampoline/cache-hppa.c:__TR_clear_cache to
+loop over addresses as it is unlikely from and to addresses would fit in
+at most two cachelines.
+  FIXME A cache line can be 16, 32, or 64 bytes.
+ */
+    /*
+     * Copyright 1995-1997 Bruno Haible, <bruno@clisp.org>
+     *
+     * This is free software distributed under the GNU General Public Licence
+     * described in the file COPYING. Contact the author if you don't have this
+     * or can't live with it. There is ABSOLUTELY NO WARRANTY, explicit or implied,
+     * on this software.
+     */
+    {
+       jit_word_t      n = f + 32;
+       register int    u, v;
+       for (; f <= t; n = f + 32, f += 64) {
+           asm volatile ("fdc 0(0,%0)"
+                         "\n\t" "fdc 0(0,%1)"
+                         "\n\t" "sync"
+                         :
+                         : "r" (f), "r" (n)
+                         );
+           asm volatile ("mfsp %%sr0,%1"
+                         "\n\t" "ldsid (0,%4),%0"
+                         "\n\t" "mtsp %0,%%sr0"
+                         "\n\t" "fic 0(%%sr0,%2)"
+                         "\n\t" "fic 0(%%sr0,%3)"
+                         "\n\t" "sync"
+                         "\n\t" "mtsp %1,%%sr0"
+                         "\n\t" "nop"
+                         "\n\t" "nop"
+                         "\n\t" "nop"
+                         "\n\t" "nop"
+                         "\n\t" "nop"
+                         "\n\t" "nop"
+                         : "=r" (u), "=r" (v)
+                         : "r" (f), "r" (n), "r" (f)
+                         );
+       }
+    }
+#else
+    /* This is supposed to work but appears to fail on multiprocessor systems */
+    __clear_cache((void *)f, (void *)t);
+#endif
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_gpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    ldxi(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_gpr_t r1)
+{
+    stxi(i0, rn(r0), rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_fpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_fpr_t r1)
+{
+    stxi_d(i0, rn(r0), rn(r1));
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+    assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_ia64-cpu.c b/deps/lightning/lib/jit_ia64-cpu.c
new file mode 100644 (file)
index 0000000..dec1465
--- /dev/null
@@ -0,0 +1,5402 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#define stack_framesize                        144
+#define params_offset                  16
+#define INST_NONE                      0       /* should never be generated */
+#define INST_STOP                      1       /* or'ed if stop is required */
+#define INST_A                         2       /* M- or I- unit */
+#define INST_As                                3
+#define INST_I                         4
+#define INST_Is                                5
+#define INST_M                         6
+#define INST_Ms                                7
+#define INST_F                         8
+#define INST_Fs                                9
+#define INST_B                         10
+#define INST_Bs                                11
+#define INST_L                         12
+#define INST_Ls                                13
+#define INST_X                         14
+#define INST_Xs                                15
+
+/* Data and instructions are referenced by 64-bit addresses. Instructions
+ * are stored in memory in little endian byte order, in which the least
+ * significant byte appears in the lowest addressed byte of a memory
+ * location. For data, modes for both big and little endian byte order are
+ * supported and can be controlled by a bit in the User Mask Register.
+ */
+#define il(ii)                         *_jit->pc.ul++ = ii
+#define set_bundle(p, l, h, tm, s0, s1, s2)                            \
+    do {                                                               \
+       l = tm | ((s0 & 0x1ffffffffffL) << 5L) | (s1 << 46L);           \
+       h = ((s1 >> 18L) & 0x7fffffLL) | (s2 << 23L);                   \
+       p[0] = byte_swap_if_big_endian(l);                              \
+       p[1] = byte_swap_if_big_endian(h);                              \
+    } while (0)
+#define get_bundle(p, l, h, tm, s0, s1, s2)                            \
+    do {                                                               \
+       l = byte_swap_if_big_endian(p[0]);                              \
+       h = byte_swap_if_big_endian(p[1]);                              \
+       tm = l & 0x1f;                                                  \
+       s0 = (l >> 5L) & 0x1ffffffffffL;                                \
+       s1 = ((l >> 46L) & 0x3ffffL) | ((h & 0x7fffffL) << 18L);        \
+       s2 = (h >> 23L) & 0x1ffffffffffL;                               \
+    } while (0)
+
+/*  Need to insert a stop if a modified register would (or could)
+ *  be read in the same cycle.
+ */
+#define TSTREG1(r0)                                                    \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->regs, r0))                        \
+           stop();                                                     \
+    } while (0)
+#define TSTREG2(r0, r1)                                                        \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->regs, r0) ||                      \
+           jit_regset_tstbit(&_jitc->regs, r1))                        \
+           stop();                                                     \
+    } while (0)
+#define TSTPRED(p0)                                                    \
+    do {                                                               \
+       if (p0 && (_jitc->pred & (1 << p0)))                            \
+           stop();                                                     \
+    } while (0)
+/* Record register was modified */
+#define SETREG(r0)             jit_regset_setbit(&_jitc->regs, r0)
+
+/* Avoid using constants in macros and code */
+typedef enum {
+    GR_0,              GR_1,           GR_2,           GR_3,
+    GR_4,              GR_5,           GR_6,           GR_7,
+    GR_8,              GR_9,           GR_10,          GR_11,
+    GR_12,             GR_13,          GR_14,          GR_15,
+    GR_16,             GR_17,          GR_18,          GR_19,
+    GR_20,             GR_21,          GR_22,          GR_23,
+    GR_24,             GR_25,          GR_26,          GR_27,
+    GR_28,             GR_29,          GR_30,          GR_31,
+    GR_32,             GR_33,          GR_34,          GR_35,
+    GR_36,             GR_37,          GR_38,          GR_39,
+    GR_40,             GR_41,          GR_42,          GR_43,
+    /* GR_44...GR_127 */
+} gr_reg_t;
+
+typedef enum {
+    PR_0,              /* constant - always 1 */
+    /* p0-p5            -  preserved */
+    PR_1,              PR_2,           PR_3,           PR_4,
+    PR_5,
+    /* p6-p15           - scratch */
+    PR_6,              PR_7,           PR_8,           PR_9,
+    PR_10,             PR_11,          PR_12,          PR_13,
+    PR_14,             PR_15,
+    /* p16-...          - preserved - rotating */
+} pr_reg_t;
+
+typedef enum {
+    BR_0,              /* scratch - Return link */
+    /* b1-b5            - preserved */
+    BR_1,              BR_2,           BR_3,           BR_4,
+    BR_5,
+    /* b6-b7           - scratch */
+    BR_6,              BR_7
+} br_reg_t;
+
+typedef enum {
+    AR_KR0,            AR_KR1,         AR_KR2,         AR_KR3,
+    AR_KR4,            AR_KR5,         AR_KR6,         AR_KR7,
+    AR_8,              AR_9,           AR_10,          AR_11,
+    AR_12,             AR_13,          AR_14,          AR_15,
+    AR_RSC,            AR_BSP,         AR_BSPSTORE,    AR_RNAT,
+    AR_20,             AR_FCR,         AR_22,          AR_23,
+    AR_EFLAG,          AR_CSD,         AR_SSD,         AR_CFLG,
+    AR_FSR,            AR_FIR,         AR_FDR,         AR_31,
+    AR_CCV,            AR_33,          AR_34,          AR_35,
+    AR_UNAT,           AR_37,          AR_38,          AR_39,
+    AR_FPSR,           AR_41,          AR_42,          AR_43,
+    AR_ITC,            AR_RUC,         AR_46,          AR_47,
+    AR_48,             AR_49,          AR_50,          AR_51,
+    AR_52,             AR_53,          AR_54,          AR_55,
+    AR_56,             AR_57,          AR_58,          AR_59,
+    AR_60,             AR_61,          AR_62,          AR_63,
+    AR_PFS,            AR_LC,          AR_EC,
+    /* AR_67 ... AR_127 */
+} ar_reg_t;
+
+typedef enum {
+    TM_M_I_I_, TM_M_I_Is,      TM_M_IsI_,      TM_M_IsIs,
+    TM_M_L_X_, TM_M_L_Xs,      TM_ILL_06,      TM_ILL_07,
+    TM_M_M_I_, TM_M_M_Is,      TM_MsM_I_,      TM_MsM_Is,
+    TM_M_F_I_, TM_M_F_Is,      TM_M_M_F_,      TM_M_M_Fs,
+    TM_M_I_B_, TM_M_I_Bs,      TM_M_B_B_,      TM_M_B_Bs,
+    TM_ILL_14, TM_ILL_15,      TM_B_B_B_,      TM_B_B_Bs,
+    TM_M_M_B_, TM_M_M_Bs,      TM_ILL_1A,      TM_ILL_1B,
+    TM_M_F_B_, TM_M_F_Bs,      TM_ILL_1E,      TM_ILL_1F,
+} template_t;
+
+#define MWH_SPTK                       0
+#define MWH_NONE                       1
+#define MWH_DPTK                       2
+
+#define IH_NONE                                0
+#define IH_IMP                         1
+
+#define LD_NONE                                0
+#define LD_NT1                         1
+#define LD_NTA                         3
+
+#define ST_NONE                                0
+#define ST_NTA                         3
+
+#define LF_NONE                                0
+#define LF_NT1                         1
+#define LF_NT2                         2
+#define LF_NTA                         3
+
+#define BR_PH_FEW                      0
+#define BR_PH_MANY                     1
+
+#define BR_BWH_SPTK                    0
+#define BR_BWH_SPNT                    1
+#define BR_BWH_DPTK                    2
+#define BR_BWH_DPNT                    3
+
+#define BRI_BWH_SPTK                   1
+#define BRI_BWH_SPNT                   3
+#define BRI_BWH_DPTK                   5
+#define BRI_BWH_DPNT                   7
+
+#define BR_DH_NONE                     0
+#define BR_DH_CLR                      1
+
+#define BR_IH_NONE                     0
+#define BR_IH_IMP                      1
+
+#define BR_IPWH_SPTK                   0
+#define BR_IPWH_LOOP                   1
+#define BR_IPWH_DPTK                   2
+#define BR_IPWH_EXIT                   3
+
+#define BR_INDWH_SPTK                  0
+#define BR_INDWH_DPTK                  2
+
+#define MUX_BRCST                      0
+#define MUX_REV                                11
+#define MUX_MIX                                8
+#define MUX_SHUF                       9
+#define MUX_ALT                                10
+
+#define ldr(r0,r1)                     ldr_l(r0,r1)
+#define ldi(r0,i0)                     ldi_l(r0,i0)
+#define str(r0,r1)                     str_l(r0,r1)
+#define sti(i0,r0)                     str_l(i0,r0)
+#define ldxr(r0,r1,r2)                 ldxr_l(r0,r1,r2)
+#define ldxi(r0,r1,i0)                 ldxi_l(r0,r1,i0)
+#define stxr(r0,r1,r2)                 stxr_l(r0,r1,r2)
+#define stxi(i0,r0,r1)                 stxi_l(i0,r0,r1)
+
+#if !HAVE_FFSL
+#  define ffsl(l)                      __builtin_ffsl(l)
+#endif
+
+/* libgcc */
+#if defined(__GNUC__)
+extern long __divdi3(long,long);
+extern unsigned long __udivdi3(unsigned long,unsigned long);
+extern long __moddi3(long,long);
+extern unsigned long __umoddi3(unsigned long,unsigned long);
+#else
+static long __divdi3(long,long);
+static unsigned long __udivdi3(unsigned long,unsigned long);
+static long __moddi3(long,long);
+static unsigned long __umoddi3(unsigned long,unsigned long);
+#endif
+#define out(n,tm,s0,s1,s2)             _out(_jit,n,tm,s0,s1,s2)
+static void _out(jit_state_t*,int,int,jit_word_t,jit_word_t,jit_word_t);
+#define stop()                         _stop(_jit)
+static void _stop(jit_state_t*);
+#define sync()                         _sync(_jit)
+static void _sync(jit_state_t*);
+#define flush()                                _flush(_jit)
+static void _flush(jit_state_t*);
+#define inst(w, t)                     _inst(_jit, w, t)
+static void _inst(jit_state_t*, jit_word_t, jit_uint8_t);
+#define A1(x4,x2,r3,r2,r1)             _A1(_jit,0,x4,x2,r3,r2,r1)
+static void _A1(jit_state_t*, jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define A2(x4,ct,r3,r2,r1)             A1(x4,ct,r3,r2,r1)
+#define A3(x4,x2,r3,im,r1)             _A3(_jit,0,x4,x2,r3,im,r1)
+static void _A3(jit_state_t*, jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define A4(x2a,r3,im,r1)               _A4(_jit,0,x2a,r3,im,r1)
+static void _A4(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define A5(r3,im,r1)                   _A5(_jit,0,r3,im,r1)
+static void _A5(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t);
+#define A6(o,x2,ta,p2,r3,r2,c,p1)      _A6(_jit,0,o,x2,ta,p2,r3,r2,c,p1)
+static void _A6(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define A7(o,x2,ta,p2,r3,c,p1)         _A7(_jit,0,o,x2,ta,p2,r3,c,p1)
+static void _A7(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define A8(o,x2,ta,p2,r3,im,c,p1)      _A8(_jit,0,o,x2,ta,p2,r3,im,c,p1)
+static void _A8(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define A9(za,zb,x4,x2,r3,r2,r1)       _A9(_jit,0,za,zb,x4,x2,r3,r2,r1)
+static void _A9(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define A10(x4,ct,r3,r2,r1)            A9(0,1,x4,ct,r3,r2,r1)
+#define I1(ct,x2,r3,r2,r1)             _I1(_jit,0,ct,x2,r3,r2,r1)
+static void _I1(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I2(za,x2a,zb,x2c,x2b,r3,r2,r1) _I2(_jit,0,za,x2a,zb,x2c,x2b,r3,r2,r1)
+static void _I2(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I3(mbt,r2,r1)                  _I3(_jit,0,mbt,r2,r1)
+static void _I3(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t)
+#if __BYTE_ORDER == __BIG_ENDIAN
+    maybe_unused
+#endif
+    ;
+#define I4(mht,r2,r1)                  _I4(_jit,0,mht,r2,r1)
+static void _I4(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I5(za,zb,x2b,r3,r2,r1)         _I5(_jit,0,za,zb,x2b,r3,r2,r1)
+static void _I5(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t);
+#define I6(za,zb,x2b,r3,ct,r1)         _I6(_jit,0,za,zb,x2b,r3,ct,r1)
+static void _I6(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I7(za,zb,r3,r2,r1)             _I7(_jit,0,za,zb,r3,r2,r1)
+static void _I7(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define I8(za,zb,ct,r2,r1)             _I8(_jit,0,za,zb,ct,r2,r1)
+static void _I8(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I9(x2c,r3,r1)                  _I9(_jit,0,x2c,r3,r1)
+static void _I9(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I10(ct,r3,r2,r1)               _I10(_jit,0,ct,r3,r2,r1)
+static void _I10(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I11(len,r3,pos,y,r1)           _I11(_jit,0,len,r3,pos,y,r1)
+static void _I11(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I12(len,pos,r2,r1)             _I12(_jit,0,len,pos,r2,r1)
+static void _I12(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I13(len,pos,im,r1)             _I13(_jit,0,len,pos,im,r1)
+static void _I13(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I14(s,len,r3,pos,r1)           _I14(_jit,0,s,len,r3,pos,r1)
+static void _I14(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I15(pos,len,r3,r2,r1)          _I15(_jit,0,pos,len,r3,r2,r1)
+static void _I15(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I16(tb,ta,p2,r3,pos,c,p1)      _I16(_jit,0,tb,ta,p2,r3,pos,c,p1)
+static void _I16(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I17(tb,ta,p2,r3,c,p1)          _I17(_jit,0,tb,ta,p2,r3,c,p1)
+static void _I17(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define I18(im,y)                      _I18(_jit,0,im,y)
+static void _I18(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define I19(im)                                _I19(_jit,0,im)
+static void _I19(jit_state_t*,jit_word_t,
+                jit_word_t)
+    maybe_unused;
+#define I20(r2,im)                     _I20(_jit,0,r2,im)
+static void _I20(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define I21(im,ih,x,wh,r2,b1)          _I21(_jit,0,im,ih,x,wh,r2,b1)
+static void _I21(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define I22(b2,r1)                     _I22(_jit,0,b2,r1)
+static void _I22(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t);
+#define I23(r2,im)                     _I23(_jit,0,r2,im)
+static void _I23(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define I24(im)                                _I24(_jit,0,im)
+static void _I24(jit_state_t*,jit_word_t,
+                jit_word_t)
+    maybe_unused;
+#define I25(x6,r1)                     _I25(_jit,0,x6,r1)
+static void _I25(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define I26(ar,r2)                     _I26(_jit,0,ar,r2)
+static void _I26(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t);
+#define I27(ar,im)                     _I27(_jit,0,ar,im)
+static void _I27(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define I28(ar,r1)                     _I28(_jit,0,ar,r1)
+static void _I28(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define I29(x6,r3,r1)                  _I29(_jit,0,x6,r3,r1)
+static void _I29(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t);
+#define I30(tb,ta,p2,im,c,p1)          _I30(_jit,0,ta,tb,p2,im,c,p1)
+static void _I30(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M1(x6,ht,x,r3,r1)              _M1(_jit,0,x6,ht,x,r3,r1)
+static void _M1(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define M2(x6,ht,r3,r2,r1)             _M2(_jit,0,x6,ht,r3,r2,r1)
+static void _M2(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M3(x6,ht,r3,im,r1)             _M3(_jit,0,x6,ht,r3,im,r1)
+static void _M3(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define M5(x6,ht,r3,r2,im)             _M5(_jit,0,x6,ht,r3,r2,im)
+static void _M5(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M6(x6,ht,x,r3,r2)              _M6(_jit,0,x6,ht,x,r3,r2)
+static void _M6(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define M13(x6,ht,r3,f2)               _M13(_jit,0,x6,ht,r3,f2)
+static void _M13(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define M14(x6,ht,r3,r2)               _M14(_jit,0,x6,ht,r3,r2)
+static void _M14(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M15(x6,ht,r3,im)               _M15(_jit,0,x6,ht,r3,im)
+static void _M15(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M16(x6,ht,r3,r2,r1)            _M16(_jit,0,x6,ht,r3,r2,r1)
+static void _M16(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M17(x6,ht,r3,im,r1)            _M17(_jit,0,x6,ht,r3,im,r1)
+static void _M17(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M20(r2,im)                     M20x(0x1,r2,im)
+#define M20x(x3,r2,im)                 _M20x(_jit,0,x3,r2,im)
+static void _M20x(jit_state_t*,jit_word_t,
+                 jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M22(x3,im,r1)                  M22x(x3,im,r1)
+#define M22x(x3,im,r1)                 _M22x(_jit,0,x3,im,r1)
+static void _M22x(jit_state_t*,jit_word_t,
+                 jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M24(x2,x4)                     _M24(_jit,0,x2,x4)
+#define M25(x4)                                M24(0,x4)
+static void _M24(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M26(r1)                                M26x(2,r1)
+#define M26x(x4,r1)                    _M26x(_jit,0,x4,r1)
+static void _M26x(jit_state_t*,jit_word_t,
+                 jit_word_t,jit_word_t)
+    maybe_unused;
+#define M28(x,r3)                      _M28(_jit,0,x,r3)
+static void _M28(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M29(ar,r2)                     _M29(_jit,0,ar,r2)
+static void _M29(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M30(ar,im)                     _M30(_jit,0,ar,im)
+static void _M30(jit_state_t*,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M31(ar,r1)                     _M31(_jit,0,ar,r1)
+static void _M31(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M32(cr,r2)                     _M32(_jit,0,cr,r2)
+static void _M32(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M33(cr,r1)                     _M33(_jit,0,cr,r1)
+static void _M33(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M34(sor,sol,sof,r1)            _M34(_jit,0,sor,sol,sof,r1)
+static void _M34(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define M35(x6,r2)                     _M35(_jit,0,x6,r2)
+static void _M35(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M36(x6,r1)                     _M36(_jit,0,x6,r1)
+static void _M36(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M37(im)                                _M37(_jit,0,im)
+static void _M37(jit_state_t*,jit_word_t,
+                jit_word_t)
+    maybe_unused;
+#define M38(x6,r3,r2,r1)               _M38(_jit,0,x6,r3,r2,r1)
+static void _M38(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M39(x6,r3,im,r1)               _M39(_jit,0,x6,r3,im,r1)
+static void _M39(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M40(x6,r3,im)                  _M40(_jit,0,x6,r3,im)
+static void _M40(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M41(x6,r2)                     _M41(_jit,0,x6,r2)
+static void _M41(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M42(x6,r3,r2)                  _M42(_jit,0,x6,r3,r2)
+static void _M42(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M43(x6,r3,r1)                  _M43(_jit,0,x6,r3,r1)
+static void _M43(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M44(x4,im)                     _M44(_jit,0,x4,im)
+static void _M44(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define M45(x6,r3,r2)                  _M45(_jit,0,x6,r3,r2)
+static void _M45(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M46(x6,r3,r1)                  _M46(_jit,0,x6,r3,r1)
+#define M47(x6,r3)                     M46(x6,r3,0)
+static void _M46(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M48(y,im)                      _M48(_jit,0,y,im)
+static void _M48(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)
+    maybe_unused;
+#define B1(d,wh,im,p,tp)               _B1(_jit,0,d,wh,im,p,tp)
+#define B2(d,wh,im,p,tp)               B1(d,wh,im,p,tp)
+static void _B1(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define B3(d,wh,im,p,b)                        _B3(_jit,0,d,wh,im,p,b)
+static void _B3(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define B4(d,wh,x6,b,p,tp)             _B4(_jit,0,d,wh,x6,b,p,tp)
+static void _B4(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t);
+#define B5(d,wh,b2,p,b1)               _B5(_jit,0,d,wh,b2,p,b1)
+static void _B5(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define B6(ih,im,tag,wh)               _B6(_jit,0,ih,im,tag,wh)
+static void _B6(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define B7(ih,x6,b2,tag,wh)            _B7(_jit,0,ih,x6,b2,tag,wh)
+static void _B7(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define B8(x6)                         _B8(_jit,0,x6)
+static void _B8(jit_state_t*,jit_word_t,
+               jit_word_t)
+    maybe_unused;
+#define B9(op,x6,im)                   _B9(_jit,0,op,x6,im)
+static void _B9(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define X1(im)                         _X1(_jit,0,im)
+static void _X1(jit_state_t*,jit_word_t,
+               jit_word_t)
+    maybe_unused;
+#define X2(r1,im)                      _X2(_jit,0,r1,im)
+static void _X2(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t);
+#define X3x(o,d,wh,p,tp,im)            _X3x(_jit,0,o,d,wh,p,tp,im)
+#define X3(d,wh,p,tp,im)               X3x(0xc,d,wh,p,tp,im)
+#define X4(d,wh,p,tp,im)               X3x(0xd,d,wh,p,tp,im)
+static void _X3x(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t);
+#define X5(y,im)                       _X5(_jit,0,y,im)
+static void _X5(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t)
+    maybe_unused;
+
+/* add */
+#define ADD(r1,r2,r3)                  A1(0,0,r3,r2,r1)
+#define ADD1(r1,r2,r3)                 A1(0,1,r3,r2,r1)
+#define ADDS(r1,im,r3)                 A4(2,r3,im,r1)
+#define ADDS_p(r1,im,r3,_p)            _A4(_jit,_p,2,r3,im,r1)
+#define ADDL(r1,im,r3)                 A5(r3,im,r1)
+#define ADDL_p(r1,im,r3,_p)            _A5(_jit,_p,r3,im,r1)
+/* addp4 */
+#define ADDP4(r1,r2,r3)                        A1(2,0,r3,r2,r1)
+#define ADDIP4(r1,im,r3)               A4(3,r3,im,r1)
+/* alloc */
+#define ALLOCR(r1,i,l,o,r)             M34((r)>>3,(i)+(l),(i)+(l)+(o),r1)
+#define ALLOC(r1,i,o)                  ALLOCR(r1,i,0,o,0)
+/* and */
+#define AND(r1,r2,r3)                  A1(3,0,r3,r2,r1)
+#define ANDI(r1,im,r3)                 A3(0xb,0,r3,im,r1)
+/* andcm */
+#define ANDCM(r1,r2,r3)                        A1(3,1,r3,r2,r1)
+#define ANDCMI(r1,im,r3)               A3(0xb,1,r3,im,r1)
+/* br */
+#define BRI(im)                                B1(BR_DH_NONE,BR_BWH_SPTK,im,BR_PH_FEW,0)
+#define BRI_COND(im,_p)                        _B1(_jit,_p,BR_DH_NONE,BR_BWH_SPTK,im,BR_PH_FEW,0)
+#define BRI_WEXIT(im)                  B1(BR_DH_NONE,BR_BWH_SPTK,im,BR_PH_MANY,2)
+#define BRI_WTOP(im)                   B1(BR_DH_NONE,BR_BWH_SPTK,im,BR_PH_MANY,3)
+#define BRI_CALL(b,im)                 B3(BR_DH_NONE,BR_BWH_SPTK,im,BR_PH_MANY,b)
+#define BRI_CLOOP(im)                  B2(BR_DH_NONE,BR_BWH_SPTK,im,BR_PH_MANY,5)
+#define BRI_CEXIT(im)                  B2(BR_DH_NONE,BR_BWH_SPTK,im,BR_PH_MANY,6)
+#define BRI_CTOP(im)                   B2(BR_DH_NONE,BR_BWH_SPTK,im,BR_PH_MANY,7)
+#define BR_COND(b,_p)                  _B4(_jit,_p,BR_DH_NONE,BR_BWH_SPTK,0x20,b,BR_PH_FEW,0)
+#define BR(b)                          B4(BR_DH_NONE,BR_BWH_SPTK,0x20,b,BR_PH_FEW,0)
+#define BR_IA(b)                       B4(BR_DH_NONE,BR_BWH_SPTK,0x20,b,BR_PH_MANY,1)
+#define BR_RET(b)                      B4(BR_DH_NONE,BR_BWH_SPTK,0x21,b,BR_PH_MANY,4)
+#define BR_CALL(b1,b2)                 B5(BR_DH_NONE,BRI_BWH_SPTK,b2,BR_PH_MANY,b1)
+/* break */
+#define BREAK_I(im)                    I19(im)
+#define BREAK_M(im)                    M37(im)
+#define BREAK_B(im)                    B9(0,0,im)
+#define BREAK_X(im)                    X1(im)
+/* brl */
+#define BRL(im)                                X3(BR_DH_NONE,BR_BWH_SPTK,BR_PH_MANY,0,im)
+#define BRL_COND(im,_p)                        _X3(_jit,_p,BR_DH_NONE,BR_BWH_SPTK,BR_PH_MANY,0,im)
+#define BRL_CALL(b1,im)                        X4(BR_DH_NONE,BR_BWH_SPTK,BR_PH_MANY,b1,im)
+/* brp */
+#define BRP(im,tag)                    B6(BR_IH_NONE,im,tag,BR_IPWH_SPTK)
+#define BRPI(b2,tag)                   B7(BR_IH_NONE,0x10,b2,tag,BR_INDWH_SPTK)
+#define BRPI_RET(b2,tag)               B7(BR_IH_NONE,0x11,b2,tag,BR_INDWH_SPTK)
+/* bsw */
+#define BSW_0()                                B8(0x0c)
+#define BSW_1()                                B8(0x0d)
+/* chk */
+#define CHK_S_I(r2,im)                 I20(r2,im)
+#define CHK_S_M(r2,im)                 M20(r2,im)
+#define CHK_A_NC(r1,im)                        M22(0x4,im,r1)
+#define CHK_A_CLR(r1,im)               M22(0x5,im,r1)
+/* clrrrb */
+#define CLRRRB()                       B8(0x04)
+#define CLRRRB_PR()                    B8(0x05)
+/* clz */
+#define CLZ(r1,r3)                     I9(3,r3,r1)
+/* cmp */
+#define CMP_LT(p1,p2,r2,r3)            A6(0xc,0,0,p2,r3,r2,0,p1)
+#define CMP_LT_p(p1,p2,r2,r3,_p)       A6(_jit,_p,0xc,0,0,p2,r3,r2,0,p1)
+#define CMP_LTU(p1,p2,r2,r3)           A6(0xd,0,0,p2,r3,r2,0,p1)
+#define CMP_EQ(p1,p2,r2,r3)            A6(0xe,0,0,p2,r3,r2,0,p1)
+#define CMP_LT_UNC(p1,p2,r2,r3)                A6(0xc,0,0,p2,r3,r2,1,p1)
+#define CMP_LTU_UNC(p1,p2,r2,r3)       A6(0xd,0,0,p2,r3,r2,1,p1)
+#define CMP_EQ_UNC(p1,p2,r2,r3)                A6(0xe,0,0,p2,r3,r2,1,p1)
+#define CMP_EQ_AND(p1,p2,r2,r3)                A6(0xc,0,1,p2,r3,r2,0,p1)
+#define CMP_EQ_OR(p1,p2,r2,r3)         A6(0xd,0,1,p2,r3,r2,0,p1)
+#define CMP_EQ_OR_ANDCM(p1,p2,r2,r3)   A6(0xe,0,1,p2,r3,r2,0,p1)
+#define CMP_NE_AND(p1,p2,r2,r3)                A6(0xc,0,1,p2,r3,r2,1,p1)
+#define CMP_NE_OR(p1,p2,r2,r3)         A6(0xd,0,1,p2,r3,r2,1,p1)
+#define CMP_NE_OR_ANDCM(p1,p2,r2,r3)   A6(0xe,0,1,p2,r3,r2,1,p1)
+#define CMPI_LT(p1,p2,im,r3)           A8(0xc,2,0,p2,r3,im,0,p1)
+#define CMPI_LTU(p1,p2,im,r3)          A8(0xd,2,0,p2,r3,im,0,p1)
+#define CMPI_EQ(p1,p2,im,r3)           A8(0xe,2,0,p2,r3,im,0,p1)
+#define CMPI_EQ_p(p1,p2,im,r3,_p)      _A8(_jit,_p,0xe,2,0,p2,r3,im,0,p1)
+#define CMPI_LT_UNC(p1,p2,im,r3)       A8(0xc,2,0,p2,r3,im,1,p1)
+#define CMPI_LTU_UNC(p1,p2,im,r3)      A8(0xd,2,0,p2,r3,im,1,p1)
+#define CMPI_EQ_UNC(p1,p2,im,r3)       A8(0xe,2,0,p2,r3,im,1,p1)
+#define CMPI_EQ_AND(p1,p2,im,r3)       A8(0xc,2,1,p2,r3,im,0,p1)
+#define CMPI_EQ_OR(p1,p2,im,r3)                A8(0xd,2,1,p2,r3,im,0,p1)
+#define CMPI_EQ_ANDCM(p1,p2,im,r3)     A8(0xe,2,1,p2,r3,im,0,p1)
+#define CMPI_NE_AND(p1,p2,im,r3)       A8(0xc,2,1,p2,r3,im,1,p1)
+#define CMPI_NE_OR(p1,p2,im,r3)                A8(0xd,2,1,p2,r3,im,1,p1)
+#define CMPI_NE_ANDCM(p1,p2,im,r3)     A8(0xe,2,1,p2,r3,im,1,p1)
+#define ZCMP_GT_AND(p1,p2,r3)          A7(0xc,0,0,p2,r3,0,p1)
+#define ZCMP_GT_OR(p1,p2,r3)           A7(0xd,0,0,p2,r3,0,p1)
+#define ZCMP_GT_ANDCM(p1,p2,r3)                A7(0xe,0,0,p2,r3,0,p1)
+#define ZCMP_LE_AND(p1,p2,r3)          A7(0xc,0,0,p2,r3,1,p1)
+#define ZCMP_LE_OR(p1,p2,r3)           A7(0xd,0,0,p2,r3,1,p1)
+#define ZCMP_LE_ANDCM(p1,p2,r3)                A7(0xe,0,0,p2,r3,1,p1)
+#define ZCMP_GE_AND(p1,p2,r3)          A7(0xc,0,1,p2,r3,0,p1)
+#define ZCMP_GE_OR(p1,p2,r3)           A7(0xd,0,1,p2,r3,0,p1)
+#define ZCMP_GE_ANDCM(p1,p2,r3)                A7(0xe,0,1,p2,r3,0,p1)
+#define ZCMP_LT_AND(p1,p2,r3)          A7(0xc,0,1,p2,r3,1,p1)
+#define ZCMP_LT_OR(p1,p2,r3)           A7(0xd,0,1,p2,r3,1,p1)
+#define ZCMP_LT_ANDCM(p1,p2,r3)                A7(0xe,0,1,p2,r3,1,p1)
+/* cmp4 */
+#define CMP4_LT(p1,p2,r2,r3)           A6(0xc,1,0,p2,r3,r2,0,p1)
+#define CMP4_LTU(p1,p2,r2,r3)          A6(0xd,1,0,p2,r3,r2,0,p1)
+#define CMP4_EQ(p1,p2,r2,r3)           A6(0xe,1,0,p2,r3,r2,0,p1)
+#define CMP4_LT_UNC(p1,p2,r2,r3)       A6(0xc,1,0,p2,r3,r2,1,p1)
+#define CMP4_LTU_UNC(p1,p2,r2,r3)      A6(0xd,1,0,p2,r3,r2,1,p1)
+#define CMP4_EQ_UNC(p1,p2,r2,r3)       A6(0xe,1,0,p2,r3,r2,1,p1)
+#define CMP4_EQ_AND(p1,p2,r2,r3)       A6(0xc,1,1,p2,r3,r2,0,p1)
+#define CMP4_EQ_OR(p1,p2,r2,r3)                A6(0xd,1,1,p2,r3,r2,0,p1)
+#define CMP4_EQ_XOR(p1,p2,r2,r3)       A6(0xe,1,1,p2,r3,r2,0,p1)
+#define CMP4_NE_AND(p1,p2,r2,r3)       A6(0xc,1,1,p2,r3,r2,1,p1)
+#define CMP4_NE_OR(p1,p2,r2,r3)                A6(0xd,1,1,p2,r3,r2,1,p1)
+#define CMP4_NE_XOR(p1,p2,r2,r3)       A6(0xe,1,1,p2,r3,r2,1,p1)
+#define CMP4I_LT(p1,p2,im,r3)          A8(0xc,3,0,p2,r3,im,0,p1)
+#define CMP4I_LTU(p1,p2,im,r3)         A8(0xd,3,0,p2,r3,im,0,p1)
+#define CMP4I_EQ(p1,p2,im,r3)          A8(0xe,3,0,p2,r3,im,0,p1)
+#define CMP4I_LT_UNC(p1,p2,im,r3)      A8(0xc,3,0,p2,r3,im,1,p1)
+#define CMP4I_LTU_UNC(p1,p2,im,r3)     A8(0xd,3,0,p2,r3,im,1,p1)
+#define CMP4I_EQ_UNC(p1,p2,im,r3)      A8(0xe,3,0,p2,r3,im,1,p1)
+#define CMP4I_EQ_AND(p1,p2,im,r3)      A8(0xc,3,1,p2,r3,im,0,p1)
+#define CMP4I_EQ_OR(p1,p2,im,r3)       A8(0xd,3,1,p2,r3,im,0,p1)
+#define CMP4I_EQ_ANDCM(p1,p2,im,r3)    A8(0xe,3,1,p2,r3,im,0,p1)
+#define CMP4I_NE_AND(p1,p2,im,r3)      A8(0xc,3,1,p2,r3,im,1,p1)
+#define CMP4I_NE_OR(p1,p2,im,r3)       A8(0xd,3,1,p2,r3,im,1,p1)
+#define CMP4I_NE_ANDCM(p1,p2,im,r3)    A8(0xe,3,1,p2,r3,im,1,p1)
+#define ZCMP4_GT_AND(p1,p2,r3)         A7(0xc,1,0,p2,r3,0,p1)
+#define ZCMP4_GT_OR(p1,p2,r3)          A7(0xd,1,0,p2,r3,0,p1)
+#define ZCMP4_GT_ANDCM(p1,p2,r3)       A7(0xe,1,0,p2,r3,0,p1)
+#define ZCMP4_LE_AND(p1,p2,r3)         A7(0xc,1,0,p2,r3,1,p1)
+#define ZCMP4_LE_OR(p1,p2,r3)          A7(0xd,1,0,p2,r3,1,p1)
+#define ZCMP4_LE_ANDCM(p1,p2,r3)       A7(0xe,1,0,p2,r3,1,p1)
+#define ZCMP4_GE_AND(p1,p2,r3)         A7(0xc,1,1,p2,r3,0,p1)
+#define ZCMP4_GE_OR(p1,p2,r3)          A7(0xd,1,1,p2,r3,0,p1)
+#define ZCMP4_GE_ANDCM(p1,p2,r3)       A7(0xe,1,1,p2,r3,0,p1)
+#define ZCMP4_LT_AND(p1,p2,r3)         A7(0xc,1,1,p2,r3,1,p1)
+#define ZCMP4_LT_OR(p1,p2,r3)          A7(0xd,1,1,p2,r3,1,p1)
+#define ZCMP4_LT_ANDCM(p1,p2,r3)       A7(0xe,1,1,p2,r3,1,p1)
+/* cmpxchg */
+#define CMPXCHG1_ACQ(r1,r3,r2)         M16(0x00,LD_NONE,r3,r2,r1)
+#define CMPXCHG2_ACQ(r1,r3,r2)         M16(0x01,LD_NONE,r3,r2,r1)
+#define CMPXCHG4_ACQ(r1,r3,r2)         M16(0x02,LD_NONE,r3,r2,r1)
+#define CMPXCHG8_ACQ(r1,r3,r2)         M16(0x03,LD_NONE,r3,r2,r1)
+#define CMPXCHG1_REL(r1,r3,r2)         M16(0x04,LD_NONE,r3,r2,r1)
+#define CMPXCHG2_REL(r1,r3,r2)         M16(0x05,LD_NONE,r3,r2,r1)
+#define CMPXCHG4_REL(r1,r3,r2)         M16(0x06,LD_NONE,r3,r2,r1)
+#define CMPXCHG8_REL(r1,r3,r2)         M16(0x07,LD_NONE,r3,r2,r1)
+#define CMP8XCHG16_ACQ(r1,r3,r2)       M16(0x20,LD_NONE,r3,r2,r1)
+#define CMP8XCHG16_REL(r1,r3,r2)       M16(0x24,LD_NONE,r3,r2,r1)
+/* cover */
+#define COVER()                                B8(0x02)
+/* cxz */
+#define CZX1_L(r1,r3)                  I29(0x18,r3,r1)
+#define CZX2_L(r1,r3)                  I29(0x19,r3,r1)
+#define CZX1_R(r1,r3)                  I29(0x1c,r3,r1)
+#define CZX2_R(r1,r3)                  I29(0x1d,r3,r1)
+/* dep */
+#define DEP_Z(r1,r2,pos,len)           I12(len,pos,r2,r1)
+#define DEPI_Z(r1,im,pos,len)          I13(len,pos,im,r1)
+#define DEPs(r1,r2,r3,pos,len)         I14(1,len,r3,pos,r1)
+#define DEPu(r1,r2,r3,pos,len)         I14(0,len,r3,pos,r1)
+#define DEP(r1,r2,r3,pos,len)          I15(pos,len,r3,r2,r1)
+/* epc */
+#define EPC()                          B8(0x10)
+/* extr */
+#define EXTR(r1,r3,pos,len)            I11(len,r3,pos,1,r1)
+#define EXTR_U(r1,r3,pos,len)          I11(len,r3,pos,0,r1)
+/* fc */
+#define FC(r3)                         M28(0,r3)
+#define FC_I(r3)                       M28(1,r3)
+/* fetchadd */
+#define FETCHADD4_ACQ(r1,r3,im)                M17(0x12,LD_NONE,r3,im,r1)
+#define FETCHADD8_ACQ(r1,r3,im)                M17(0x13,LD_NONE,r3,im,r1)
+#define FETCHADD4_REL(r1,r3,im)                M17(0x16,LD_NONE,r3,im,r1)
+#define FETCHADD8_REL(r1,r3,im)                M17(0x17,LD_NONE,r3,im,r1)
+/* flushrs */
+#define FLUSHRS()                      M25(0xc)
+/* fwb */
+#define FWB()                          M24(2,0)
+/* hint */
+#define HINT_I(im)                     I18(im,1)
+#define HINT_M(im)                     M48(1,im)
+#define HINT_B(im)                     B9(2,1,im)
+#define HINT_X(im)                     X5(1,im)
+/* invala */
+#define INVALA()                       M24(1,0)
+#define INVALA_E(r1)                   M26(r1)
+/* itc */
+#define ITC_I(r2)                      M41(0x2f,r2)
+#define ITC_D(r2)                      M41(0x2e,r2)
+/* itr */
+#define ITR_I(r3,r2)                   M42(0x0f,r3,r2)
+#define ITR_D(r3,r2)                   M42(0x0e,r3,r2)
+/* ld */
+#define LD1(r1,r3)                     M1(0x00,LD_NONE,0,r3,r1)
+#define LD2(r1,r3)                     M1(0x01,LD_NONE,0,r3,r1)
+#define LD4(r1,r3)                     M1(0x02,LD_NONE,0,r3,r1)
+#define LD8(r1,r3)                     M1(0x03,LD_NONE,0,r3,r1)
+#define LD1_S(r1,r3)                   M1(0x04,LD_NONE,0,r3,r1)
+#define LD2_S(r1,r3)                   M1(0x05,LD_NONE,0,r3,r1)
+#define LD4_S(r1,r3)                   M1(0x06,LD_NONE,0,r3,r1)
+#define LD8_S(r1,r3)                   M1(0x07,LD_NONE,0,r3,r1)
+#define LD1_A(r1,r3)                   M1(0x08,LD_NONE,0,r3,r1)
+#define LD2_A(r1,r3)                   M1(0x09,LD_NONE,0,r3,r1)
+#define LD4_A(r1,r3)                   M1(0x0a,LD_NONE,0,r3,r1)
+#define LD8_A(r1,r3)                   M1(0x0b,LD_NONE,0,r3,r1)
+#define LD1_SA(r1,r3)                  M1(0x0c,LD_NONE,0,r3,r1)
+#define LD2_SA(r1,r3)                  M1(0x0d,LD_NONE,0,r3,r1)
+#define LD4_SA(r1,r3)                  M1(0x0e,LD_NONE,0,r3,r1)
+#define LD8_SA(r1,r3)                  M1(0x0f,LD_NONE,0,r3,r1)
+#define LD1_BIAS(r1,r3)                        M1(0x10,LD_NONE,0,r3,r1)
+#define LD2_BIAS(r1,r3)                        M1(0x11,LD_NONE,0,r3,r1)
+#define LD4_BIAS(r1,r3)                        M1(0x12,LD_NONE,0,r3,r1)
+#define LD8_BIAS(r1,r3)                        M1(0x13,LD_NONE,0,r3,r1)
+#define LD1_ACQ(r1,r3)                 M1(0x14,LD_NONE,0,r3,r1)
+#define LD2_ACQ(r1,r3)                 M1(0x15,LD_NONE,0,r3,r1)
+#define LD4_ACQ(r1,r3)                 M1(0x16,LD_NONE,0,r3,r1)
+#define LD8_ACQ(r1,r3)                 M1(0x17,LD_NONE,0,r3,r1)
+#define LD8_FILL(r1,r3)                        M1(0x1b,LD_NONE,0,r3,r1)
+#define LD1_C_CLR(r1,r3)               M1(0x20,LD_NONE,0,r3,r1)
+#define LD2_C_CLR(r1,r3)               M1(0x21,LD_NONE,0,r3,r1)
+#define LD4_C_CLR(r1,r3)               M1(0x22,LD_NONE,0,r3,r1)
+#define LD8_C_CLR(r1,r3)               M1(0x23,LD_NONE,0,r3,r1)
+#define LD1_C_NC(r1,r3)                        M1(0x24,LD_NONE,0,r3,r1)
+#define LD2_C_NC(r1,r3)                        M1(0x25,LD_NONE,0,r3,r1)
+#define LD4_C_NC(r1,r3)                        M1(0x26,LD_NONE,0,r3,r1)
+#define LD8_C_NC(r1,r3)                        M1(0x27,LD_NONE,0,r3,r1)
+#define LD1_C_CLR_ACQ(r1,r3)           M1(0x28,LD_NONE,0,r3,r1)
+#define LD2_C_CLR_ACQ(r1,r3)           M1(0x29,LD_NONE,0,r3,r1)
+#define LD4_C_CLR_ACQ(r1,r3)           M1(0x2a,LD_NONE,0,r3,r1)
+#define LD8_C_CLR_ACQ(r1,r3)           M1(0x2b,LD_NONE,0,r3,r1)
+#define LD16(r1,r3)                    M1(0x28,LD_NONE,1,r3,r1)
+#define LD16_ACQ(r1,r3)                        M1(0x2c,LD_NONE,1,r3,r1)
+#define LD1_inc(r1,r3,im)              M3(0x00,LD_NONE,r3,im,r1)
+#define LD2_inc(r1,r3,im)              M3(0x01,LD_NONE,r3,im,r1)
+#define LD4_inc(r1,r3,im)              M3(0x02,LD_NONE,r3,im,r1)
+#define LD8_inc(r1,r3,im)              M3(0x03,LD_NONE,r3,im,r1)
+#define LD1_S_inc(r1,r3,im)            M3(0x04,LD_NONE,r3,im,r1)
+#define LD2_S_inc(r1,r3,im)            M3(0x05,LD_NONE,r3,im,r1)
+#define LD4_S_inc(r1,r3,im)            M3(0x06,LD_NONE,r3,im,r1)
+#define LD8_S_inc(r1,r3,im)            M3(0x07,LD_NONE,r3,im,r1)
+#define LD1_A_inc(r1,r3,im)            M3(0x08,LD_NONE,r3,im,r1)
+#define LD2_A_inc(r1,r3,im)            M3(0x09,LD_NONE,r3,im,r1)
+#define LD4_A_inc(r1,r3,im)            M3(0x0a,LD_NONE,r3,im,r1)
+#define LD8_A_inc(r1,r3,im)            M3(0x0b,LD_NONE,r3,im,r1)
+#define LD1_SA_inc(r1,r3,im)           M3(0x0c,LD_NONE,r3,im,r1)
+#define LD2_SA_inc(r1,r3,im)           M3(0x0d,LD_NONE,r3,im,r1)
+#define LD4_SA_inc(r1,r3,im)           M3(0x0e,LD_NONE,r3,im,r1)
+#define LD8_SA_inc(r1,r3,im)           M3(0x0f,LD_NONE,r3,im,r1)
+#define LD1_BIAS_inc(r1,r3,im)         M3(0x10,LD_NONE,r3,im,r1)
+#define LD2_BIAS_inc(r1,r3,im)         M3(0x11,LD_NONE,r3,im,r1)
+#define LD4_BIAS_inc(r1,r3,im)         M3(0x12,LD_NONE,r3,im,r1)
+#define LD8_BIAS_inc(r1,r3,im)         M3(0x13,LD_NONE,r3,im,r1)
+#define LD1_ACQ_inc(r1,r3,im)          M3(0x14,LD_NONE,r3,im,r1)
+#define LD2_ACQ_inc(r1,r3,im)          M3(0x15,LD_NONE,r3,im,r1)
+#define LD4_ACQ_inc(r1,r3,im)          M3(0x16,LD_NONE,r3,im,r1)
+#define LD8_AVQ_inc(r1,r3,im)          M3(0x17,LD_NONE,r3,im,r1)
+#define LD8_FILL_inc(r1,r3,im)         M3(0x1b,LD_NONE,r3,im,r1)
+#define LD1_C_CLR_inc(r1,r3,im)                M3(0x20,LD_NONE,r3,im,r1)
+#define LD2_C_CLR_inc(r1,r3,im)                M3(0x21,LD_NONE,r3,im,r1)
+#define LD4_C_CLR_inc(r1,r3,im)                M3(0x22,LD_NONE,r3,im,r1)
+#define LD8_C_CLR_inc(r1,r3,im)                M3(0x23,LD_NONE,r3,im,r1)
+#define LD1_C_NC_inc(r1,r3,im)         M3(0x24,LD_NONE,r3,im,r1)
+#define LD2_C_NC_inc(r1,r3,im)         M3(0x25,LD_NONE,r3,im,r1)
+#define LD4_C_NC_inc(r1,r3,im)         M3(0x26,LD_NONE,r3,im,r1)
+#define LD8_C_NC_inc(r1,r3,im)         M3(0x27,LD_NONE,r3,im,r1)
+#define LD1_C_CLR_ACQ_inc(r1,r3,im)    M3(0x28,LD_NONE,r3,im,r1)
+#define LD2_C_CLR_ACQ_inc(r1,r3,im)    M3(0x29,LD_NONE,r3,im,r1)
+#define LD4_C_CLR_ACQ_inc(r1,r3,im)    M3(0x2a,LD_NONE,r3,im,r1)
+#define LD8_C_CLR_ACQ_inc(r1,r3,im)    M3(0x2b,LD_NONE,r3,im,r1)
+#define LDX1(r1,r3,r2)                 M2(0x00,LD_NONE,r3,r2,r1)
+#define LDX2(r1,r3,r2)                 M2(0x01,LD_NONE,r3,r2,r1)
+#define LDX4(r1,r3,r2)                 M2(0x02,LD_NONE,r3,r2,r1)
+#define LDX8(r1,r3,r2)                 M2(0x03,LD_NONE,r3,r2,r1)
+#define LDX1_S(r1,r3,r2)               M2(0x04,LD_NONE,r3,r2,r1)
+#define LDX2_S(r1,r3,r2)               M2(0x05,LD_NONE,r3,r2,r1)
+#define LDX4_S(r1,r3,r2)               M2(0x06,LD_NONE,r3,r2,r1)
+#define LDX8_S(r1,r3,r2)               M2(0x07,LD_NONE,r3,r2,r1)
+#define LDX1_A(r1,r3,r2)               M2(0x08,LD_NONE,r3,r2,r1)
+#define LDX2_A(r1,r3,r2)               M2(0x09,LD_NONE,r3,r2,r1)
+#define LDX4_A(r1,r3,r2)               M2(0x0a,LD_NONE,r3,r2,r1)
+#define LDX8_A(r1,r3,r2)               M2(0x0b,LD_NONE,r3,r2,r1)
+#define LDX1_SA(r1,r3,r2)              M2(0x0c,LD_NONE,r3,r2,r1)
+#define LDX2_SA(r1,r3,r2)              M2(0x0d,LD_NONE,r3,r2,r1)
+#define LDX4_SA(r1,r3,r2)              M2(0x0e,LD_NONE,r3,r2,r1)
+#define LDX8_SA(r1,r3,r2)              M2(0x0f,LD_NONE,r3,r2,r1)
+#define LDX1_BIAS(r1,r3,r2)            M2(0x10,LD_NONE,r3,r2,r1)
+#define LDX2_BIAS(r1,r3,r2)            M2(0x11,LD_NONE,r3,r2,r1)
+#define LDX4_BIAS(r1,r3,r2)            M2(0x12,LD_NONE,r3,r2,r1)
+#define LDX8_BIAS(r1,r3,r2)            M2(0x13,LD_NONE,r3,r2,r1)
+#define LDX1_ACQ(r1,r3,r2)             M2(0x14,LD_NONE,r3,r2,r1)
+#define LDX2_ACQ(r1,r3,r2)             M2(0x15,LD_NONE,r3,r2,r1)
+#define LDX4_ACQ(r1,r3,r2)             M2(0x16,LD_NONE,r3,r2,r1)
+#define LDX8_ACQ(r1,r3,r2)             M2(0x17,LD_NONE,r3,r2,r1)
+#define LDX8_FILL(r1,r3,r2)            M2(0x1b,LD_NONE,r3,r2,r1)
+#define LDX1_C_CLR(r1,r3,r2)           M2(0x20,LD_NONE,r3,r2,r1)
+#define LDX2_C_CLR(r1,r3,r2)           M2(0x21,LD_NONE,r3,r2,r1)
+#define LDX4_C_CLR(r1,r3,r2)           M2(0x22,LD_NONE,r3,r2,r1)
+#define LDX8_C_CLR(r1,r3,r2)           M2(0x23,LD_NONE,r3,r2,r1)
+#define LDX1_C_NC(r1,r3,r2)            M2(0x24,LD_NONE,r3,r2,r1)
+#define LDX2_C_NC(r1,r3,r2)            M2(0x25,LD_NONE,r3,r2,r1)
+#define LDX4_C_NC(r1,r3,r2)            M2(0x26,LD_NONE,r3,r2,r1)
+#define LDX8_C_NC(r1,r3,r2)            M2(0x27,LD_NONE,r3,r2,r1)
+#define LDX1_C_CLR_ACQ(r1,r3,r2)       M2(0x28,LD_NONE,r3,r2,r1)
+#define LDX2_C_CLR_ACQ(r1,r3,r2)       M2(0x29,LD_NONE,r3,r2,r1)
+#define LDX4_C_CLR_ACQ(r1,r3,r2)       M2(0x2a,LD_NONE,r3,r2,r1)
+#define LDX8_C_CLR_ACQ(r1,r3,r2)       M2(0x2b,LD_NONE,r3,r2,r1)
+/* lfetch */
+#define LFETCH_EXCL(r3)                        M13(0x2d,LF_NONE,r3,GR_0)
+#define LFETCH_FAULT(r3)               M13(0x2e,LF_NONE,r3,GR_0)
+#define LFETCH_FAULT_EXCL(r3)          M13(0x2f,LF_NONE,r3,GR_0)
+#define LXFETCH(r3,r2)                 M14(0x2c,LF_NONE,r3,r2)
+#define LXFETCH_EXCL(r3,r2)            M14(0x2d,LF_NONE,r3,r2)
+#define LXFETCH_FAULT(r3,r2)           M14(0x2e,LF_NONE,r3,r2)
+#define LXFETCH_FAULT_EXCL(r3,r2)      M14(0x2f,LF_NONE,r3,r2)
+#define LFETCHI(r3,im)                 M15(0x2c,LF_NONE,r3,im)
+#define LFETCHI_EXCL(r3,im)            M15(0x2d,LF_NONE,r3,im)
+#define LFETCHI_FAULT(r3,im)           M15(0x2e,LF_NONE,r3,im)
+#define LFETCHI_FAULT_EXCL(r3,im)      M15(0x2f,LF_NONE,r3,im)
+/* loadrs */
+#define LOADRS()                       M25(0xa)
+/* mf */
+#define MF()                           M24(2,2)
+#define MF_A()                         M24(2,3)
+/* mix */
+#define MIX1_R(r1,r2,r3)               I2(0,2,0,2,0,r3,r2,r1)
+#define MIX2_R(r1,r2,r3)               I2(0,2,1,2,0,r3,r2,r1)
+#define MIX4_R(r1,r2,r3)               I2(1,2,0,2,0,r3,r2,r1)
+#define MIX1_L(r1,r2,r3)               I2(0,2,0,2,2,r3,r2,r1)
+#define MIX2_L(r1,r2,r3)               I2(0,2,1,2,2,r3,r2,r1)
+#define MIX4_L(r1,r2,r3)               I2(1,2,0,2,2,r3,r2,r1)
+/* mov - Move Application Register */
+#define MOV_I_rn_ar(r1,ar)             I28(ar,r1)
+#define MOV_I_ar_rn(ar,r2)             I26(ar,r2)
+#define MOV_I_ar_im(ar,im)             I27(ar,im)
+#define MOV_M_rn_a(r1,ar)              M31(r1,ar)
+#define MOV_M_ar_rn(ar,r2)             M29(ar,r2)
+#define MOV_M_ar_im(ar,im)             M30(ar,im)
+/* mov - Move Branch Register */
+#define MOV_rn_br(r1,b2)               I22(b2,r1)
+#define MOV_br_rn_tg(b1,r2,tag)                I21(tag,IH_NONE,0,MWH_NONE,r2,b1)
+#define MOV_br_rn(b1,r2)               MOV_br_rn_tg(b1,r2,0)
+#define MOV_RET_br_rn_tg(b1,r2,tag)    I21(tag,IH_NONE,1,MWH_NONE,r2,b1)
+/* mov - Move Control Register */
+#define MOV_rn_cr(cr,r1)               M33(cr,r1)
+#define MOV_cr_rr(cr,r2)               M32(cr,r2)
+/* mov - Move General Register */
+#define MOV(r0,r1)                     ADDS(r0,0,r1)
+#define MOV_p(r0,r1,_p)                        ADDS_p(r0,0,r1,_p)
+/* mov - Move Immediate */
+#define MOVI(r1,im)                    ADDL(r1,im,GR_0)
+#define MOVI_p(r1,im,_p)               ADDL_p(r1,im,GR_0,_p)
+/* mov - Move Indirect Register */
+#define MOV_rn_RR(r1,r3)               M43(0x10,r3,r1)
+#define MOV_rn_DBR(r1,r3)              M43(0x11,r3,r1)
+#define MOV_rn_IBR(r1,r3)              M43(0x012,r3,r1)
+#define MOV_rn_PKR(r1,r3)              M43(0x13,r3,r1)
+#define MOV_rn_PMC(r1,r3)              M43(0x14,r3,r1)
+#define MOV_rn_PMD(r1,r3)              M43(0x15,r3,r1)
+#define MOV_rn_CPUID(r1,r3)            M43(0x17,r3,r1)
+#define MOV_RR_rn(r3,r2)               M42(0x00,r3,r2)
+#define MOV_DBR_rn(r3,r2)              M42(0x01,r3,r2)
+#define MOV_IBR_rn(r3,r2)              M42(0x02,r3,r2)
+#define MOV_PKR_rn(r3,r2)              M42(0x03,r3,r2)
+#define MOV_PMC_rn(r3,r2)              M42(0x04,r3,r2)
+#define MOV_PMD_rn(r3,r2)              M42(0x05,r3,r2)
+/* mov - Move Instruction Pointer */
+#define MOV_rn_ip(r1)                  I25(0x30,r1)
+/* mov - Move Predicates */
+#define MOV_rn_pr(r1)                  I25(0x33,r1)
+#define MOV_pr_rn(r2,im)               I23(r2,im)
+#define MOVI_pr(im)                    I24(im)
+/* mov - Move Processor Status Register */
+#define MOV_rn_psr(r1)                 M36(0x25,r1)
+#define MOV_psr_l_rn(r2)               M35(0x2d,r2)
+/* mov - Move User Mask */
+#define MOV_rn_psr_um(r1)              M36(0x21,r1)
+#define MOV_psr_um_rn(r2)              M35(0x29,r2)
+/* movl */
+#define MOVL(r1,im)                    X2(r1,im)
+/* mpy4 */
+#define MPY4(r1,r2,r3)                 I2(1,0,0,3,1,r3,r2,r1)
+/* mpyshl4 */
+#define MPYSHL4(r1,r2,r3)              I2(1,0,0,3,3,r3,r2,r1)
+/* mux */
+#define MUX1(r1,r2,mbt)                        I3(mbt,r2,r1)
+#define MUX2(r1,r2,mht)                        I4(mht,r2,r1)
+/* nop */
+#define NOP_I(im)                      I18(im,0)
+#define NOP_M(im)                      M48(0,im)
+#define NOP_B(im)                      B9(2,0,im)
+#define NOP_X(im)                      X5(0,im)
+/* or */
+#define OR(r1,r2,r3)                   A1(3,2,r3,r2,r1)
+#define ORI(r1,im,r3)                  A3(0xb,2,r3,im,r1)
+/* pack */
+#define PACK2_USS(r1,r2,r3)            I2(0,2,1,0,0,r3,r2,r1)
+#define PACK2_SSS(r1,r2,r3)            I2(0,2,1,0,2,r3,r2,r1)
+#define PACK4_SSS(r1,r2,r3)            I2(1,2,0,0,2,r3,r2,r1)
+/* padd */
+#define PADD1(r1,r2,r3)                        A9(0,0,0,0,r3,r2,r1)
+#define PADD1_SSS(r1,r2,r3)            A9(0,0,0,1,r3,r2,r1)
+#define PADD1_UUU(r1,r2,r3)            A9(0,0,0,2,r3,r2,r1)
+#define PADD1_UUS(r1,r2,r3)            A9(0,0,0,3,r3,r2,r1)
+#define PADD2(r1,r2,r3)                        A9(0,1,0,0,r3,r2,r1)
+#define PADD2_SSS(r1,r2,r3)            A9(0,1,0,1,r3,r2,r1)
+#define PADD2_UUU(r1,r2,r3)            A9(0,1,0,2,r3,r2,r1)
+#define PADD2_UUS(r1,r2,r3)            A9(0,1,0,3,r3,r2,r1)
+#define PADD4(r1,r2,r3)                        A9(1,0,0,0,r3,r2,r1)
+/* pavg */
+#define PAVG1(r1,r2,r3)                        A9(0,0,2,2,r3,r2,r1)
+#define PAVG2(r1,r2,r3)                        A9(0,1,2,2,r3,r2,r1)
+#define PAVG1_RAZ(r1,r2,r3)            A9(0,0,2,3,r3,r2,r1)
+#define PAVG2_RAZ(r1,r2,r3)            A9(0,1,2,3,r3,r2,r1)
+/* pavgsub */
+#define PAVGSUB1(r1,r2,r3)             A9(0,0,3,2,r3,r2,r1)
+#define PAVGSUB2(r1,r2,r3)             A9(0,1,3,2,r3,r2,r1)
+/* pcmp */
+#define PCMP1_EQ(r1,r2,r3)             A9(0,0,9,0,r3,r2,r1)
+#define PCMP2_EQ(r1,r2,r3)             A9(0,1,9,0,r3,r2,r1)
+#define PCMP4_EQ(r1,r2,r3)             A9(1,0,9,0,r3,r2,r1)
+#define PCMP1_GT(r1,r2,r3)             A9(0,0,9,1,r3,r2,r1)
+#define PCMP2_GT(r1,r2,r3)             A9(0,1,9,1,r3,r2,r1)
+#define PCMP4_GT(r1,r2,r3)             A9(1,0,9,1,r3,r2,r1)
+/* pmax */
+#define PMAX1_U(r1,r2,r3)              I2(0,2,0,1,1,r3,r2,r1)
+#define PMAX2(r1,r2,r3)                        I2(0,2,1,1,3,r3,r2,r1)
+/* pmin */
+#define PMIN1_U(r1,r2,r3)              I2(0,2,0,0,1,r3,r2,r1)
+#define PMIN2(r1,r2,r3)                        I2(0,2,1,0,3,r3,r2,r1)
+/* pmpy */
+#define PMPY2_R(r1,r2,r3)              I2(0,2,1,3,1,r3,r2,r1)
+#define PMPY2_L(r1,r2,r3)              I2(0,2,1,3,3,r3,r2,r1)
+/* pmpyshr */
+#define PMPYSHR2(r1,r2,r3,im)          I1(im,3,r3,r2,r1)
+#define PMPYSHR2_U(r1,r2,r3,im)                I1(im,1,r3,r2,r1)
+/* popcnt */
+#define POPCNT(r1,r3)                  I9(2,r3,r1)
+/* probe */
+#define PROBE_R(r1,r3,r2)              M38(0x38,r3,r2,r1)
+#define PROBE_W(r1,r3,r2)              M38(0x39,r3,r2,r1)
+#define PROBEI_R(r1,r3,im)             M39(0x18,r3,im,r1)
+#define PROBEI_W(r1,r3,im)             M39(0x19,r3,im,r1)
+#define PROBE_RW_FAULT(r3,im)          M40(0x31,r3,im)
+#define PROBE_R_FAULT(r3,im)           M40(0x32,r3,im)
+#define PROBE_W_FAULT(r3,im)           M40(0x33,r3,im)
+/* psad */
+#define PSAD1(r1,r2,r3)                        I2(0,2,0,2,3,r3,r2,r1)
+/* pshl */
+#define PSHL2(r1,r2,r3)                        I7(0,1,r3,r2,r1)
+#define PSHL4(r1,r2,r3)                        I7(1,0,r3,r2,r1)
+#define PSHL2I(r1,r2,im)               I8(0,1,im,r2,r1)
+#define PSHL4I(r1,r2,im)               I8(1,0,im,r2,r1)
+/* pshladd */
+#define PSHLADD2(r1,r2,im,r3)          A10(4,im,r3,r2,r1)
+/* pshr */
+#define PSHR2(r1,r3,r2)                        I5(0,1,2,r3,r2,r1)
+#define PSHR2I(r1,r3,im)               I6(0,1,3,r3,im,r1)
+#define PSHR2_U(r1,r3,r2)              I5(0,1,0,r3,r2,r1)
+#define PSHR2I_U(r1,r3,im)             I6(0,1,1,r3,im,r1)
+#define PSHR4(r1,r3,r2)                        I5(1,0,2,r3,r2,r1)
+#define PSHR4I(r1,r3,im)               I6(1,0,3,r3,im,r1)
+#define PSHR4_U(r1,r3,r2)              I5(1,0,0,r3,r2,r1)
+#define PSHR4I_U(r1,r3,im)             I6(1,0,1,r3,im,r1)
+/* pshradd */
+#define PSHRADD2(r1,r2,im,r3)          A10(6,im,r3,r2,r1)
+/* psub */
+#define PSUB1(r1,r2,r3)                        A9(0,0,1,0,r3,r2,r1)
+#define PSUB1_SSS(r1,r2,r3)            A9(0,0,1,1,r3,r2,r1)
+#define PSUB1_UUU(r1,r2,r3)            A9(0,0,1,2,r3,r2,r1)
+#define PSUB1_UUS(r1,r2,r3)            A9(0,0,1,3,r3,r2,r1)
+#define PSUB2(r1,r2,r3)                        A9(0,1,1,0,r3,r2,r1)
+#define PSUB2_SSS(r1,r2,r3)            A9(0,1,1,1,r3,r2,r1)
+#define PSUB2_UUU(r1,r2,r3)            A9(0,1,1,2,r3,r2,r1)
+#define PSUB2_UUS(r1,r2,r3)            A9(0,1,1,3,r3,r2,r1)
+#define PSUB4(r1,r2,r3)                        A9(1,0,1,0,r3,r2,r1)
+/* ptc.e */
+#define PTC_E(r3)                      M47(0x34,r3)
+/* ptc.g, ptc.ga */
+#define PTC_G(r3,r2)                   M45(0xa,r3,r2)
+#define PTC_GA(r3,r2)                  M45(0xb,r3,r2)
+/* ptc.l */
+#define PTC_L(r3,r2)                   M45(0x9,r3,r2)
+/* ptr */
+#define PTR_D(r3,r2)                   M45(0xc,r3,r2)
+#define PTR_I(r3,r2)                   M45(0xd,r3,r2)
+/* rfi */
+#define RFI()                          B8(0x08)
+/* rsm */
+#define RSM(im)                                M44(7,im)
+/* rum */
+#define RUM(im)                                M44(5,im)
+/* shl */
+#define SHL(r1,r2,r3)                  I7(1,1,r3,r2,r1)
+/* shladd */
+#define SHLADD(r1,r2,im,r3)            A2(4,im,r3,r2,r1)
+/* shladdp4 */
+#define SHLADDP4(r1,r2,im,r3)          A2(6,im,r3,r2,r1)
+/* shr */
+#define SHR(r1,r3,r2)                  I5(1,1,2,r3,r2,r1)
+#define SHR_U(r1,r3,r2)                        I5(1,1,0,r3,r2,r1)
+/* shrp */
+#define SHRP(r1,r2,r3,im)              I10(im,r3,r2,r1)
+/* srlz */
+#define SRLZ_I()                       M24(3,1)
+#define SRLZ_D()                       M24(3,0)
+/* ssm */
+#define SSM(im)                                M44(6,im)
+/* st */
+#define ST1(r3,r2)                     M6(0x30,ST_NONE,0,r3,r2)
+#define ST2(r3,r2)                     M6(0x31,ST_NONE,0,r3,r2)
+#define ST4(r3,r2)                     M6(0x32,ST_NONE,0,r3,r2)
+#define ST8(r3,r2)                     M6(0x33,ST_NONE,0,r3,r2)
+#define ST1_REL(r3,r2)                 M6(0x34,ST_NONE,0,r3,r2)
+#define ST2_REL(r3,r2)                 M6(0x35,ST_NONE,0,r3,r2)
+#define ST4_REL(r3,r2)                 M6(0x36,ST_NONE,0,r3,r2)
+#define ST8_REL(r3,r2)                 M6(0x37,ST_NONE,0,r3,r2)
+#define ST8_SPILL(r3,r2)               M6(0x3b,ST_NONE,0,r3,r2)
+#define ST16(r3,r2)                    M6(0x30,ST_NONE,1,r3,r2)
+#define ST16_REL(r3,r2)                        M6(0x34,ST_NONE,1,r3,r2)
+#define ST1_inc(r3,r2,im)              M5(0x30,ST_NONE,r3,r2,im)
+#define ST2_inc(r3,r2,im)              M5(0x31,ST_NONE,r3,r2,im)
+#define ST4_inc(r3,r2,im)              M5(0x32,ST_NONE,r3,r2,im)
+#define ST8_inc(r3,r2,im)              M5(0x33,ST_NONE,r3,r2,im)
+#define ST1_REL_inc(r3,r2,im)          M5(0x34,ST_NONE,r3,r2,im)
+#define ST2_REL_inc(r3,r2,im)          M5(0x35,ST_NONE,r3,r2,im)
+#define ST4_REL_inc(r3,r2,im)          M5(0x36,ST_NONE,r3,r2,im)
+#define ST8_REL_inc(r3,r2,im)          M5(0x37,ST_NONE,r3,r2,im)
+#define ST8_SPILL_inc(r3,r2,im)                M5(0x3b,ST_NONE,r3,r2,im)
+/* sub */
+#define SUB(r1,r2,r3)                  A1(1,1,r3,r2,r1)
+#define SUB1(r1,r2,r3)                 A1(1,0,r3,r2,r1)
+#define SUBI(r1,im,r3)                 A3(9,1,r3,im,r1)
+/* sum */
+#define SUM(im)                                M44(4,im)
+/* sxt */
+#define SXT1(r1,r3)                    I29(0x14,r3,r1)
+#define SXT2(r1,r3)                    I29(0x15,r3,r1)
+#define SXT4(r1,r3)                    I29(0x16,r3,r1)
+/* sync */
+#define SYNC_I()                       M24(3,3)
+/* tak */
+#define TAK(r1,r3)                     M46(0x1f,r3,r1)
+/* tbit */
+#define TBIT_Z(p1,p2,r3,pos)           I16(0,0,p2,r3,pos,0,p1)
+#define TBIT_Z_UNC(p1,p2,r3,pos)       I16(0,0,p2,r3,pos,1,p1)
+#define TBIT_Z_AND(p1,p2,r3,pos)       I16(1,0,p2,r3,pos,0,p1)
+#define TBIT_NZ_AND(p1,p2,r3,pos)      I16(1,0,p2,r3,pos,1,p1)
+#define TBIT_Z_OR(p1,p2,r3,pos)                I16(0,1,p2,r3,pos,0,p1)
+#define TBIT_NZ_OR(p1,p2,r3,pos)       I16(0,1,p2,r3,pos,1,p1)
+#define TBIT_Z_ANDCM(p1,p2,r3,pos)     I16(1,1,p2,r3,pos,0,p1)
+#define TBIT_NZ_ANDCM(p1,p2,r3,pos)    I16(1,1,p2,r3,pos,1,p1)
+/* tf */
+#define TF_Z(p1,p2,im)                 I30(0,0,p2,im,0,p1)
+#define TF_Z_UNC(p1,p2,im)             I30(0,0,p2,im,1,p1)
+#define TF_Z_AND(p1,p2,im)             I30(1,0,p2,im,0,p1)
+#define TF_NZ_AND(p1,p2,im)            I30(1,0,p2,im,1,p1)
+#define TF_Z_OR(p1,p2,im)              I30(0,1,p2,im,0,p1)
+#define TF_NZ_OR(p1,p2,im)             I30(0,1,p2,im,1,p1)
+#define TF_Z_ANDCM(p1,p2,im)           I30(1,1,p2,im,0,p1)
+#define TF_NZ_ANDCM(p1,p2,im)          I30(1,1,p2,im,1,p1)
+/* thash */
+#define THASH(r1,r3)                   M46(0x1a,r3,r1)
+/* tnat */
+#define TNAT_Z(p1,p2,r3)               I17(0,0,p2,r3,0,p1)
+#define TNAT_Z_UNC(p1,p2,r3)           I17(0,0,p2,r3,1,p1)
+#define TNAT_Z_AND(p1,p2,r3)           I17(1,0,p2,r3,0,p1)
+#define TNAT_NZ_AND(p1,p2,r3)          I17(1,0,p2,r3,1,p1)
+#define TNAT_Z_OR(p1,p2,r3)            I17(0,1,p2,r3,0,p1)
+#define TNAT_NZ_OR(p1,p2,r3)           I17(0,1,p2,r3,1,p1)
+#define TNAT_Z_ANDCM(p1,p2,r3)         I17(1,1,p2,r3,0,p1)
+#define TNAT_NZ_ANDCM(p1,p2,r3)                I17(1,1,p2,r3,1,p1)
+/* tpa */
+#define TPA(r1,r3)                     M46(0x1e,r3,r1)
+/* ttag */
+#define TTAG(r1,r3)                    M46(0x1b,r3,r1)
+/* unpack */
+#define UNPACK1_H(r1,r2,r3)            I2(0,2,0,1,0,r3,r2,r1)
+#define UNPACK2_H(r1,r2,r3)            I2(0,2,1,1,0,r3,r2,r1)
+#define UNPACK4_H(r1,r2,r3)            I2(1,2,0,1,0,r3,r2,r1)
+#define UNPACK1_L(r1,r2,r3)            I2(0,2,0,1,2,r3,r2,r1)
+#define UNPACK2_L(r1,r2,r3)            I2(0,2,1,1,2,r3,r2,r1)
+#define UNPACK4_L(r1,r2,r3)            I2(1,2,0,1,2,r3,r2,r1)
+/* vmsw */
+#define VMSW_0()                       B8(0x18)
+#define VMSW_1()                       B8(0x19)
+/* xchg */
+#define XCHG1_ACQ(r1,r3,r2)            M16(0x08,LD_NONE,r3,r2,r1)
+#define XCHG2_ACQ(r1,r3,r2)            M16(0x09,LD_NONE,r3,r2,r1)
+#define XCHG4_ACQ(r1,r3,r2)            M16(0x0a,LD_NONE,r3,r2,r1)
+#define XCHG8_ACQ(r1,r3,r2)            M16(0x0b,LD_NONE,r3,r2,r1)
+/* xor */
+#define XOR(r1,r2,r3)                  A1(3,3,r3,r2,r1)
+#define XORI(r1,im,r3)                 A3(0xb,3,r3,im,r1)
+/* zxt */
+#define ZXT1(r1,r3)                    I29(0x10,r3,r1)
+#define ZXT2(r1,r3)                    I29(0x11,r3,r1)
+#define ZXT4(r1,r3)                    I29(0x12,r3,r1)
+
+#define addr(r0,r1,r2)                 ADD(r0,r1,r2)
+#define addi(r0,r1,i0)                 _addi(_jit,r0,r1,i0)
+static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define addcr(r0, r1, r2)              _addcr(_jit, r0, r1, r2)
+static void _addcr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#define addci(r0, r1, i0)              _addci(_jit, r0, r1, i0)
+static void _addci(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define addxr(r0, r1, r2)            _addxr(_jit, r0, r1, r2)
+static void _addxr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define addxi(r0, r1, i0)            _addxi(_jit, r0, r1, i0)
+static void _addxi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#define subr(r0,r1,r2)                 SUB(r0,r1,r2)
+#define subi(r0,r1,i0)                 _subi(_jit,r0,r1,i0)
+static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subcr(r0, r1, r2)            _subcr(_jit, r0, r1, r2)
+static void _subcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subci(r0, r1, i0)            _subci(_jit, r0, r1, i0)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subxr(r0, r1, r2)            _subxr(_jit, r0, r1, r2)
+static void _subxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subxi(r0, r1, i0)            _subxi(_jit, r0, r1, i0)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rsbi(r0, r1, i0)             _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define mulr(r0,r1,r2)                 _mulr(_jit,r0,r1,r2)
+static void _mulr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define muli(r0,r1,i0)                 _muli(_jit,r0,r1,i0)
+static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define divr(r0,r1,r2)                 _divr(_jit,r0,r1,r2)
+static void _divr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define divi(r0,r1,i0)                 _divi(_jit,r0,r1,i0)
+static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define divr_u(r0,r1,r2)               _divr_u(_jit,r0,r1,r2)
+static void _divr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define divi_u(r0,r1,i0)               _divi_u(_jit,r0,r1,i0)
+static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define remr(r0,r1,r2)                 _remr(_jit,r0,r1,r2)
+static void _remr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define remi(r0,r1,i0)                 _remi(_jit,r0,r1,i0)
+static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define remr_u(r0,r1,r2)               _remr_u(_jit,r0,r1,r2)
+static void _remr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define remi_u(r0,r1,i0)               _remi_u(_jit,r0,r1,i0)
+static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define mulh(r0,r1,r2,sign)            _mulh(_jit,r0,r1,r2,sign)
+static void _mulh(jit_state_t*,jit_bool_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define qmulr(r0,r1,r2,r3)             iqmulr(r0,r1,r2,r3,1)
+#define qmulr_u(r0,r1,r2,r3)           iqmulr(r0,r1,r2,r3,0)
+#define iqmulr(r0,r1,r2,r3,sign)       _iqmulr(_jit,r0,r1,r2,r3,sign)
+static void _iqmulr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#define qmuli(r0,r1,r2,i0)             iqmuli(r0,r1,r2,i0,1)
+#define qmuli_u(r0,r1,r2,i0)           iqmuli(r0,r1,r2,i0,0)
+#define iqmuli(r0,r1,r2,i0,sign)       _iqmuli(_jit,r0,r1,r2,i0,sign)
+static void _iqmuli(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#define qdivr(r0,r1,r2,r3)             iqdivr(r0,r1,r2,r3,1)
+#define qdivr_u(r0,r1,r2,r3)           iqdivr(r0,r1,r2,r3,0)
+#define iqdivr(r0,r1,r2,r3,sign)       _iqdivr(_jit,r0,r1,r2,r3,sign)
+static void _iqdivr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#define qdivi(r0,r1,r2,i0)             iqdivi(r0,r1,r2,i0,1)
+#define qdivi_u(r0,r1,r2,i0)           iqdivi(r0,r1,r2,i0,0)
+#define iqdivi(r0,r1,r2,i0,sign)       _iqdivi(_jit,r0,r1,r2,i0,sign)
+static void _iqdivi(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#define andr(r0,r1,r2)                 AND(r0,r1,r2)
+#define andi(r0,r1,i0)                 _andi(_jit,r0,r1,i0)
+static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define orr(r0,r1,r2)                  OR(r0,r1,r2)
+#define ori(r0,r1,i0)                  _ori(_jit,r0,r1,i0)
+static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define xorr(r0,r1,r2)                 XOR(r0,r1,r2)
+#define xori(r0,r1,i0)                 _xori(_jit,r0,r1,i0)
+static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define lshr(r0,r1,r2)                 SHL(r0,r1,r2)
+#define lshi(r0,r1,i0)                 _lshi(_jit,r0,r1,i0)
+static void _lshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define rshr(r0,r1,r2)                 SHR(r0,r1,r2)
+#define rshi(r0,r1,i0)                 _rshi(_jit,r0,r1,i0)
+static void _rshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define rshr_u(r0,r1,r2)               SHR_U(r0,r1,r2)
+#define rshi_u(r0,r1,i0)               _rshi_u(_jit,r0,r1,i0)
+static void _rshi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ltr(r0,r1,r2)                  _ltr(_jit,r0,r1,r2)
+static void _ltr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define lti(r0,r1,i0)                  _lti(_jit,r0,r1,i0)
+static void _lti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ltr_u(r0,r1,r2)                        _ltr_u(_jit,r0,r1,r2)
+static void _ltr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define lti_u(r0,r1,i0)                        _lti_u(_jit,r0,r1,i0)
+static void _lti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ler(r0,r1,r2)                  _ler(_jit,r0,r1,r2)
+static void _ler(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define lei(r0,r1,i0)                  _lei(_jit,r0,r1,i0)
+static void _lei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ler_u(r0,r1,r2)                        _ler_u(_jit,r0,r1,r2)
+static void _ler_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define lei_u(r0,r1,i0)                        _lei_u(_jit,r0,r1,i0)
+static void _lei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define eqr(r0,r1,r2)                  _eqr(_jit,r0,r1,r2)
+static void _eqr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define eqi(r0,r1,i0)                  _eqi(_jit,r0,r1,i0)
+static void _eqi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ger(r0,r1,r2)                  _ger(_jit,r0,r1,r2)
+static void _ger(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define gei(r0,r1,i0)                  _gei(_jit,r0,r1,i0)
+static void _gei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ger_u(r0,r1,r2)                        _ger_u(_jit,r0,r1,r2)
+static void _ger_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define gei_u(r0,r1,i0)                        _gei_u(_jit,r0,r1,i0)
+static void _gei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define gtr(r0,r1,r2)                  _gtr(_jit,r0,r1,r2)
+static void _gtr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define gti(r0,r1,i0)                  _gti(_jit,r0,r1,i0)
+static void _gti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define gtr_u(r0,r1,r2)                        _gtr_u(_jit,r0,r1,r2)
+static void _gtr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define gti_u(r0,r1,i0)                        _gti_u(_jit,r0,r1,i0)
+static void _gti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ner(r0,r1,r2)                  _ner(_jit,r0,r1,r2)
+static void _ner(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define nei(r0,r1,i0)                  _nei(_jit,r0,r1,i0)
+static void _nei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define negr(r0,r1)                    subr(r0,0,r1)
+#define comr(r0,r1)                    ANDCMI(r0,-1,r1)
+#define movr(r0,r1)                    _movr(_jit,r0,r1)
+static void _movr(jit_state_t*,jit_int32_t,jit_int32_t);
+#define movi(r0,i0)                    _movi(_jit,r0,i0)
+static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
+#define movi_p(r0,i0)                  _movi_p(_jit,r0,i0)
+static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define htonr_us(r0,r1)              _htonr_us(_jit,r0,r1)
+static void _htonr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define htonr_ui(r0,r1)              _htonr_ui(_jit,r0,r1)
+static void _htonr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define htonr_ul(r0,r1)              MUX1(r0,r1,MUX_REV)
+#else
+#  define htonr_us(r0,r1)              extr_us(r0,r1)
+#  define htonr_ui(r0,r1)              extr_ui(r0,r1)
+#  define htonr_ul(r0,r1)              movr(r0,r1)
+#endif
+#define extr_c(r0,r1)                  SXT1(r0,r1)
+#define extr_uc(r0,r1)                 ZXT1(r0,r1)
+#define extr_s(r0,r1)                  SXT2(r0,r1)
+#define extr_us(r0,r1)                 ZXT2(r0,r1)
+#define extr_i(r0,r1)                  SXT4(r0,r1)
+#define extr_ui(r0,r1)                 ZXT4(r0,r1)
+#define bltr(i0,r0,r1)                 _bltr(_jit,i0,r0,r1)
+static jit_word_t _bltr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blti(i0,r0,i1)                 _blti(_jit,i0,r0,i1)
+static jit_word_t _blti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bltr_u(i0,r0,r1)               _bltr_u(_jit,i0,r0,r1)
+static jit_word_t _bltr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blti_u(i0,r0,i1)               _blti_u(_jit,i0,r0,i1)
+static jit_word_t _blti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bler(i0,r0,r1)                 _bler(_jit,i0,r0,r1)
+static jit_word_t _bler(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blei(i0,r0,i1)                 _blei(_jit,i0,r0,i1)
+static jit_word_t _blei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bler_u(i0,r0,r1)               _bler_u(_jit,i0,r0,r1)
+static jit_word_t _bler_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blei_u(i0,r0,i1)               _blei_u(_jit,i0,r0,i1)
+static jit_word_t _blei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define beqr(i0,r0,r1)                 _beqr(_jit,i0,r0,r1)
+static jit_word_t _beqr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define beqi(i0,r0,i1)                 _beqi(_jit,i0,r0,i1)
+static jit_word_t _beqi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bger(i0,r0,r1)                 _bger(_jit,i0,r0,r1)
+static jit_word_t _bger(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgei(i0,r0,i1)                 _bgei(_jit,i0,r0,i1)
+static jit_word_t _bgei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bger_u(i0,r0,r1)               _bger_u(_jit,i0,r0,r1)
+static jit_word_t _bger_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgei_u(i0,r0,i1)               _bgei_u(_jit,i0,r0,i1)
+static jit_word_t _bgei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bgtr(i0,r0,r1)                 _bgtr(_jit,i0,r0,r1)
+static jit_word_t _bgtr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgti(i0,r0,i1)                 _bgti(_jit,i0,r0,i1)
+static jit_word_t _bgti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bgtr_u(i0,r0,r1)               _bgtr_u(_jit,i0,r0,r1)
+static jit_word_t _bgtr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgti_u(i0,r0,i1)               _bgti_u(_jit,i0,r0,i1)
+static jit_word_t _bgti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bner(i0,r0,r1)                 _bner(_jit,i0,r0,r1)
+static jit_word_t _bner(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bnei(i0,r0,i1)                 _bnei(_jit,i0,r0,i1)
+static jit_word_t _bnei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bmsr(i0,r0,r1)                 _bmsr(_jit,i0,r0,r1)
+static jit_word_t _bmsr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bmsi(i0,r0,i1)                 _bmsi(_jit,i0,r0,i1)
+static jit_word_t _bmsi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bmcr(i0,r0,r1)                 _bmcr(_jit,i0,r0,r1)
+static jit_word_t _bmcr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bmci(i0,r0,i1)                 _bmci(_jit,i0,r0,i1)
+static jit_word_t _bmci(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define baddr(i0,r0,r1,cc)             _baddr(_jit,i0,r0,r1,cc)
+static jit_word_t _baddr(jit_state_t*,jit_word_t,
+                        jit_int32_t,jit_int32_t,jit_bool_t);
+#define baddi(i0,r0,i1,cc)             _baddi(_jit,i0,r0,i1,cc)
+static jit_word_t _baddi(jit_state_t*,jit_word_t,
+                        jit_int32_t,jit_word_t,jit_bool_t);
+#define baddr_u(i0,r0,r1,cc)           _baddr_u(_jit,i0,r0,r1,cc)
+static jit_word_t _baddr_u(jit_state_t*,jit_word_t,
+                          jit_int32_t,jit_int32_t,jit_bool_t);
+#define baddi_u(i0,r0,i1,cc)           _baddi_u(_jit,i0,r0,i1,cc)
+static jit_word_t _baddi_u(jit_state_t*,jit_word_t,
+                          jit_int32_t,jit_word_t,jit_bool_t);
+#define bsubr(i0,r0,r1,cc)             _bsubr(_jit,i0,r0,r1,cc)
+static jit_word_t _bsubr(jit_state_t*,jit_word_t,
+                        jit_int32_t,jit_int32_t,jit_bool_t);
+#define bsubi(i0,r0,i1,cc)             _bsubi(_jit,i0,r0,i1,cc)
+static jit_word_t _bsubi(jit_state_t*,jit_word_t,
+                        jit_int32_t,jit_word_t,jit_bool_t);
+#define bsubr_u(i0,r0,r1,cc)           _bsubr_u(_jit,i0,r0,r1,cc)
+static jit_word_t _bsubr_u(jit_state_t*,jit_word_t,
+                          jit_int32_t,jit_int32_t,jit_bool_t);
+#define bsubi_u(i0,r0,i1,cc)           _bsubi_u(_jit,i0,r0,i1,cc)
+static jit_word_t _bsubi_u(jit_state_t*,jit_word_t,
+                          jit_int32_t,jit_word_t,jit_bool_t);
+#define boaddr(i0,r0,r1)               baddr(i0,r0,r1,1)
+#define boaddi(i0,r0,i1)               baddi(i0,r0,i1,1)
+#define boaddr_u(i0,r0,r1)             baddr_u(i0,r0,r1,1)
+#define boaddi_u(i0,r0,i1)             baddi_u(i0,r0,i1,1)
+#define bxaddr(i0,r0,r1)               baddr(i0,r0,r1,0)
+#define bxaddi(i0,r0,i1)               baddi(i0,r0,i1,0)
+#define bxaddr_u(i0,r0,r1)             baddr_u(i0,r0,r1,0)
+#define bxaddi_u(i0,r0,i1)             baddi_u(i0,r0,i1,0)
+#define bosubr(i0,r0,r1)               bsubr(i0,r0,r1,1)
+#define bosubi(i0,r0,i1)               bsubi(i0,r0,i1,1)
+#define bosubr_u(i0,r0,r1)             bsubr_u(i0,r0,r1,1)
+#define bosubi_u(i0,r0,i1)             bsubi_u(i0,r0,i1,1)
+#define bxsubr(i0,r0,r1)               bsubr(i0,r0,r1,0)
+#define bxsubi(i0,r0,i1)               bsubi(i0,r0,i1,0)
+#define bxsubr_u(i0,r0,r1)             bsubr_u(i0,r0,r1,0)
+#define bxsubi_u(i0,r0,i1)             bsubi_u(i0,r0,i1,0)
+#define ldr_c(r0,r1)                   _ldr_c(_jit,r0,r1)
+static void _ldr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#define ldi_c(r0,i0)                   _ldi_c(_jit,r0,i0)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldr_uc(r0,r1)                  LD1(r0,r1)
+#define ldi_uc(r0,i0)                  _ldi_uc(_jit,r0,i0)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldr_s(r0,r1)                   _ldr_s(_jit,r0,r1)
+static void _ldr_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#define ldi_s(r0,i0)                   _ldi_s(_jit,r0,i0)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldr_us(r0,r1)                  LD2(r0,r1)
+#define ldi_us(r0,i0)                  _ldi_us(_jit,r0,i0)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldr_i(r0,r1)                   _ldr_i(_jit,r0,r1)
+static void _ldr_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#define ldi_i(r0,i0)                   _ldi_i(_jit,r0,i0)
+static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldr_ui(r0,r1)                  LD4(r0,r1)
+#define ldi_ui(r0,i0)                  _ldi_ui(_jit,r0,i0)
+static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldr_l(r0,r1)                   LD8(r0,r1)
+#define ldi_l(r0,i0)                   _ldi_l(_jit,r0,i0)
+static void _ldi_l(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldxr_c(r0,r1,r2)               _ldxr_c(_jit,r0,r1,r2)
+static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_c(r0,r1,i0)               _ldxi_c(_jit,r0,r1,i0)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldxr_uc(r0,r1,r2)              _ldxr_uc(_jit,r0,r1,r2)
+static void _ldxr_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_uc(r0,r1,i0)              _ldxi_uc(_jit,r0,r1,i0)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldxr_s(r0,r1,r2)               _ldxr_s(_jit,r0,r1,r2)
+static void _ldxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_s(r0,r1,i0)               _ldxi_s(_jit,r0,r1,i0)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldxr_us(r0,r1,r2)              _ldxr_us(_jit,r0,r1,r2)
+static void _ldxr_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_us(r0,r1,i0)              _ldxi_us(_jit,r0,r1,i0)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldxr_i(r0,r1,r2)               _ldxr_i(_jit,r0,r1,r2)
+static void _ldxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_i(r0,r1,i0)               _ldxi_i(_jit,r0,r1,i0)
+static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldxr_ui(r0,r1,r2)              _ldxr_ui(_jit,r0,r1,r2)
+static void _ldxr_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_ui(r0,r1,i0)              _ldxi_ui(_jit,r0,r1,i0)
+static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldxr_l(r0,r1,r2)               _ldxr_l(_jit,r0,r1,r2)
+static void _ldxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_l(r0,r1,i0)               _ldxi_l(_jit,r0,r1,i0)
+static void _ldxi_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define str_c(r0,r1)                   ST1(r0,r1)
+#define sti_c(i0,r0)                   _sti_c(_jit,i0,r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#define str_s(r0,r1)                   ST2(r0,r1)
+#define sti_s(i0,r0)                   _sti_s(_jit,i0,r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#define str_i(r0,r1)                   ST4(r0,r1)
+#define sti_i(i0,r0)                   _sti_i(_jit,i0,r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#define str_l(r0,r1)                   ST8(r0,r1)
+#define sti_l(i0,r0)                   _sti_l(_jit,i0,r0)
+static void _sti_l(jit_state_t*,jit_word_t,jit_int32_t);
+#define stxr_c(r0,r1,r2)               _stxr_c(_jit,r0,r1,r2)
+static void _stxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define stxi_c(i0,r0,r1)               _stxi_c(_jit,i0,r0,r1)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define stxr_s(r0,r1,r2)               _stxr_s(_jit,r0,r1,r2)
+static void _stxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define stxi_s(i0,r0,r1)               _stxi_s(_jit,i0,r0,r1)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define stxr_i(r0,r1,r2)               _stxr_i(_jit,r0,r1,r2)
+static void _stxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define stxi_i(i0,r0,r1)               _stxi_i(_jit,i0,r0,r1)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define stxr_l(r0,r1,r2)               _stxr_l(_jit,r0,r1,r2)
+static void _stxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define stxi_l(i0,r0,r1)               _stxi_l(_jit,i0,r0,r1)
+static void _stxi_l(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define jmpr(r0)                       _jmpr(_jit,r0)
+static void _jmpr(jit_state_t*,jit_int32_t);
+#define jmpi(i0)                       _jmpi(_jit,i0)
+static void _jmpi(jit_state_t*,jit_word_t);
+#define jmpi_p(i0)                     _jmpi_p(_jit,i0)
+static jit_word_t _jmpi_p(jit_state_t*,jit_word_t);
+#define callr(r0)                      _callr(_jit,r0)
+static void _callr(jit_state_t*,jit_int32_t);
+#define calli(i0)                      _calli(_jit,i0)
+static void _calli(jit_state_t*,jit_word_t);
+#define calli_p(i0)                    _calli_p(_jit,i0)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t);
+#define prolog(node)                   _prolog(_jit,node)
+static void _prolog(jit_state_t*,jit_node_t*);
+#define epilog(node)                   _epilog(_jit,node)
+static void _epilog(jit_state_t*,jit_node_t*);
+#  define vastart(r0)                  _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#  define vaarg(r0, r1)                        _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#define patch_at(node,instr,label)     _patch_at(_jit,node,instr,label)
+static void _patch_at(jit_state_t*,jit_code_t,jit_word_t,jit_word_t);
+#endif
+
+#if CODE
+#if __BYTE_ORDER == __BIG_ENDIAN
+static jit_word_t
+byte_swap_if_big_endian(jit_word_t w)
+{
+    union {
+       char    c[8];
+       long    w;
+    } l, h;
+    l.w = w;
+    h.c[0] = l.c[7];
+    h.c[1] = l.c[6];
+    h.c[2] = l.c[5];
+    h.c[3] = l.c[4];
+    h.c[4] = l.c[3];
+    h.c[5] = l.c[2];
+    h.c[6] = l.c[1];
+    h.c[7] = l.c[0];
+    return (h.w);
+}
+#else
+#define byte_swap_if_big_endian(w)             (w)
+#endif
+
+static void
+_out(jit_state_t *_jit, int n, int tm,
+     jit_word_t s0, jit_word_t s1, jit_word_t s2)
+{
+    int                         i;
+    jit_word_t          l, h, *w;
+    set_bundle(_jit->pc.ul, l, h, tm, s0, s1, s2);
+    _jit->pc.ul += 2;
+    w = (jit_word_t *)_jitc->inst;
+    for (i = n; i < _jitc->ioff; i++)
+       w[i - n] = w[i];
+    _jitc->ioff -= n;
+}
+
+#define nop_m          0x0008000000L
+#define nop_i          0x0008000000L
+#define nop_b          0x4000000000L
+static void
+_stop(jit_state_t *_jit)
+{
+    /* Clear set of live registers */
+    jit_regset_set_ui(&_jitc->regs, 0);
+    _jitc->pred = 0;
+    /* Flag a stop is required */
+    if (_jitc->ioff)
+       _jitc->inst[_jitc->ioff - 1].t |= INST_STOP;
+    else
+       inst(nop_m, INST_Ms);
+}
+
+static void
+_sync(jit_state_t *_jit)
+{
+    /* Taken branches are supposed to not need a stop, so, it
+     * should not be required to stop if no registers live in
+     * sequential code */
+    if (jit_regset_cmp_ui(&_jitc->regs, 0) != 0 || _jitc->pred)
+       stop();
+    do
+       flush();
+    while (_jitc->ioff);
+}
+
+#define A_0            INST_A
+#define As0            INST_As
+#define I_0            INST_I
+#define Is0            INST_Is
+#define M_0            INST_M
+#define Ms0            INST_Ms
+#define F_0            INST_F
+#define Fs0            INST_Fs
+#define B_0            INST_B
+#define Bs0            INST_Bs
+#define L_0            INST_L
+#define Ls0            INST_Ls
+#define X_0            INST_X
+#define Xs0            INST_Xs
+#define A_1            (INST_A<<4)
+#define As1            (INST_As<<4)
+#define I_1            (INST_I<<4)
+#define Is1            (INST_Is<<4)
+#define M_1            (INST_M<<4)
+#define Ms1            (INST_Ms<<4)
+#define F_1            (INST_F<<4)
+#define Fs1            (INST_Fs<<4)
+#define B_1            (INST_B<<4)
+#define Bs1            (INST_Bs<<4)
+#define L_1            (INST_L<<4)
+#define Ls1            (INST_Ls<<4)
+#define X_1            (INST_X<<4)
+#define Xs1            (INST_Xs<<4)
+#define A_2            (INST_A<<8)
+#define As2            (INST_As<<8)
+#define I_2            (INST_I<<8)
+#define Is2            (INST_Is<<8)
+#define M_2            (INST_M<<8)
+#define Ms2            (INST_Ms<<8)
+#define F_2            (INST_F<<8)
+#define Fs2            (INST_Fs<<8)
+#define B_2            (INST_B<<8)
+#define Bs2            (INST_Bs<<8)
+#define L_2            (INST_L<<8)
+#define Ls2            (INST_Ls<<8)
+#define X_2            (INST_X<<8)
+#define Xs2            (INST_Xs<<8)
+
+#define I_             I_0
+#define I_I_           I_0|I_1
+#define I_Is           I_0|Is1
+#define I_B_           I_0|B_1
+#define I_Bs           I_0|Bs1
+#define Is             Is0
+#define IsI_           Is0|I_1
+#define IsIs           Is0|Is1
+#define M_             M_0
+#define M_I_           M_0|I_1
+#define M_Is           M_0|Is1
+#define M_M_           M_0|M_1
+#define M_Ms           M_0|Ms1
+#define M_F_           M_0|F_1
+#define M_Fs           M_0|Fs1
+#define M_B_           M_0|B_1
+#define M_Bs           M_0|Bs1
+#define M_I_I_         M_0|I_1|I_2
+#define M_I_Is         M_0|I_1|Is2
+#define M_I_B_         M_0|I_1|B_2
+#define M_I_Bs         M_0|I_1|Bs2
+#define M_IsI_         M_0|Is1|I_2
+#define M_IsIs         M_0|Is1|Is2
+#define M_M_I_         M_0|M_1|I_2
+#define M_M_Is         M_0|M_1|Is2
+#define M_M_F_         M_0|M_1|F_2
+#define M_M_Fs         M_0|M_1|Fs2
+#define M_M_B_         M_0|M_1|B_2
+#define M_M_Bs         M_0|M_1|Bs2
+#define M_F_I_         M_0|F_1|I_2
+#define M_F_Is         M_0|F_1|Is2
+#define M_F_B_         M_0|F_1|B_2
+#define M_F_Bs         M_0|F_1|Bs2
+#define M_B_B_         M_0|B_1|B_2
+#define M_B_Bs         M_0|B_1|Bs2
+#define M_L_X_         M_0|L_1|X_2
+#define M_L_Xs         M_0|L_1|Xs2
+#define Ms             Ms0
+#define MsI_           Ms0|I_1
+#define MsIs           Ms0|Is1
+#define MsM_           Ms0|M_1
+#define MsMs           Ms0|Ms1
+#define MsM_I_         Ms0|M_1|I_2
+#define MsM_Is         Ms0|M_1|Is2
+#define F_             F_0
+#define F_I_           F_0|I_1
+#define F_Is           F_0|Is1
+#define F_B_           F_0|B_1
+#define F_Bs           F_0|Bs1
+#define Fs             Fs0
+#define B_             B_0
+#define B_B_           B_0|B_1
+#define B_Bs           B_0|Bs1
+#define B_B_B_         B_0|B_1|B_2
+#define B_B_Bs         B_0|B_1|Bs2
+#define Bs             Bs0
+#define L_X_           L_0|X_1
+#define L_Xs           L_0|Xs1
+
+static jit_word_t
+templat(jit_word_t cc)
+{
+    switch (cc) {
+       case I_:
+       case I_I_:      case I_Is:
+       case I_B_:      case I_Bs:
+       case Is:
+       case IsI_:      case IsIs:
+       case M_:
+       case M_I_:      case M_Is:
+       case M_M_:      case M_Ms:
+       case M_F_:      case M_Fs:
+       case M_B_:      case M_Bs:
+       case M_I_I_:    case M_I_Is:
+       case M_I_B_:    case M_I_Bs:
+       case M_IsI_:    case M_IsIs:
+       case M_M_I_:    case M_M_Is:
+       case M_M_F_:    case M_M_Fs:
+       case M_M_B_:    case M_M_Bs:
+       case M_F_I_:    case M_F_Is:
+       case M_F_B_:    case M_F_Bs:
+       case M_B_B_:    case M_B_Bs:
+       case M_L_X_:    case M_L_Xs:
+       case Ms:
+       case MsI_:      case MsIs:
+       case MsM_:      case MsMs:
+       case MsM_I_:    case MsM_Is:
+       case F_:
+       case F_I_:      case F_Is:
+       case F_B_:      case F_Bs:
+       case Fs:
+       case B_:
+       case B_B_:      case B_Bs:
+       case B_B_B_:    case B_B_Bs:
+       case Bs:
+       case L_X_:      case L_Xs:
+           return (cc);
+       default:
+           return (0);
+    }
+}
+
+/* match* functions recurse attempting to find a template for A-
+ * instructions, that may be executed in M- or I- unit.
+ * It also uses an heuristic of trying first M- for slot 0 and 2,
+ * and I- for slot 1, but tries all possible matches.
+ */
+static jit_word_t
+match_2(jit_word_t cc)
+{
+    jit_word_t         t;
+    if ((t = templat(cc | M_2)))
+       return (t);
+    if ((t = templat(cc | I_2)))
+       return (t);
+    return (0);
+}
+
+static jit_word_t
+matchs2(jit_word_t cc)
+{
+    jit_word_t         t;
+    if ((t = templat(cc | Ms2)))
+       return (t);
+    if ((t = templat(cc | Is2)))
+       return (t);
+    return (0);
+}
+
+static jit_word_t
+match2(jit_word_t cc)
+{
+    if ((cc & 0xf00) == A_2)
+       return (match_2(cc & ~0xf00));
+    if ((cc & 0xf00) == As2)
+       return (matchs2(cc & ~0xf00));
+    return (0);
+}
+
+static jit_word_t
+match_1(jit_word_t cc)
+{
+    jit_word_t         t;
+    if ((t = templat(cc | I_1)))
+       return (t);
+    if ((t = templat(cc | M_1)))
+       return (t);
+    if ((t = match2(cc | I_1)))
+       return (t);
+    if ((t = match2(cc | M_1)))
+       return (t);
+    return (0);
+}
+
+static jit_word_t
+matchs1(jit_word_t cc)
+{
+    jit_word_t         t;
+    if ((t = templat(cc | Is1)))
+       return (t);
+    if ((t = templat(cc | Ms1)))
+       return (t);
+    if ((t = match2(cc | Is1)))
+       return (t);
+    if ((t = match2(cc | Ms1)))
+       return (t);
+    return (0);
+}
+
+static jit_word_t
+match1(jit_word_t cc)
+{
+    if ((cc & 0x0f0) == A_1)
+       return (match_1(cc & ~0x0f0));
+    if ((cc & 0x0f0) == As1)
+       return (matchs1(cc & ~0x0f0));
+    return (0);
+}
+
+static jit_word_t
+match_0(jit_word_t cc)
+{
+    jit_word_t         t;
+    if ((t = templat(cc | M_0)))
+       return (t);
+    if ((t = templat(cc | I_0)))
+       return (t);
+    if ((t = match1(cc | M_0)))
+       return (t);
+    if ((t = match1(cc | I_0)))
+       return (t);
+    return (0);
+}
+
+static jit_word_t
+matchs0(jit_word_t cc)
+{
+    jit_word_t         t;
+    if ((t = templat(cc | Ms0)))
+       return (t);
+    if ((t = templat(cc | Is0)))
+       return (t);
+    if ((t = match1(cc | Ms0)))
+       return (t);
+    if ((t = match1(cc | Is0)))
+       return (t);
+    return (0);
+}
+
+static jit_word_t
+match0(jit_word_t cc)
+{
+    if ((cc & 0x00f) == A_0)
+       return (match_0(cc & ~0x00f));
+    if ((cc & 0x00f) == As0)
+       return (matchs0(cc & ~0x00f));
+    return (0);
+}
+
+static void
+_flush(jit_state_t *_jit)
+{
+    int                        n, soff;
+    jit_word_t         t, cc, tm, s0, s1, s2;
+
+    if (!_jitc->ioff)
+       return;
+    for (cc = 0, n = soff = 0; n < _jitc->ioff; n++, soff += 4)
+       cc |= (jit_uword_t)(_jitc->inst[n].t) << soff;
+
+    soff = 0xf00;
+    while (soff) {
+       /* Try to find a template, or reduce down
+        * to one instruction if no template match */
+       if ((t = templat(cc))) {
+           cc = t;
+           break;
+       }
+       /* A- instructions may be execute in M- or I- unit */
+       if ((t = match0(cc))) {
+           cc = t;
+           break;
+       }
+       cc &= ~soff;
+       soff >>= 4;
+    }
+    assert(soff);
+
+    /* Prefer tail nop if need to add some nop, so that patching is easier */
+#define ii(n)          _jitc->inst[n].i
+    switch (cc) {
+       case I_:
+           n = 1;              tm = TM_M_I_I_;
+           s0 = nop_m;         s1 = ii(0);             s2 = nop_i;
+           break;
+       case I_I_:
+           n = 2;              tm = TM_M_I_I_;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case I_Is:
+           n = 2;              tm = TM_M_I_Is;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case I_B_:
+           n = 2;              tm = TM_M_I_B_;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case I_Bs:
+           n = 2;              tm = TM_M_I_Bs;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case Is:
+           n = 1;              tm = TM_M_IsI_;
+           s0 = nop_m;         s1 = ii(0);             s2 = nop_i;
+           break;
+       case IsI_:
+           n = 2;              tm = TM_M_IsI_;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case IsIs:
+           n = 2;              tm = TM_M_IsIs;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case M_:
+           n = 1;              tm = TM_M_I_I_;
+           s0 = ii(0);         s1 = nop_i;             s2 = nop_i;
+           break;
+       case M_I_:
+           n = 2;              tm = TM_M_I_I_;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_i;
+           break;
+       case M_Is:
+           n = 2;              tm = TM_M_IsI_;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_i;
+           break;
+       case M_M_:
+           n = 2;              tm = TM_M_M_I_;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_i;
+           break;
+       case M_Ms:
+           n = 2;              tm = TM_M_M_Is;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_i;
+           break;
+       case M_F_:
+           n = 2;              tm = TM_M_F_I_;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_i;
+           break;
+       case M_Fs:
+           n = 2;              tm = TM_M_F_Is;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_i;
+           break;
+       case M_B_:
+           n = 2;              tm = TM_M_B_B_;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_b;
+           break;
+       case M_Bs:
+           n = 2;              tm = TM_M_B_Bs;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_b;
+           break;
+       case M_I_I_:
+           n = 3;              tm = TM_M_I_I_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_I_Is:
+           n = 3;              tm = TM_M_I_Is;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_I_B_:
+           n = 3;              tm = TM_M_I_B_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_I_Bs:
+           n = 3;              tm = TM_M_I_Bs;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_IsI_:
+           n = 3;              tm = TM_M_IsI_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_IsIs:
+           n = 3;              tm = TM_M_IsIs;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_M_I_:
+           n = 3;              tm = TM_M_M_I_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_M_Is:
+           n = 3;              tm = TM_M_M_Is;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_M_F_:
+           n = 3;              tm = TM_M_M_F_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_M_Fs:
+           n = 3;              tm = TM_M_M_Fs;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_M_B_:
+           n = 3;              tm = TM_M_M_B_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_M_Bs:
+           n = 3;              tm = TM_M_M_Bs;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_F_I_:
+           n = 3;              tm = TM_M_F_I_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_F_Is:
+           n = 3;              tm = TM_M_F_Is;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_F_B_:
+           n = 3;              tm = TM_M_F_B_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_F_Bs:
+           n = 3;              tm = TM_M_F_Bs;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_B_B_:
+           n = 3;              tm = TM_M_B_B_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_B_Bs:
+           n = 3;              tm = TM_M_B_Bs;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_L_X_:
+           n = 3;              tm = TM_M_L_X_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case M_L_Xs:
+           n = 3;              tm = TM_M_L_Xs;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case Ms:
+           n = 1;              tm = TM_MsM_I_;
+           s0 = ii(0);         s1 = nop_m;             s2 = nop_i;
+           break;
+       case MsI_:
+           n = 2;              tm = TM_MsM_I_;
+           s0 = ii(0);         s1 = nop_m;             s2 = ii(1);
+           break;
+       case MsIs:
+           n = 2;              tm = TM_MsM_Is;
+           s0 = ii(0);         s1 = nop_m;             s2 = ii(1);
+           break;
+       case MsM_:
+           n = 2;              tm = TM_MsM_I_;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_i;
+           break;
+       case MsMs:
+           n = 2;              tm = TM_MsM_Is;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_i;
+           break;
+       case MsM_I_:
+           n = 3;              tm = TM_MsM_I_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case MsM_Is:
+           n = 3;              tm = TM_MsM_Is;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case F_:
+           n = 1;              tm = TM_M_F_I_;
+           s0 = nop_m;         s1 = ii(0);             s2 = nop_i;
+           break;
+       case F_I_:
+           n = 2;              tm = TM_M_F_I_;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case F_Is:
+           n = 2;              tm = TM_M_F_Is;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case F_B_:
+           n = 2;              tm = TM_M_F_B_;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case F_Bs:
+           n = 2;              tm = TM_M_F_Bs;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case Fs:
+           n = 1;              tm = TM_M_F_Is;
+           s0 = nop_m;         s1 = ii(0);             s2 = nop_i;
+           break;
+       case B_:
+           n = 1;              tm = TM_B_B_B_;
+           s0 = ii(0);         s1 = nop_b;             s2 = nop_b;
+           break;
+       case B_B_:
+           n = 2;              tm = TM_B_B_B_;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_b;
+           break;
+       case B_Bs:
+           n = 2;              tm = TM_B_B_Bs;
+           s0 = ii(0);         s1 = ii(1);             s2 = nop_b;
+           break;
+       case B_B_B_:
+           n = 3;              tm = TM_B_B_B_;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case B_B_Bs:
+           n = 3;              tm = TM_B_B_Bs;
+           s0 = ii(0);         s1 = ii(1);             s2 = ii(2);
+           break;
+       case Bs:
+           n = 1;              tm = TM_B_B_Bs;
+           s0 = ii(0);         s1 = nop_b;             s2 = nop_b;
+           break;
+       case L_X_:
+           n = 2;              tm = TM_M_L_X_;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       case L_Xs:
+           n = 2;              tm = TM_M_L_Xs;
+           s0 = nop_m;         s1 = ii(0);             s2 = ii(1);
+           break;
+       default:
+           abort();
+    }
+    out(n, tm, s0, s1, s2);
+}
+
+static void
+_inst(jit_state_t *_jit, jit_word_t i, jit_uint8_t t)
+{
+    if (_jitc->ioff > 2)
+       flush();
+    assert(!(i & 0x11111e0000000000L));
+    _jitc->inst[_jitc->ioff].i = i;
+    _jitc->inst[_jitc->ioff].t = t;
+    ++_jitc->ioff;
+}
+
+static void
+_A1(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x4, jit_word_t x2, jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x4 &  ~0xfL));
+    assert(!(x2 &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((8L<<37)|(x4<<29)|(x2<<27)|(r3<<20)|(r2<<13)|(r1<<6)|_p, INST_A);
+    SETREG(r1);
+}
+
+static void
+_A3(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x4, jit_word_t x2, jit_word_t r3, jit_word_t im, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x4 &  ~0xfL));
+    assert(!(x2 &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(im >= -128 && im <= 127);
+    assert(!(r1 & ~0x7f));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((8L<<37)|(((im>>7)&1L)<<36)|(x4<<29)|(x2<<27)|
+        (r3<<20)|((im&0x7fL)<<13)|(r1<<6)|_p, INST_A);
+    SETREG(r1);
+}
+
+static void
+_A4(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x2, jit_word_t r3, jit_word_t im, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x2 &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(im >= -8192 && im <= 8191);
+    assert(!(r1  & ~0x7f));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((8L<<37)|(((im>>13)&1L)<<36)|(x2<<34)|(((im>>7)&0x3fL)<<27)|
+        (r3<<20)|((im&0x7fL)<<13)|(r1<<6)|_p, INST_A);
+    SETREG(r1);
+}
+
+static void
+_A5(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t r3, jit_word_t im, jit_word_t r1)
+{
+    jit_word_t         s, i5, i9, i7;
+    assert(!(_p & ~0x3fL));
+    assert(!(r3  & ~0x3L));
+    assert(im >= -2097152 && im <= 2097151);
+    assert(!(r1  & ~0x7fL));
+    /* imm22 = sign_ext(s << 21 | imm5c << 16 | imm9d << 7 | imm7b, 22) */
+    s  = (im & 0x200000) >> 21;
+    i5 = (im & 0x1f0000) >> 16;
+    i9 = (im &   0xff80) >>  7;
+    i7 =  im &     0x7f;
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((9L<<37)|(s<<36)|(i9<<27)|(i5<<22)|
+        (r3<<20)|(i7<<13)|(r1<<6)|_p, INST_A);
+    SETREG(r1);
+}
+
+static void
+_A6(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t o, jit_word_t x2, jit_word_t ta, jit_word_t p2,
+    jit_word_t r3, jit_word_t r2, jit_word_t c, jit_word_t p1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(o  &  ~0xfL));
+    assert(!(x2 &  ~0x3L));
+    assert(!(ta &  ~0x1L));
+    assert(!(p2 & ~0x7fL));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(c  &  ~0x1L));
+    assert(!(p1 & ~0x3fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    inst((o<<37)|(x2<<34)|(ta<<33)|(p2<<27)|(r3<<20)|
+        (r2<<13)|(c<<12)|(p1<<6)|_p, INST_A);
+    if (p1)
+       _jitc->pred |= 1 << p1;
+    if (p2)
+       _jitc->pred |= 1 << p2;
+}
+
+static void
+_A7(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t o, jit_word_t x2, jit_word_t ta,
+    jit_word_t p2, jit_word_t r3, jit_word_t c, jit_word_t p1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(o  &  ~0xfL));
+    assert(!(x2 &  ~0x3L));
+    assert(!(ta &  ~0x1L));
+    assert(!(p2 & ~0x7fL));
+    assert(!(r3 & ~0x7fL));
+    assert(!(c  &  ~0x1L));
+    assert(!(p1 & ~0x3fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    inst((o<<37)|(1L<<36)|(x2<<34)|(ta<<33)|
+        (p2<<27)|(r3<<20)|(c<<12)|(p1<<6)|_p, INST_A);
+    if (p1)
+       _jitc->pred |= 1 << p1;
+    if (p2)
+       _jitc->pred |= 1 << p2;
+}
+
+static void
+_A8(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t o, jit_word_t x2, jit_word_t ta, jit_word_t p2,
+    jit_word_t r3, jit_word_t im, jit_word_t c, jit_word_t p1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(o  &  ~0xfL));
+    assert(!(x2 &  ~0x3L));
+    assert(!(ta &  ~0x1L));
+    assert(!(p2 & ~0x7fL));
+    assert(!(r3 & ~0x7fL));
+    assert(im >= -128 && im <= 127);
+    assert(!(c  &  ~0x1L));
+    assert(!(p1 & ~0x3fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    inst((o<<37)|(((im>>7)&1L)<<36)|(x2<<34)|(ta<<33)|(p2<<27)|(r3<<20)|
+        ((im&0x7fL)<<13)|(c<<12)|(p1<<6)|_p, INST_A);
+    if (p1)
+       _jitc->pred |= 1 << p1;
+    if (p2)
+       _jitc->pred |= 1 << p2;
+}
+
+static void
+_A9(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t za, jit_word_t zb, jit_word_t x4,
+    jit_word_t x2, jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(za &  ~0x1L));
+    assert(!(zb &  ~0x1L));
+    assert(!(x4 &  ~0xfL));
+    assert(!(x2 &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((8L<<37)|(za<<36)|(1L<<34)|(zb<<33)|(x4<<29)|(x2<<27)|
+        (r3<<20)|(r2<<13)|(r1<<6)|_p, INST_A);
+    SETREG(r1);
+}
+
+static void
+_I1(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t ct, jit_word_t x2, jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(ct &  ~0x3L));
+    assert(!(x2 &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((7L<<37)|(1L<<33)|(ct<<30)|(x2<<28)|
+        (r3<<20)|(r2<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I2(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t za, jit_word_t xa, jit_word_t zb, jit_word_t xc,
+    jit_word_t xb ,jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(za &  ~0x1L));
+    assert(!(xa &  ~0x3L));
+    assert(!(zb &  ~0x1L));
+    assert(!(xc &  ~0x3L));
+    assert(!(xb &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((7L<<37)|(za<<36)|(xa<<34)|(zb<<33)|(xc<<30)|
+        (xb<<28)|(r3<<20)|(r2<<13)|(r1<<6), INST_I);
+    SETREG(r1);
+}
+
+static void
+_I3(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t mb, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(mb &  ~0xfL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((7L<<37)|(3L<<34)|(2L<<30)|(2L<<28)|
+        (mb<<20)|(r2<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I4(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t mh, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(mh & ~0xffL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((7L<<37)|(3L<<34)|(1L<<33)|(2L<<30)|
+        (2L<<28)|(mh<<20)|(r2<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I5(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t za, jit_word_t zb, jit_word_t x2,
+    jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(za &  ~0x1L));
+    assert(!(zb &  ~0x1L));
+    assert(!(x2 &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((7L<<37)|(za<<36)|(zb<<33)|(x2<<28)|
+        (r3<<20)|(r2<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I6(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t za, jit_word_t zb, jit_word_t x2,
+    jit_word_t r3, jit_word_t ct, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(za &  ~0x1L));
+    assert(!(zb &  ~0x1L));
+    assert(!(x2 &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(ct & ~0x1fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((7L<<37)|(za<<36)|(1L<<34)|(zb<<33)|
+        (x2<<28)|(r3<<20)|(ct<<14)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I7(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t za, jit_word_t zb, jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(za &  ~0x1L));
+    assert(!(zb &  ~0x1L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((7L<<37)|(za<<36)|(zb<<33)|(1L<<30)|
+        (r3<<20)|(r2<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I8(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t za, jit_word_t zb, jit_word_t im, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(za &  ~0x1L));
+    assert(!(zb &  ~0x1L));
+    assert(!(im & ~0x1fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((7L<<37)|(za<<36)|(3L<<34)|(zb<<33)|(1L<<30)|(1L<<28)|
+        (im<<20)|(r2<<13)|(r1<<6), INST_I);
+    SETREG(r1);
+}
+
+static void
+_I9(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x2, jit_word_t r3, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x2 &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((7L<<37)|(1L<<34)|(1L<<34)|(1L<<33)|
+        (x2<<30)|(1L<<28)|(r3<<20)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I10(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t ct, jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(ct & ~0x3fL));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((5L<<37)|(3L<<34)|(ct<<27)|(r3<<20)|(r2<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I11(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t len, jit_word_t r3,
+     jit_word_t pos, jit_word_t y, jit_word_t r1)
+{
+    assert(!(_p  & ~0x3fL));
+    assert(!(len & ~0x3fL));
+    assert(!(r3  & ~0x7fL));
+    assert(!(pos & ~0x1fL));
+    assert(!(y   &  ~0x1L));
+    assert(!(r1  & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((5L<<37)|(1L<<34)|(len<<27)|(r3<<20)|
+        (pos<<14)|(y<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I12(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t len, jit_word_t pos, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p  & ~0x3fL));
+    assert(!(len & ~0x3fL));
+    assert(!(pos & ~0x3fL));
+    assert(!(r2  & ~0x7fL));
+    assert(!(r1  & ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((5L<<37)|(1L<<34)|(1L<<33)|(len<<27)|
+        (pos<<20)|(r2<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I13(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t len, jit_word_t pos, jit_word_t im, jit_word_t r1)
+{
+    assert(!(_p  & ~0x3fL));
+    assert(!(len & ~0x3fL));
+    assert(!(pos & ~0x3fL));
+    assert(!(im  & ~0x7fL));
+    assert(!(r1  & ~0x7fL));
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((5L<<37)|(((im>>7)&1L)<<36)|(1L<<34)|(1L<<33)|(len<<27)|
+        (1L<<26)|(pos<<20)|((im&0x7fL)<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I14(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t s, jit_word_t len, jit_word_t r3, jit_word_t pos, jit_word_t r1)
+{
+    assert(!(_p  & ~0x3fL));
+    assert(!(s   &  ~0x1L));
+    assert(!(len & ~0x3fL));
+    assert(!(r3  & ~0x7fL));
+    assert(!(pos & ~0x1fL));
+    assert(!(r1  & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((5L<<37)|(s<<36)|(3L<<34)|(1L<<33)|
+        (len<<27)|(r3<<20)|(pos<<14)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I15(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t pos, jit_word_t len,
+     jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p  & ~0x3fL));
+    assert(!(pos & ~0x3fL));
+    assert(!(len &  ~0xfL));
+    assert(!(r3  & ~0x7fL));
+    assert(!(r2  & ~0x7fL));
+    assert(!(r1  & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((4L<<37)|(pos<<31)|(len<<27)|(r3<<20)|(r2<<13)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I16(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t tb, jit_word_t ta, jit_word_t p2,
+     jit_word_t r3, jit_word_t ps, jit_word_t c, jit_word_t p1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(tb &  ~0x1L));
+    assert(!(ta &  ~0x1L));
+    assert(!(p2 & ~0x7fL));
+    assert(!(r3 & ~0x7fL));
+    assert(!(ps & ~0x3fL));
+    assert(!(c  &  ~0x1L));
+    assert(!(p1 & ~0x3fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    inst((5L<<37)|(tb<<36)|(ta<<33)|(p2<<27)|
+        (r3<<20)|(ps<<14)|(c<<12)|(p1<<6), INST_I);
+    if (p1)
+       _jitc->pred |= 1 << p1;
+    if (p2)
+       _jitc->pred |= 1 << p2;
+}
+
+static void
+_I17(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t tb, jit_word_t ta, jit_word_t p2,
+     jit_word_t r3, jit_word_t c, jit_word_t p1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(tb &  ~0x1L));
+    assert(!(ta &  ~0x1L));
+    assert(!(p2 & ~0x7fL));
+    assert(!(r3 & ~0x7fL));
+    assert(!(c  &  ~0x1L));
+    assert(!(p1 & ~0x3fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    inst((5L<<37)|(tb<<36)|(ta<<33)|(p2<<27)|
+        (r3<<20)|(1L<<13)|(c<<12)|(p1<<6)|_p, INST_I);
+    if (p1)
+       _jitc->pred |= 1 << p1;
+    if (p2)
+       _jitc->pred |= 1 << p2;
+}
+
+static void
+_I18(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t im, jit_word_t y)
+{
+    assert(!(_p &     ~0x3fL));
+    assert(!(im & ~0x1fffffL));
+    assert(!(y  &      ~0x1L));
+    TSTPRED(_p);
+    inst((((im>>20)&1L)<<26)|(1L<<27)|(y<<26)|((im&0xffffL)<<6)|_p, INST_I);
+}
+
+static void
+_I19(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t im)
+{
+    assert(!(_p &     ~0x3fL));
+    assert(!(im & ~0x1fffffL));
+    TSTPRED(_p);
+    inst(((im>>20)&1L)|((im&0xffffL)<<6)|_p, INST_I);
+}
+
+static void
+_I20(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t r2, jit_word_t im)
+{
+    assert(!(_p &     ~0x3fL));
+    assert(!(r2 &     ~0x7fL));
+    assert(!(im & ~0x1fffffL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    inst(((im>>20)&1L)|(1L<<33)|(((im>>7)&0x1fffL)<<20)|
+        (r2<<13)|((im&0x7fL)<<6)|_p, INST_I);
+}
+
+static void
+_I21(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t im, jit_word_t ih, jit_word_t x,
+     jit_word_t wh, jit_word_t r2, jit_word_t b1)
+{
+    assert(!(_p &     ~0x3fL));
+    assert(!(im &    ~0x1ffL));
+    assert(!(ih &      ~0x1L));
+    assert(!(x  &      ~0x1L));
+    assert(!(wh &      ~0x3L));
+    assert(!(r2 &     ~0x7fL));
+    assert(!(b1 &      ~0x7L));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    inst((7L<<33)|(im<<24)|(ih<<23)|(x<<22)|(wh<<20)|
+        (r2<<13)|(b1<<6), INST_I);
+}
+
+static void
+_I22(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t b2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(b2 &  ~0x7L));
+    assert(!(r1 & ~0x7fL));
+    TSTPRED(_p);
+    inst((0x31L<<27)|(b2<<13)|(r1<<6)|_p, INST_I);
+}
+
+static void
+_I23(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t r2, jit_word_t im)
+{
+    assert(!(_p &   ~0x3fL));
+    assert(!(r2 &   ~0x7fL));
+    assert(!(im & ~0xffffL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    inst((((im>>15)&1L)<<36)|(3L<<33)|(((im>>7)&0xffL)<<24)|
+        (r2<<13)|(im&0x7fL)|_p, INST_I);
+}
+
+static void
+_I24(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t im)
+{
+    jit_uint8_t                cc = INST_I;
+    assert(!(_p &      ~0x3fL));
+    assert(!(im & ~0xfffffffL));
+    TSTPRED(_p);
+    inst((((im>>27)&1L)<<36)|(2L<<33)|((im&0x7ffffffL)<<6)|_p, cc);
+}
+
+static void
+_I25(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(r1 & ~0x7fL));
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((x6<<27)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I26(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t ar,jit_word_t r2)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(ar & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    inst((0x2aL<<27)|(ar<<20)|(r2<<13)|_p, INST_I);
+}
+
+static void
+_I27(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t ar,jit_word_t im)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(ar & ~0x7fL));
+    assert(!(im & ~0xffL));
+    TSTPRED(_p);
+    inst((((im>>7)&1L)<<36)|(0xaL<<27)|(ar<<20)|((im&0x7fL)<<13)|_p, INST_I);
+}
+
+static void
+_I28(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t ar, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(ar & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((0x32L<<27)|(ar<<20)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I29(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r3,jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((x6<<27)|(r3<<20)|(r1<<6)|_p, INST_I);
+    SETREG(r1);
+}
+
+static void
+_I30(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t ta, jit_word_t tb, jit_word_t p2,
+     jit_word_t im, jit_word_t c, jit_word_t p1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(ta &  ~0x1L));
+    assert(!(tb &  ~0x1L));
+    assert(!(p2 & ~0x3fL));
+    assert(!(im & ~0x1fL));
+    assert(!(c  &  ~0x1L));
+    assert(!(p1 & ~0x1fL));
+    TSTPRED(_p);
+    inst((5L<<37)|(tb<<36)|(ta<<33)|(1L<<19)|(im<<14)|
+        (1L<<13)|(c<<12)|(p1<<6)|_p, INST_I);
+    if (p1)
+       _jitc->pred |= 1 << p1;
+    if (p2)
+       _jitc->pred |= 1 << p2;
+}
+
+static void
+_M1(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x6, jit_word_t ht, jit_word_t x, jit_word_t r3, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(x  &  ~0x1L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((4L<<37)|(x6<<30)|(ht<<28)|(x<<27)|(r3<<20)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+_M2(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((4L<<37)|(1L<<36)|(x6<<30)|(ht<<28)|
+        (r3<<20)|(r2<<13)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+    SETREG(r3);
+}
+
+static void
+_M3(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t im, jit_word_t r1)
+{
+    jit_uint8_t                cc = INST_M;
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(ht &   ~0x3L));
+    assert(!(r3 &  ~0x7fL));
+    assert(im > -256 && im <= 255);
+    assert(!(r1 &  ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((5L<<37)|(((im>>8)&1L)<<36)|(x6<<30)|(ht<<28)|
+        (((im>>7)&1L)<<27)|(r3<<20)|((im&0x7fL)<<13)|(r1<<6)|_p, cc);
+    SETREG(r1);
+    SETREG(r3);
+}
+
+static void
+_M5(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t r2, jit_word_t im)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(ht &   ~0x3L));
+    assert(!(r3 &  ~0x7fL));
+    assert(!(r2 &  ~0x7fL));
+    assert(im > -256 && im <= 255);
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    inst((5L<<37)|(((im>>8)&1L)<<36)|(x6<<30)|(ht<<28)|
+        (((im>>7)&1L)<<27)|(r3<<20)|(r2<<13)|((im&0x7fL)<<6)|_p, INST_M);
+    SETREG(r3);
+}
+
+static void
+_M6(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x6, jit_word_t ht, jit_word_t x, jit_word_t r3, jit_word_t r2)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(x  &  ~0x1L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    inst((4L<<37)|(x6<<30)|(ht<<28)|(x<<27)|(r3<<20)|(r2<<13)|_p, INST_M);
+}
+
+static void
+_M13(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t r2)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    TSTREG1(r3);
+    if (r2)
+       TSTFREG1(r2);
+    TSTPRED(_p);
+    inst((6L<<37)|(x6<<30)|(ht<<28)|(r3<<20)|(r2<<13)|_p, INST_M);
+}
+
+static void
+_M14(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t r2)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    inst((6L<<37)|(1L<<36)|(x6<<30)|(ht<<28)|(r3<<20)|(r2<<13)|_p, INST_M);
+}
+
+static void
+_M15(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t im)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(ht &   ~0x3L));
+    assert(!(r3 &  ~0x7fL));
+    assert(!(im & ~0x1ffL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    inst((7L<<37)|(((im>>8)&1L)<<36)|(x6<<30)|(ht<<28)|
+        (((im>>7)&1L)<<27)|(r3<<20)|((im&0x7fL)<<13)|_p, INST_M);
+}
+
+static void
+_M16(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((4L<<37)|(x6<<30)|(ht<<28)|(1L<<27)|
+        (r3<<20)|(r2<<13)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+_M17(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t im, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(im &  ~0x7L));
+    assert(!(r1 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((4L<<37)|(x6<<30)|(ht<<28)|(1L<<27)|
+        (r3<<20)|(im<<13)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+_M20x(jit_state_t *_jit, jit_word_t _p,
+      jit_word_t x3, jit_word_t r2, jit_word_t im)
+{
+    assert(!(_p &     ~0x3fL));
+    assert(!(x3 &      ~0x7L));
+    assert(!(r2 &     ~0x7fL));
+    assert(!(im & ~0x1fffffL));
+    if (x3 == 1)
+       TSTREG1(r2);
+    else
+       TSTFREG1(r2);
+    TSTPRED(_p);
+    inst((1L<<37)|(((im>>20)&1L)<<36)|(x3<<33)|
+        (((im>>7)&0x1fffL)<<20)|(r2<<13)|((im&0x7fL)<<6)|_p, INST_M);
+}
+
+static void
+_M22x(jit_state_t *_jit, jit_word_t _p,
+      jit_word_t x3, jit_word_t im, jit_word_t r1)
+{
+    assert(!(_p &     ~0x3fL));
+    assert(!(x3 &      ~0x7L));
+    assert(!(im & ~0x1fffffL));
+    assert(!(r1 &     ~0x7fL));
+    TSTPRED(_p);
+    if (x3 < 6)
+       TSTREG1(r1);
+    else
+       TSTFREG1(r1);
+    inst((((im>>20)&1L)<<36)|(x3<<33)|((im&0xffffL)<<13)|(r1<<6)|_p, INST_M);
+    if (x3 < 6)
+       SETREG(r1);
+    else
+       SETFREG(r1);
+}
+
+static void
+_M24(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x2, jit_word_t x4)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x2 &  ~0x3L));
+    assert(!(x4 &  ~0xfL));
+    TSTPRED(_p);
+    inst((x2<<31)|(x4<<27)|_p, INST_M);
+}
+
+static void
+_M26x(jit_state_t *_jit, jit_word_t _p,
+      jit_word_t x4, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x4 &  ~0xfL));
+    assert(!(r1 & ~0x7fL));
+    if (x4 == 2)
+       TSTREG1(r1);
+    else
+       TSTFREG1(r1);
+    TSTPRED(_p);
+    inst((1L<<31)|(x4<<27)|(r1<<6)|_p, INST_M);
+}
+
+static void
+_M28(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x, jit_word_t r3)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x  &  ~0x1L));
+    assert(!(r3 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    inst((1L<<37)|(x<<36)|(0x30L<<27)|(r3<<20)|_p, INST_M);
+}
+
+static void
+_M29(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t ar, jit_word_t r2)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(ar  & ~0x7L));
+    assert(!(r2 & ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    inst((1L<<37)|(0x2aL<<27)|(ar<<20)|(r2<<13)|_p, INST_M);
+}
+
+static void
+_M30(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t ar, jit_word_t im)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(ar  & ~0x7L));
+    assert(!(im & ~0xffL));
+    TSTPRED(_p);
+    inst((((im>>7)&1L)<<36)|(2L<<31)|(0x8L<<27)|
+        (ar<<20)|((im&0x7fL)<<13)|_p, INST_M);
+}
+
+static void
+_M31(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t ar, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(ar  & ~0x7L));
+    assert(!(r1 & ~0x7fL));
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((1L<<37)|(0x22L<<27)|(ar<<20)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+_M32(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t cr, jit_word_t r2)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(cr  & ~0x7L));
+    assert(!(r2 & ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    inst((1L<<37)|(0x2cL<<27)|(cr<<20)|(r2<<13)|_p, INST_M);
+}
+
+static void
+_M33(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t cr, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(cr  & ~0x7L));
+    assert(!(r1 & ~0x7fL));
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((1L<<37)|(0x24L<<27)|(cr<<20)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+_M34(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t sor, jit_word_t sol, jit_word_t sof, jit_word_t r1)
+{
+    assert(!(_p  & ~0x3fL));
+    assert(!(sor &  ~0xfL));
+    assert(!(sol & ~0x7fL));
+    assert(!(sof & ~0x7fL));
+    assert(!(r1  & ~0x7fL));
+    TSTPRED(_p);
+    inst((1L<<37)|(6L<<33)|(sor<<27)|(sol<<20)|(sof<<13)|(r1<<6)|_p, INST_M);
+}
+
+static void
+_M35(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r2)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(r2 & ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    inst((1L<<37)|(x6<<27)|(r2<<13)|_p, INST_M);
+}
+
+static void
+_M36(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(r1 & ~0x7fL));
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((1L<<37)|(x6<<27)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+_M37(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t im)
+{
+    assert(!(_p &    ~0x3fL));
+    assert(!(im & ~0x1ffffL));
+    TSTPRED(_p);
+    inst((((im>>20)&1L)<<36)|((im&0xffffL)<<6)|_p, INST_M);
+}
+
+static void
+_M38(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r3, jit_word_t r2, jit_word_t r1)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(r3 &  ~0x7fL));
+    assert(!(r2 &  ~0x7fL));
+    assert(!(r1 &  ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((1L<<37)|(x6<<27)|(r3<<20)|(r2<<13)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+_M39(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r3, jit_word_t im, jit_word_t r1)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(r3 &  ~0x7fL));
+    assert(!(im &   ~0x7L));
+    assert(!(r1 &  ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((1L<<37)|(x6<<27)|(r3<<20)|(im<<13)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+_M40(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r3, jit_word_t im)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(r3 &  ~0x7fL));
+    assert(!(im &   ~0x7L));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    inst((1L<<37)|(x6<<27)|(r3<<20)|(im<<13)|_p, INST_M);
+}
+
+static void
+_M41(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r2)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(r2 &  ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    inst((1L<<37)|(x6<<27)|(r2<<13)|_p, INST_M);
+}
+
+static void
+_M42(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r3, jit_word_t r2)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(r3 &  ~0x7fL));
+    assert(!(r2 &  ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    inst((1L<<37)|(x6<<27)|(r3<<20)|(r2<<13)|_p, INST_M);
+}
+
+static void
+_M43(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r3, jit_word_t r1)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(r3 &  ~0x7fL));
+    assert(!(r1 &  ~0x7fL));
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((1L<<37)|(x6<<27)|(r3<<20)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+_M44(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x4, jit_word_t im)
+{
+    assert(!(_p &    ~0x3fL));
+    assert(!(x4 &     ~0xfL));
+    assert(!(im & ~0xfffffL));
+    TSTPRED(_p);
+    inst((((im>>23)&1L)<<36)|(((im>>21)&3L)<<31)|
+        (x4<<27)|((im&0x1ffffL)<<6)|_p, INST_M);
+}
+
+static void
+_M45(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r3, jit_word_t r2)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(r3 &  ~0x7fL));
+    assert(!(r2 &  ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    inst((1L<<37)|(x6<<27)|(r3<<20)|(r2<<13)|_p, INST_M);
+}
+
+static void
+_M46(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r3, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    if (r1)    TSTREG1(r1);
+    inst((1L<<37)|(x6<<27)|(r3<<20)|(r1<<6)|_p, INST_M);
+    if (r1)    SETREG(r1);
+}
+
+static void
+_M48(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t y, jit_word_t im)
+{
+    assert(!(_p &    ~0x3fL));
+    assert(!(y  &     ~0x1L));
+    assert(!(im & ~0x1ffffL));
+    TSTPRED(_p);
+    inst((((im>>20)&1L)<<36)|(1L<<27)|(y<<26)|((im&0xffffL)<<6)|_p, INST_M);
+}
+
+static void
+_B1(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t d, jit_word_t wh, jit_word_t im, jit_word_t p, jit_word_t tp)
+{
+    assert(!(_p &    ~0x3fL));
+    assert(!(d  &     ~0x1L));
+    assert(!(wh &     ~0x3L));
+    assert(im >= -1048576 && im <= 1048575);
+    assert(!(p  &     ~0x1L));
+    assert(!(tp &     ~0x7L));
+    TSTPRED(_p);
+    inst((4L<<37)|(((im>>20)&1L)<<36)|(d<<35)|(wh<<33)|
+        ((im&0xfffffL)<<13)|(p<<12)|(tp<<6)|_p, INST_B);
+}
+
+static void
+_B3(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t d, jit_word_t wh, jit_word_t im, jit_word_t p, jit_word_t b)
+{
+    assert(!(_p &    ~0x3fL));
+    assert(!(d  &     ~0x1L));
+    assert(!(wh &     ~0x3L));
+    assert(im >= -1048576 && im <= 1048575);
+    assert(!(p  &     ~0x1L));
+    assert(!(b  &     ~0x3L));
+    TSTPRED(_p);
+    inst((5L<<37)|(((im>>20)&1L)<<36)|(d<<35)|(wh<<33)|
+        ((im&0xfffffL)<<13)|(p<<12)|(b<<6)|_p, INST_B);
+}
+
+static void
+_B4(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t d, jit_word_t wh, jit_word_t x6,
+    jit_word_t b, jit_word_t p, jit_word_t tp)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(d  &  ~0x1L));
+    assert(!(wh &  ~0x3L));
+    assert(!(x6 & ~0x3fL));
+    assert(!(b  &  ~0x7L));
+    assert(!(p  &  ~0x1L));
+    assert(!(tp &  ~0x7L));
+    TSTPRED(_p);
+    inst((d<<35)|(wh<<33)|(x6<<27)|(b<<13)|(p<<12)|(tp<<6)|_p, INST_B);
+}
+
+static void
+_B5(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t d, jit_word_t wh, jit_word_t b2, jit_word_t p, jit_word_t b1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(d  &  ~0x1L));
+    assert(!(wh &  ~0x3L));
+    assert(!(b2 &  ~0x7L));
+    assert(!(p  &  ~0x1L));
+    assert(!(b1 &  ~0x7L));
+    TSTPRED(_p);
+    inst((1L<<37)|(d<<35)|(wh<<32)|(b2<<13)|(p<<12)|(b1<<6)|_p, INST_B);
+}
+
+static void
+_B6(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t ih, jit_word_t im, jit_word_t tag, jit_word_t wh)
+{
+    assert(!(_p &     ~0x3fL));
+    assert(!(ih  &     ~0x1L));
+    assert(!(im  & ~0x1ffffL));
+    assert(!(tag &   ~0x1ffL));
+    assert(!(wh  &     ~0x3L));
+    TSTPRED(_p);
+    inst((7L<<37)|(((im>>20)&1L)<<36)|(ih<<35)|(((tag>>7)&3L)<<33)|
+        ((im&0xfffffL)<<13)|((tag&0x7fL)<<6)|(wh<<3)|_p, INST_B);
+}
+
+static void
+_B7(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t ih, jit_word_t x6, jit_word_t b2, jit_word_t tag, jit_word_t wh)
+{
+    assert(!(_p &   ~0x3fL));
+    assert(!(ih  &   ~0x1L));
+    assert(!(x6  &  ~0x3fL));
+    assert(!(b2  &   ~0x7L));
+    assert(!(tag & ~0x1ffL));
+    assert(!(wh  &   ~0x3L));
+    TSTPRED(_p);
+    inst((2L<<37)|(ih<<35)|(((tag>>7)&3L)<<33)|(x6<<27)|
+        (b2<<13)|((tag&0x7fL)<<6)|(wh<<3)|_p, INST_B);
+}
+
+static void
+_B8(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x6)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    TSTPRED(_p);
+    inst((x6<<27)|_p, INST_B);
+}
+
+static void
+_B9(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t op, jit_word_t x6, jit_word_t im)
+{
+    assert(!(_p &    ~0x3fL));
+    assert(!(op &     ~0xfL));
+    assert(!(x6 &    ~0x3fL));
+    assert(!(im & ~0x1ffffL));
+    TSTPRED(_p);
+    inst((op<<37)|(((im>>20)&1L)<<36)|(x6<<27)|((im&0xffffL)<<6)|_p, INST_B);
+}
+
+static void
+_X1(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t im)
+{
+    jit_word_t         i41, i1, i20;
+    assert(!(_p &               ~0x3fL));
+    assert(im > -0x2000000000000000 && im <= 0x1fffffffffffffff);
+    i41 = (im >> 22) & 0x1ffffffffffL;
+    i1  = (im >> 21) &           0x1L;
+    i20 =  im        &       0xfffffL;
+    TSTPRED(_p);
+    inst(i41, INST_L);
+    inst((i1<<36)|(i20<<6)|_p, INST_X);
+}
+
+static void
+_X2(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t r1, jit_word_t im)
+{
+    jit_word_t         i1, i41, ic, i5, i9, i7;
+    assert(!(_p & ~0x3fL));
+    assert(!(r1 & ~0x7fL));
+    i1  = (im >> 63) &           0x1L;
+    i41 = (im >> 22) & 0x1ffffffffffL;
+    ic  = (im >> 21) &           0x1L;
+    i5  = (im >> 16) &          0x1fL;
+    i9  = (im >>  7) &         0x1ffL;
+    i7  =  im        &          0x7fL;
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst(i41, INST_L);
+    inst((6L<<37)|(i1<<36)|(i9<<27)|(i5<<22)|
+        (ic<<21)|(i7<<13)|(r1<<6)|_p, INST_X);
+    SETREG(r1);
+}
+
+static void
+_X3x(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t op, jit_word_t d, jit_word_t wh,
+     jit_word_t p, jit_word_t tp, jit_word_t im)
+{
+    /* target64 = IP + ((i1 << 59 | imm39 << 20 | imm20b) << 4) */
+    jit_word_t         i1, i41, i20;
+    assert(!(_p &               ~0x3fL));
+    assert(!(op &                ~0xfL));
+    assert(!(d  &                ~0x1L));
+    assert(!(wh &                ~0x3L));
+    assert(!(p  &                ~0x1L));
+    assert(!(tp &                ~0x7L));
+    i1  = (im >> 61) &           0x1L;
+    i41 = (im >> 22) & 0x1ffffffffffL;
+    i20 =  im        &       0xfffffL;
+    TSTPRED(_p);
+    inst(i41, INST_L);
+    inst((op<<37)|(i1<<36)|(d<<35)|(wh<<33)|
+        (i20<<13)|(p<<12)|(tp<<6)|_p, INST_X);
+}
+
+static void
+_X5(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t y, jit_word_t im)
+{
+    jit_word_t         i41, i1, i20;
+    assert(!(_p &               ~0x3fL));
+    assert(im > -0x2000000000000000 && im <= 0x1fffffffffffffff);
+    i41 = (im >> 22) & 0x1ffffffffffL;
+    i1  = (im >> 21) &           0x1L;
+    i20 =  im        &       0xfffffL;
+    TSTPRED(_p);
+    inst(i41, INST_L);
+    inst((i1<<36)|(1L<<27)|(y<<26)|(i20<<6)|_p, INST_X);
+}
+
+static void
+_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    /* patch pushargr */
+    if (r0 >= 120)
+       r0 = _jitc->rout + (r0 - 120);
+
+    MOV(r0, r1);
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    /* patch pushargi */
+    if (r0 >= 120)
+       r0 = _jitc->rout + (r0 - 120);
+
+    if (i0 >= -2097152 && i0 <= 2097151)
+       MOVI(r0, i0);
+    else
+       MOVL(r0, i0);
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    sync();
+    w = _jit->pc.w;
+    MOVL(r0, i0);
+    return (w);
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -8192 && i0 <= 8191)
+       ADDS(r0, i0, r1);
+    else if (!(r1 & ~3) && i0 >= -2097152 && i0 <= 2097151)
+       ADDL(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       addr(rn(reg), r1, r2);
+       ltr_u(rn(jit_carry), rn(reg), r1);
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       addr(r0, r1, r2);
+       ltr_u(rn(jit_carry), r0, r1);
+    }
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ltr_u(rn(jit_carry), rn(reg), r1);
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       addi(r0, r1, i0);
+       ltr_u(rn(jit_carry), r0, r1);
+    }
+}
+
+static void
+_addxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    addcr(r0, r1, r2);
+    addcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    addci(r0, r1, i0);
+    addcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    subr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       subr(rn(reg), r1, r2);
+       ltr_u(rn(jit_carry), r1, rn(reg));
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       subr(r0, r1, r2);
+       ltr_u(rn(jit_carry), r1, r0);
+    }
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, -i0);
+       ltr_u(rn(jit_carry), r1, rn(reg));
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       addi(r0, r1, -i0);
+       ltr_u(rn(jit_carry), r1, r0);
+    }
+}
+
+static void
+_subxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    subcr(r0, r1, r2);
+    subcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    subci(r0, r1, i0);
+    subcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -128 && i0 <= 127)
+       SUBI(r0, i0, r1);
+    else if (!(r1 & ~3) && i0 >= -2097151 && i0 <= 2097152)
+       ADDL(r1, -i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subr(r0, rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_mulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                f0, f1;
+    f0 = jit_get_reg(jit_class_fpr);
+    f1 = jit_get_reg(jit_class_fpr);
+    SETF_SIG(rn(f0), r1);
+    SETF_SIG(rn(f1), r2);
+    XMPY_L(rn(f0), rn(f0), rn(f1));
+    GETF_SIG(r0, rn(f0));
+    jit_unget_reg(f0);
+    jit_unget_reg(f1);
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    mulr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+#if !defined(__GNUC__)
+static long
+__divdi3(long u, long v)
+{
+    return (u / v);
+}
+
+static unsigned long
+__udivdi3(unsigned long u, unsigned long v)
+{
+    return (u / v);
+}
+
+static long
+__moddi3(long u, long v)
+{
+    return (u % v);
+}
+
+static unsigned long
+__umoddi3(unsigned long u, unsigned long v)
+{
+    return (u % v);
+}
+#endif
+
+static void
+_divr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    MOV(_jitc->rout, r1);
+    MOV(_jitc->rout + 1, r2);
+    calli((jit_word_t)__divdi3);
+    MOV(r0, GR_8);
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    switch (i0) {
+       case 1:
+           movr(r0, r1);
+           return;
+       case -1:
+           negr(r0, r1);
+           return;
+       default:
+           if (i0 > 0 && !(i0 & (i0 - 1))) {
+               movr(r0, r1);
+               rshi(r0, r0, ffsl(i0) - 1);
+               return;
+           }
+           break;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_divr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    MOV(_jitc->rout, r1);
+    MOV(_jitc->rout + 1, r2);
+    calli((jit_word_t)__udivdi3);
+    MOV(r0, GR_8);
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 1) {
+       movr(r0, r1);
+       return;
+    }
+    else if (i0 > 0 && !(i0 & (i0 - 1))) {
+       movr(r0, r1);
+       rshi_u(r0, r0, ffsl(i0) - 1);
+       return;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    MOV(_jitc->rout, r1);
+    MOV(_jitc->rout + 1, r2);
+    calli((jit_word_t)__moddi3);
+    MOV(r0, GR_8);
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 1 || i0 == -1) {
+       MOV(r0, GR_0);
+       return;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    MOV(_jitc->rout, r1);
+    MOV(_jitc->rout + 1, r2);
+    calli((jit_word_t)__umoddi3);
+    MOV(r0, GR_8);
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 1) {
+       MOV(r0, GR_0);
+       return;
+    }
+    else if (i0 > 0 && !(i0 & (i0 - 1))) {
+       andi(r0, r1, i0 - 1);
+       return;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_mulh(jit_state_t *_jit,
+      jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_bool_t sign)
+{
+    jit_int32_t                f0, f1;
+    f0 = jit_get_reg(jit_class_fpr);
+    f1 = jit_get_reg(jit_class_fpr);
+    SETF_SIG(rn(f0), r1);
+    SETF_SIG(rn(f1), r2);
+    if (sign)
+       XMPY_H(rn(f0), rn(f0), rn(f1));
+    else
+       XMPY_HU(rn(f0), rn(f0), rn(f1));
+    GETF_SIG(r0, rn(f0));
+    jit_unget_reg(f0);
+    jit_unget_reg(f1);
+}
+
+static void
+_iqmulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    if (r0 == r2 || r0 == r3) {
+       reg = jit_get_reg(jit_class_gpr);
+       mulr(rn(reg), r2, r3);
+    }
+    else
+       mulr(r0, r2, r3);
+    mulh(r1, r2, r3, sign);
+    if (r0 == r2 || r0 == r3) {
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_iqmuli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    iqmulr(r0, r1, r2, rn(reg), sign);
+    jit_unget_reg(reg);
+}
+
+static void
+_iqdivr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    jit_int32_t                sv0, rg0;
+    jit_int32_t                sv1, rg1;
+
+    if (r0 == r2 || r0 == r3) {
+       sv0 = jit_get_reg(jit_class_gpr);
+       rg0 = rn(sv0);
+    }
+    else
+       rg0 = r0;
+    if (r1 == r2 || r1 == r3) {
+       sv1 = jit_get_reg(jit_class_gpr);
+       rg1 = rn(sv1);
+    }
+    else
+       rg1 = r1;
+
+    if (sign)
+       divr(rg0, r2, r3);
+    else
+       divr_u(rg0, r2, r3);
+    mulr(rg1, r3, rg0);
+    subr(rg1, r2, rg1);
+    if (rg0 != r0) {
+       movr(r0, rg0);
+       jit_unget_reg(sv0);
+    }
+    if (rg1 != r1) {
+       movr(r1, rg1);
+       jit_unget_reg(sv1);
+    }
+}
+
+static void
+_iqdivi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    iqdivr(r0, r1, r2, rn(reg), sign);
+    jit_unget_reg(reg);
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -128 && i0 <= 127)
+       ANDI(r0, i0, r1);
+    else if (~i0 >= -128 && ~i0 <= 127)
+       ANDCMI(r0, ~i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       andr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -128 && i0 <= 127)
+       ORI(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       orr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -128 && i0 <= 127)
+       XORI(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       xorr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static void
+_htonr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    rshi(rn(t0), r1, 8);
+    andi(r0, r1, 0xff);
+    andi(rn(t0), rn(t0), 0xff);
+    lshi(r0, r0, 8);
+    orr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_htonr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr);
+    t2 = jit_get_reg(jit_class_gpr);
+    rshi(rn(t0), r1, 24);
+    rshi(rn(t1), r1, 16);
+    rshi(rn(t2), r1,  8);
+    andi(rn(t0), rn(t0), 0xff);
+    andi(rn(t1), rn(t1), 0xff);
+    andi(rn(t2), rn(t2), 0xff);
+    andi(r0, r1, 0xff);
+    lshi(r0, r0, 24);
+    lshi(rn(t1), rn(t1), 8);
+    orr(r0, r0, rn(t0));
+    lshi(rn(t2), rn(t2), 16);
+    orr(r0, r0, rn(t1));
+    orr(r0, r0, rn(t2));
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+}
+#endif
+
+static void
+_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    lshr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_rshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    rshr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_rshi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    rshr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ltr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_LT(PR_6, PR_7, r1, r2);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+
+static void
+_lti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -127 && i0 <= 128)
+       CMPI_LT(PR_7, PR_6, i0 - 1, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMP_LT(PR_6, PR_7, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+
+static void
+_ltr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_LTU(PR_6, PR_7, r1, r2);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+
+static void
+_lti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -127 && i0 <= 128)
+       CMPI_LTU(PR_7, PR_6, i0 - 1, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMP_LTU(PR_6, PR_7, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+
+static void
+_ler(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_LT(PR_6, PR_7, r2, r1);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+
+static void
+_lei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ler(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ler_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_LTU(PR_6, PR_7, r2, r1);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+
+static void
+_lei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ler_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_eqr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_EQ(PR_6, PR_7, r1, r2);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+
+static void
+_eqi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -128 && i0 <= 127)
+       CMPI_EQ(PR_6, PR_7, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMP_EQ(PR_6, PR_7, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+
+static void
+_ger(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_LT(PR_6, PR_7, r1, r2);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+
+static void
+_gei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -127 && i0 <= 128)
+       CMPI_LT(PR_7, PR_6, i0 - 1, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMP_LT(PR_6, PR_7, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+
+static void
+_ger_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_LTU(PR_6, PR_7, r1, r2);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+
+static void
+_gei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -127 && i0 <= 128)
+       CMPI_LTU(PR_7, PR_6, i0 - 1, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMP_LTU(PR_6, PR_7, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+
+static void
+_gtr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_LT(PR_6, PR_7, r2, r1);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+
+static void
+_gti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    gtr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_gtr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_LTU(PR_6, PR_7, r2, r1);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+
+static void
+_gti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    gtr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ner(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP_EQ(PR_6, PR_7, r1, r2);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+
+static void
+_nei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 >= -128 && i0 <= 127)
+       CMPI_EQ(PR_6, PR_7, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMP_EQ(PR_6, PR_7, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+
+static void
+_ldr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ldr_uc(r0, r1);
+    extr_c(r0, r0);
+}
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_c(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_uc(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ldr_us(r0, r1);
+    extr_s(r0, r0);
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_s(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_us(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ldr_ui(r0, r1);
+    extr_i(r0, r0);
+}
+
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_i(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_ui(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_l(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_l(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_c(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_c(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldr_c(r0, r1);
+}
+
+static void
+_ldxr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_uc(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_uc(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldr_uc(r0, r1);
+}
+
+static void
+_ldxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_s(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_s(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldr_s(r0, r1);
+}
+
+static void
+_ldxr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_us(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_us(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldr_us(r0, r1);
+}
+
+static void
+_ldxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_i(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_i(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldr_i(r0, r1);
+}
+
+static void
+_ldxr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_ui(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_ui(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldr_ui(r0, r1);
+}
+
+static void
+_ldxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_l(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_l(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldr_l(r0, r1);
+}
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_c(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_s(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_i(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_sti_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_l(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_c(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_c(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+    else
+       str_c(r0, r1);
+}
+
+static void
+_stxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_s(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_s(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+    else
+       str_s(r0, r1);
+}
+
+static void
+_stxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_i(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_i(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+    else
+       str_i(r0, r1);
+}
+
+static void
+_stxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_l(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_l(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+    else
+       str_l(r0, r1);
+}
+
+static jit_word_t
+_bltr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_LT(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_blti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -127 && i1 <= 128)
+       CMPI_LT(PR_7, PR_6, i1 - 1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMP_LT(PR_6, PR_7, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_bltr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_LTU(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_blti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -127 && i1 <= 128)
+       CMPI_LTU(PR_7, PR_6, i1 - 1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMP_LTU(PR_6, PR_7, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_bler(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_LT(PR_6, PR_7, r1, r0);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_blei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bler(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bler_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_LTU(PR_6, PR_7, r1, r0);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_blei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bler_u(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_beqr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_EQ(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_beqi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -128 && i1 <= 127)
+       CMPI_EQ(PR_6, PR_7, i1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMP_EQ(PR_6, PR_7, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_bger(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_LT(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_bgei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -127 && i1 <= 128)
+       CMPI_LT(PR_7, PR_6, i1 - 1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMP_LT(PR_6, PR_7, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_bger_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_LTU(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_bgei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -127 && i1 <= 128)
+       CMPI_LTU(PR_7, PR_6, i1 - 1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMP_LTU(PR_6, PR_7, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_bgtr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_LT(PR_6, PR_7, r1, r0);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_bgti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bgtr(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bgtr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_LTU(PR_6, PR_7, r1, r0);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_bgti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bgtr_u(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bner(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_EQ(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_bnei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (i1 >= -128 && i1 <= 127)
+       CMPI_EQ(PR_6, PR_7, i1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMP_EQ(PR_6, PR_7, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_bmsr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    andr(rn(reg), r0, r1);
+    CMPI_EQ(PR_6, PR_7, 0, rn(reg));
+    jit_unget_reg(reg);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_bmsi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i1);
+    andr(rn(reg), r0, rn(reg));
+    CMPI_EQ(PR_6, PR_7, 0, rn(reg));
+    jit_unget_reg(reg);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+
+static jit_word_t
+_bmcr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    andr(rn(reg), r0, r1);
+    CMPI_EQ(PR_6, PR_7, 0, rn(reg));
+    jit_unget_reg(reg);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_bmci(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i1);
+    andr(rn(reg), r0, rn(reg));
+    CMPI_EQ(PR_6, PR_7, 0, rn(reg));
+    jit_unget_reg(reg);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+
+static jit_word_t
+_baddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1,
+       jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+    /* t1 = r0 + r1;   overflow = r1 < 0 ? r0 < t1 : t1 < r0 */
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    lti(rn(t0), r1, 0);                        /* t0 = r1 < 0 */
+    addr(rn(t1), r0, r1);              /* t1 = r0 + r1 */
+    ltr(rn(t2), rn(t1), r0);           /* t2 = t1 < r0 */
+    ltr(rn(t1), r0, rn(t1));           /* t1 = r0 < t1 */
+    CMPI_EQ(PR_6, PR_7, 0, rn(t0));
+    CMPI_EQ_p(PR_8, PR_9, 0, rn(t2), PR_6);/* if (t0==0) p8=t2==0,p9=t2!=0; */
+    CMPI_EQ_p(PR_8, PR_9, 0, rn(t1), PR_7);/* if (t0!=0) p8=t1==0,p9=t1!=0; */
+    addr(r0, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, carry ? PR_9 : PR_8);
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_baddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1,
+       jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = baddr(i0, r0, rn(reg), carry);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_baddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1,
+        jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    addr(rn(t0), r0, r1);
+    ltr_u(rn(t1), rn(t0), r0);
+    CMPI_EQ(PR_6, PR_7, 0, rn(t1));
+    MOV(r0, rn(t0));
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, carry ? PR_7 : PR_6);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_baddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1,
+        jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = baddr_u(i0, r0, rn(reg), carry);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bsubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1,
+       jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+    /* t1 = r0 - r1;   overflow = 0 < r1 ? r0 < t1 : t1 < r0 */
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    gti(rn(t0), r1, 0);                        /* t0 = r1 > 0 */
+    subr(rn(t1), r0, r1);              /* t1 = r0 - r1 */
+    ltr(rn(t2), rn(t1), r0);           /* t2 = t1 < r0 */
+    ltr(rn(t1), r0, rn(t1));           /* t1 = r0 < t1 */
+    CMPI_EQ(PR_6, PR_7, 0, rn(t0));
+    CMPI_EQ_p(PR_8, PR_9, 0, rn(t2), PR_6);/* if (t0==0) p4=t2==0,p5=t2!=0; */
+    CMPI_EQ_p(PR_8, PR_9, 0, rn(t1), PR_7);/* if (t0!=0) p4=t1==0,p5=t1!=0; */
+    subr(r0, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, carry ? PR_9 : PR_8);
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bsubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1,
+       jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bsubr(i0, r0, rn(reg), carry);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bsubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1,
+        jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    subr(rn(t0), r0, r1);
+    ltr_u(rn(t1), r0, rn(t0));
+    CMPI_EQ(PR_6, PR_7, 0, rn(t1));
+    MOV(r0, rn(t0));
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, carry ? PR_7 : PR_6);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bsubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1,
+        jit_bool_t carry)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bsubr_u(i0, r0, rn(reg), carry);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_jmpr(jit_state_t *_jit, jit_int32_t r0)
+{
+    MOV_br_rn(BR_6, r0);
+    BR(BR_6);
+}
+
+static void
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         d;
+    sync();
+    d = ((jit_word_t)i0 - _jit->pc.w) >> 4;
+    if (d >= -16777216 && d <= 16777215)
+       BRI(d);
+    else
+       BRL(d);
+}
+
+static jit_word_t
+_jmpi_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         d, w;
+    sync();
+    w = _jit->pc.w;
+    d = ((jit_word_t)i0 - w) >> 4;
+    BRL(d);
+    return (w);
+}
+
+static void
+_callr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    LD8_inc(rn(reg), r0, 8);
+    MOV_br_rn(BR_6, rn(reg));
+    jit_unget_reg(reg);
+    LD8(GR_1, r0);
+    BR_CALL(BR_0, BR_6);
+}
+
+static void
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    callr(rn(reg));
+    jit_unget_reg(reg);
+}
+
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    w = movi_p(rn(reg), i0);
+    callr(rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                reg, ruse, rout;
+
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar)
+       _jitc->function->self.aoff &= -16;
+    _jitc->function->stack = ((_jitc->function->self.alen -
+                              _jitc->function->self.aoff) + 15) & -16;
+
+    /* First lowest unused register is first output register */
+    for (reg = _R115; reg >= _R40; reg--) {
+       if (jit_regset_tstbit(&_jitc->function->regset, reg))
+           break;
+    }
+    _jitc->breg = rn(reg) + 1;
+    _jitc->rout = _jitc->breg + 5;
+    ruse = _jitc->rout - GR_32;
+
+    /* How many out argument registers required? */
+    if (!_jitc->function->define_frame) {
+       for (reg = _OUT7; reg >= _OUT0; --reg) {
+           if (jit_regset_tstbit(&_jitc->function->regset, reg))
+               break;
+       }
+       rout = (reg + 1) - _OUT0;
+    }
+    else
+       rout = 8;
+
+    /* Do not know if will call div/mod functions (sqrt* needs one) */
+    if (rout < 2)
+       rout = 2;
+
+    /* Match gcc prolog */
+    ALLOC(_jitc->breg + 1, ruse, rout);
+    MOV(_jitc->breg + 2, GR_12);
+    MOV_rn_br(_jitc->breg, BR_0);
+    MOV(_jitc->breg + 3, GR_1);
+
+    /* lightning specific, use r4 as frame pointer */
+    MOV(_jitc->breg + 4, GR_4);
+    addi(GR_4, GR_12, -(stack_framesize + params_offset));
+
+    /* adjust stack pointer */
+    addi(GR_12, GR_12, -(stack_framesize +
+                        (params_offset << 1) + _jitc->function->stack));
+
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F0))
+       STF_SPILL(GR_4, rn(JIT_F0));
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F1)) {
+       addi(GR_2, GR_4, 16);
+       STF_SPILL(GR_2, rn(JIT_F1));
+    }
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F2)) {
+       addi(GR_2, GR_4, 32);
+       STF_SPILL(GR_2, rn(JIT_F2));
+    }
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F3)) {
+       addi(GR_2, GR_4, 48);
+       STF_SPILL(GR_2, rn(JIT_F3));
+    }
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F4)) {
+       addi(GR_2, GR_4, 64);
+       STF_SPILL(GR_2, rn(JIT_F4));
+    }
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F5)) {
+       addi(GR_2, GR_4, 80);
+       STF_SPILL(GR_2, rn(JIT_F5));
+    }
+
+    if (_jitc->function->allocar) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, GR_4, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    if (_jitc->function->self.call & jit_call_varargs) {
+       for (reg = _jitc->function->vagp; reg < 8; ++reg)
+           stxi(112 + reg * 8, GR_4, GR_32 + reg);
+    }
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    if (_jitc->function->assume_frame)
+       return;
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F0))
+       LDF_FILL(rn(JIT_F0), GR_4);
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F1)) {
+       addi(GR_2, GR_4, 16);
+       LDF_FILL(rn(JIT_F1), GR_2);
+    }
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F2)) {
+       addi(GR_2, GR_4, 32);
+       LDF_FILL(rn(JIT_F2), GR_2);
+    }
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F3)) {
+       addi(GR_2, GR_4, 48);
+       LDF_FILL(rn(JIT_F3), GR_2);
+    }
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F4)) {
+       addi(GR_2, GR_4, 64);
+       LDF_FILL(rn(JIT_F4), GR_2);
+    }
+    if (jit_regset_tstbit(&_jitc->function->regset, JIT_F5)) {
+       addi(GR_2, GR_4, 80);
+       LDF_FILL(rn(JIT_F5), GR_2);
+    }
+    /* Match gcc epilog */
+    MOV(GR_1, _jitc->breg + 3);
+    MOV_I_ar_rn(AR_PFS, _jitc->breg + 1);
+    MOV_br_rn(BR_0, _jitc->breg);
+    MOV(GR_12, _jitc->breg + 2);
+    /* Restore lightning specific r4 as frame pointer */
+    MOV(GR_4, _jitc->breg + 4);
+    BR_RET(BR_0);
+    flush();
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Initialize va_list to the first stack argument. */
+    if (_jitc->function->vagp < 8)
+       addi(r0, GR_4, 112 + _jitc->function->vagp * 8);
+    else
+       addi(r0, GR_4, _jitc->function->self.size);
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Load argument. */
+    ldr(r0, r1);
+    /* Update va_list. */
+    addi(r1, r1, 8);
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_code_t code,
+         jit_word_t instr, jit_word_t label)
+{
+    jit_word_t          l, h, tm, s0, s1, s2;
+    union {
+       jit_word_t       w;
+       jit_word_t      *p;
+    } c;
+    jit_word_t          i1, i41, i20, ic, i5, i9, i7;
+    c.w = instr;
+    get_bundle(c.p, l, h, tm, s0, s1, s2);
+    switch (code) {
+       case jit_code_movi:
+           /* Handle jit functions as C function, so that jit function
+            * pointers can be passed to C code, and jit code does not
+            * need to try to differentiate them. */
+       case jit_code_calli:
+           i1  = (label >> 63) &           0x1L;
+           i41 = (label >> 22) & 0x1ffffffffffL;
+           ic  = (label >> 21) &           0x1L;
+           i5  = (label >> 16) &          0x1fL;
+           i9  = (label >>  7) &         0x1ffL;
+           i7  =  label        &          0x7fL;
+           s1 = i41;
+           assert((tm & ~1) == TM_M_L_X_ &&
+                  (s2 & 0xfL<<37) == (6L<<37) &&
+                  s0 == nop_m);
+           s2 &= (6L<<37)|(0x7fL<<6);
+           s2 |= (i1<<36)|(i9<<27)|(i5<<22)|(ic<<21)|(i7<<13);
+           break;
+       case jit_code_jmpi:
+           if (_jitc->jump) {
+               /* kludge to hide function descriptors; check that gp
+                * is zero, what is done for all jit functions */
+               if (((long *)label)[1] == 0) {
+                   for (ic = 0; ic < _jitc->prolog.offset; ic++) {
+                       if (_jitc->prolog.ptr[ic] == label) {
+                           label += 16;
+                           break;
+                       }
+                   }
+               }
+           }
+           ic = (label - instr) >> 4;
+           i1  = (ic >> 61) &           0x1L;
+           i41 = (ic >> 22) & 0x1ffffffffffL;
+           i20 =  ic        &       0xfffffL;
+           assert((tm & ~1) == TM_M_L_X_ &&
+                  (s2 & 0xfL<<37) == (0xcL<<37) &&
+                  s0 == nop_m);
+           s1 = i41;
+           s2 &= (0xcL<<37)|(0x7L<<33)|(1L<<12);
+           s2 |= (i1<<36)|(i20<<13);
+           break;
+       default:
+           /* Only B1 in slot 0 expected due to need to either
+            * a stop to update predicates, or a sync before
+            * unconditional short branch */
+           ic = (label - instr) >> 4;
+           assert((s0 >> 37) == 4 && (s0 & (7 << 6)) == 0);
+           s0 &= (4L<<37)|(7L<<33)|(1L<<12)|0x1f;
+           s0 |= (((ic>>20)&1L)<<36)|((ic&0xfffffL)<<13);
+           break;
+    }
+    set_bundle(c.p, l, h, tm, s0, s1, s2);
+}
+#endif
diff --git a/deps/lightning/lib/jit_ia64-fpu.c b/deps/lightning/lib/jit_ia64-fpu.c
new file mode 100644 (file)
index 0000000..19cc381
--- /dev/null
@@ -0,0 +1,1762 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#define SF_S0                          0
+#define SF_S1                          1
+#define SF_S2                          2
+#define SF_S3                          3
+
+#define TSTFREG1(r0)                                                   \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->regs, r0 + 128))                  \
+           stop();                                                     \
+    } while (0)
+#define TSTFREG2(r0, r1)                                               \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->regs, r0 + 128) ||                \
+           jit_regset_tstbit(&_jitc->regs, r1 + 128))                  \
+           stop();                                                     \
+    } while (0)
+#define TSTFREG3(r0, r1, r2)                                           \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->regs, r0 + 128) ||                \
+           jit_regset_tstbit(&_jitc->regs, r1 + 128) ||                \
+           jit_regset_tstbit(&_jitc->regs, r2 + 128))                  \
+           stop();                                                     \
+    } while (0)
+#define SETFREG(r0)            jit_regset_setbit(&_jitc->regs, r0 + 128)
+
+/* libm */
+extern float sqrtf(float);
+extern double sqrt(double);
+#define M7(x6,ht,r3,r2,f1)             _M7(_jit,0,x6,ht,r3,r2,f1)
+static void _M7(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M8(x6,ht,r3,im,f1)             _M8(_jit,0,x6,ht,r3,im,f1)
+static void _M8(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M9(x6,ht,r3,f1)                        _M9(_jit,0,x6,ht,r3,f1)
+static void _M9(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define M10(x6,ht,r3,r2,im)            _M10(_jit,0,x6,ht,r3,r2,im)
+static void _M10(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M11(x6,ht,r3,f2,f1)            _M11(_jit,0,x6,ht,r3,f2,f1)
+static void _M11(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M12(x6,ht,r3,f2,f1)            _M12(_jit,0,x6,ht,r3,f2,f1)
+static void _M12(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define M18(x6,r2,f1)                  _M18(_jit,0,x6,r2,f1)
+static void _M18(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t);
+#define M19(x6,f2,r1)                  _M19(_jit,0,x6,f2,r1)
+static void _M19(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t);
+#define M21(f2,im)                     M20x(0x3,f2,im)
+#define M23(x3,im,f1)                  M22x(x3,im,f1)
+#define M27(f1)                                M26x(3,f1)
+#define F1(op,x,sf,f4,f3,f2,f1)                F1_(_jit,0,op,x,sf,f4,f3,f2,f1)
+#define F2(x2,f4,f3,f2,f1)             F1(0xe,1,x2,f4,f3,f2,f1)
+#define F3(f4,f3,f2,f1)                        F1(0xe,0,0,f4,f3,f2,f1)
+static void F1_(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define F4(rb,sf,ra,p2,f3,f2,ta,p1)    F4_(_jit,0,rb,sf,ra,p2,f3,f2,ta,p1)
+static void F4_(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define F5(p2,fc,f2,ta,p1)             F5_(_jit,0,p2,fc,f2,ta,p1)
+static void F5_(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define F6x(op,q,sf,p2,f3,f2,f1)       F6x_(_jit,0,op,q,sf,p2,f3,f2,f1)
+#define F6(op,sf,p2,f3,f2,f1)          F6x(op,0,sf,p2,f3,f2,f1)
+#define F7(op,sf,p2,f3,f1)             F6x(op,1,sf,p2,f3,0,f1)
+static void F6x_(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t);
+#define F8(op,sf,x6,f3,f2,f1)          F8_(_jit,0,op,sf,x6,f3,f2,f1)
+#define F9(op,x6,f3,f2,f1)             F8(op,0,x6,f3,f2,f1)
+#define F10(op,sf,x6,f2,f1)            F8(op,sf,x6,0,f2,f1)
+#define F11(x6,f2,f1)                  F8(0,0,x6,0,f2,f1)
+static void F8_(jit_state_t*,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t,
+               jit_word_t,jit_word_t,jit_word_t);
+#define F12(sf,x6,omsk,amsk)           F12_(_jit,0,sf,x6,omsk,amsk)
+#define F13(sf,x6)                     F12(sf,x6,0,0)
+static void F12_(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define F14x(sf,x,x6,im)               F14x_(_jit,0,sf,x,x6,im)
+#define F14(sf,im)                     F14x(sf,0,8,im)
+#define F15(im)                                F14x(0,0,0,im)
+static void F14x_(jit_state_t*,jit_word_t,
+                 jit_word_t,jit_word_t,jit_word_t,jit_word_t)
+    maybe_unused;
+#define F16(y,im)                      F16_(_jit,0,y,im)
+static void F16_(jit_state_t*,jit_word_t,
+                jit_word_t,jit_word_t)maybe_unused;
+
+/* break */
+#define BREAK_F(im)                    F15(im)
+/* chk */
+#define CHK_S(f2,im)                   M21(f2,im)
+#define CHKF_A_NC(f1,im)               M23(0x6,im,f1)
+#define CHKF_A_CLR(f1,im)              M23(0x7,im,f1)
+/* fabs */
+#define FABS(f1,f3)                    FMERGE_S(f1,0,f3)
+/* fadd */
+#define FADD(f1,f3,f2)                 FMA(f1,f3,1,f2)
+#define FADD_S(f1,f3,f2)               FMA_S(f1,f3,1,f2)
+#define FADD_D(f1,f3,f2)               FMA_D(f1,f3,1,f2)
+/* famax */
+#define FAMAX(f1,f2,f3)                        F8(0,SF_S0,0x17,f3,f2,f1)
+/* famin */
+#define FAMIN(f1,f2,f3)                        F8(0,SF_S0,0x16,f3,f2,f1)
+/* fand */
+#define FAND(f1,f2,f3)                 F9(0,0x2c,f3,f2,f1)
+/* fandcm */
+#define FANDCM(f1,f2,f3)               F9(0,0x2d,f3,f2,f1)
+/* fchkf */
+#define FCHKF(im)                      F14(SF_S0,im)
+/* fclass */
+#define FCLASS_M(p1,p2,f2,fc)          F5(p2,fc,f2,0,p1)
+#define FCLASS_M_UNC(p1,p2,f2,fc)      F5(p2,fc,f2,1,p1)
+/* fclrf */
+#define FCLRF()                                F13(SF_S0,5)
+/* fcmp */
+#define FCMP_EQ(p1,p2,f2,f3)           F4(0,SF_S0,0,p2,f3,f2,0,p1)
+#define FCMP_LT(p1,p2,f2,f3)           F4(1,SF_S0,0,p2,f3,f2,0,p1)
+#define FCMP_LE(p1,p2,f2,f3)           F4(0,SF_S0,1,p2,f3,f2,0,p1)
+#define FCMP_UNORD(p1,p2,f2,f3)                F4(1,SF_S0,1,p2,f3,f2,0,p1)
+#define FCMP_EQ_UNC(p1,p2,f2,f3)       F4(0,SF_S0,0,p2,f3,f2,1,p1)
+#define FCMP_LT_UNC(p1,p2,f2,f3)       F4(1,SF_S0,0,p2,f3,f2,1,p1)
+#define FCMP_LE_UNC(p1,p2,f2,f3)       F4(0,SF_S0,1,p2,f3,f2,1,p1)
+#define FCMP_UNORD_UNC(p1,p2,f2,f3)    F4(1,SF_S0,1,p2,f3,f2,1,p1)
+/* fcvt.fx */
+#define FCVT_FX(f1,f2)                 F10(0,SF_S0,0x18,f2,f1)
+#define FCVT_FXU(f1,f2)                        F10(0,SF_S0,0x19,f2,f1)
+#define FCVT_FX_TRUNC(f1,f2)           F10(0,SF_S0,0x1a,f2,f1)
+#define FCVT_FXU_TRUNC(f1,f2)          F10(0,SF_S0,0x1b,f2,f1)
+/* fcvt.xf */
+#define FCVT_XF(f1,f2)                 F11(0x1c,f2,f1)
+/* fcvt.fxuf */
+#define FCVT_XUF(f1,f3)                        FMA(f1,f3,1,0)
+/* fma */
+#define FMA(f1,f3,f4,f2)               F1(0x8,0,SF_S0,f4,f3,f2,f1)
+#define FMA_p(f1,f3,f4,f2,sf,_p)       F1_(_jit,_p,0x8,0,sf,f4,f3,f2,f1)
+#define FMA_S(f1,f3,f4,f2)             F1(0x8,1,SF_S0,f4,f3,f2,f1)
+#define FMA_S_p(f1,f3,f4,f2,sf,_p)     F1_(_jit,_p,0x8,1,sf,f4,f3,f2,f1)
+#define FMA_D(f1,f3,f4,f2)             F1(0x9,0,SF_S0,f4,f3,f2,f1)
+#define FMA_D_p(f1,f3,f4,f2,sf,_p)     F1_(_jit,_p,0x9,0,sf,f4,f3,f2,f1)
+/* fmax */
+#define FMAX(f1,f2,f3)                 F8(0,SF_S0,0x15,f3,f2,f1)
+/* fmerge */
+#define FMERGE_S(f1,f2,f3)             F9(0,0x10,f3,f2,f1)
+#define FMERGE_NS(f1,f2,f3)            F9(0,0x11,f3,f2,f1)
+#define FMERGE_SE(f1,f2,f3)            F9(0,0x12,f3,f2,f1)
+/* fmin */
+#define FMIN(f1,f2,f3)                 F8(0,SF_S0,0x14,f3,f2,f1)
+/* fmix */
+#define FMIX_LR(f1,f2,f3)              F9(0,0x39,f3,f2,f1)
+#define FMIX_R(f1,f2,f3)               F9(0,0x3a,f3,f2,f1)
+#define FMIX_L(f1,f2,f3)               F9(0,0x3b,f3,f2,f1)
+/* fmpy */
+#define FMPY(f1,f3,f4)                 FMA(f1,f3,f4,0)
+#define FMPY_p(f1,f3,f4,sf,_p)         FMA_p(f1,f3,f4,0,sf,_p)
+#define FMPY_S(f1,f3,f4)               FMA_S(f1,f3,f4,0)
+#define FMPY_S_p(f1,f3,f4,sf,_p)       FMA_S_p(f1,f3,f4,0,sf,_p)
+#define FMPY_D(f1,f3,f4)               FMA_D(f1,f3,f4,0)
+#define FMPY_D_p(f1,f3,f4,sf,_p)       FMA_D_p(f1,f3,f4,0,sf,_p)
+/* fms */
+#define FMS(f1,f3,f4,f2)               F1(0xa,0,SF_S0,f4,f3,f2,f1)
+#define FMS_S(f1,f3,f4,f2)             F1(0xa,1,SF_S0,f4,f3,f2,f1)
+#define FMS_D(f1,f3,f4,f2)             F1(0xb,0,SF_S0,f4,f3,f2,f1)
+/* fneg */
+#define FNEG(f1,f3)                    FMERGE_NS(f1,f3,f3)
+/* fnegabs */
+#define FNEGABS(f1,f3)                 FMERGE_NS(f1,0,f3)
+/* fnma */
+#define FNMA(f1,f3,f4,f2)              F1(0xc,0,SF_S0,f4,f3,f2,f1)
+#define FNMA_p(f1,f3,f4,f2,sf,_p)      F1_(_jit,_p,0xc,0,sf,f4,f3,f2,f1)
+#define FNMA_S(f1,f3,f4,f2)            F1(0xc,1,SF_S0,f4,f3,f2,f1)
+#define FNMA_D(f1,f3,f4,f2)            F1(0xd,0,SF_S0,f4,f3,f2,f1)
+/* fnmpy */
+#define FNMPY(f1,f3,f4)                        FNMA(f1,f3,f4,0)
+/* fnorm */
+#define FNORM(f1,f3)                   FMA(f1,f3,1,0)
+#define FNORM_S(f1,f3)                 FMA_S(f1,f3,1,0)
+#define FNORM_D(f1,f3)                 FMA_D(f1,f3,1,0)
+/* for */
+#define FOR(f1,f2,f3)                  F9(0,0x2e,f3,f2,f1)
+/* fpabs */
+#define FPABS(f1,f3)                   FPMERGE_S(f1,0,f3)
+/* fpack */
+#define FPACK(f1,f2,f3)                        F9(0,0x28,f3,f2,f1)
+/* fpamax */
+#define FPAMAX(f1,f2,f3)               F8(1,SF_S0,0x17,f3,f2,f1)
+/* fpamin */
+#define FPAMIN(f1,f2,f3)               F8(1,SF_S0,0x16,f3,f2,f1)
+/* fpcmp */
+#define FPCMP_EQ(f1,f2,f3)             F8(1,SF_S0,0x30,f3,f2,f1)
+#define FPCMP_LT(f1,f2,f3)             F8(1,SF_S0,0x31,f3,f2,f1)
+#define FPCMP_LE(f1,f2,f3)             F8(1,SF_S0,0x32,f3,f2,f1)
+#define FPCMP_UNORD(f1,f2,f3)          F8(1,SF_S0,0x33,f3,f2,f1)
+#define FPCMP_NEQ(f1,f2,f3)            F8(1,SF_S0,0x34,f3,f2,f1)
+#define FPCMP_NLT(f1,f2,f3)            F8(1,SF_S0,0x35,f3,f2,f1)
+#define FPCMP_NLE(f1,f2,f3)            F8(1,SF_S0,0x36,f3,f2,f1)
+#define FPCMP_ORD(f1,f2,f3)            F8(1,SF_S0,0x37,f3,f2,f1)
+/* fpcvt.fx */
+#define FPCVT_FX(f1,f2)                        F10(1,SF_S0,0x18,f2,f1)
+#define FPCVT_FXU(f1,f2)               F10(1,SF_S0,0x19,f2,f1)
+#define FPCVT_FX_TRUNC(f1,f2)          F10(1,SF_S0,0x1a,f2,f1)
+#define FPCVT_FXU_TRUNC(f1,f2)         F10(1,SF_S0,0x1b,f2,f1)
+/* fpma */
+#define FPMA(f1,f3,f4,f2)              F1(0x9,1,SF_S0,f4,f3,f3,f1)
+/* fpmax */
+#define FPMAX(f1,f2,f3)                        F8(1,SF_S0,0x15,f3,f2,f1)
+/* fpmerge */
+#define FPMERGE_S(f1,f2,f3)            F9(1,0x10,f3,f2,f1)
+#define FPMERGE_NS(f1,f2,f3)           F9(1,0x11,f3,f2,f1)
+#define FPMERGE_SE(f1,f2,f3)           F9(1,0x12,f3,f2,f1)
+/* fpmin */
+#define FPMIN(f1,f2,f3)                        F8(1,SF_S0,0x14,f3,f2,f1)
+/* fpmpy */
+#define FPMPY(f1,f3,f4)                        FPMA(f1,f3,f4,0)
+/* fpms */
+#define FPMS(f1,f3,f4,f2)              F1(0xb,1,SF_S0,f4,f3,f3,f1)
+/* fpneg */
+#define FPNEG(f1,f3)                   FPMERGE_NS(f1,f3,f3)
+/* fpnegabs */
+#define FPNEGABS(f1,f3)                        FPMERGE_NS(f1,0,f3)
+/* fpnma */
+#define FPNMA(f1,f3,f4,f2)             F1(0xd,1,SF_S0,f4,f3,f3,f1)
+/* fpnmpy */
+#define FPNMPY(f1,f3,f4)               FPNMA(f1,f3,f4,0)
+/* fprcpa */
+#define FPRCPA(f1,p2,f2,f3)            F6(1,SF_S0,p2,f3,f2,f1)
+/* fprsqrta */
+#define FPRSQRTA(f1,p2,f3)             F7(1,SF_S0,p2,f3,f1)
+/* frcpa */
+#define FRCPA(f1,p2,f2,f3)             F6(0,SF_S0,p2,f3,f2,f1)
+/* frsqrta */
+#define FRSQRTA(f1,p2,f3)              F7(0,SF_S0,p2,f3,f1)
+/* fselect */
+#define FSELECT(f1,f3,f4,f2)           F3(f4,f3,f2,f1)
+#define FSETC(amsk,omsk)               F12(SF_S0,4,omsk,amsk)
+/* fsub */
+#define FSUB(f1,f3,f2)                 FMS(f1,f3,1,f2)
+#define FSUB_S(f1,f3,f2)               FMS_S(f1,f3,1,f2)
+#define FSUB_D(f1,f3,f2)               FMS_D(f1,f3,1,f2)
+/* fswap */
+#define FSWAP(f1,f2,f3)                        F9(0,0x34,f3,f2,f1)
+#define FSWAP_NL(f1,f2,f3)             F9(0,0x35,f3,f2,f1)
+#define FSWAP_NR(f1,f2,f3)             F9(0,0x36,f3,f2,f1)
+/* fsxt */
+#define FSXT_R(f1,f2,f3)               F9(0,0x3c,f3,f2,f1)
+#define FSXT_L(f1,f2,f3)               F9(0,0x3d,f3,f2,f1)
+/* fxor */
+#define FXOR(f1,f2,f3)                 F9(0,0x2f,f3,f2,f1)
+/* getf */
+#define GETF_S(r1,f2)                  M19(0x1e,f2,r1)
+#define GETF_D(r1,f2)                  M19(0x1f,f2,r1)
+#define GETF_EXP(r1,f2)                        M19(0x1d,f2,r1)
+#define GETF_SIG(r1,f2)                        M19(0x1c,f2,r1)
+/* hint */
+#define HINT_F(im)                     F16(1,im)
+/* invala */
+#define INVALAF_E(f1)                  M27(f1)
+/* ldf */
+#define LDFS(f1,r3)                    M9(0x02,LD_NONE,r3,f1)
+#define LDFD(f1,r3)                    M9(0x03,LD_NONE,r3,f1)
+#define LDF8(f1,r3)                    M9(0x01,LD_NONE,r3,f1)
+#define LDFE(f1,r3)                    M9(0x00,LD_NONE,r3,f1)
+#define LDFS_S(f1,r3)                  M9(0x06,LD_NONE,r3,f1)
+#define LDFD_S(f1,r3)                  M9(0x07,LD_NONE,r3,f1)
+#define LDF8_S(f1,r3)                  M9(0x05,LD_NONE,r3,f1)
+#define LDFE_S(f1,r3)                  M9(0x04,LD_NONE,r3,f1)
+#define LDFS_A(f1,r3)                  M9(0x0a,LD_NONE,r3,f1)
+#define LDFD_A(f1,r3)                  M9(0x0b,LD_NONE,r3,f1)
+#define LDF8_A(f1,r3)                  M9(0x09,LD_NONE,r3,f1)
+#define LDFE_A(f1,r3)                  M9(0x08,LD_NONE,r3,f1)
+#define LDFS_SA(f1,r3)                 M9(0x0e,LD_NONE,r3,f1)
+#define LDFD_SA(f1,r3)                 M9(0x0f,LD_NONE,r3,f1)
+#define LDF8_SA(f1,r3)                 M9(0x0d,LD_NONE,r3,f1)
+#define LDFE_SA(f1,r3)                 M9(0x0c,LD_NONE,r3,f1)
+#define LDF_FILL(f1,r3)                        M9(0x1b,LD_NONE,r3,f1)
+#define LDFS_C_CLR(f1,r3)              M9(0x22,LD_NONE,r3,f1)
+#define LDFD_C_CLR(f1,r3)              M9(0x23,LD_NONE,r3,f1)
+#define LDF8_C_CLR(f1,r3)              M9(0x21,LD_NONE,r3,f1)
+#define LDFE_C_CLR(f1,r3)              M9(0x20,LD_NONE,r3,f1)
+#define LDFS_C_NC(f1,r3)               M9(0x26,LD_NONE,r3,f1)
+#define LDFD_C_NC(f1,r3)               M9(0x27,LD_NONE,r3,f1)
+#define LDF8_C_NC(f1,r3)               M9(0x25,LD_NONE,r3,f1)
+#define LDFE_C_NC(f1,r3)               M9(0x24,LD_NONE,r3,f1)
+#define LDFS_inc(f1,r3,r2)             M7(0x02,LD_NONE,r3,r2,f1)
+#define LDFD_inc(f1,r3,r2)             M7(0x03,LD_NONE,r3,r2,f1)
+#define LDF8_inc(f1,r3,r2)             M7(0x01,LD_NONE,r3,r2,f1)
+#define LDFE_inc(f1,r3,r2)             M7(0x00,LD_NONE,r3,r2,f1)
+#define LDFS_S_inc(f1,r3,r2)           M7(0x06,LD_NONE,r3,r2,f1)
+#define LDFD_S_inc(f1,r3,r2)           M7(0x07,LD_NONE,r3,r2,f1)
+#define LDF8_S_inc(f1,r3,r2)           M7(0x05,LD_NONE,r3,r2,f1)
+#define LDFE_S_inc(f1,r3,r2)           M7(0x04,LD_NONE,r3,r2,f1)
+#define LDFS_A_inc(f1,r3,r2)           M7(0x0a,LD_NONE,r3,r2,f1)
+#define LDXFD_A_inc(f1,r3,r2)          M7(0x0b,LD_NONE,r3,r2,f1)
+#define LDXF8_A_inc(f1,r3,r2)          M7(0x09,LD_NONE,r3,r2,f1)
+#define LDXFE_A_inc(f1,r3,r2)          M7(0x08,LD_NONE,r3,r2,f1)
+#define LDXFS_SA_inc(f1,r3,r2)         M7(0x0e,LD_NONE,r3,r2,f1)
+#define LDXFD_SA_inc(f1,r3,r2)         M7(0x0f,LD_NONE,r3,r2,f1)
+#define LDXF8_SA_inc(f1,r3,r2)         M7(0x0d,LD_NONE,r3,r2,f1)
+#define LDXFE_SA_inc(f1,r3,r2)         M7(0x0c,LD_NONE,r3,r2,f1)
+#define LDXFS_FILL_inc(f1,r3,r2)       M7(0x1b,LD_NONE,r3,r2,f1)
+#define LDXFS_C_CLR_inc(f1,r3,r2)      M7(0x22,LD_NONE,r3,r2,f1)
+#define LDXFD_C_CLR_inc(f1,r3,r2)      M7(0x23,LD_NONE,r3,r2,f1)
+#define LDXF8_C_CLR_inc(f1,r3,r2)      M7(0x21,LD_NONE,r3,r2,f1)
+#define LDXFE_C_CLR_inc(f1,r3,r2)      M7(0x20,LD_NONE,r3,r2,f1)
+#define LDXFS_C_NC_inc(f1,r3,r2)       M7(0x26,LD_NONE,r3,r2,f1)
+#define LDXFD_C_NC_inc(f1,r3,r2)       M7(0x27,LD_NONE,r3,r2,f1)
+#define LDXF8_C_NC_inc(f1,r3,r2)       M7(0x25,LD_NONE,r3,r2,f1)
+#define LDXFE_C_NC_inc(f1,r3,r2)       M7(0x24,LD_NONE,r3,r2,f1)
+#define LDIFS_inc(f1,f3,im)            M8(0x02,LD_NONE,f3,im,f1)
+#define LDIFD_inc(f1,f3,im)            M8(0x03,LD_NONE,f3,im,f1)
+#define LDIF8_inc(f1,f3,im)            M8(0x01,LD_NONE,f3,im,f1)
+#define LDIFE_inc(f1,f3,im)            M8(0x00,LD_NONE,f3,im,f1)
+#define LDIFS_S_inc(f1,f3,im)          M8(0x06,LD_NONE,f3,im,f1)
+#define LDIFD_S_inc(f1,f3,im)          M8(0x07,LD_NONE,f3,im,f1)
+#define LDIF8_S_inc(f1,f3,im)          M8(0x05,LD_NONE,f3,im,f1)
+#define LDIFE_S_inc(f1,f3,im)          M8(0x04,LD_NONE,f3,im,f1)
+#define LDIFS_A_inc(f1,f3,im)          M8(0x0a,LD_NONE,f3,im,f1)
+#define LDIFD_A_inc(f1,f3,im)          M8(0x0b,LD_NONE,f3,im,f1)
+#define LDIF8_A_inc(f1,f3,im)          M8(0x09,LD_NONE,f3,im,f1)
+#define LDIFE_A_inc(f1,f3,im)          M8(0x08,LD_NONE,f3,im,f1)
+#define LDIF_FILL_inc(f1,f3,im)                M8(0x1b,LD_NONE,f3,im,f1)
+#define LDIFS_C_CLR_inc(f1,f3,im)      M8(0x22,LD_NONE,f3,im,f1)
+#define LDIFD_C_CLR_inc(f1,f3,im)      M8(0x23,LD_NONE,f3,im,f1)
+#define LDIF8_C_CLR_inc(f1,f3,im)      M8(0x21,LD_NONE,f3,im,f1)
+#define LDIFE_C_CLR_inc(f1,f3,im)      M8(0x20,LD_NONE,f3,im,f1)
+#define LDIFS_C_NC_inc(f1,f3,im)       M8(0x26,LD_NONE,f3,im,f1)
+#define LDIFD_C_NC_inc(f1,f3,im)       M8(0x27,LD_NONE,f3,im,f1)
+#define LDIF8_C_NC_inc(f1,f3,im)       M8(0x25,LD_NONE,f3,im,f1)
+#define LDIFE_C_NC_inc(f1,f3,im)       M8(0x24,LD_NONE,f3,im,f1)
+/* ldpf */
+#define LDFPS(f1,f2,r3)                        M11(0x02,LD_NONE,r3,f2,f1)
+#define LDFPD(f1,f2,r3)                        M11(0x03,LD_NONE,r3,f2,f1)
+#define LDFP8(f1,f2,r3)                        M11(0x01,LD_NONE,r3,f2,f1)
+#define LDFPS_S(f1,f2,r3)              M11(0x06,LD_NONE,r3,f2,f1)
+#define LDFPD_S(f1,f2,r3)              M11(0x07,LD_NONE,r3,f2,f1)
+#define LDFP8_S(f1,f2,r3)              M11(0x05,LD_NONE,r3,f2,f1)
+#define LDFPS_A(f1,f2,r3)              M11(0x0a,LD_NONE,r3,f2,f1)
+#define LDFPD_A(f1,f2,r3)              M11(0x0b,LD_NONE,r3,f2,f1)
+#define LDFP8_A(f1,f2,r3)              M11(0x09,LD_NONE,r3,f2,f1)
+#define LDFPS_SA(f1,f2,r3)             M11(0x0e,LD_NONE,r3,f2,f1)
+#define LDFPD_SA(f1,f2,r3)             M11(0x0f,LD_NONE,r3,f2,f1)
+#define LDFP8_SA(f1,f2,r3)             M11(0x0d,LD_NONE,r3,f2,f1)
+#define LDFPS_C_CLR(f1,f2,r3)          M11(0x22,LD_NONE,r3,f2,f1)
+#define LDFPD_C_CLR(f1,f2,r3)          M11(0x23,LD_NONE,r3,f2,f1)
+#define LDFP8_C_CLR(f1,f2,r3)          M11(0x21,LD_NONE,r3,f2,f1)
+#define LDFPS_C_NC(f1,f2,r3)           M11(0x26,LD_NONE,r3,f2,f1)
+#define LDFPD_C_NC(f1,f2,r3)           M11(0x27,LD_NONE,r3,f2,f1)
+#define LDFP8_C_NC(f1,f2,r3)           M11(0x25,LD_NONE,r3,f2,f1)
+#define LDIFPS(f1,f2,r3)               M12(0x02,LD_NONE,r3,f2,f1)
+#define LDIFPD(f1,f2,r3)               M12(0x03,LD_NONE,r3,f2,f1)
+#define LDIFP8(f1,f2,r3)               M12(0x01,LD_NONE,r3,f2,f1)
+#define LDIFPS_S(f1,f2,r3)             M12(0x06,LD_NONE,r3,f2,f1)
+#define LDIFPD_S(f1,f2,r3)             M12(0x07,LD_NONE,r3,f2,f1)
+#define LDIFP8_S(f1,f2,r3)             M12(0x05,LD_NONE,r3,f2,f1)
+#define LDIFPS_A(f1,f2,r3)             M12(0x0a,LD_NONE,r3,f2,f1)
+#define LDIFPD_A(f1,f2,r3)             M12(0x0b,LD_NONE,r3,f2,f1)
+#define LDIFP8_A(f1,f2,r3)             M12(0x09,LD_NONE,r3,f2,f1)
+#define LDIFPS_SA(f1,f2,r3)            M12(0x0e,LD_NONE,r3,f2,f1)
+#define LDIFPD_SA(f1,f2,r3)            M12(0x0f,LD_NONE,r3,f2,f1)
+#define LDIFP8_SA(f1,f2,r3)            M12(0x0d,LD_NONE,r3,f2,f1)
+#define LDIFPS_C_CLR(f1,f2,r3)         M12(0x22,LD_NONE,r3,f2,f1)
+#define LDIFPD_C_CLR(f1,f2,r3)         M12(0x23,LD_NONE,r3,f2,f1)
+#define LDIFP8_C_CLR(f1,f2,r3)         M12(0x21,LD_NONE,r3,f2,f1)
+#define LDIFPS_C_NC(f1,f2,r3)          M12(0x26,LD_NONE,r3,f2,f1)
+#define LDIFPD_C_NC(f1,f2,r3)          M12(0x27,LD_NONE,r3,f2,f1)
+#define LDIFP8_C_NC(f1,f2,r3)          M12(0x25,LD_NONE,r3,f2,f1)
+/* mov - Move Floating-point Register */
+#define MOVF(f1,f3)                    FMERGE_S(f1,f3,f3)
+/* nop */
+#define NOP_F(im)                      F16(0,im)
+/* setf */
+#define SETF_S(f1,r2)                  M18(0x1e,r2,f1)
+#define SETF_D(f1,r2)                  M18(0x1f,r2,f1)
+#define SETF_EXP(f1,r2)                        M18(0x1d,r2,f1)
+#define SETF_SIG(f1,r2)                        M18(0x1c,r2,f1)
+/* stf */
+#define STFS(r3,f2)                    M13(0x32,ST_NONE,r3,f2)
+#define STFD(r3,f2)                    M13(0x33,ST_NONE,r3,f2)
+#define STF8(r3,f2)                    M13(0x31,ST_NONE,r3,f2)
+#define STFE(r3,f2)                    M13(0x30,ST_NONE,r3,f2)
+#define STF_SPILL(r3,f2)               M13(0x3b,ST_NONE,r3,f2)
+#define STFS_inc(r3,f2,im)             M10(0x32,ST_NONE,r3,f2,im)
+#define STFD_inc(r3,f2,im)             M10(0x33,ST_NONE,r3,f2,im)
+#define STF8_inc(r3,f2,im)             M10(0x31,ST_NONE,r3,f2,im)
+#define STFE_inc(r3,f2,im)             M10(0x30,ST_NONE,r3,f2,im)
+#define STF_SPILL_inc(r3,f2,im)                M10(0x3b,ST_NONE,r3,f2,im)
+/* xma */
+#define XMA_L(f1,f3,f4,f2)             F2(0,f4,f3,f2,f1)
+#define XMA_LU(f1,f3,f4,f2)            XMA_L(f1,f3,f4,f2)
+#define XMA_H(f1,f3,f4,f2)             F2(3,f4,f3,f2,f1)
+#define XMA_HU(f1,f3,f4,f2)            F2(2,f4,f3,f2,f1)
+/* xmpy */
+#define XMPY_L(f1,f3,f4)               XMA_L(f1,f3,f4,0)
+#define XMPY_LU(f1,f3,f4)              XMA_L(f1,f3,f4,0)
+#define XMPY_H(f1,f3,f4)               XMA_H(f1,f3,f4,0)
+#define XMPY_HU(f1,f3,f4)              XMA_HU(f1,f3,f4,0)
+
+#define movr_f(r0,r1)                  movr_d(r0,r1)
+#define movr_d(r0,r1)                  MOVF(r0,r1)
+#define movi_f(r0,i0)                  _movi_f(_jit,r0,i0)
+static void _movi_f(jit_state_t*,jit_int32_t,jit_float32_t*);
+#define movi_d(r0,i0)                  _movi_d(_jit,r0,i0)
+static void _movi_d(jit_state_t*,jit_int32_t,jit_float64_t*);
+#define movr_w_f(r0,r1)                        _movr_w_f(_jit,r0,r1)
+static void _movr_w_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#define movr_f_w(r0,r1)                        _movr_f_w(_jit,r0,r1)
+static void _movr_f_w(jit_state_t*,jit_int32_t,jit_int32_t);
+#define movr_w_d(r0,r1)                        _movr_w_d(_jit,r0,r1)
+static void _movr_w_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#define movr_d_w(r0,r1)                        _movr_d_w(_jit,r0,r1)
+static void _movr_d_w(jit_state_t*,jit_int32_t,jit_int32_t);
+#define movi_f_w(r0,i0)                        _movi_f_w(_jit,r0,i0)
+static void _movi_f_w(jit_state_t*,jit_int32_t,jit_float32_t*);
+#define movi_d_w(r0,i0)                        _movi_d_w(_jit,r0,i0)
+static void _movi_d_w(jit_state_t*,jit_int32_t,jit_float64_t*);
+#define absr_f(r0,r1)                  absr_d(r0,r1)
+#define absr_d(r0,r1)                  FABS(r0,r1)
+#define negr_f(r0,r1)                  negr_d(r0,r1)
+#define negr_d(r0,r1)                  FNEG(r0,r1)
+#define sqrtr_f(r0,r1)                 _sqrtr_f(_jit,r0,r1)
+static void _sqrtr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#define sqrtr_d(r0,r1)                 _sqrtr_d(_jit,r0,r1)
+static void _sqrtr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#define extr_f_d(r0,r1)                        FNORM_D(r0,r1)
+#define extr_d_f(r0,r1)                        FNORM_S(r0,r1)
+#define extr_f(r0,r1)                  _extr_f(_jit,r0,r1)
+static void _extr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#define extr_d(r0,r1)                  _extr_d(_jit,r0,r1)
+static void _extr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#define truncr_f_i(r0,r1)              truncr_d_l(r0,r1)
+#define truncr_d_i(r0,r1)              truncr_d_l(r0,r1)
+#define truncr_f_l(r0,r1)              truncr_d_l(r0,r1)
+#define truncr_d_l(r0,r1)              _truncr_d_l(_jit,r0,r1)
+static void _truncr_d_l(jit_state_t*,jit_int32_t,jit_int32_t);
+#define addr_f(r0,r1,r2)               FADD_S(r0,r1,r2)
+#define addi_f(r0,r1,i0)               _addi_f(_jit,r0,r1,i0)
+static void _addi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define addr_d(r0,r1,r2)               FADD_D(r0,r1,r2)
+#define addi_d(r0,r1,i0)               _addi_d(_jit,r0,r1,i0)
+static void _addi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define subr_f(r0,r1,r2)               FSUB_S(r0,r1,r2)
+#define subi_f(r0,r1,i0)               _subi_f(_jit,r0,r1,i0)
+static void _subi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define subr_d(r0,r1,r2)               FSUB_D(r0,r1,r2)
+#define subi_d(r0,r1,i0)               _subi_d(_jit,r0,r1,i0)
+static void _subi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define rsbr_f(r0,r1,r2)               subr_f(r0,r2,r1)
+#define rsbi_f(r0,r1,i0)               _rsbi_f(_jit,r0,r1,i0)
+static void _rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define rsbr_d(r0,r1,r2)               subr_d(r0,r2,r1)
+#define rsbi_d(r0,r1,i0)               _rsbi_d(_jit,r0,r1,i0)
+static void _rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define mulr_f(r0,r1,r2)               FMPY_S(r0,r1,r2)
+#define muli_f(r0,r1,i0)               _muli_f(_jit,r0,r1,i0)
+static void _muli_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define mulr_d(r0,r1,r2)               FMPY_D(r0,r1,r2)
+#define muli_d(r0,r1,i0)               _muli_d(_jit,r0,r1,i0)
+static void _muli_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define divr_f(r0,r1,r2)               _divr_f(_jit,r0,r1,r2)
+static void _divr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define divi_f(r0,r1,i0)               _divi_f(_jit,r0,r1,i0)
+static void _divi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define divr_d(r0,r1,r2)               _divr_d(_jit,r0,r1,r2)
+static void _divr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define divi_d(r0,r1,i0)               _divi_d(_jit,r0,r1,i0)
+static void _divi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define ltr_f(r0,r1,r2)                        ltr_d(r0,r1,r2)
+#define ltr_d(r0,r1,r2)                        _ltr_d(_jit,r0,r1,r2)
+static void _ltr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define lti_f(r0,r1,i0)                        _lti_f(_jit,r0,r1,i0)
+static void _lti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define lti_d(r0,r1,i0)                        _lti_d(_jit,r0,r1,i0)
+static void _lti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define ler_f(r0,r1,r2)                        ler_d(r0,r1,r2)
+#define ler_d(r0,r1,r2)                        _ler_d(_jit,r0,r1,r2)
+static void _ler_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define lei_f(r0,r1,i0)                        _lei_f(_jit,r0,r1,i0)
+static void _lei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define lei_d(r0,r1,i0)                        _lei_d(_jit,r0,r1,i0)
+static void _lei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define eqr_f(r0,r1,r2)                        eqr_d(r0,r1,r2)
+#define eqr_d(r0,r1,r2)                        _eqr_d(_jit,r0,r1,r2)
+static void _eqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define eqi_f(r0,r1,i0)                        _eqi_f(_jit,r0,r1,i0)
+static void _eqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define eqi_d(r0,r1,i0)                        _eqi_d(_jit,r0,r1,i0)
+static void _eqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define ger_f(r0,r1,r2)                        ger_d(r0,r1,r2)
+#define ger_d(r0,r1,r2)                        _ger_d(_jit,r0,r1,r2)
+static void _ger_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define gei_f(r0,r1,i0)                        _gei_f(_jit,r0,r1,i0)
+static void _gei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define gei_d(r0,r1,i0)                        _gei_d(_jit,r0,r1,i0)
+static void _gei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define gtr_f(r0,r1,r2)                        gtr_d(r0,r1,r2)
+#define gtr_d(r0,r1,r2)                        _gtr_d(_jit,r0,r1,r2)
+static void _gtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define gti_f(r0,r1,i0)                        _gti_f(_jit,r0,r1,i0)
+static void _gti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define gti_d(r0,r1,i0)                        _gti_d(_jit,r0,r1,i0)
+static void _gti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define ner_f(r0,r1,r2)                        ner_d(r0,r1,r2)
+#define ner_d(r0,r1,r2)                        _ner_d(_jit,r0,r1,r2)
+static void _ner_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define nei_f(r0,r1,i0)                        _nei_f(_jit,r0,r1,i0)
+static void _nei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define nei_d(r0,r1,i0)                        _nei_d(_jit,r0,r1,i0)
+static void _nei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define unltr_f(r0,r1,r2)              unltr_d(r0,r1,r2)
+#define unltr_d(r0,r1,r2)              _unltr_d(_jit,r0,r1,r2)
+static void _unltr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define unlti_f(r0,r1,i0)              _unlti_f(_jit,r0,r1,i0)
+static void _unlti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define unlti_d(r0,r1,i0)              _unlti_d(_jit,r0,r1,i0)
+static void _unlti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define unler_f(r0,r1,r2)              unler_d(r0,r1,r2)
+#define unler_d(r0,r1,r2)              _unler_d(_jit,r0,r1,r2)
+static void _unler_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define unlei_f(r0,r1,i0)              _unlei_f(_jit,r0,r1,i0)
+static void _unlei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define unlei_d(r0,r1,i0)              _unlei_d(_jit,r0,r1,i0)
+static void _unlei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define uneqr_f(r0,r1,r2)              uneqr_d(r0,r1,r2)
+#define uneqr_d(r0,r1,r2)              _uneqr_d(_jit,r0,r1,r2)
+static void _uneqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define uneqi_f(r0,r1,i0)              _uneqi_f(_jit,r0,r1,i0)
+static void _uneqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define uneqi_d(r0,r1,i0)              _uneqi_d(_jit,r0,r1,i0)
+static void _uneqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define unger_f(r0,r1,r2)              unger_d(r0,r1,r2)
+#define unger_d(r0,r1,r2)              _unger_d(_jit,r0,r1,r2)
+static void _unger_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ungei_f(r0,r1,i0)              _ungei_f(_jit,r0,r1,i0)
+static void _ungei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define ungei_d(r0,r1,i0)              _ungei_d(_jit,r0,r1,i0)
+static void _ungei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define ungtr_f(r0,r1,r2)              ungtr_d(r0,r1,r2)
+#define ungtr_d(r0,r1,r2)              _ungtr_d(_jit,r0,r1,r2)
+static void _ungtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ungti_f(r0,r1,i0)              _ungti_f(_jit,r0,r1,i0)
+static void _ungti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define ungti_d(r0,r1,i0)              _ungti_d(_jit,r0,r1,i0)
+static void _ungti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define ltgtr_f(r0,r1,r2)              ltgtr_d(r0,r1,r2)
+#define ltgtr_d(r0,r1,r2)              _ltgtr_d(_jit,r0,r1,r2)
+static void _ltgtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ltgti_f(r0,r1,i0)              _ltgti_f(_jit,r0,r1,i0)
+static void _ltgti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define ltgti_d(r0,r1,i0)              _ltgti_d(_jit,r0,r1,i0)
+static void _ltgti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define ordr_f(r0,r1,r2)               ordr_d(r0,r1,r2)
+#define ordr_d(r0,r1,r2)               _ordr_d(_jit,r0,r1,r2)
+static void _ordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ordi_f(r0,r1,i0)               _ordi_f(_jit,r0,r1,i0)
+static void _ordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define ordi_d(r0,r1,i0)               _ordi_d(_jit,r0,r1,i0)
+static void _ordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define unordr_f(r0,r1,r2)             unordr_d(r0,r1,r2)
+#define unordr_d(r0,r1,r2)             _unordr_d(_jit,r0,r1,r2)
+static void _unordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define unordi_f(r0,r1,i0)             _unordi_f(_jit,r0,r1,i0)
+static void _unordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#define unordi_d(r0,r1,i0)             _unordi_d(_jit,r0,r1,i0)
+static void _unordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define ldr_f(r0,r1)                   LDFS(r0,r1)
+#define ldi_f(r0,i0)                   _ldi_f(_jit,r0,i0)
+static void _ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldxr_f(r0,r1,r2)               _ldxr_f(_jit,r0,r1,r2)
+static void _ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_f(r0,r1,i0)               _ldxi_f(_jit,r0,r1,i0)
+static void _ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ldr_d(r0,r1)                   LDFD(r0,r1)
+#define ldi_d(r0,i0)                   _ldi_d(_jit,r0,i0)
+static void _ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#define ldxr_d(r0,r1,r2)               _ldxr_d(_jit,r0,r1,r2)
+static void _ldxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define ldxi_d(r0,r1,i0)               _ldxi_d(_jit,r0,r1,i0)
+static void _ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define str_f(r0,r1)                   STFS(r0,r1)
+#define sti_f(i0,r0)                   _sti_f(_jit,i0,r0)
+static void _sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#define stxr_f(r0,r1,r2)               _stxr_f(_jit,r0,r1,r2)
+static void _stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define stxi_f(i0,r0,r1)               _stxi_f(_jit,i0,r0,r1)
+static void _stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define str_d(r0,r1)                   STFD(r0,r1)
+#define sti_d(i0,r0)                   _sti_d(_jit,i0,r0)
+static void _sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#define stxr_d(r0,r1,r2)               _stxr_d(_jit,r0,r1,r2)
+static void _stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define stxi_d(i0,r0,r1)               _stxi_d(_jit,i0,r0,r1)
+static void _stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bltr_f(i0,r0,r1)               bltr_d(i0,r0,r1)
+#define bltr_d(i0,r0,r1)               _bltr_d(_jit,i0,r0,r1)
+static jit_word_t _bltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blti_f(i0,r0,i1)               _blti_f(_jit,i0,r0,i1)
+static jit_word_t _blti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define blti_d(i0,r0,i1)               _blti_d(_jit,i0,r0,i1)
+static jit_word_t _blti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bler_f(i0,r0,r1)               bler_d(i0,r0,r1)
+#define bler_d(i0,r0,r1)               _bler_d(_jit,i0,r0,r1)
+static jit_word_t _bler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blei_f(i0,r0,i1)               _blei_f(_jit,i0,r0,i1)
+static jit_word_t _blei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define blei_d(i0,r0,i1)               _blei_d(_jit,i0,r0,i1)
+static jit_word_t _blei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define beqr_f(i0,r0,r1)               beqr_d(i0,r0,r1)
+#define beqr_d(i0,r0,r1)               _beqr_d(_jit,i0,r0,r1)
+static jit_word_t _beqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define beqi_f(i0,r0,i1)               _beqi_f(_jit,i0,r0,i1)
+static jit_word_t _beqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define beqi_d(i0,r0,i1)               _beqi_d(_jit,i0,r0,i1)
+static jit_word_t _beqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bger_f(i0,r0,r1)               bger_d(i0,r0,r1)
+#define bger_d(i0,r0,r1)               _bger_d(_jit,i0,r0,r1)
+static jit_word_t _bger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgei_f(i0,r0,i1)               _bgei_f(_jit,i0,r0,i1)
+static jit_word_t _bgei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bgei_d(i0,r0,i1)               _bgei_d(_jit,i0,r0,i1)
+static jit_word_t _bgei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bgtr_f(i0,r0,r1)               bgtr_d(i0,r0,r1)
+#define bgtr_d(i0,r0,r1)               _bgtr_d(_jit,i0,r0,r1)
+static jit_word_t _bgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgti_f(i0,r0,i1)               _bgti_f(_jit,i0,r0,i1)
+static jit_word_t _bgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bgti_d(i0,r0,i1)               _bgti_d(_jit,i0,r0,i1)
+static jit_word_t _bgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bner_f(i0,r0,r1)               bner_d(i0,r0,r1)
+#define bner_d(i0,r0,r1)               _bner_d(_jit,i0,r0,r1)
+static jit_word_t _bner_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bnei_f(i0,r0,i1)               _bnei_f(_jit,i0,r0,i1)
+static jit_word_t _bnei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bnei_d(i0,r0,i1)               _bnei_d(_jit,i0,r0,i1)
+static jit_word_t _bnei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bunltr_f(i0,r0,r1)             bunltr_d(i0,r0,r1)
+#define bunltr_d(i0,r0,r1)             _bunltr_d(_jit,i0,r0,r1)
+static jit_word_t _bunltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bunlti_f(i0,r0,i1)             _bunlti_f(_jit,i0,r0,i1)
+static jit_word_t _bunlti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bunlti_d(i0,r0,i1)             _bunlti_d(_jit,i0,r0,i1)
+static jit_word_t _bunlti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bunler_f(i0,r0,r1)             bunler_d(i0,r0,r1)
+#define bunler_d(i0,r0,r1)             _bunler_d(_jit,i0,r0,r1)
+static jit_word_t _bunler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bunlei_f(i0,r0,i1)             _bunlei_f(_jit,i0,r0,i1)
+static jit_word_t _bunlei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bunlei_d(i0,r0,i1)             _bunlei_d(_jit,i0,r0,i1)
+static jit_word_t _bunlei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define buneqr_f(i0,r0,r1)             buneqr_d(i0,r0,r1)
+#define buneqr_d(i0,r0,r1)             _buneqr_d(_jit,i0,r0,r1)
+static jit_word_t _buneqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define buneqi_f(i0,r0,i1)             _buneqi_f(_jit,i0,r0,i1)
+static jit_word_t _buneqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define buneqi_d(i0,r0,i1)             _buneqi_d(_jit,i0,r0,i1)
+static jit_word_t _buneqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bunger_f(i0,r0,r1)             bunger_d(i0,r0,r1)
+#define bunger_d(i0,r0,r1)             _bunger_d(_jit,i0,r0,r1)
+static jit_word_t _bunger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bungei_f(i0,r0,i1)             _bungei_f(_jit,i0,r0,i1)
+static jit_word_t _bungei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bungei_d(i0,r0,i1)             _bungei_d(_jit,i0,r0,i1)
+static jit_word_t _bungei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bungtr_f(i0,r0,r1)             bungtr_d(i0,r0,r1)
+#define bungtr_d(i0,r0,r1)             _bungtr_d(_jit,i0,r0,r1)
+static jit_word_t _bungtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bungti_f(i0,r0,i1)             _bungti_f(_jit,i0,r0,i1)
+static jit_word_t _bungti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bungti_d(i0,r0,i1)             _bungti_d(_jit,i0,r0,i1)
+static jit_word_t _bungti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bltgtr_f(i0,r0,r1)             bltgtr_d(i0,r0,r1)
+#define bltgtr_d(i0,r0,r1)             _bltgtr_d(_jit,i0,r0,r1)
+static jit_word_t _bltgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bltgti_f(i0,r0,i1)             _bltgti_f(_jit,i0,r0,i1)
+static jit_word_t _bltgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bltgti_d(i0,r0,i1)             _bltgti_d(_jit,i0,r0,i1)
+static jit_word_t _bltgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bordr_f(i0,r0,r1)              bordr_d(i0,r0,r1)
+#define bordr_d(i0,r0,r1)              _bordr_d(_jit,i0,r0,r1)
+static jit_word_t _bordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bordi_f(i0,r0,i1)              _bordi_f(_jit,i0,r0,i1)
+static jit_word_t _bordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bordi_d(i0,r0,i1)              _bordi_d(_jit,i0,r0,i1)
+static jit_word_t _bordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#define bunordr_f(i0,r0,r1)            bunordr_d(i0,r0,r1)
+#define bunordr_d(i0,r0,r1)            _bunordr_d(_jit,i0,r0,r1)
+static jit_word_t _bunordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bunordi_f(i0,r0,i1)            _bunordi_f(_jit,i0,r0,i1)
+static jit_word_t _bunordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#define bunordi_d(i0,r0,i1)            _bunordi_d(_jit,i0,r0,i1)
+static jit_word_t _bunordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define vaarg_d(r0, r1)              _vaarg_d(_jit, r0, r1)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif
+
+#if CODE
+static void
+_M7(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t r2, jit_word_t f1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(f1 & ~0x7fL));
+    TSTREG2(r2, r3);
+    TSTPRED(_p);
+    TSTFREG1(f1);
+    inst((6L<<37)|(1L<<36)|(x6<<30)|(ht<<28)|
+        (r3<<20)|(r2<<13)|(f1<<6)|_p, INST_M);
+    SETFREG(f1);
+    SETREG(r3);
+}
+
+static void
+_M8(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t im, jit_word_t f1)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(ht &   ~0x3L));
+    assert(!(r3 &  ~0x7fL));
+    assert(im > -256 && im <= 255);
+    assert(!(f1 &  ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTFREG1(f1);
+    inst((7L<<37)|(((im>>8)&1L)<<36)|(x6<<30)|(ht<<28)|
+        (((im>>8)&1L)<<27)|(r3<<20)|((im&0x7fLL)<<13)|(f1<<6)|_p, INST_M);
+    SETFREG(f1);
+    SETREG(r3);
+}
+
+static void
+_M9(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t f1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(f1 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTFREG1(f1);
+    inst((6L<<37)|(x6<<30)|(ht<<28)|(r3<<20)|(f1<<6)|_p, INST_M);
+    SETFREG(f1);
+}
+
+static void
+_M10(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t f2, jit_word_t im)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(x6 &  ~0x3fL));
+    assert(!(ht &   ~0x3L));
+    assert(!(r3 &  ~0x7fL));
+    assert(!(f2 &  ~0x7fL));
+    assert(im > -256 && im <= 255);
+    TSTREG1(r3);
+    TSTFREG1(f2);
+    TSTPRED(_p);
+    inst((7L<<37)|(((im>>8)&1L)<<36)|(x6<<30)|(ht<<28)|
+        (((im>>8)&1L)<<27)|(r3<<20)|(f2<<13)|((im&0x7fL)<<6)|_p, INST_M);
+    SETREG(r3);
+}
+
+static void
+_M11(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t f2, jit_word_t f1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(f2 & ~0x7fL));
+    assert(!(f1 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTFREG2(f1, f2);
+    inst((6L<<37)|(x6<<30)|(ht<<28)|(1L<<27)|
+        (r3<<20)|(f2<<13)|(f1<<6)|_p, INST_M);
+    SETFREG(f1);
+    SETFREG(f2);
+}
+
+static void
+_M12(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t ht, jit_word_t r3, jit_word_t f2, jit_word_t f1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(ht &  ~0x3L));
+    assert(!(r3 & ~0x7fL));
+    assert(!(f2 & ~0x7fL));
+    assert(!(f1 & ~0x7fL));
+    TSTREG1(r3);
+    TSTPRED(_p);
+    TSTFREG2(f1, f2);
+    inst((6L<<37)|(1L<<36)|(x6<<30)|(ht<<28)|
+        (1L<<27)|(r3<<20)|(f2<<13)|(f1<<6)|_p, INST_M);
+    SETFREG(f1);
+    SETFREG(f2);
+    SETREG(r3);
+}
+
+static void
+_M18(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t r2, jit_word_t f1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(r2 & ~0x7fL));
+    assert(!(f1 & ~0x7fL));
+    TSTREG1(r2);
+    TSTPRED(_p);
+    TSTFREG1(f1);
+    inst((6L<<37)|(x6<<30)|(1L<<27)|(r2<<13)|(f1<<6)|_p, INST_M);
+    SETFREG(f1);
+}
+
+static void
+_M19(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t x6, jit_word_t f2, jit_word_t r1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(x6 & ~0x3fL));
+    assert(!(f2 & ~0x7fL));
+    assert(!(r1 & ~0x7fL));
+    TSTFREG1(f2);
+    TSTPRED(_p);
+    TSTREG1(r1);
+    inst((4L<<37)|(x6<<30)|(1L<<27)|(f2<<13)|(r1<<6)|_p, INST_M);
+    SETREG(r1);
+}
+
+static void
+F1_(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t op, jit_word_t x, jit_word_t sf,
+    jit_word_t f4, jit_word_t f3, jit_word_t f2, jit_word_t f1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(op &  ~0xfL));
+    assert(!(x  &  ~0x1L));
+    assert(!(sf &  ~0x3L));
+    assert(!(f4 & ~0x7fL));
+    assert(!(f3 & ~0x7fL));
+    assert(!(f2 & ~0x7fL));
+    assert(!(f1 & ~0x7fL));
+    TSTFREG3(f2, f3, f4);
+    TSTPRED(_p);
+    TSTFREG1(f1);
+    inst((op<<37)|(x<<36)|(sf<<34)|(f4<<27)|
+        (f3<<20)|(f2<<13)|(f1<<6)|_p, INST_F);
+    SETFREG(f1);
+}
+
+static void
+F4_(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t rb, jit_word_t sf, jit_word_t ra, jit_word_t p2,
+    jit_word_t f3, jit_word_t f2, jit_word_t ta, jit_word_t p1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(rb &  ~0x1L));
+    assert(!(sf &  ~0x3L));
+    assert(!(ra &  ~0x1L));
+    assert(!(p2 & ~0x3fL));
+    assert(!(f3 & ~0x7fL));
+    assert(!(f2 & ~0x7fL));
+    assert(!(ta &  ~0x1L));
+    assert(!(p1 & ~0x3fL));
+    TSTFREG2(f2, f3);
+    TSTPRED(_p);
+    inst((4L<<37)|(rb<<36)|(sf<<34)|(ra<<33)|(p2<<27)|
+        (f3<<20)|(f2<<13)|(ta<<12)|(p1<<6)|_p, INST_F);
+    if (p1)
+       _jitc->pred |= 1 << p1;
+    if (p2)
+       _jitc->pred |= 1 << p2;
+}
+
+static void
+F5_(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t p2, jit_word_t fc, jit_word_t f2, jit_word_t ta, jit_word_t p1)
+{
+    assert(!(_p &  ~0x3fL));
+    assert(!(p2 &  ~0x3fL));
+    assert(!(fc & ~0x1ffL));
+    assert(!(f2 &  ~0x7fL));
+    assert(!(ta &   ~0x1L));
+    assert(!(p1 &  ~0x3fL));
+    TSTFREG1(f2);
+    TSTPRED(_p);
+    inst((5L<<37)|(((fc>>7)&3L)<<33)|(p2<<27)|
+        ((fc&0x7fL)<<20)|(f2<<13)|(ta<<12)|(p1<<6)|_p, INST_F);
+    if (p1)
+       _jitc->pred |= 1 << p1;
+    if (p2)
+       _jitc->pred |= 1 << p2;
+}
+
+static void
+F6x_(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t op, jit_word_t q, jit_word_t sf,
+     jit_word_t p2,  jit_word_t f3, jit_word_t f2, jit_word_t f1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(op &  ~0xfL));
+    assert(!(q  &  ~0x1L));
+    assert(!(sf &  ~0x3L));
+    assert(!(p2 & ~0x3fL));
+    assert(!(f3 & ~0x7fL));
+    assert(!(f2 & ~0x7fL));
+    assert(!(f1 & ~0x7fL));
+    TSTFREG2(f2, f3);
+    TSTPRED(_p);
+    TSTFREG1(f1);
+    inst((op<<37)|(q<<36)|(sf<<34)|(1L<<33)|
+        (p2<<27)|(f3<<20)|(f2<<13)|(f1<<6)|_p, INST_F);
+    SETFREG(f1);
+    if (p2)
+       _jitc->pred |= 1 << p2;
+}
+
+static void
+F8_(jit_state_t *_jit, jit_word_t _p,
+    jit_word_t op, jit_word_t sf, jit_word_t x6,
+    jit_word_t f3, jit_word_t f2, jit_word_t f1)
+{
+    assert(!(_p & ~0x3fL));
+    assert(!(op &  ~0xfL));
+    assert(!(sf &  ~0x3L));
+    assert(!(x6 & ~0x3fL));
+    assert(!(f3 & ~0x7fL));
+    assert(!(f2 & ~0x7fL));
+    assert(!(f1 & ~0x7fL));
+    TSTFREG2(f2, f3);
+    TSTPRED(_p);
+    TSTFREG1(f1);
+    inst((op<<37)|(sf<<34)|(x6<<27)|(f3<<20)|(f2<<13)|(f1<<6)|_p, INST_F);
+    SETFREG(f1);
+}
+
+static void
+F12_(jit_state_t *_jit, jit_word_t _p,
+     jit_word_t sf, jit_word_t x6, jit_word_t omsk, jit_word_t amsk)
+{
+    assert(!(_p   & ~0x3fL));
+    assert(!(sf   &  ~0x3L));
+    assert(!(x6   & ~0x3fL));
+    assert(!(omsk & ~0x7fL));
+    assert(!(amsk & ~0x7fL));
+    TSTPRED(_p);
+    inst((sf<<34)|(x6<<27)|(omsk<<20)|(amsk<<13), INST_F);
+}
+
+static void
+F14x_(jit_state_t* _jit, jit_word_t _p,
+      jit_word_t sf,  jit_word_t x, jit_word_t x6, jit_word_t im)
+{
+    assert(!(_p &    ~0x3fL));
+    assert(!(sf &     ~0x3L));
+    assert(!(x  &     ~0x1L));
+    assert(!(x6 &    ~0x3fL));
+    assert(!(im & ~0x1ffffL));
+    TSTPRED(_p);
+    inst((((im>>20)&1L)<<36)|(sf<<34)|(x<<33)|
+        (x6<<27)|((im&0xffffL)<<6)|_p, INST_F);
+}
+
+static void
+F16_(jit_state_t* _jit, jit_word_t _p,
+     jit_word_t y, jit_word_t im)
+{
+    assert(!(_p &    ~0x3fL));
+    assert(!(y  &     ~0x1L));
+    assert(!(im & ~0x1ffffL));
+    TSTPRED(_p);
+    inst((((im>>20)&1L)<<36)|(y<<27)|(1L<<26)|((im&0xffffL)<<6)|_p, INST_F);
+}
+
+static void
+_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t      i;
+       jit_float32_t    f;
+    } data;
+    jit_int32_t                 reg;
+
+    if (_jitc->no_data) {
+       data.f = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.i & 0xffffffff);
+       SETF_S(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldi_f(r0, (jit_word_t)i0);
+}
+
+static void
+_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+       jit_word_t       w;
+       jit_float64_t    d;
+    } data;
+    jit_int32_t                 reg;
+
+    if (_jitc->no_data) {
+       data.d = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.w);
+       SETF_D(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldi_d(r0, (jit_word_t)i0);
+}
+
+static void
+_movr_w_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    /* Should be used only in this case (with out0 == 120) */
+    if (r1 >= 120)
+       r1 = _jitc->rout + (r1 - 120);
+    SETF_S(r0, r1);
+}
+
+static void
+_movr_f_w(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    /* Should actually be used only in this case (with out0 == 120) */
+    if (r0 >= 120)
+       r0 = _jitc->rout + (r0 - 120);
+    GETF_S(r0, r1);
+}
+
+static void
+_movi_f_w(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    jit_data_t         data;
+
+    /* Should be used only in this case (with out0 == 120) */
+    if (r0 >= 120)
+       r0 = _jitc->rout + (r0 - 120);
+    if (_jitc->no_data) {
+       data.f = *i0;
+       movi(r0, data.q.l);
+    }
+    else
+       ldi_i(r0, (jit_word_t)i0);
+}
+
+static void
+_movr_w_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    /* Should be used only in this case (with out0 == 120) */
+    if (r1 >= 120)
+       r1 = _jitc->rout + (r1 - 120);
+    SETF_D(r0, r1);
+}
+
+static void
+_movr_d_w(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    /* Should be used only in this case (with out0 == 120) */
+    if (r0 >= 120)
+       r0 = _jitc->rout + (r0 - 120);
+    GETF_D(r0, r1);
+}
+
+static void
+_movi_d_w(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+       jit_word_t       w;
+       jit_float64_t    d;
+    } data;
+
+    /* Should be used only in this case (with out0 == 120) */
+    if (r0 >= 120)
+       r0 = _jitc->rout + (r0 - 120);
+    if (_jitc->no_data) {
+       data.d = *i0;
+       movi(r0, data.w);
+    }
+    else
+       ldi_l(r0, (jit_word_t)i0);
+}
+
+#define fpr_opi(name, type, size)                                      \
+static void                                                            \
+_##name##i_##type(jit_state_t *_jit,                                   \
+                 jit_int32_t r0, jit_int32_t r1,                       \
+                 jit_float##size##_t *i0)                              \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    movi_##type(rn(reg), i0);                                          \
+    name##r_##type(r0, r1, rn(reg));                                   \
+    jit_unget_reg(reg);                                                        \
+}
+#define fpr_bopi(name, type, size)                                     \
+static jit_word_t                                                      \
+_b##name##i_##type(jit_state_t *_jit,                                  \
+                 jit_word_t i0, jit_int32_t r0,                        \
+                 jit_float##size##_t *i1)                              \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|                \
+                                         jit_class_nospill);           \
+    movi_##type(rn(reg), i1);                                          \
+    word = b##name##r_##type(i0, r0, rn(reg));                         \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+#define fopi(name)                     fpr_opi(name, f, 32)
+#define fbopi(name)                    fpr_bopi(name, f, 32)
+#define dopi(name)                     fpr_opi(name, d, 64)
+#define dbopi(name)                    fpr_bopi(name, d, 64)
+
+fopi(add)
+fopi(sub)
+fopi(rsb)
+fopi(mul)
+fopi(div)
+dopi(add)
+dopi(sub)
+dopi(rsb)
+dopi(mul)
+dopi(div)
+
+/* translation from gcc -O0 */
+static void
+_divr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0, t1, t2;
+    t0 = jit_get_reg(jit_class_fpr);
+    t1 = jit_get_reg(jit_class_fpr);
+    t2 = jit_get_reg(jit_class_fpr);
+    FRCPA(rn(t0), PR_6, r1, r2);
+    FNMA_p(rn(t1), r2, rn(t0), GR_1, SF_S1, PR_6);
+    FMA_p(rn(t2), rn(t0), rn(t1), rn(t0), SF_S1, PR_6);
+    FMPY_p(rn(t1), rn(t1), rn(t1), SF_S1, PR_6);
+    FMA_p(rn(t2), rn(t2), rn(t1), rn(t2), SF_S1, PR_6);
+    FMPY_p(rn(t1), rn(t1), rn(t1), SF_S1, PR_6);
+    FMA_p(rn(t1), rn(t2), rn(t1), rn(t2), SF_S1, PR_6);
+    FMPY_S_p(rn(t2), r1, rn(t1), SF_S1, PR_6);
+    FNMA_p(rn(t0), r2, rn(t2), r1, SF_S1, PR_6);
+    FMA_S_p(r0, rn(t0), rn(t1), rn(t2), SF_S0, PR_6);
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+}
+
+static void
+_divr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0, t1, t2;
+    t0 = jit_get_reg(jit_class_fpr);
+    t1 = jit_get_reg(jit_class_fpr);
+    t2 = jit_get_reg(jit_class_fpr);
+    FRCPA(rn(t0), PR_6, r1, r2);
+    FNMA_p(rn(t1), r2, rn(t0), GR_1, SF_S1, PR_6);
+    FMA_p(rn(t2), rn(t0), rn(t1), rn(t0), SF_S1, PR_6);
+    FMPY_p(rn(t1), rn(t1), rn(t1), SF_S1, PR_6);
+    FMA_p(rn(t2), rn(t2), rn(t1), rn(t2), SF_S1, PR_6);
+    FMPY_p(rn(t1), rn(t1), rn(t1), SF_S1, PR_6);
+    FMA_p(rn(t1), rn(t2), rn(t1), rn(t2), SF_S1, PR_6);
+    FMPY_D_p(rn(t2), r1, rn(t1), SF_S1, PR_6);
+    FNMA_p(rn(t0), r2, rn(t2), r1, SF_S1, PR_6);
+    FMA_D_p(r0, rn(t0), rn(t1), rn(t2), SF_S0, PR_6);
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+}
+
+static void
+_extr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    SETF_SIG(rn(reg), r1);
+    FCVT_XF(r0, rn(reg));
+    FNORM_S(r0, r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_extr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    SETF_SIG(rn(reg), r1);
+    FCVT_XF(r0, rn(reg));
+    FNORM_D(r0, r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_truncr_d_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    FCVT_FX_TRUNC(rn(reg), r1);
+    GETF_SIG(r0, rn(reg));
+    FNORM(r0, r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_ltr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_LT(PR_6, PR_7, r1, r2);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+fopi(lt)
+dopi(lt)
+
+static void
+_ler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_LE(PR_6, PR_7, r1, r2);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+fopi(le)
+dopi(le)
+
+static void
+_eqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_EQ(PR_6, PR_7, r1, r2);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+fopi(eq)
+dopi(eq)
+
+static void
+_ger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_LE(PR_6, PR_7, r2, r1);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+fopi(ge)
+dopi(ge)
+
+static void
+_gtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_LT(PR_6, PR_7, r2, r1);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+fopi(gt)
+dopi(gt)
+
+static void
+_ner_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_EQ(PR_6, PR_7, r1, r2);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+fopi(ne)
+dopi(ne)
+
+static void
+_unltr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_LE(PR_6, PR_7, r2, r1);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+fopi(unlt)
+dopi(unlt)
+
+static void
+_unler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_LT(PR_6, PR_7, r2, r1);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+fopi(unle)
+dopi(unle)
+
+static void
+_uneqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    MOVI(r0, 1);
+    FCMP_LT(PR_8, PR_9, r1, r2);
+    FCMP_LT(PR_6, PR_7, r2, r1);
+    MOV_p(r0, GR_0, PR_8);             /* !(r1 < r2) && !(r2 < r1) */
+    MOV_p(r0, GR_0, PR_6);
+}
+fopi(uneq)
+dopi(uneq)
+
+static void
+_unger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_LT(PR_6, PR_7, r1, r2);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+fopi(unge)
+dopi(unge)
+
+static void
+_ungtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_LE(PR_6, PR_7, r1, r2);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+fopi(ungt)
+dopi(ungt)
+
+static void
+_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    MOVI(r0, 1);
+    FCMP_EQ(PR_8, PR_9, r1, r2);
+    FCMP_UNORD(PR_6, PR_7, r1, r2);
+    MOV_p(r0, GR_0, PR_8);
+    MOV_p(r0, GR_0, PR_6);
+}
+fopi(ltgt)
+dopi(ltgt)
+
+static void
+_ordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_UNORD(PR_6, PR_7, r1, r2);
+    MOV_p(r0, GR_0, PR_6);
+    MOVI_p(r0, 1, PR_7);
+}
+fopi(ord)
+dopi(ord)
+
+static void
+_unordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMP_UNORD(PR_6, PR_7, r1, r2);
+    MOVI_p(r0, 1, PR_6);
+    MOV_p(r0, GR_0, PR_7);
+}
+fopi(unord)
+dopi(unord)
+
+static void
+_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_f(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_f(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (r0) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldr_f(r0, r1);
+}
+
+static void
+_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ldr_d(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_d(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (r0) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       ldr_d(r0, r1);
+}
+
+static void
+_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_f(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_f(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_f(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+    else
+       str_f(r0, r1);
+}
+
+static void
+_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    str_d(rn(reg), r0);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_d(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_d(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+    else
+       str_d(r0, r1);
+}
+
+static void
+_sqrtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    movr_f(GR_8, r1);
+    calli((jit_word_t)sqrtf);
+    MOVF(r0, GR_8);
+}
+
+static void
+_sqrtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    movr_d(GR_8, r1);
+    calli((jit_word_t)sqrt);
+    MOVF(r0, GR_8);
+}
+
+static jit_word_t
+_bltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_LT(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+fbopi(lt)
+dbopi(lt)
+
+static jit_word_t
+_bler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_LE(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+fbopi(le)
+dbopi(le)
+
+static jit_word_t
+_beqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_EQ(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+fbopi(eq)
+dbopi(eq)
+
+static jit_word_t
+_bger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_LE(PR_6, PR_7, r1, r0);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+fbopi(ge)
+dbopi(ge)
+
+static jit_word_t
+_bgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_LT(PR_6, PR_7, r1, r0);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+fbopi(gt)
+dbopi(gt)
+
+static jit_word_t
+_bner_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_EQ(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+fbopi(ne)
+dbopi(ne)
+
+static jit_word_t
+_bunltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_LE(PR_6, PR_7, r1, r0);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+fbopi(unlt)
+dbopi(unlt)
+
+static jit_word_t
+_bunler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_LT(PR_6, PR_7, r1, r0);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+fbopi(unle)
+dbopi(unle)
+
+static jit_word_t
+_buneqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_word_t         junord, jne;
+    FCMP_UNORD(PR_8, PR_9, r0, r1);
+    sync();
+    /* junord L1 */
+    junord = _jit->pc.w;
+    BRI_COND(3, PR_8);
+    FCMP_EQ(PR_6, PR_7, r0, r1);
+    sync();
+    /* jne L2 */
+    jne = _jit->pc.w;
+    BRI_COND(2, PR_7);
+    sync();
+    w = _jit->pc.w;
+    /* L1: */
+    patch_at(jit_code_bunordr_d, junord, _jit->pc.w);
+    BRI((i0 - w) >> 4);                /* unconditional jump to patch */
+    sync();
+    /* L2: */
+    patch_at(jit_code_bner_d, jne, _jit->pc.w);
+    return (w);
+}
+fbopi(uneq)
+dbopi(uneq)
+
+static jit_word_t
+_bunger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_LT(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+fbopi(unge)
+dbopi(unge)
+
+static jit_word_t
+_bungtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_LE(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+fbopi(ungt)
+dbopi(ungt)
+
+static jit_word_t
+_bltgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_word_t         jeq, junord;
+    FCMP_EQ(PR_8, PR_9, r0, r1);
+    /* jeq L1 */
+    sync();
+    jeq = _jit->pc.w;
+    BRI_COND(4, PR_8);
+    FCMP_UNORD(PR_6, PR_7, r0, r1);
+    /* junord L1 */
+    sync();
+    junord = _jit->pc.w;
+    BRI_COND(2, PR_6);
+    sync();
+    w = _jit->pc.w;
+    BRI((i0 - w) >> 4);                /* unconditional jump to patch */
+    /* L1 */
+    sync();
+    patch_at(jit_code_beqr_d, jeq, _jit->pc.w);
+    patch_at(jit_code_bordr_d, junord, _jit->pc.w);
+    return (w);
+}
+fbopi(ltgt)
+dbopi(ltgt)
+
+static jit_word_t
+_bordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_UNORD(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_7);
+    return (w);
+}
+fbopi(ord)
+dbopi(ord)
+
+static jit_word_t
+_bunordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMP_UNORD(PR_6, PR_7, r0, r1);
+    sync();
+    w = _jit->pc.w;
+    BRI_COND((i0 - w) >> 4, PR_6);
+    return (w);
+}
+fbopi(unord)
+dbopi(unord)
+
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Load argument. */
+    ldr_d(r0, r1);
+    /* Update va_list. */
+    addi(r1, r1, 8);
+}
+#endif
diff --git a/deps/lightning/lib/jit_ia64-sz.c b/deps/lightning/lib/jit_ia64-sz.c
new file mode 100644 (file)
index 0000000..59826d9
--- /dev/null
@@ -0,0 +1,402 @@
+
+#if __WORDSIZE == 64
+#define JIT_INSTR_MAX 224
+    0, /* data */
+    0, /* live */
+    0, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    224,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    16,        /* va_start */
+    32,        /* va_arg */
+    32,        /* va_arg_d */
+    0, /* va_end */
+    16,        /* addr */
+    32,        /* addi */
+    32,        /* addcr */
+    48,        /* addci */
+    64,        /* addxr */
+    64,        /* addxi */
+    16,        /* subr */
+    32,        /* subi */
+    32,        /* subcr */
+    48,        /* subci */
+    64,        /* subxr */
+    64,        /* subxi */
+    32,        /* rsbi */
+    48,        /* mulr */
+    64,        /* muli */
+    112,       /* qmulr */
+    112,       /* qmuli */
+    112,       /* qmulr_u */
+    112,       /* qmuli_u */
+    80,        /* divr */
+    96,        /* divi */
+    80,        /* divr_u */
+    96,        /* divi_u */
+    144,       /* qdivr */
+    144,       /* qdivi */
+    144,       /* qdivr_u */
+    144,       /* qdivi_u */
+    80,        /* remr */
+    96,        /* remi */
+    80,        /* remr_u */
+    96,        /* remi_u */
+    16,        /* andr */
+    32,        /* andi */
+    16,        /* orr */
+    32,        /* ori */
+    16,        /* xorr */
+    32,        /* xori */
+    16,        /* lshr */
+    16,        /* lshi */
+    16,        /* rshr */
+    16,        /* rshi */
+    16,        /* rshr_u */
+    16,        /* rshi_u */
+    16,        /* negr */
+    16,        /* comr */
+    32,        /* ltr */
+    32,        /* lti */
+    32,        /* ltr_u */
+    32,        /* lti_u */
+    32,        /* ler */
+    32,        /* lei */
+    32,        /* ler_u */
+    32,        /* lei_u */
+    32,        /* eqr */
+    32,        /* eqi */
+    32,        /* ger */
+    32,        /* gei */
+    32,        /* ger_u */
+    32,        /* gei_u */
+    32,        /* gtr */
+    32,        /* gti */
+    32,        /* gtr_u */
+    32,        /* gti_u */
+    32,        /* ner */
+    32,        /* nei */
+    16,        /* movr */
+    16,        /* movi */
+    16,        /* extr_c */
+    16,        /* extr_uc */
+    16,        /* extr_s */
+    16,        /* extr_us */
+    16,        /* extr_i */
+    16,        /* extr_ui */
+    64,        /* htonr_us */
+    160,       /* htonr_ui */
+    16,        /* htonr_ul */
+    16,        /* ldr_c */
+    32,        /* ldi_c */
+    16,        /* ldr_uc */
+    32,        /* ldi_uc */
+    16,        /* ldr_s */
+    32,        /* ldi_s */
+    16,        /* ldr_us */
+    32,        /* ldi_us */
+    16,        /* ldr_i */
+    32,        /* ldi_i */
+    16,        /* ldr_ui */
+    32,        /* ldi_ui */
+    16,        /* ldr_l */
+    32,        /* ldi_l */
+    32,        /* ldxr_c */
+    48,        /* ldxi_c */
+    16,        /* ldxr_uc */
+    32,        /* ldxi_uc */
+    32,        /* ldxr_s */
+    48,        /* ldxi_s */
+    16,        /* ldxr_us */
+    32,        /* ldxi_us */
+    32,        /* ldxr_i */
+    48,        /* ldxi_i */
+    16,        /* ldxr_ui */
+    32,        /* ldxi_ui */
+    16,        /* ldxr_l */
+    32,        /* ldxi_l */
+    16,        /* str_c */
+    32,        /* sti_c */
+    16,        /* str_s */
+    32,        /* sti_s */
+    16,        /* str_i */
+    32,        /* sti_i */
+    16,        /* str_l */
+    32,        /* sti_l */
+    16,        /* stxr_c */
+    32,        /* stxi_c */
+    16,        /* stxr_s */
+    32,        /* stxi_s */
+    16,        /* stxr_i */
+    32,        /* stxi_i */
+    16,        /* stxr_l */
+    32,        /* stxi_l */
+    32,        /* bltr */
+    32,        /* blti */
+    32,        /* bltr_u */
+    32,        /* blti_u */
+    32,        /* bler */
+    32,        /* blei */
+    32,        /* bler_u */
+    32,        /* blei_u */
+    32,        /* beqr */
+    48,        /* beqi */
+    32,        /* bger */
+    32,        /* bgei */
+    32,        /* bger_u */
+    32,        /* bgei_u */
+    32,        /* bgtr */
+    32,        /* bgti */
+    32,        /* bgtr_u */
+    32,        /* bgti_u */
+    32,        /* bner */
+    48,        /* bnei */
+    32,        /* bmsr */
+    48,        /* bmsi */
+    32,        /* bmcr */
+    48,        /* bmci */
+    96,        /* boaddr */
+    112,       /* boaddi */
+    64,        /* boaddr_u */
+    64,        /* boaddi_u */
+    96,        /* bxaddr */
+    112,       /* bxaddi */
+    64,        /* bxaddr_u */
+    64,        /* bxaddi_u */
+    112,       /* bosubr */
+    112,       /* bosubi */
+    64,        /* bosubr_u */
+    64,        /* bosubi_u */
+    112,       /* bxsubr */
+    112,       /* bxsubi */
+    64,        /* bxsubr_u */
+    64,        /* bxsubi_u */
+    16,        /* jmpr */
+    16,        /* jmpi */
+    32,        /* callr */
+    48,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    128,       /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    16,        /* addr_f */
+    48,        /* addi_f */
+    16,        /* subr_f */
+    48,        /* subi_f */
+    48,        /* rsbi_f */
+    16,        /* mulr_f */
+    48,        /* muli_f */
+    160,       /* divr_f */
+    192,       /* divi_f */
+    16,        /* negr_f */
+    16,        /* absr_f */
+    80,        /* sqrtr_f */
+    32,        /* ltr_f */
+    64,        /* lti_f */
+    32,        /* ler_f */
+    64,        /* lei_f */
+    32,        /* eqr_f */
+    64,        /* eqi_f */
+    32,        /* ger_f */
+    64,        /* gei_f */
+    32,        /* gtr_f */
+    64,        /* gti_f */
+    32,        /* ner_f */
+    64,        /* nei_f */
+    32,        /* unltr_f */
+    64,        /* unlti_f */
+    32,        /* unler_f */
+    64,        /* unlei_f */
+    48,        /* uneqr_f */
+    96,        /* uneqi_f */
+    32,        /* unger_f */
+    64,        /* ungei_f */
+    32,        /* ungtr_f */
+    64,        /* ungti_f */
+    48,        /* ltgtr_f */
+    96,        /* ltgti_f */
+    32,        /* ordr_f */
+    64,        /* ordi_f */
+    32,        /* unordr_f */
+    64,        /* unordi_f */
+    32,        /* truncr_f_i */
+    32,        /* truncr_f_l */
+    48,        /* extr_f */
+    16,        /* extr_d_f */
+    16,        /* movr_f */
+    32,        /* movi_f */
+    16,        /* ldr_f */
+    32,        /* ldi_f */
+    16,        /* ldxr_f */
+    32,        /* ldxi_f */
+    16,        /* str_f */
+    32,        /* sti_f */
+    16,        /* stxr_f */
+    32,        /* stxi_f */
+    32,        /* bltr_f */
+    64,        /* blti_f */
+    32,        /* bler_f */
+    64,        /* blei_f */
+    32,        /* beqr_f */
+    64,        /* beqi_f */
+    32,        /* bger_f */
+    64,        /* bgei_f */
+    32,        /* bgtr_f */
+    64,        /* bgti_f */
+    32,        /* bner_f */
+    64,        /* bnei_f */
+    32,        /* bunltr_f */
+    64,        /* bunlti_f */
+    32,        /* bunler_f */
+    64,        /* bunlei_f */
+    80,        /* buneqr_f */
+    112,       /* buneqi_f */
+    32,        /* bunger_f */
+    64,        /* bungei_f */
+    32,        /* bungtr_f */
+    64,        /* bungti_f */
+    80,        /* bltgtr_f */
+    112,       /* bltgti_f */
+    32,        /* bordr_f */
+    64,        /* bordi_f */
+    32,        /* bunordr_f */
+    64,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    16,        /* addr_d */
+    48,        /* addi_d */
+    16,        /* subr_d */
+    48,        /* subi_d */
+    48,        /* rsbi_d */
+    16,        /* mulr_d */
+    48,        /* muli_d */
+    160,       /* divr_d */
+    192,       /* divi_d */
+    16,        /* negr_d */
+    16,        /* absr_d */
+    80,        /* sqrtr_d */
+    32,        /* ltr_d */
+    64,        /* lti_d */
+    32,        /* ler_d */
+    64,        /* lei_d */
+    32,        /* eqr_d */
+    64,        /* eqi_d */
+    32,        /* ger_d */
+    64,        /* gei_d */
+    32,        /* gtr_d */
+    64,        /* gti_d */
+    32,        /* ner_d */
+    64,        /* nei_d */
+    32,        /* unltr_d */
+    64,        /* unlti_d */
+    32,        /* unler_d */
+    64,        /* unlei_d */
+    48,        /* uneqr_d */
+    96,        /* uneqi_d */
+    32,        /* unger_d */
+    64,        /* ungei_d */
+    32,        /* ungtr_d */
+    64,        /* ungti_d */
+    48,        /* ltgtr_d */
+    96,        /* ltgti_d */
+    32,        /* ordr_d */
+    64,        /* ordi_d */
+    32,        /* unordr_d */
+    64,        /* unordi_d */
+    32,        /* truncr_d_i */
+    32,        /* truncr_d_l */
+    48,        /* extr_d */
+    16,        /* extr_f_d */
+    16,        /* movr_d */
+    32,        /* movi_d */
+    16,        /* ldr_d */
+    32,        /* ldi_d */
+    16,        /* ldxr_d */
+    32,        /* ldxi_d */
+    16,        /* str_d */
+    32,        /* sti_d */
+    16,        /* stxr_d */
+    32,        /* stxi_d */
+    32,        /* bltr_d */
+    64,        /* blti_d */
+    32,        /* bler_d */
+    64,        /* blei_d */
+    32,        /* beqr_d */
+    64,        /* beqi_d */
+    32,        /* bger_d */
+    64,        /* bgei_d */
+    32,        /* bgtr_d */
+    64,        /* bgti_d */
+    32,        /* bner_d */
+    64,        /* bnei_d */
+    32,        /* bunltr_d */
+    64,        /* bunlti_d */
+    32,        /* bunler_d */
+    64,        /* bunlei_d */
+    80,        /* buneqr_d */
+    112,       /* buneqi_d */
+    32,        /* bunger_d */
+    64,        /* bungei_d */
+    32,        /* bungtr_d */
+    64,        /* bungti_d */
+    80,        /* bltgtr_d */
+    112,       /* bltgti_d */
+    32,        /* bordr_d */
+    64,        /* bordi_d */
+    32,        /* bunordr_d */
+    64,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    16,        /* movr_d_w */
+    32,        /* movi_d_w */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_ia64.c b/deps/lightning/lib/jit_ia64.c
new file mode 100644 (file)
index 0000000..9207d81
--- /dev/null
@@ -0,0 +1,1769 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+
+#define jit_arg_reg_p(i)               ((i) >= 0 && (i) < 8)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define C_DISP                       0
+#  define S_DISP                       0
+#  define I_DISP                       0
+#  define F_DISP                       0
+#else
+#  define C_DISP                       8 - sizeof(jit_int8_t)
+#  define S_DISP                       8 - sizeof(jit_int16_t)
+#  define I_DISP                       8 - sizeof(jit_int32_t)
+#  define F_DISP                       8 - sizeof(jit_float32_t)
+#endif
+
+/*
+ * Types
+ */
+typedef jit_pointer_t jit_va_list_t;
+
+/*
+ * Prototypes
+ */
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+#if defined(__GNUC__)
+/* libgcc */
+extern void __clear_cache(void *, void *);
+#endif
+
+#define PROTO                          1
+#  include "jit_ia64-cpu.c"
+#  include "jit_ia64-fpu.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_register_t         _rvs[] = {
+    /* Always 0 */
+    { 0,                "r0"  },
+    /* Global Pointer */
+    { rc(sav)|1,        "r1"  },
+    /* Used when a register cannot be allocated */
+    { 2,                "r2"  },
+    /* First scratch register */
+    { rc(gpr)|3,        "r3"  },
+    /* Use r4 as lightning fp register */
+    { rc(sav)|4,        "r4"  },
+    /* Do not touch callee save registers not automatically spill/reloaded */
+    { rc(sav)|5,        "r5"  },       { rc(sav)|6,            "r6"  },
+    { rc(sav)|7,        "r7"  },
+    /* Do not touch return register for the sake of simplicity, besides
+     * having JIT_R0 being the same as JIT_RET usually an optimization */
+    { 8,                "r8"  },
+    /* Return registers, use as temporaries */
+    { rc(gpr)|9,        "r9"  },
+    { rc(gpr)|10,       "r10" },       { rc(gpr)|11,           "r11" },
+    /* Stack pointer */
+    { rc(sav)|12,       "r12" },
+    /* Thread pointer */
+    { rc(sav)|13,       "r13" },
+    /* (Usually) assembly temporaries */
+    { rc(gpr)|31,       "r31" },       { rc(gpr)|30,           "r30" },
+    { rc(gpr)|29,       "r29" },       { rc(gpr)|28,           "r28" },
+    { rc(gpr)|27,       "r27" },       { rc(gpr)|26,           "r26" },
+    { rc(gpr)|25,       "r25" },       { rc(gpr)|24,           "r24" },
+    { rc(gpr)|23,       "r23" },       { rc(gpr)|22,           "r22" },
+    { rc(gpr)|21,       "r21" },       { rc(gpr)|20,           "r20" },
+    { rc(gpr)|19,       "r19" },       { rc(gpr)|18,           "r18" },
+    { rc(gpr)|17,       "r17" },       { rc(gpr)|16,           "r16" },
+    { rc(gpr)|15,       "r15" },       { rc(gpr)|14,           "r14" },
+    /* Do not allow allocating r32-r41 as temoraries for the sake of
+     * avoiding the need of extra complexity  in the non backend code */
+    { rc(arg)|32,       "r32" },       { rc(arg)|33,           "r33" },
+    { rc(arg)|34,       "r34" },       { rc(arg)|35,           "r35" },
+    { rc(arg)|36,       "r36" },       { rc(arg)|37,           "r37" },
+    { rc(arg)|38,       "r38" },       { rc(arg)|39,           "r39" },
+    /* JIT_R0-JIT_V3 */
+    { rc(gpr)|rc(sav)|40, "r40" },     { rc(gpr)|rc(sav)|41,   "r41" },
+    { rc(gpr)|rc(sav)|42, "r42" },     { rc(gpr)|rc(sav)|43,   "r43" },
+    { rc(gpr)|rc(sav)|44, "r44" },     { rc(gpr)|rc(sav)|45,   "r45" },
+    { rc(gpr)|rc(sav)|46, "r46" },     { rc(gpr)|rc(sav)|47,   "r47" },
+    /* Temporaries/locals */
+    { rc(gpr)|rc(sav)|48, "r48" },     { rc(gpr)|rc(sav)|49,   "r49" },
+    { rc(gpr)|rc(sav)|50, "r50" },     { rc(gpr)|rc(sav)|51,   "r51" },
+    { rc(gpr)|rc(sav)|52, "r52" },     { rc(gpr)|rc(sav)|53,   "r53" },
+    { rc(gpr)|rc(sav)|54, "r54" },     { rc(gpr)|rc(sav)|55,   "r55" },
+    { rc(gpr)|rc(sav)|56, "r56" },     { rc(gpr)|rc(sav)|57,   "r57" },
+    { rc(gpr)|rc(sav)|58, "r58" },     { rc(gpr)|rc(sav)|59,   "r59" },
+    { rc(gpr)|rc(sav)|60, "r60" },     { rc(gpr)|rc(sav)|61,   "r61" },
+    { rc(gpr)|rc(sav)|62, "r62" },     { rc(gpr)|rc(sav)|63,   "r63" },
+    { rc(gpr)|rc(sav)|64, "r64" },     { rc(gpr)|rc(sav)|65,   "r65" },
+    { rc(gpr)|rc(sav)|66, "r66" },     { rc(gpr)|rc(sav)|67,   "r67" },
+    { rc(gpr)|rc(sav)|68, "r68" },     { rc(gpr)|rc(sav)|69,   "r69" },
+    { rc(gpr)|rc(sav)|70, "r70" },     { rc(gpr)|rc(sav)|71,   "r71" },
+    { rc(gpr)|rc(sav)|72, "r72" },     { rc(gpr)|rc(sav)|73,   "r73" },
+    { rc(gpr)|rc(sav)|74, "r74" },     { rc(gpr)|rc(sav)|75,   "r75" },
+    { rc(gpr)|rc(sav)|76, "r76" },     { rc(gpr)|rc(sav)|77,   "r77" },
+    { rc(gpr)|rc(sav)|78, "r78" },     { rc(gpr)|rc(sav)|79,   "r79" },
+    { rc(gpr)|rc(sav)|80, "r80" },     { rc(gpr)|rc(sav)|81,   "r81" },
+    { rc(gpr)|rc(sav)|82, "r82" },     { rc(gpr)|rc(sav)|83,   "r83" },
+    { rc(gpr)|rc(sav)|84, "r84" },     { rc(gpr)|rc(sav)|85,   "r85" },
+    { rc(gpr)|rc(sav)|86, "r86" },     { rc(gpr)|rc(sav)|87,   "r87" },
+    { rc(gpr)|rc(sav)|88, "r88" },     { rc(gpr)|rc(sav)|89,   "r89" },
+    { rc(gpr)|rc(sav)|90, "r90" },     { rc(gpr)|rc(sav)|91,   "r91" },
+    { rc(gpr)|rc(sav)|92, "r92" },     { rc(gpr)|rc(sav)|93,   "r93" },
+    { rc(gpr)|rc(sav)|94, "r94" },     { rc(gpr)|rc(sav)|95,   "r95" },
+    { rc(gpr)|rc(sav)|96, "r96" },     { rc(gpr)|rc(sav)|97,   "r97" },
+    { rc(gpr)|rc(sav)|98, "r98" },     { rc(gpr)|rc(sav)|99,   "r99" },
+    { rc(gpr)|rc(sav)|100,"r100"},     { rc(gpr)|rc(sav)|101,  "r101"},
+    { rc(gpr)|rc(sav)|102,"r102"},     { rc(gpr)|rc(sav)|103,  "r103"},
+    { rc(gpr)|rc(sav)|104,"r104"},     { rc(gpr)|rc(sav)|105,  "r105"},
+    { rc(gpr)|rc(sav)|106,"r106"},     { rc(gpr)|rc(sav)|107,  "r107"},
+    { rc(gpr)|rc(sav)|108,"r108"},     { rc(gpr)|rc(sav)|109,  "r109"},
+    { rc(gpr)|rc(sav)|110,"r110"},     { rc(gpr)|rc(sav)|111,  "r111"},
+    { rc(gpr)|rc(sav)|112,"r112"},     { rc(gpr)|rc(sav)|113,  "r113"},
+    { rc(gpr)|rc(sav)|114,"r114"},
+    /* Do not enable these because no matter what, want 13 free registers,
+     * 5 for prolog and epilog and 8 for outgoing arguments */
+    { 115,              "r115"},
+    { 116,              "r116"},       { 117,                  "r117"},
+    { 118,              "r118"},       { 119,                  "r119"},
+    { 120,              "r120"},       { 121,                  "r121"},
+    { 122,              "r122"},       { 123,                  "r123"},
+    { 124,              "r124"},       { 125,                  "r125"},
+    { 126,              "r126"},       { 127,                  "r127"},
+    /* Always 0.0 */
+    { 0,                "f0"  },
+    /* Always 1.0 */
+    { 1,                "f1"  },
+    /* Do not touch callee save registers not automatically spill/reloaded */
+    { rc(sav)|2,        "f2"  },       { rc(sav)|3,            "f3"  },
+    { rc(sav)|4,        "f4"  },       { rc(sav)|5,            "f5"  },
+    /* Scratch */
+    { rc(fpr)|6,        "f6"  },       { rc(fpr)|7,            "f7"  },
+    /* Do not allocate for the sake of simplification */
+    { rc(arg)|8,        "f8"  },
+    /* Scratch - Argument/return registers */
+    { rc(arg)|9,        "f9"  },
+    { rc(arg)|10,       "f10" },       { rc(arg)|11,           "f11" },
+    { rc(arg)|12,       "f12" },       { rc(arg)|13,           "f13" },
+    { rc(arg)|14,       "f14" },       { rc(arg)|15,           "f15" },
+    /* Do not touch callee save registers not automatically spill/reloaded */
+    { rc(sav)|16,       "f16" },       { rc(sav)|17,           "f17" },
+    { rc(sav)|18,       "f18" },       { rc(sav)|19,           "f19" },
+    { rc(sav)|20,       "f20" },       { rc(sav)|21,           "f21" },
+    { rc(sav)|22,       "f22" },       { rc(sav)|23,           "f23" },
+    { rc(sav)|24,       "f24" },       { rc(sav)|25,           "f25" },
+    { rc(sav)|26,       "f26" },       { rc(sav)|27,           "f27" },
+    { rc(sav)|28,       "f28" },       { rc(sav)|29,           "f29" },
+    { rc(sav)|30,       "f30" },       { rc(sav)|31,           "f31" },
+    /* Scratch */
+    { rc(fpr)|32,       "f32" },       { rc(fpr)|33,           "f33" },
+    { rc(fpr)|34,       "f34" },       { rc(fpr)|35,           "f35" },
+    { rc(fpr)|36,       "f36" },       { rc(fpr)|37,           "f37" },
+    { rc(fpr)|38,       "f38" },       { rc(fpr)|39,           "f39" },
+    { rc(fpr)|40,       "f40" },       { rc(fpr)|41,           "f41" },
+    { rc(fpr)|42,       "f42" },       { rc(fpr)|43,           "f43" },
+    { rc(fpr)|44,       "f44" },       { rc(fpr)|45,           "f45" },
+    { rc(fpr)|46,       "f46" },       { rc(fpr)|47,           "f47" },
+    { rc(fpr)|48,       "f48" },       { rc(fpr)|49,           "f49" },
+    { rc(fpr)|50,       "f50" },       { rc(fpr)|51,           "f51" },
+    { rc(fpr)|52,       "f52" },       { rc(fpr)|53,           "f53" },
+    { rc(fpr)|54,       "f54" },       { rc(fpr)|55,           "f55" },
+    { rc(fpr)|56,       "f56" },       { rc(fpr)|57,           "f57" },
+    { rc(fpr)|58,       "f58" },       { rc(fpr)|59,           "f59" },
+    { rc(fpr)|60,       "f60" },       { rc(fpr)|61,           "f61" },
+    { rc(fpr)|62,       "f62" },       { rc(fpr)|63,           "f63" },
+    { rc(fpr)|64,       "f64" },       { rc(fpr)|65,           "f65" },
+    { rc(fpr)|66,       "f66" },       { rc(fpr)|67,           "f67" },
+    { rc(fpr)|68,       "f68" },       { rc(fpr)|69,           "f69" },
+    { rc(fpr)|70,       "f70" },       { rc(fpr)|71,           "f71" },
+    { rc(fpr)|72,       "f72" },       { rc(fpr)|73,           "f73" },
+    { rc(fpr)|74,       "f74" },       { rc(fpr)|75,           "f75" },
+    { rc(fpr)|76,       "f76" },       { rc(fpr)|77,           "f77" },
+    { rc(fpr)|78,       "f78" },       { rc(fpr)|79,           "f79" },
+    { rc(fpr)|80,       "f80" },       { rc(fpr)|81,           "f81" },
+    { rc(fpr)|82,       "f82" },       { rc(fpr)|83,           "f83" },
+    { rc(fpr)|84,       "f84" },       { rc(fpr)|85,           "f85" },
+    { rc(fpr)|86,       "f86" },       { rc(fpr)|87,           "f87" },
+    { rc(fpr)|88,       "f88" },       { rc(fpr)|89,           "f89" },
+    { rc(fpr)|90,       "f90" },       { rc(fpr)|91,           "f91" },
+    { rc(fpr)|92,       "f92" },       { rc(fpr)|93,           "f93" },
+    { rc(fpr)|94,       "f94" },       { rc(fpr)|95,           "f95" },
+    { rc(fpr)|96,       "f96" },       { rc(fpr)|97,           "f97" },
+    { rc(fpr)|98,       "f98" },       { rc(fpr)|99,           "f99" },
+    { rc(fpr)|100,      "f100"},       { rc(fpr)|101,          "f101"},
+    { rc(fpr)|102,      "f102"},       { rc(fpr)|103,          "f103"},
+    { rc(fpr)|104,      "f104"},       { rc(fpr)|105,          "f105"},
+    { rc(fpr)|106,      "f106"},       { rc(fpr)|107,          "f107"},
+    { rc(fpr)|108,      "f108"},       { rc(fpr)|109,          "f109"},
+    { rc(fpr)|110,      "f110"},       { rc(fpr)|111,          "f111"},
+    { rc(fpr)|112,      "f112"},       { rc(fpr)|113,          "f113"},
+    { rc(fpr)|114,      "f114"},       { rc(fpr)|115,          "f115"},
+    { rc(fpr)|116,      "f116"},       { rc(fpr)|117,          "f117"},
+    { rc(fpr)|118,      "f118"},       { rc(fpr)|119,          "f119"},
+#if 0
+    /* commented to fit a jit_regset_t in 256 bits, so that the fake
+     * O0-O7 registers are easily patched when an argument is pushed */
+    { rc(fpr)|120,      "f120"},       { rc(fpr)|121,          "f121"},
+    { rc(fpr)|122,      "f122"},       { rc(fpr)|123,          "f123"},
+    { rc(fpr)|124,      "f124"},       { rc(fpr)|125,          "f125"},
+    { rc(fpr)|126,      "f126"},       { rc(fpr)|127,          "f127"},
+#endif
+    /* Fake registers to patch in movr and movi arguments */
+    { rc(arg)|120,      "o0"  },       { rc(arg)|121,          "o1"  },
+    { rc(arg)|122,      "o2"  },       { rc(arg)|123,          "o3"  },
+    { rc(arg)|124,      "o4"  },       { rc(arg)|125,          "o5"  },
+    { rc(arg)|126,      "o6"  },       { rc(arg)|127,          "o7"  },
+    { _NOREG,           "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    _jitc->reglen = jit_size(_rvs) - 1;
+    jit_regset_new(&_jitc->regs);
+    jit_carry = _NOREG;
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    /* params_offset << 1, once for ours arguments, once for arguments
+     * to any called function; required because offsets are computed
+     * as JIT_FP displacement */
+    _jitc->function->self.size = stack_framesize + (params_offset << 1);
+    _jitc->function->self.argi = _jitc->function->self.argf =
+       _jitc->function->self.aoff = _jitc->function->self.alen = 0;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    return (_jitc->function->self.aoff);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 reg;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    jit_negr(reg, v);
+    jit_andi(reg, reg, -16);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, reg);
+    jit_addr(JIT_SP, JIT_SP, reg);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(reg);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    jit_movr(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    jit_movr_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    jit_movr_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    assert(u->code == jit_code_arg ||
+          u->code == jit_code_arg_f || u->code == jit_code_arg_d);
+    return (jit_arg_reg_p(u->u.w));
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare) {
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+       jit_link_prepare();
+    }
+    else {
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+       _jitc->function->vagp = _jitc->function->self.argi;
+       jit_link_prolog();
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       if (!(_jitc->function->self.call & jit_call_varargs))
+           offset = 8 + _jitc->function->self.argf++;
+       else
+           offset = _jitc->function->self.argi;
+       ++_jitc->function->self.argi;
+    }
+   else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg_f, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       if (!(_jitc->function->self.call & jit_call_varargs))
+           offset = 8 + _jitc->function->self.argf++;
+       else
+           offset = _jitc->function->self.argi;
+       ++_jitc->function->self.argi;
+    }
+   else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_float64_t);
+    }
+    node = jit_new_node_ww(jit_code_arg_d, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, _R32 + v->u.w);
+    else
+       jit_ldxi_c(u, JIT_FP, v->u.w + C_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, _R32 + v->u.w);
+    else
+       jit_ldxi_uc(u, JIT_FP, v->u.w + C_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, _R32 + v->u.w);
+    else
+       jit_ldxi_s(u, JIT_FP, v->u.w + S_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, _R32 + v->u.w);
+    else
+       jit_ldxi_us(u, JIT_FP, v->u.w + S_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_i(u, _R32 + v->u.w);
+    else
+       jit_ldxi_i(u, JIT_FP, v->u.w + I_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_ui, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_ui(u, _R32 + v->u.w);
+    else
+       jit_ldxi_ui(u, JIT_FP, v->u.w + I_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_l, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, _R32 + v->u.w);
+    else
+       jit_ldxi(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(_R32 + v->u.w, u);
+    else
+       jit_stxi(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi(_R32 + v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_w_f(u, _OUT0 + v->u.w);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_f(u, _F8 + (v->u.w - 8));
+    else
+       jit_ldxi_f(u, JIT_FP, v->u.w + F_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_f_w(_OUT0 + v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_f(_F8 + (v->u.w - 8), u);
+    else
+       jit_stxi_f(v->u.w, JIT_FP, u + F_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi_f_w(_OUT0 + v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movi_f(_F8 + (v->u.w - 8), u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(v->u.w, JIT_FP, regno + F_DISP);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_w_d(u, _OUT0 + v->u.w);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_d(u, _F8 + (v->u.w - 8));
+    else
+       jit_ldxi_d(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_d_w(_OUT0 + v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_d(_F8 + (v->u.w - 8), u);
+    else
+       jit_stxi_d(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi_d_w(_OUT0 + v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movi_d(_F8 + (v->u.w - 8), u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(_OUT0 + _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi(_jitc->function->call.size + params_offset, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(_OUT0 + _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size + params_offset, JIT_SP, regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       if (!(_jitc->function->call.call & jit_call_varargs)) {
+           jit_movr_f(_F8 + _jitc->function->call.argf, u);
+           ++_jitc->function->call.argf;
+       }
+       else
+           jit_movr_f_w(_OUT0 + _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size + params_offset + F_DISP,
+                  JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       if (!(_jitc->function->call.call & jit_call_varargs)) {
+           jit_movi_f(_F8 + _jitc->function->call.argf, u);
+           ++_jitc->function->call.argf;
+       }
+       else
+           jit_movi_f_w(_OUT0 + _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(_jitc->function->call.size + params_offset + F_DISP,
+                  JIT_SP, regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       if (!(_jitc->function->call.call & jit_call_varargs)) {
+           jit_movr_d(_F8 + _jitc->function->call.argf, u);
+           ++_jitc->function->call.argf;
+       }
+       else
+           jit_movr_d_w(_OUT0 + _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_d(_jitc->function->call.size + params_offset, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       if (!(_jitc->function->call.call & jit_call_varargs)) {
+           jit_movi_d(_F8 + _jitc->function->call.argf, u);
+           ++_jitc->function->call.argf;
+       }
+       else
+           jit_movi_d_w(_OUT0 + _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(_jitc->function->call.size + params_offset, JIT_SP, regno);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    /* Argument registers are allocated from the pool of unused registers */
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *call;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    call = jit_callr(r0);
+    call->v.w = _jitc->function->call.argi;
+    call->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_calli(i0);
+    node->v.w = _jitc->function->call.argi;
+    node->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_c, r0);
+    jit_extr_c(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_uc, r0);
+    jit_extr_uc(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_s, r0);
+    jit_extr_s(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_us, r0);
+    jit_extr_us(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+    jit_extr_i(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_ui, r0);
+    jit_extr_ui(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_l, r0);
+    jit_movr(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_l, r0);
+    jit_movr_f(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_d, r0);
+    jit_movr_d(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_int32_t                 value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_int32_t      patch_offset;
+       jit_word_t       prolog_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    /* If did resize the code buffer, these were not reset */
+    _jitc->ioff = 0;
+    jit_regset_set_ui(&_jitc->regs, 0);
+    _jitc->pred = 0;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.patch_offset = 0;
+
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    undo.prolog_offset = 0;
+    for (node = _jitc->head; node; node = node->next)
+       if (node->code != jit_code_label &&
+           node->code != jit_code_note &&
+           node->code != jit_code_name)
+           break;
+    if (node && (node->code != jit_code_prolog ||
+                !(_jitc->functions.ptr + node->w.w)->assume_frame)) {
+       /* code may start with a jump so add an initial function descriptor */
+       word = _jit->pc.w + 16;
+       il(word);               /* addr */
+       il(0);                  /* gp */
+    }
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_rrf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               assert(node->flag & jit_flag_data);                     \
+               name##i##type(rn(node->u.w), rn(node->v.w),             \
+                             (jit_float##size##_t *)node->w.n->u.w);   \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w, rn(node->v.w),             \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w, rn(node->v.w),     \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+       value = jit_classify(node->code);
+#if GET_JIT_SIZE
+       sync();
+#endif
+#if DEVEL_DISASSEMBLER
+       /* FIXME DEVEL_DISASSEMBLER should become DISASSEMBLER,
+        * but a "real" DEVEL_DISASSEMBLER should be required
+        * to turn the below "#if 0" into "#if 1" */
+#  if 0                /* Since disassembly outputs 3 instructions at a time,
+                * make it "#if 1" for more clear debug output. */
+       sync();
+#  endif
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               /* nothing done */
+               break;
+           case jit_code_note:         case jit_code_name:
+               sync();
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               sync();
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rr(neg,);
+               case_rr(com,);
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), node->v.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+               case_rr(hton, _ul);
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+               case_rr(ext, _i);
+               case_rr(ext, _ui);
+               case_rr(trunc, _f_i);
+               case_rr(trunc, _d_i);
+               case_rr(trunc, _f_l);
+               case_rr(trunc, _d_l);
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+               case_rr(ld, _ui);
+               case_rw(ld, _ui);
+               case_rr(ld, _l);
+               case_rw(ld, _l);
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+               case_rrr(ldx, _ui);
+               case_rrw(ldx, _ui);
+               case_rrr(ldx, _l);
+               case_rrw(ldx, _l);
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+               case_rr(st, _l);
+               case_wr(st, _l);
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+               case_rrr(stx, _l);
+               case_wrr(stx, _l);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_rrr(add, _f);
+               case_rrf(add, _f, 32);
+               case_rrr(sub, _f);
+               case_rrf(sub, _f, 32);
+               case_rrf(rsb, _f, 32);
+               case_rrr(mul, _f);
+               case_rrf(mul, _f, 32);
+               case_rrr(div, _f);
+               case_rrf(div, _f, 32);
+               case_rr(ext, _f);
+               case_rr(abs, _f);
+               case_rr(neg, _f);
+               case_rr(sqrt, _f);
+               case_rr(ld, _f);
+               case_rw(ld, _f);
+               case_rrr(ldx, _f);
+               case_rrw(ldx, _f);
+               case_rr(st, _f);
+               case_wr(st, _f);
+               case_rrr(stx, _f);
+               case_wrr(stx, _f);
+               case_rr(mov, _f);
+           case jit_code_movi_f:
+               assert(node->flag & jit_flag_data);
+               movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _d_f);
+               case_rrr(lt, _f);
+               case_rrf(lt, _f, 32);
+               case_rrr(le, _f);
+               case_rrf(le, _f, 32);
+               case_rrr(eq, _f);
+               case_rrf(eq, _f, 32);
+               case_rrr(ge, _f);
+               case_rrf(ge, _f, 32);
+               case_rrr(gt, _f);
+               case_rrf(gt, _f, 32);
+               case_rrr(ne, _f);
+               case_rrf(ne, _f, 32);
+               case_rrr(unlt, _f);
+               case_rrf(unlt, _f, 32);
+               case_rrr(unle, _f);
+               case_rrf(unle, _f, 32);
+               case_rrr(uneq, _f);
+               case_rrf(uneq, _f, 32);
+               case_rrr(unge, _f);
+               case_rrf(unge, _f, 32);
+               case_rrr(ungt, _f);
+               case_rrf(ungt, _f, 32);
+               case_rrr(ltgt, _f);
+               case_rrf(ltgt, _f, 32);
+               case_rrr(ord, _f);
+               case_rrf(ord, _f, 32);
+               case_rrr(unord, _f);
+               case_rrf(unord, _f, 32);
+               case_brr(blt, _f);
+               case_brf(blt, _f, 32);
+               case_brr(ble, _f);
+               case_brf(ble, _f, 32);
+               case_brr(beq, _f);
+               case_brf(beq, _f, 32);
+               case_brr(bge, _f);
+               case_brf(bge, _f, 32);
+               case_brr(bgt, _f);
+               case_brf(bgt, _f, 32);
+               case_brr(bne, _f);
+               case_brf(bne, _f, 32);
+               case_brr(bunlt, _f);
+               case_brf(bunlt, _f, 32);
+               case_brr(bunle, _f);
+               case_brf(bunle, _f, 32);
+               case_brr(buneq, _f);
+               case_brf(buneq, _f, 32);
+               case_brr(bunge, _f);
+               case_brf(bunge, _f, 32);
+               case_brr(bungt, _f);
+               case_brf(bungt, _f, 32);
+               case_brr(bltgt, _f);
+               case_brf(bltgt, _f, 32);
+               case_brr(bord, _f);
+               case_brf(bord, _f, 32);
+               case_brr(bunord, _f);
+               case_brf(bunord, _f, 32);
+               case_rrr(add, _d);
+               case_rrf(add, _d, 64);
+               case_rrr(sub, _d);
+               case_rrf(sub, _d, 64);
+               case_rrf(rsb, _d, 64);
+               case_rrr(mul, _d);
+               case_rrf(mul, _d, 64);
+               case_rrr(div, _d);
+               case_rrf(div, _d, 64);
+               case_rr(ext, _d);
+               case_rr(abs, _d);
+               case_rr(neg, _d);
+               case_rr(sqrt, _d);
+               case_rr(ld, _d);
+               case_rw(ld, _d);
+               case_rrr(ldx, _d);
+               case_rrw(ldx, _d);
+               case_rr(st, _d);
+               case_wr(st, _d);
+               case_rrr(stx, _d);
+               case_wrr(stx, _d);
+               case_rr(mov, _d);
+           case jit_code_movi_d:
+               assert(node->flag & jit_flag_data);
+               movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _f_d);
+               case_rrr(lt, _d);
+               case_rrf(lt, _d, 64);
+               case_rrr(le, _d);
+               case_rrf(le, _d, 64);
+               case_rrr(eq, _d);
+               case_rrf(eq, _d, 64);
+               case_rrr(ge, _d);
+               case_rrf(ge, _d, 64);
+               case_rrr(gt, _d);
+               case_rrf(gt, _d, 64);
+               case_rrr(ne, _d);
+               case_rrf(ne, _d, 64);
+               case_rrr(unlt, _d);
+               case_rrf(unlt, _d, 64);
+               case_rrr(unle, _d);
+               case_rrf(unle, _d, 64);
+               case_rrr(uneq, _d);
+               case_rrf(uneq, _d, 64);
+               case_rrr(unge, _d);
+               case_rrf(unge, _d, 64);
+               case_rrr(ungt, _d);
+               case_rrf(ungt, _d, 64);
+               case_rrr(ltgt, _d);
+               case_rrf(ltgt, _d, 64);
+               case_rrr(ord, _d);
+               case_rrf(ord, _d, 64);
+               case_rrr(unord, _d);
+               case_rrf(unord, _d, 64);
+               case_brr(blt, _d);
+               case_brf(blt, _d, 64);
+               case_brr(ble, _d);
+               case_brf(ble, _d, 64);
+               case_brr(beq, _d);
+               case_brf(beq, _d, 64);
+               case_brr(bge, _d);
+               case_brf(bge, _d, 64);
+               case_brr(bgt, _d);
+               case_brf(bgt, _d, 64);
+               case_brr(bne, _d);
+               case_brf(bne, _d, 64);
+               case_brr(bunlt, _d);
+               case_brf(bunlt, _d, 64);
+               case_brr(bunle, _d);
+               case_brf(bunle, _d, 64);
+               case_brr(buneq, _d);
+               case_brf(buneq, _d, 64);
+               case_brr(bunge, _d);
+               case_brf(bunge, _d, 64);
+               case_brr(bungt, _d);
+               case_brf(bungt, _d, 64);
+               case_brr(bltgt, _d);
+               case_brf(bltgt, _d, 64);
+               case_brr(bord, _d);
+               case_brf(bord, _d, 64);
+               case_brr(bunord, _d);
+               case_brf(bunord, _d, 64);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   if (_jit->pc.uc == _jit->code.ptr + 16)
+                       _jitc->jump = 1;
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   word = calli_p(temp->u.w);
+                   if (!(temp->flag & jit_flag_patch))
+                       patch(word, node);
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               jit_regset_set_ui(&_jitc->regs, 0);
+               _jitc->pred = 0;
+               sync();
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+               undo.prolog_offset = _jitc->prolog.offset;
+           restart_function:
+               _jitc->again = 0;
+               if (_jitc->jump && !_jitc->function->assume_frame) {
+                   /* remember prolog to hide offset adjustment for a jump
+                    * to the start of a function, what is expected to be
+                    * a common practice as first jit instruction */
+                   if (_jitc->prolog.offset >= _jitc->prolog.length) {
+                       _jitc->prolog.length += 16;
+                       jit_realloc((jit_pointer_t *)&_jitc->prolog.ptr,
+                                   (_jitc->prolog.length - 16) *
+                                   sizeof(jit_word_t),
+                                   _jitc->prolog.length * sizeof(jit_word_t));
+                   }
+                   _jitc->prolog.ptr[_jitc->prolog.offset++] = _jit->pc.w;
+                   /* function descriptor */
+                   word = _jit->pc.w + 16;
+                   il(word);                   /* addr */
+                   il(0);                      /* gp */
+               }
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+                   _jitc->prolog.offset = undo.prolog_offset;
+                   _jitc->ioff = 0;
+                   jit_regset_set_ui(&_jitc->regs, 0);
+                   _jitc->pred = 0;
+                   goto restart_function;
+               }
+               /* remember label is defined */
+               sync();
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               jit_regset_set_ui(&_jitc->regs, 0);
+               _jitc->pred = 0;
+               _jitc->function = NULL;
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:
+           case jit_code_arg:                  case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:             case jit_code_getarg_ui:
+           case jit_code_getarg_l:
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+           case jit_code_retval_ui:            case jit_code_retval_l:
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           case jit_code_movr_w_f:
+               movr_w_f(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movr_f_w:
+               movr_f_w(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movr_w_d:
+               movr_w_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movr_d_w:
+               movr_d_w(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movi_f_w:
+               movi_f_w(rn(node->u.w), node->v.n->u.p);
+               break;
+           case jit_code_movi_d_w:
+               movi_d_w(rn(node->u.w), node->v.n->u.p);
+               break;
+           default:
+               abort();
+       }
+       if (jit_carry != _NOREG) {
+           switch (node->code) {
+               case jit_code_note:
+               case jit_code_addcr:            case jit_code_addci:
+               case jit_code_addxr:            case jit_code_addxi:
+               case jit_code_subcr:            case jit_code_subci:
+               case jit_code_subxr:            case jit_code_subxi:
+                   break;
+               default:
+                   jit_unget_reg(jit_carry);
+                   jit_carry = _NOREG;
+                   break;
+           }
+       }
+#if GET_JIT_SIZE
+       sync();
+#endif
+       jit_regarg_clr(node, value);
+       if (jit_regset_cmp_ui(&_jitc->regarg, 0) != 0) {
+           assert(jit_regset_scan1(&_jitc->regarg, 0) == jit_carry);
+           assert(jit_regset_scan1(&_jitc->regarg, jit_carry + 1) == ULONG_MAX);
+       }
+       assert(_jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+    }
+    sync();
+#undef case_brf
+#undef case_brw
+#undef case_brr
+#undef case_wrr
+#undef case_rrrw
+#undef case_rrf
+#undef case_rrw
+#undef case_rrrr
+#undef case_rrr
+#undef case_wr
+#undef case_rw
+#undef case_rr
+
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(node->code, _jitc->patches.ptr[offset].inst, word);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_ia64-cpu.c"
+#  include "jit_ia64-fpu.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+#if defined(__GNUC__)
+    jit_word_t         f, t, s;
+
+    s = sysconf(_SC_PAGE_SIZE);
+    f = (jit_word_t)fptr & -s;
+    t = (((jit_word_t)tptr) + s - 1) & -s;
+#  if 0
+    __clear_cache((void *)f, (void *)t);
+#  else
+    /* __clear_cache is a noop in (old?) gcc, but cache flush is
+     * required on a multi processor Linux system. */
+    for (s = f; s < t; s += 32)
+       asm volatile("fc %0" :: "r"(s) : "memory");
+#  endif
+#endif
+}
+
+/* Use r2 that is reserved to not require a jit_get_reg call, also note
+ * that addil needs a register that first in 2 bits, so, if using a
+ * register other than r2 must be less than r8 (or check for a smaller
+ * immediate, i.e. i0 >= -8192 && i0 <= 8191) */
+void
+_emit_ldxi(jit_state_t *_jit, jit_gpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    assert(i0 >= -2097152 && i0 < 2097151);
+    addi(GR_2, rn(r1), i0);
+    ldr(rn(r0), GR_2);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_gpr_t r1)
+{
+    assert(i0 >= -2097152 && i0 < 2097151);
+    addi(GR_2, rn(r0), i0);
+    str(GR_2, rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_fpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    assert(i0 >= -2097152 && i0 < 2097151);
+    addi(GR_2, rn(r1), i0);
+    ldr_d(rn(r0), GR_2);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_fpr_t r1)
+{
+    assert(i0 >= -2097152 && i0 < 2097151);
+    addi(GR_2, rn(r0), i0);
+    str_d(GR_2, rn(r1));
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+    assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_memory.c b/deps/lightning/lib/jit_memory.c
new file mode 100644 (file)
index 0000000..33b1c35
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+#ifdef _WIN32
+#  include <mman.h>
+#else
+#  include <sys/mman.h>
+#endif
+
+/*
+ * Prototypes
+ */
+static void *jit_default_alloc_func(size_t);
+static void *jit_default_realloc_func(void*, size_t);
+static void jit_default_free_func(void *);
+
+/*
+ * Initialization
+ */
+static jit_alloc_func_ptr jit_alloc_ptr = jit_default_alloc_func;
+static jit_realloc_func_ptr jit_realloc_ptr = jit_default_realloc_func;
+static jit_free_func_ptr jit_free_ptr = jit_default_free_func;
+
+/*
+ * Implementation
+ */
+jit_pointer_t
+jit_memcpy(jit_pointer_t dst, const void * src, jit_word_t size)
+{
+    if (size)
+       return (memcpy(dst, src, size));
+    return (dst);
+}
+
+jit_pointer_t
+jit_memmove(jit_pointer_t dst, const void *src , jit_word_t size)
+{
+    if (size)
+       return (memmove(dst, src, size));
+    return (dst);
+}
+
+void
+jit_set_memory_functions(jit_alloc_func_ptr alloc_ptr,
+                        jit_realloc_func_ptr realloc_ptr,
+                        jit_free_func_ptr free_ptr)
+{
+    if (alloc_ptr == NULL)
+       alloc_ptr = jit_default_alloc_func;
+    if (realloc_ptr == NULL)
+       realloc_ptr = jit_default_realloc_func;
+    if (free_ptr == NULL)
+       free_ptr = jit_default_free_func;
+    jit_alloc_ptr = alloc_ptr;
+    jit_realloc_ptr = realloc_ptr;
+    jit_free_ptr = free_ptr;
+}
+
+void
+jit_get_memory_functions(jit_alloc_func_ptr *alloc_ptr,
+                        jit_realloc_func_ptr *realloc_ptr,
+                        jit_free_func_ptr *free_ptr)
+{
+    *alloc_ptr = jit_alloc_ptr;
+    *realloc_ptr = jit_realloc_ptr;
+    *free_ptr = jit_free_ptr;
+}
+
+void
+jit_alloc(jit_pointer_t *ptr, jit_word_t size)
+{
+    *ptr = (*jit_alloc_ptr)(size);
+    memset(*ptr, 0, size);
+}
+
+void
+jit_realloc(jit_pointer_t *ptr, jit_word_t old_size, jit_word_t new_size)
+{
+    *ptr = (*jit_realloc_ptr)(*ptr, new_size);
+    if (old_size < new_size)
+       memset((jit_int8_t*)*ptr + old_size, 0, new_size - old_size);
+}
+
+void
+jit_free(jit_pointer_t *ptr)
+{
+    if (*ptr) {
+       (*jit_free_ptr)(*ptr);
+       *ptr = NULL;
+    }
+}
+
+static void *
+jit_default_alloc_func(size_t size)
+{
+    return (malloc(size));
+}
+
+static void *
+jit_default_realloc_func(void *ptr, size_t size)
+{
+    return (realloc(ptr, size));
+}
+
+static void
+jit_default_free_func(void *ptr)
+{
+    free(ptr);
+}
diff --git a/deps/lightning/lib/jit_mips-cpu.c b/deps/lightning/lib/jit_mips-cpu.c
new file mode 100644 (file)
index 0000000..8fb7fa1
--- /dev/null
@@ -0,0 +1,3157 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+typedef union {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    struct {   jit_uint32_t _:26;      jit_uint32_t b :  6; } hc;
+    struct {   jit_uint32_t _:21;      jit_uint32_t b :  5; } rs;
+    struct {   jit_uint32_t _:21;      jit_uint32_t b :  5; } fm;
+    struct {   jit_uint32_t _:16;      jit_uint32_t b :  5; } rt;
+    struct {   jit_uint32_t _:16;      jit_uint32_t b :  5; } ft;
+    struct {   jit_uint32_t _:11;      jit_uint32_t b :  5; } rd;
+    struct {   jit_uint32_t _:11;      jit_uint32_t b :  5; } fs;
+    struct {   jit_uint32_t _: 6;      jit_uint32_t b :  5; } ic;
+    struct {   jit_uint32_t _: 6;      jit_uint32_t b :  5; } fd;
+    struct {   jit_uint32_t _: 6;      jit_uint32_t b : 10; } tr;
+    struct {   jit_uint32_t _: 6;      jit_uint32_t b : 20; } br;
+    struct {                           jit_uint32_t b :  6; } tc;
+    struct {                           jit_uint32_t b : 11; } cc;
+    struct {                           jit_uint32_t b : 16; } is;
+    struct {                           jit_uint32_t b : 26; } ii;
+#else
+    struct {                           jit_uint32_t b :  6; } hc;
+    struct {   jit_uint32_t _: 6;      jit_uint32_t b :  5; } rs;
+    struct {   jit_uint32_t _: 6;      jit_uint32_t b :  5; } fm;
+    struct {   jit_uint32_t _:11;      jit_uint32_t b :  5; } rt;
+    struct {   jit_uint32_t _:11;      jit_uint32_t b :  5; } ft;
+    struct {   jit_uint32_t _:16;      jit_uint32_t b :  5; } rd;
+    struct {   jit_uint32_t _:16;      jit_uint32_t b :  5; } fs;
+    struct {   jit_uint32_t _:21;      jit_uint32_t b :  5; } ic;
+    struct {   jit_uint32_t _:21;      jit_uint32_t b :  5; } fd;
+    struct {   jit_uint32_t _:21;      jit_uint32_t b : 10; } tr;
+    struct {   jit_uint32_t _:21;      jit_uint32_t b : 20; } br;
+    struct {   jit_uint32_t _:26;      jit_uint32_t b :  6; } tc;
+    struct {   jit_uint32_t _:21;      jit_uint32_t b : 11; } cc;
+    struct {   jit_uint32_t _:16;      jit_uint32_t b : 16; } is;
+    struct {   jit_uint32_t _: 6;      jit_uint32_t b : 26; } ii;
+#endif
+    int                                        op;
+} jit_instr_t;
+/* FIXME */
+#  define jit_mips2_p()                        0
+#  define _ZERO_REGNO                  0
+#  define _T0_REGNO                    0x08
+#  define _T1_REGNO                    0x09
+#  define _T2_REGNO                    0x0a
+#  define _T3_REGNO                    0x0b
+#  define _T4_REGNO                    0x0c
+#  define _T5_REGNO                    0x0d
+#  define _T6_REGNO                    0x0e
+#  define _T7_REGNO                    0x0f
+#  define _S0_REGNO                    0x10
+#  define _S1_REGNO                    0x11
+#  define _S2_REGNO                    0x12
+#  define _S3_REGNO                    0x13
+#  define _S4_REGNO                    0x14
+#  define _S5_REGNO                    0x15
+#  define _S6_REGNO                    0x16
+#  define _S7_REGNO                    0x17
+#  define _T8_REGNO                    0x18
+#  define _T9_REGNO                    0x19
+#  define _SP_REGNO                    0x1d
+#  define _BP_REGNO                    0x1e
+#  define _RA_REGNO                    0x1f
+#  define _F16_REGNO                   16
+#  define _F18_REGNO                   18
+#  define _F20_REGNO                   20
+#  define _F22_REGNO                   22
+#  define _F24_REGNO                   24
+#  define _F26_REGNO                   26
+#  define _F28_REGNO                   28
+#  define _F30_REGNO                   30
+#  if __WORDSIZE == 32
+#    if NEW_ABI
+#      define stack_framesize          144
+#    else
+#      define stack_framesize          112
+#    endif
+#    define ldr(u,v)                   ldr_i(u,v)
+#    define ldi(u,v)                   ldi_i(u,v)
+#    define ldxi(u,v,w)                        ldxi_i(u,v,w)
+#    define sti(u,v)                   sti_i(u,v)
+#    define stxi(u,v,w)                        stxi_i(u,v,w)
+#  else
+#    define stack_framesize            144
+#    define ldr(u,v)                   ldr_l(u,v)
+#    define ldi(u,v)                   ldi_l(u,v)
+#    define ldxi(u,v,w)                        ldxi_l(u,v,w)
+#    define sti(u,v)                   sti_l(u,v)
+#    define stxi(u,v,w)                        stxi_l(u,v,w)
+#  endif
+#  define can_sign_extend_short_p(im)  ((im) >= -32678 && (im) <= 32767)
+#  define can_zero_extend_short_p(im)  ((im) >= 0 && (im) <= 65535)
+#  if __WORDSIZE == 32
+#    define can_sign_extend_int_p(im)  1
+#    define can_zero_extend_int_p(im)  1
+#  else
+#    define can_sign_extend_int_p(im)                                  \
+       (((im) >= 0 && (im) <=  0x7fffffffL) ||                         \
+        ((im) <  0 && (im) >= -0x80000000L))
+#    define can_zero_extend_int_p(im)  ((im) >= 0 && (im) <= 0xffffffff)
+#  endif
+#  define MIPS_SPECIAL                 0x00
+#  define MIPS_REGIMM                  0x01
+#  define MIPS_J                       0x02
+#  define MIPS_SRL                     0x02
+#  define MIPS_JAL                     0x03
+#  define MIPS_SRA                     0x03
+#  define MIPS_BEQ                     0x04
+#  define MIPS_BNE                     0x05
+#  define MIPS_BLEZ                    0x06
+#  define MIPS_BGTZ                    0x07
+#  define MIPS_ADDI                    0x08
+#  define MIPS_ADDIU                   0x09
+#  define MIPS_SLTI                    0x0a
+#  define MIPS_SLTIU                   0x0b
+#  define MIPS_ANDI                    0x0c
+#  define MIPS_ORI                     0x0d
+#  define MIPS_XORI                    0x0e
+#  define MIPS_LUI                     0x0f
+#  define MIPS_COP0                    0x10
+#  define MIPS_COP1                    0x11
+#  define MIPS_COP2                    0x12
+#  define MIPS_COP1X                   0x13
+#  define MIPS_BEQL                    0x14
+#  define MIPS_BNEL                    0x15
+#  define MIPS_BLEZL                   0x16
+#  define MIPS_BGTZL                   0x17
+#  define MIPS_DADDI                   0x18
+#  define MIPS_DADDIU                  0x19
+#  define MIPS_LDL                     0x1a
+#  define MIPS_LDR                     0x1b
+#  define MIPS_SPECIAL2                        0x1c
+#  define MIPS_JALX                    0x1d
+#  define MIPS_SPECIAL3                        0x1f
+#  define MIPS_LB                      0x20
+#  define MIPS_LH                      0x21
+#  define MIPS_LWL                     0x22
+#  define MIPS_LW                      0x23
+#  define MIPS_LBU                     0x24
+#  define MIPS_LHU                     0x25
+#  define MIPS_LWR                     0x26
+#  define MIPS_LWU                     0x27
+#  define MIPS_SB                      0x28
+#  define MIPS_SH                      0x29
+#  define MIPS_SWL                     0x2a
+#  define MIPS_SW                      0x2b
+#  define MIPS_SWR                     0x2e
+#  define MIPS_CACHE                   0x2f
+#  define MIPS_LL                      0x30
+#  define MIPS_LWC1                    0x31
+#  define MIPS_LWC2                    0x32
+#  define MIPS_PREF                    0x33
+#  define MIPS_LLD                     0x34
+#  define MIPS_LDC1                    0x35
+#  define MIPS_LDC2                    0x36
+#  define MIPS_LD                      0x37
+#  define MIPS_SC                      0x38
+#  define MIPS_SCD                     0x3c
+#  define MIPS_SDC1                    0x3d
+#  define MIPS_SDC2                    0x3e
+#  define MIPS_SWC1                    0x39
+#  define MIPS_SWC2                    0x3a
+#  define MIPS_SD                      0x3f
+#  define MIPS_MF                      0x00
+#  define MIPS_DMF                     0x01
+#  define MIPS_CF                      0x02
+#  define MIPS_MFH                     0x03
+#  define MIPS_MT                      0x04
+#  define MIPS_DMT                     0x05
+#  define MIPS_CT                      0x06
+#  define MIPS_MTH                     0x07
+#  define MIPS_BC                      0x08
+#  define MIPS_WRPGPR                  0x0e
+#  define MIPS_BGZAL                   0x11
+#  define MIPS_MFMC0                   0x11
+#  define MIPS_BCF                     0x00
+#  define MIPS_BLTZ                    0x00
+#  define MIPS_BCT                     0x01
+#  define MIPS_BGEZ                    0x01
+#  define MIPS_BCFL                    0x02
+#  define MIPS_BLTZL                   0x02
+#  define MIPS_BCTL                    0x03
+#  define MIPS_BGEZL                   0x03
+#  define MIPS_TGEI                    0x08
+#  define MIPS_TGEIU                   0x09
+#  define MIPS_TLTI                    0x0a
+#  define MIPS_TLTIU                   0x0b
+#  define MIPS_TEQI                    0x0c
+#  define MIPS_TNEI                    0x0e
+#  define MIPS_BLTZAL                  0x10
+#  define MIPS_BGEZAL                  0x11
+#  define MIPS_BLTZALL                 0x12
+#  define MIPS_BGEZALL                 0x13
+#  define MIPS_SYNCI                   0x1f
+#  define MIPS_WSBH                    0x02
+#  define MIPS_DBSH                    0x02
+#  define MIPS_DSHD                    0x05
+#  define MIPS_SEB                     0x10
+#  define MIPS_SEH                     0x18
+#  define MIPS_MADD                    0x00
+#  define MIPS_SLL                     0x00
+#  define MIPS_EXT                     0x00
+#  define MIPS_DEXTM                   0x01
+#  define MIPS_MADDU                   0x01
+#  define MIPS_MOVFT                   0x01
+#  define MIPS_TLBR                    0x01
+#  define MIPS_MUL                     0x02
+#  define MIPS_DEXTU                   0x02
+#  define MIPS_TLBWI                   0x02
+#  define MIPS_DEXT                    0x03
+#  define MIPS_SLLV                    0x04
+#  define MIPS_INS                     0x04
+#  define MIPS_MSUB                    0x04
+#  define MIPS_DINSM                   0x05
+#  define MIPS_MSUBU                   0x05
+#  define MIPS_SRLV                    0x06
+#  define MIPS_DINSU                   0x06
+#  define MIPS_TLBWR                   0x06
+#  define MIPS_SRAV                    0x07
+#  define MIPS_DINS                    0x07
+#  define MIPS_JR                      0x08
+#  define MIPS_TLBP                    0x08
+#  define MIPS_JALR                    0x09
+#  define MIPS_MOVZ                    0x0a
+#  define MIPS_MOVN                    0x0b
+#  define MIPS_SYSCALL                 0x0c
+#  define MIPS_BREAK                   0x0d
+#  define MIPS_PREFX                   0x0f
+#  define MIPS_SYNC                    0x0f
+#  define MIPS_MFHI                    0x10
+#  define MIPS_MTHI                    0x11
+#  define MIPS_MFLO                    0x12
+#  define MIPS_MTLO                    0x13
+#  define MIPS_DSLLV                   0x14
+#  define MIPS_DSRLV                   0x16
+#  define MIPS_DSRAV                   0x17
+#  define MIPS_MULT                    0x18
+#  define MIPS_ERET                    0x18
+#  define MIPS_MULTU                   0x19
+#  define MIPS_DIV                     0x1a
+#  define MIPS_DIVU                    0x1b
+#  define MIPS_DMULT                   0x1c
+#  define MIPS_DMULTU                  0x1d
+#  define MIPS_DDIV                    0x1e
+#  define MIPS_DDIVU                   0x1f
+#  define MIPS_DERET                   0x1f
+#  define MIPS_ADD                     0x20
+#  define MIPS_CLZ                     0x20
+#  define MIPS_BSHFL                   0x20
+#  define MIPS_ADDU                    0x21
+#  define MIPS_CLO                     0x21
+#  define MIPS_SUB                     0x22
+#  define MIPS_SUBU                    0x23
+#  define MIPS_AND                     0x24
+#  define MIPS_DCLZ                    0x24
+#  define MIPS_DBSHFL                  0x24
+#  define MIPS_OR                      0x25
+#  define MIPS_DCLO                    0x25
+#  define MIPS_XOR                     0x26
+#  define MIPS_NOR                     0x27
+#  define MIPS_SLT                     0x2a
+#  define MIPS_SLTU                    0x2b
+#  define MIPS_DADD                    0x2c
+#  define MIPS_DADDU                   0x2d
+#  define MIPS_DSUB                    0x2e
+#  define MIPS_DSUBU                   0x2f
+#  define MIPS_TGE                     0x30
+#  define MIPS_TGEU                    0x31
+#  define MIPS_TLT                     0x32
+#  define MIPS_TLTU                    0x33
+#  define MIPS_TEQ                     0x34
+#  define MIPS_TNE                     0x36
+#  define MIPS_DSLL                    0x38
+#  define MIPS_DSRL                    0x3a
+#  define MIPS_DSRA                    0x3b
+#  define MIPS_DSLL32                  0x3c
+#  define MIPS_DSRL32                  0x3e
+#  define MIPS_DSRA32                  0x3f
+#  define MIPS_SDBPP                   0x3f
+#  define ii(i)                                *_jit->pc.ui++ = i
+static void
+_hrrrit(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+       jit_int32_t,jit_int32_t);
+#  define hrrrit(hc,rs,rt,rd,im,tc)    _hrrrit(_jit,hc,rs,rt,rd,im,tc)
+#  define hrrr_t(hc,rs,rt,rd,tc)       hrrrit(hc,rs,rt,rd,0,tc)
+#  define rrr_t(rs,rt,rd,tc)           hrrr_t(0,rs,rt,rd,tc)
+#  define hrri(hc,rs,rt,im)            _hrri(_jit,hc,rs,rt,im)
+static void _hrri(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define hi(hc,im)                    _hi(_jit,hc,im)
+static void _hi(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define NOP(i0)                      ii(0)
+#  define nop(i0)                      _nop(_jit,i0)
+static void _nop(jit_state_t*,jit_int32_t);
+#  define h_ri(hc,rt,im)               _hrri(_jit,hc,0,rt,im)
+#  define rrit(rt,rd,im,tc)            _hrrrit(_jit,0,0,rt,rd,im,tc)
+#  define LUI(rt,im)                   h_ri(MIPS_LUI,rt,im)
+#  define ADDU(rd,rs,rt)               rrr_t(rs,rt,rd,MIPS_ADDU)
+#  define DADDU(rd,rs,rt)              rrr_t(rs,rt,rd,MIPS_DADDU)
+#  define ADDIU(rt,rs,im)              hrri(MIPS_ADDIU,rs,rt,im)
+#  define DADDIU(rt,rs,im)             hrri(MIPS_DADDIU,rs,rt,im)
+#  define SUBU(rd,rs,rt)               rrr_t(rs,rt,rd,MIPS_SUBU)
+#  define DSUBU(rd,rs,rt)              rrr_t(rs,rt,rd,MIPS_DSUBU)
+#  define MULT(rs,rt)                  rrr_t(rs,rt,_ZERO_REGNO,MIPS_MULT)
+#  define MULTU(rs,rt)                 rrr_t(rs,rt,_ZERO_REGNO,MIPS_MULTU)
+#  define DMULT(rs,rt)                 rrr_t(rs,rt,_ZERO_REGNO,MIPS_DMULT)
+#  define DMULTU(rs,rt)                        rrr_t(rs,rt,_ZERO_REGNO,MIPS_DMULTU)
+#  define DIV(rs,rt)                   rrr_t(rs,rt,_ZERO_REGNO,MIPS_DIV)
+#  define DIVU(rs,rt)                  rrr_t(rs,rt,_ZERO_REGNO,MIPS_DIVU)
+#  define DDIV(rs,rt)                  rrr_t(rs,rt,_ZERO_REGNO,MIPS_DDIV)
+#  define DDIVU(rs,rt)                 rrr_t(rs,rt,_ZERO_REGNO,MIPS_DDIVU)
+#  define SLLV(rd,rt,rs)               rrr_t(rs,rt,rd,MIPS_SLLV)
+#  define SLL(rd,rt,sa)                        rrit(rt,rd,sa,MIPS_SLL)
+#  define DSLLV(rd,rt,rs)              rrr_t(rs,rt,rd,MIPS_DSLLV)
+#  define DSLL(rd,rt,sa)               rrit(rt,rd,sa,MIPS_DSLL)
+#  define DSLL32(rd,rt,sa)             rrit(rt,rd,sa,MIPS_DSLL32)
+#  define SRAV(rd,rt,rs)               rrr_t(rs,rt,rd,MIPS_SRAV)
+#  define SRA(rd,rt,sa)                        rrit(rt,rd,sa,MIPS_SRA)
+#  define SRLV(rd,rt,rs)               rrr_t(rs,rt,rd,MIPS_SRLV)
+#  define SRL(rd,rt,sa)                        rrit(rt,rd,sa,MIPS_SRL)
+#  define DSRAV(rd,rt,rs)              rrr_t(rs,rt,rd,MIPS_DSRAV)
+#  define DSRA(rd,rt,sa)               rrit(rt,rd,sa,MIPS_DSRA)
+#  define DSRA32(rd,rt,sa)             rrit(rt,rd,sa,MIPS_DSRA32)
+#  define DSRLV(rd,rt,rs)              rrr_t(rs,rt,rd,MIPS_DSRLV)
+#  define DSRL(rd,rt,sa)               rrit(rt,rd,sa,MIPS_DSRL)
+#  define DSRL32(rd,rt,sa)             rrit(rt,rd,sa,MIPS_DSRL32)
+#  define INS(rt,rs,pos,size)          hrrrit(MIPS_SPECIAL3,rs,rt,pos,pos+size-1,MIPS_INS)
+#  define DINS(rt,rs,pos,size)         hrrrit(MIPS_SPECIAL3,rs,rt,pos,pos+size-1,MIPS_DINS)
+#  define ROTR(rd,rt,sa)               hrrrit(MIPS_SPECIAL,1,rt,rd,sa,MIPS_SRL)
+#  define DROTR(rd,rt,sa)              hrrrit(MIPS_SPECIAL,1,rt,rd,sa,MIPS_DSRL)
+#  define MFHI(rd)                     rrr_t(_ZERO_REGNO,_ZERO_REGNO,rd,MIPS_MFHI)
+#  define MFLO(rd)                     rrr_t(_ZERO_REGNO,_ZERO_REGNO,rd,MIPS_MFLO)
+#  define MTHI(rs)                     rrr_t(rs,_ZERO_REGNO,_ZERO_REGNO,MIPS_MTHI)
+#  define MTLO(rs)                     rrr_t(rs,_ZERO_REGNO,_ZERO_REGNO,MIPS_MTLO)
+#  define AND(rd,rs,rt)                        rrr_t(rs,rt,rd,MIPS_AND)
+#  define ANDI(rt,rs,im)               hrri(MIPS_ANDI,rs,rt,im)
+#  define OR(rd,rs,rt)                 rrr_t(rs,rt,rd,MIPS_OR)
+#  define ORI(rt,rs,im)                        hrri(MIPS_ORI,rs,rt,im)
+#  define XOR(rd,rs,rt)                        rrr_t(rs,rt,rd,MIPS_XOR)
+#  define XORI(rt,rs,im)               hrri(MIPS_XORI,rs,rt,im)
+#  define LB(rt,of,rb)                 hrri(MIPS_LB,rb,rt,of)
+#  define LBU(rt,of,rb)                        hrri(MIPS_LBU,rb,rt,of)
+#  define LH(rt,of,rb)                 hrri(MIPS_LH,rb,rt,of)
+#  define LHU(rt,of,rb)                        hrri(MIPS_LHU,rb,rt,of)
+#  define LW(rt,of,rb)                 hrri(MIPS_LW,rb,rt,of)
+#  define LWU(rt,of,rb)                        hrri(MIPS_LWU,rb,rt,of)
+#  define LD(rt,of,rb)                 hrri(MIPS_LD,rb,rt,of)
+#  define SB(rt,of,rb)                 hrri(MIPS_SB,rb,rt,of)
+#  define SH(rt,of,rb)                 hrri(MIPS_SH,rb,rt,of)
+#  define SW(rt,of,rb)                 hrri(MIPS_SW,rb,rt,of)
+#  define SD(rt,of,rb)                 hrri(MIPS_SD,rb,rt,of)
+#  define WSBH(rd,rt)                  hrrrit(MIPS_SPECIAL3,0,rt,rd,MIPS_WSBH,MIPS_BSHFL)
+#  define SEB(rd,rt)                   hrrrit(MIPS_SPECIAL3,0,rt,rd,MIPS_SEB,MIPS_BSHFL)
+#  define SEH(rd,rt)                   hrrrit(MIPS_SPECIAL3,0,rt,rd,MIPS_SEH,MIPS_BSHFL)
+#  define SLT(rd,rs,rt)                        rrr_t(rs,rt,rd,MIPS_SLT)
+#  define SLTU(rd,rs,rt)               rrr_t(rs,rt,rd,MIPS_SLTU)
+#  define SLTI(rt,rs,im)               hrri(MIPS_SLTI,rs,rt,im)
+#  define SLTIU(rt,rs,im)              hrri(MIPS_SLTIU,rs,rt,im)
+#  define BLTZ(rs,im)                  hrri(MIPS_REGIMM,rs,MIPS_BLTZ,im)
+#  define BLEZ(rs,im)                  hrri(MIPS_BLEZ,rs,_ZERO_REGNO,im)
+#  define BEQ(rs,rt,im)                        hrri(MIPS_BEQ,rs,rt,im)
+#  define BGEZ(rs,im)                  hrri(MIPS_REGIMM,rs,MIPS_BGEZ,im)
+#  define BGTZ(rs,im)                  hrri(MIPS_BGTZ,rs,_ZERO_REGNO,im)
+#  define BNE(rs,rt,im)                        hrri(MIPS_BNE,rs,rt,im)
+#  define JALR(r0)                     hrrrit(MIPS_SPECIAL,r0,0,_RA_REGNO,0,MIPS_JALR)
+#  if 1 /* supports MIPS32 R6 */
+#   define JR(r0)                      hrrrit(MIPS_SPECIAL,r0,0,0,0,MIPS_JALR)
+#  else /* does not support MIPS32 R6 */
+#   define JR(r0)                      hrrrit(MIPS_SPECIAL,r0,0,0,0,MIPS_JR)
+#  endif
+#  define J(i0)                                hi(MIPS_J,i0)
+#  define MOVZ(rd,rs,rt)               hrrrit(0,rs,rt,rd,0,MIPS_MOVZ)
+#  define comr(r0,r1)                  xori(r0,r1,-1)
+#  define negr(r0,r1)                  subr(r0,_ZERO_REGNO,r1)
+#  if __WORDSIZE == 32
+#    define addr(rd,rs,rt)             ADDU(rd,rs,rt)
+#    define addiu(r0,r1,i0)            ADDIU(r0,r1,i0)
+#    define subr(rd,rs,rt)             SUBU(rd,rs,rt)
+#    define mult(rs,rt)                        MULT(rs,rt)
+#    define multu(rs,rt)               MULTU(rs,rt)
+#    define div(rs,rt)                 DIV(rs,rt)
+#    define divu(rs,rt)                        DIVU(rs,rt)
+#  else
+#    define addr(rd,rs,rt)             DADDU(rd,rs,rt)
+#    define addiu(r0,r1,i0)            DADDIU(r0,r1,i0)
+#    define subr(rd,rs,rt)             DSUBU(rd,rs,rt)
+#    define mult(rs,rt)                        DMULT(rs,rt)
+#    define multu(rs,rt)               DMULTU(rs,rt)
+#    define div(rs,rt)                 DDIV(rs,rt)
+#    define divu(rs,rt)                        DDIVU(rs,rt)
+#  endif
+#  define addi(r0,r1,i0)               _addi(_jit,r0,r1,i0)
+static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define addcr(r0,r1,r2)                        _addcr(_jit,r0,r1,r2)
+static void _addcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define addci(r0,r1,i0)                        _addci(_jit,r0,r1,i0)
+static void _addci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addxr(r0,r1,r2)              _addxr(_jit,r0,r1,r2)
+static void _addxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addxi(r0,r1,i0)              _addxi(_jit,r0,r1,i0)
+static void _addxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subi(r0,r1,i0)               _subi(_jit,r0,r1,i0)
+static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subcr(r0,r1,r2)              _subcr(_jit,r0,r1,r2)
+static void _subcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subci(r0,r1,i0)              _subci(_jit,r0,r1,i0)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subxr(r0,r1,r2)              _subxr(_jit,r0,r1,r2)
+static void _subxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subxi(r0,r1,i0)              _subxi(_jit,r0,r1,i0)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rsbi(r0, r1, i0)             _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define mulr(r0,r1,r2)               _mulr(_jit,r0,r1,r2)
+static void _mulr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define muli(r0,r1,i0)               _muli(_jit,r0,r1,i0)
+static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr(r0,r1,r2,r3)           iqmulr(r0,r1,r2,r3,1)
+#  define qmulr_u(r0,r1,r2,r3)         iqmulr(r0,r1,r2,r3,0)
+#  define iqmulr(r0,r1,r2,r3,cc)       _iqmulr(_jit,r0,r1,r2,r3,cc)
+static void _iqmulr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#  define qmuli(r0,r1,r2,i0)           iqmuli(r0,r1,r2,i0,1)
+#  define qmuli_u(r0,r1,r2,i0)         iqmuli(r0,r1,r2,i0,0)
+#  define iqmuli(r0,r1,r2,i0,cc)       _iqmuli(_jit,r0,r1,r2,i0,cc)
+static void _iqmuli(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#  define divr(r0,r1,r2)               _divr(_jit,r0,r1,r2)
+static void _divr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi(r0,r1,i0)               _divi(_jit,r0,r1,i0)
+static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define divr_u(r0,r1,r2)             _divr_u(_jit,r0,r1,r2)
+static void _divr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi_u(r0,r1,i0)             _divi_u(_jit,r0,r1,i0)
+static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qdivr(r0,r1,r2,r3)           iqdivr(r0,r1,r2,r3,1)
+#  define qdivr_u(r0,r1,r2,r3)         iqdivr(r0,r1,r2,r3,0)
+#  define iqdivr(r0,r1,r2,r3,cc)       _iqdivr(_jit,r0,r1,r2,r3,cc)
+static void _iqdivr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#  define qdivi(r0,r1,r2,i0)           iqdivi(r0,r1,r2,i0,1)
+#  define qdivi_u(r0,r1,r2,i0)         iqdivi(r0,r1,r2,i0,0)
+#  define iqdivi(r0,r1,r2,i0,cc)       _iqdivi(_jit,r0,r1,r2,i0,cc)
+static void _iqdivi(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#  define remr(r0,r1,r2)               _remr(_jit,r0,r1,r2)
+static void _remr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi(r0,r1,i0)               _remi(_jit,r0,r1,i0)
+static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define remr_u(r0,r1,r2)             _remr_u(_jit,r0,r1,r2)
+static void _remr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi_u(r0,r1,i0)             _remi_u(_jit,r0,r1,i0)
+static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define lshr(r0,r1,r2)             SLLV(r0,r1,r2)
+#    define lshi(r0,r1,i0)             SLL(r0,r1,i0)
+#    define rshr(r0,r1,r2)             SRAV(r0,r1,r2)
+#    define rshi(r0,r1,i0)             SRA(r0,r1,i0)
+#    define rshr_u(r0,r1,r2)           SRLV(r0,r1,r2)
+#    define rshi_u(r0,r1,i0)           SRL(r0,r1,i0)
+#  else
+#    define lshr(r0,r1,r2)             DSLLV(r0,r1,r2)
+#    define lshi(r0,r1,i0)             _lshi(_jit,r0,r1,i0)
+static void _lshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#    define rshr(r0,r1,r2)             DSRAV(r0,r1,r2)
+#    define rshi(r0,r1,i0)             _rshi(_jit,r0,r1,i0)
+static void _rshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#    define rshr_u(r0,r1,r2)           DSRLV(r0,r1,r2)
+#    define rshi_u(r0,r1,i0)           _rshi_u(_jit,r0,r1,i0)
+static void _rshi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  endif
+#  define andr(r0,r1,r2)               AND(r0,r1,r2)
+#  define andi(r0,r1,i0)               _andi(_jit,r0,r1,i0)
+static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define orr(r0,r1,r2)                        OR(r0,r1,r2)
+#  define ori(r0,r1,i0)                        _ori(_jit,r0,r1,i0)
+static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define xorr(r0,r1,r2)               XOR(r0,r1,r2)
+#  define xori(r0,r1,i0)               _xori(_jit,r0,r1,i0)
+static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define movr(r0,r1)                  orr(r0,r1,_ZERO_REGNO)
+#  define movi(r0,i0)                  _movi(_jit,r0,i0)
+static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
+#  define movi_p(r0,i0)                        _movi_p(_jit,r0,i0)
+static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_c(r0,r1)                 LB(r0,0,r1)
+#  define ldi_c(r0,i0)                 _ldi_c(_jit,r0,i0)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_uc(r0,r1)                        LBU(r0,0,r1)
+#  define ldi_uc(r0,i0)                        _ldi_uc(_jit,r0,i0)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_s(r0,r1)                 LH(r0,0,r1)
+#  define ldi_s(r0,i0)                 _ldi_s(_jit,r0,i0)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_us(r0,r1)                        LHU(r0,0,r1)
+#  define ldi_us(r0,i0)                        _ldi_us(_jit,r0,i0)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_i(r0,r1)                 LW(r0,0,r1)
+#  define ldi_i(r0,i0)                 _ldi_i(_jit,r0,i0)
+static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 64
+#    define ldr_ui(r0,r1)              LWU(r0,0,r1)
+#    define ldi_ui(r0,i0)              _ldi_ui(_jit,r0,i0)
+static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
+#    define ldr_l(r0,r1)               LD(r0,0,r1)
+#    define ldi_l(r0,i0)               _ldi_l(_jit,r0,i0)
+static void _ldi_l(jit_state_t*,jit_int32_t,jit_word_t);
+#  endif
+#  define ldxr_c(r0,r1,r2)             _ldxr_c(_jit,r0,r1,r2)
+static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_c(r0,r1,i0)             _ldxi_c(_jit,r0,r1,i0)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_uc(r0,r1,r2)            _ldxr_uc(_jit,r0,r1,r2)
+static void _ldxr_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_uc(r0,r1,i0)            _ldxi_uc(_jit,r0,r1,i0)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_s(r0,r1,r2)             _ldxr_s(_jit,r0,r1,r2)
+static void _ldxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_s(r0,r1,i0)             _ldxi_s(_jit,r0,r1,i0)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_us(r0,r1,r2)            _ldxr_us(_jit,r0,r1,r2)
+static void _ldxr_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_us(r0,r1,i0)            _ldxi_us(_jit,r0,r1,i0)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_i(r0,r1,r2)             _ldxr_i(_jit,r0,r1,r2)
+static void _ldxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_i(r0,r1,i0)             _ldxi_i(_jit,r0,r1,i0)
+static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 64
+#    define ldxr_ui(r0,r1,r2)          _ldxr_ui(_jit,r0,r1,r2)
+static void _ldxr_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define ldxi_ui(r0,r1,i0)          _ldxi_ui(_jit,r0,r1,i0)
+static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#    define ldxr_l(r0,r1,r2)           _ldxr_l(_jit,r0,r1,r2)
+static void _ldxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define ldxi_l(r0,r1,i0)           _ldxi_l(_jit,r0,r1,i0)
+static void _ldxi_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  endif
+#  define str_c(r0,r1)                 SB(r1,0,r0)
+#  define sti_c(i0,r0)                 _sti_c(_jit,i0,r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_s(r0,r1)                 SH(r1,0,r0)
+#  define sti_s(i0,r0)                 _sti_s(_jit,i0,r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_i(r0,r1)                 SW(r1,0,r0)
+#  define sti_i(i0,r0)                 _sti_i(_jit,i0,r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#    define str_l(r0,r1)               SD(r1,0,r0)
+#    define sti_l(i0,r0)               _sti_l(_jit,i0,r0)
+static void _sti_l(jit_state_t*,jit_word_t,jit_int32_t);
+#  endif
+#  define stxr_c(r0,r1,r2)             _stxr_c(_jit,r0,r1,r2)
+static void _stxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_c(i0,r0,r1)             _stxi_c(_jit,i0,r0,r1)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_s(r0,r1,r2)             _stxr_s(_jit,r0,r1,r2)
+static void _stxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_s(i0,r0,r1)             _stxi_s(_jit,i0,r0,r1)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_i(r0,r1,r2)             _stxr_i(_jit,r0,r1,r2)
+static void _stxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_i(i0,r0,r1)             _stxi_i(_jit,i0,r0,r1)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#    define stxr_l(r0,r1,r2)           _stxr_l(_jit,r0,r1,r2)
+static void _stxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define stxi_l(i0,r0,r1)           _stxi_l(_jit,i0,r0,r1)
+static void _stxi_l(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  endif
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+#    define htonr_us(r0,r1)            _htonr_us(_jit,r0,r1)
+static void _htonr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#    define htonr_ui(r0,r1)            _htonr_ui(_jit,r0,r1)
+static void _htonr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#    if __WORDSIZE == 64
+#      define htonr_ul(r0,r1)          _htonr_ul(_jit,r0,r1)
+static void _htonr_ul(jit_state_t*,jit_int32_t,jit_int32_t);
+#    endif
+#  else
+#    define htonr_us(r0,r1)            extr_us(r0,r1)
+#    if __WORDSIZE == 32
+#      define htonr_ui(r0,r1)          movr(r0,r1)
+#    else
+#      define htonr_ui(r0,r1)          extr_ui(r0,r1)
+#      define htonr_ul(r0,r1)          movr(r0,r1)
+#    endif
+#  endif
+#  define extr_c(r0,r1)                        _extr_c(_jit,r0,r1)
+static void _extr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_uc(r0,r1)               ANDI(r0,r1,0xff)
+#  define extr_s(r0,r1)                        _extr_s(_jit,r0,r1)
+static void _extr_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_us(r0,r1)               ANDI(r0,r1,0xffff)
+#  if __WORDSIZE == 64
+#    define extr_i(r0,r1)              SLL(r0,r1,0)
+#    define extr_ui(r0,r1)             _extr_ui(_jit,r0,r1)
+static void _extr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  endif
+#  define ltr(r0,r1,r2)                        SLT(r0,r1,r2)
+#  define lti(r0,r1,i0)                        _lti(_jit,r0,r1,i0)
+static void _lti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ltr_u(r0,r1,r2)              SLTU(r0,r1,r2)
+#  define lti_u(r0,r1,i0)              _lti_u(_jit,r0,r1,i0)
+static void _lti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ler(r0,r1,r2)                  _ler(_jit,r0,r1,r2)
+static void _ler(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define lei(r0,r1,i0)                  _lei(_jit,r0,r1,i0)
+static void _lei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ler_u(r0,r1,r2)                        _ler_u(_jit,r0,r1,r2)
+static void _ler_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define lei_u(r0,r1,i0)                        _lei_u(_jit,r0,r1,i0)
+static void _lei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define eqr(r0,r1,r2)                  _eqr(_jit,r0,r1,r2)
+static void _eqr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define eqi(r0,r1,i0)                  _eqi(_jit,r0,r1,i0)
+static void _eqi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ger(r0,r1,r2)                  _ger(_jit,r0,r1,r2)
+static void _ger(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define gei(r0,r1,i0)                  _gei(_jit,r0,r1,i0)
+static void _gei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ger_u(r0,r1,i0)                        _ger_u(_jit,r0,r1,i0)
+static void _ger_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define gei_u(r0,r1,i0)                        _gei_u(_jit,r0,r1,i0)
+static void _gei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define gtr(r0,r1,r2)                        SLT(r0,r2,r1)
+#define gti(r0,r1,i0)                  _gti(_jit,r0,r1,i0)
+static void _gti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define gtr_u(r0,r1,r2)              SLTU(r0,r2,r1)
+#  define gti_u(r0,r1,i0)              _gti_u(_jit,r0,r1,i0)
+static void _gti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define ner(r0,r1,r2)                  _ner(_jit,r0,r1,r2)
+static void _ner(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#define nei(r0,r1,i0)                  _nei(_jit,r0,r1,i0)
+static void _nei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define bltr(i0,r0,r1)                 _bltr(_jit,i0,r0,r1)
+static jit_word_t _bltr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bltr_u(i0,r0,r1)               _bltr_u(_jit,i0,r0,r1)
+static jit_word_t _bltr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blti(i0,r0,i1)                 _blti(_jit,i0,r0,i1)
+static jit_word_t _blti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define blti_u(i0,r0,i1)               _blti_u(_jit,i0,r0,i1)
+static jit_word_t _blti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bler(i0,r0,r1)                 _bler(_jit,i0,r0,r1)
+static jit_word_t _bler(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bler_u(i0,r0,r1)               _bler_u(_jit,i0,r0,r1)
+static jit_word_t _bler_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blei(i0,r0,i1)                 _blei(_jit,i0,r0,i1)
+static jit_word_t _blei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define blei_u(i0,r0,i1)               _blei_u(_jit,i0,r0,i1)
+static jit_word_t _blei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define beqr(i0,r0,r1)                 _beqr(_jit,i0,r0,r1)
+static jit_word_t _beqr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define beqi(i0,r0,i1)                 _beqi(_jit,i0,r0,i1)
+static jit_word_t _beqi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bger(i0,r0,r1)                 _bger(_jit,i0,r0,r1)
+static jit_word_t _bger(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bger_u(i0,r0,r1)               _bger_u(_jit,i0,r0,r1)
+static jit_word_t _bger_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgei(i0,r0,i1)                 _bgei(_jit,i0,r0,i1)
+static jit_word_t _bgei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bgei_u(i0,r0,i1)               _bgei_u(_jit,i0,r0,i1)
+static jit_word_t _bgei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bgtr(i0,r0,r1)                 _bgtr(_jit,i0,r0,r1)
+static jit_word_t _bgtr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgtr_u(i0,r0,r1)               _bgtr_u(_jit,i0,r0,r1)
+static jit_word_t _bgtr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgti(i0,r0,i1)                 _bgti(_jit,i0,r0,i1)
+static jit_word_t _bgti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bgti_u(i0,r0,i1)               _bgti_u(_jit,i0,r0,i1)
+static jit_word_t _bgti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bner(i0,r0,r1)                 _bner(_jit,i0,r0,r1)
+static jit_word_t _bner(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bnei(i0,r0,i1)                 _bnei(_jit,i0,r0,i1)
+static jit_word_t _bnei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define jmpr(r0)                     _jmpr(_jit,r0)
+static void _jmpr(jit_state_t*,jit_int32_t);
+#  define jmpi(i0)                     _jmpi(_jit,i0)
+static jit_word_t _jmpi(jit_state_t*,jit_word_t);
+#  define boaddr(i0,r0,r1)             _boaddr(_jit,i0,r0,r1)
+static jit_word_t _boaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define boaddi(i0,r0,i1)             _boaddi(_jit,i0,r0,i1)
+static jit_word_t _boaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define boaddr_u(i0,r0,r1)           _boaddr_u(_jit,i0,r0,r1)
+static jit_word_t _boaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define boaddi_u(i0,r0,i1)           _boaddi_u(_jit,i0,r0,i1)
+static jit_word_t _boaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxaddr(i0,r0,r1)             _bxaddr(_jit,i0,r0,r1)
+static jit_word_t _bxaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bxaddi(i0,r0,i1)             _bxaddi(_jit,i0,r0,i1)
+static jit_word_t _bxaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxaddr_u(i0,r0,r1)           _bxaddr_u(_jit,i0,r0,r1)
+static jit_word_t _bxaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bxaddi_u(i0,r0,i1)           _bxaddi_u(_jit,i0,r0,i1)
+static jit_word_t _bxaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bosubr(i0,r0,r1)             _bosubr(_jit,i0,r0,r1)
+static jit_word_t _bosubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bosubi(i0,r0,i1)             _bosubi(_jit,i0,r0,i1)
+static jit_word_t _bosubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bosubr_u(i0,r0,r1)           _bosubr_u(_jit,i0,r0,r1)
+static jit_word_t _bosubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bosubi_u(i0,r0,i1)           _bosubi_u(_jit,i0,r0,i1)
+static jit_word_t _bosubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxsubr(i0,r0,r1)             _bxsubr(_jit,i0,r0,r1)
+static jit_word_t _bxsubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bxsubi(i0,r0,i1)             _bxsubi(_jit,i0,r0,i1)
+static jit_word_t _bxsubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxsubr_u(i0,r0,r1)           _bxsubr_u(_jit,i0,r0,r1)
+static jit_word_t _bxsubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bxsubi_u(i0,r0,i1)           _bxsubi_u(_jit,i0,r0,i1)
+static jit_word_t _bxsubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bmsr(i0,r0,r1)               _bmsr(_jit,i0,r0,r1)
+static jit_word_t _bmsr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bmsi(i0,r0,i1)               _bmsi(_jit,i0,r0,i1)
+static jit_word_t _bmsi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bmcr(i0,r0,r1)               _bmcr(_jit,i0,r0,r1)
+static jit_word_t _bmcr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bmci(i0,r0,i1)               _bmci(_jit,i0,r0,i1)
+static jit_word_t _bmci(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define callr(r0)                    _callr(_jit,r0)
+static void _callr(jit_state_t*,jit_int32_t);
+#  define calli(i0)                    _calli(_jit,i0)
+static void _calli(jit_state_t*,jit_word_t);
+#  define calli_p(i0)                  _calli_p(_jit,i0)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t);
+#  define prolog(node)                 _prolog(_jit,node)
+static void _prolog(jit_state_t*,jit_node_t*);
+#  define epilog(node)                 _epilog(_jit,node)
+static void _epilog(jit_state_t*,jit_node_t*);
+#  define vastart(r0)                  _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#  define vaarg(r0, r1)                        _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#define patch_abs(instr,label)         _patch_abs(_jit,instr,label)
+static void _patch_abs(jit_state_t*,jit_word_t,jit_word_t);
+#define patch_at(jump,label)           _patch_at(_jit,jump,label)
+static void _patch_at(jit_state_t*,jit_word_t,jit_word_t);
+#endif
+
+#if CODE
+static void
+_hrrrit(jit_state_t *_jit,jit_int32_t hc,
+       jit_int32_t rs, jit_int32_t rt, jit_int32_t rd,
+       jit_int32_t ic, jit_int32_t tc)
+{
+    jit_instr_t                i;
+    i.tc.b = tc;
+    i.ic.b = ic;
+    i.rd.b = rd;
+    i.rt.b = rt;
+    i.rs.b = rs;
+    i.hc.b = hc;
+    ii(i.op);
+}
+
+static void
+_hrri(jit_state_t *_jit, jit_int32_t hc,
+      jit_int32_t rs, jit_int32_t rt, jit_int32_t im)
+{
+    jit_instr_t                i;
+    i.op = 0;
+    i.is.b = im;
+    i.rt.b = rt;
+    i.rs.b = rs;
+    i.hc.b = hc;
+    ii(i.op);
+}
+
+static void
+_hi(jit_state_t *_jit, jit_int32_t hc, jit_int32_t im)
+{
+    jit_instr_t                i;
+    i.ii.b = im;
+    i.hc.b = hc;
+    ii(i.op);
+}
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t i0)
+{
+    for (; i0 > 0; i0 -= 4)
+       NOP();
+    assert(i0 == 0);
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (can_sign_extend_short_p(i0))
+       addiu(r0, r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       t0 = jit_get_reg(jit_class_gpr);
+       addr(rn(t0), r1, r2);
+       SLTU(rn(jit_carry), rn(t0), r1);
+       movr(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    else {
+       addr(r0, r1, r2);
+       SLTU(rn(jit_carry), r0, r1);
+    }
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    t0 = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       if (can_sign_extend_short_p(i0))
+           addiu(rn(t0), r1, i0);
+       else {
+           movi(rn(t0), i0);
+           addr(rn(t0), r1, rn(t0));
+       }
+       SLTU(rn(jit_carry), rn(t0), r1);
+       movr(r0, rn(t0));
+    }
+    else {
+       if (can_sign_extend_short_p(i0))
+           addiu(r0, r1, i0);
+       else {
+           movi(rn(t0), i0);
+           addr(r0, r1, rn(t0));
+       }
+       SLTU(rn(jit_carry), r0, r1);
+    }
+    jit_unget_reg(t0);
+}
+
+static void
+_addxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+
+    assert(jit_carry != _NOREG);
+    t0 = jit_get_reg(jit_class_gpr);
+    movr(rn(t0), rn(jit_carry));
+    addcr(r0, r1, r2);
+    addcr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+
+    assert(jit_carry != _NOREG);
+    t0 = jit_get_reg(jit_class_gpr);
+    movr(rn(t0), rn(jit_carry));
+    addci(r0, r1, i0);
+    addcr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (can_sign_extend_short_p(i0) && (i0 & 0xffff) != 0x8000)
+       addiu(r0, r1, -i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_subcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       t0 = jit_get_reg(jit_class_gpr);
+       subr(rn(t0), r1, r2);
+       SLTU(rn(jit_carry), r1, rn(t0));
+       movr(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    else {
+       subr(r0, r1, r2);
+       SLTU(rn(jit_carry), r1, r0);
+    }
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    t0 = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       if (can_sign_extend_short_p(i0) && (i0 & 0xffff) != 0x8000)
+           addiu(rn(t0), r1, -i0);
+       else {
+           movi(rn(t0), i0);
+           subr(rn(t0), r1, rn(t0));
+       }
+       SLTU(rn(jit_carry), r1, rn(t0));
+       movr(r0, rn(t0));
+    }
+    else {
+       if (can_sign_extend_short_p(i0) && (i0 & 0xffff) != 0x8000)
+           addiu(r0, r1, -i0);
+       else {
+           movi(rn(t0), i0);
+           subr(r0, r1, rn(t0));
+       }
+       SLTU(rn(jit_carry), r1, r0);
+    }
+    jit_unget_reg(t0);
+}
+
+static void
+_subxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+
+    assert(jit_carry != _NOREG);
+    t0 = jit_get_reg(jit_class_gpr);
+    movr(rn(t0), rn(jit_carry));
+    subcr(r0, r1, r2);
+    subcr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+
+    assert(jit_carry != _NOREG);
+    t0 = jit_get_reg(jit_class_gpr);
+    movr(rn(t0), rn(jit_carry));
+    subci(r0, r1, i0);
+    subcr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    subi(r0, r1, i0);
+    negr(r0, r0);
+}
+
+static void
+_mulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    multu(r1, r2);
+    MFLO(r0);
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    mulr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_iqmulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    if (sign)
+       mult(r2, r3);
+    else
+       multu(r2, r3);
+    MFLO(r0);
+    MFHI(r1);
+}
+
+static void
+_iqmuli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    iqmulr(r0, r1, r2, rn(reg), sign);
+    jit_unget_reg(reg);
+}
+
+static void
+_divr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    div(r1, r2);
+    MFLO(r0);
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_divr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    divu(r1, r2);
+    MFLO(r0);
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_iqdivr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    if (sign)
+       div(r2, r3);
+    else
+       divu(r2, r3);
+    MFLO(r0);
+    MFHI(r1);
+}
+
+static void
+_iqdivi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    iqdivr(r0, r1, r2, rn(reg), sign);
+    jit_unget_reg(reg);
+}
+
+static void
+_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    div(r1, r2);
+    MFHI(r0);
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    divu(r1, r2);
+    MFHI(r0);
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+#if __WORDSIZE == 64
+static void
+_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    assert(i0 >= 0 && i0 <= 63);
+    if (i0 < 32)
+       DSLL(r0, r1, i0);
+    else
+       DSLL32(r0, r1, i0 - 32);
+}
+
+static void
+_rshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    assert(i0 >= 0 && i0 <= 63);
+    if (i0 < 32)
+       DSRA(r0, r1, i0);
+    else
+       DSRA32(r0, r1, i0 - 32);
+}
+
+static void
+_rshi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    assert(i0 >= 0 && i0 <= 63);
+    if (i0 < 32)
+       DSRL(r0, r1, i0);
+    else
+       DSRL32(r0, r1, i0 - 32);
+}
+#endif
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       ANDI(r0, r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       AND(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       ORI(r0, r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       OR(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       XORI(r0, r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       XOR(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    if (i0 == 0)
+       OR(r0, _ZERO_REGNO, _ZERO_REGNO);
+    else if (can_sign_extend_short_p(i0))
+       addiu(r0, _ZERO_REGNO, i0);
+    else if (can_zero_extend_short_p(i0))
+       ORI(r0, _ZERO_REGNO, i0);
+    else {
+       if (can_sign_extend_int_p(i0))
+           LUI(r0, i0 >> 16);
+       else if (can_zero_extend_int_p(i0)) {
+           if (i0 & 0xffff0000) {
+               ORI(r0, _ZERO_REGNO, i0 >> 16);
+               lshi(r0, r0, 16);
+           }
+       }
+#  if __WORDSIZE == 64
+       else {
+           movi(r0, (jit_uword_t)i0 >> 32);
+           if (i0 & 0xffff0000) {
+               lshi(r0, r0, 16);
+               ORI(r0, r0, i0 >> 16);
+               lshi(r0, r0, 16);
+           }
+           else
+               lshi(r0, r0, 32);
+       }
+#  endif
+       if (i0 & 0xffff)
+           ORI(r0, r0, i0);
+    }
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+
+    w = _jit->pc.w;
+#  if __WORDSIZE == 32
+    LUI(r0, i0 >> 16);
+    ORI(r0, r0, i0);
+#  else
+    LUI(r0, i0 >> 48);
+    ORI(r0, r0, i0 >> 32);
+    lshi(r0, r0, 16);
+    ORI(r0, r0, i0 >> 16);
+    lshi(r0, r0, 16);
+    ORI(r0, r0, i0);
+#  endif
+
+    return (w);
+}
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LB(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_c(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LBU(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_uc(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LH(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_s(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LHU(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_us(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LW(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#if __WORDSIZE == 64
+static void
+_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LWU(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_ui(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_l(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LD(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_l(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+#endif
+
+static void
+_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_c(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LB(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_c(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_uc(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LBU(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_uc(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_s(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LH(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_s(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_us(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LHU(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_us(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_i(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LW(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#if __WORDSIZE == 64
+static void
+_ldxr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_ui(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LWU(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_ui(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_l(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LD(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_l(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+#endif
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SB(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_c(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SH(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_s(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SW(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_i(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+#if __WORDSIZE == 64
+static void
+_sti_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SD(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_l(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+#endif
+
+static void
+_stxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_c(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SB(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_c(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_s(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SH(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_s(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_i(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SW(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_i(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+#if __WORDSIZE == 64
+static void
+_stxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1 ,jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_l(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SD(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_l(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+#endif
+
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+static void
+_htonr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    rshi(rn(t0), r1, 8);
+    andi(r0, r1, 0xff);
+    andi(rn(t0), rn(t0), 0xff);
+    lshi(r0, r0, 8);
+    orr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_htonr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr);
+    t2 = jit_get_reg(jit_class_gpr);
+    rshi(rn(t0), r1, 24);
+    rshi(rn(t1), r1, 16);
+    rshi(rn(t2), r1,  8);
+    andi(rn(t0), rn(t0), 0xff);
+    andi(rn(t1), rn(t1), 0xff);
+    andi(rn(t2), rn(t2), 0xff);
+    andi(r0, r1, 0xff);
+    lshi(r0, r0, 24);
+    lshi(rn(t1), rn(t1), 8);
+    orr(r0, r0, rn(t0));
+    lshi(rn(t2), rn(t2), 16);
+    orr(r0, r0, rn(t1));
+    orr(r0, r0, rn(t2));
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+}
+
+static void
+_htonr_ul(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    rshi_u(rn(reg), r1, 32);
+    htonr_ui(r0, r1);
+    htonr_ui(rn(reg), rn(reg));
+    lshi(r0, r0, 32);
+    orr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+#  endif
+
+static void
+_extr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_mips2_p())
+       SEB(r0, r1);
+    else {
+       lshi(r0, r1, __WORDSIZE - 8);
+       rshi(r0, r0, __WORDSIZE - 8);
+    }
+}
+
+static void
+_extr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (jit_mips2_p())
+       SEH(r0, r1);
+    else {
+       lshi(r0, r1, __WORDSIZE - 16);
+       rshi(r0, r0, __WORDSIZE - 16);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_extr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 32);
+    rshi_u(r0, r0, 32);
+}
+#  endif
+
+static void
+_lti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    if (can_sign_extend_short_p(i0))
+       SLTI(r0, r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ltr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_lti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    if (can_sign_extend_short_p(i0))
+       SLTIU(r0, r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ltr_u(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ler(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SLT(r0, r2, r1);
+    XORI(r0, r0, 1);
+}
+
+static void
+_lei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    if (i0 == 0) {
+       SLT(r0, _ZERO_REGNO, r1);
+       XORI(r0, r0, 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ler(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ler_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SLTU(r0, r2, r1);
+    XORI(r0, r0, 1);
+}
+
+static void
+_lei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    if (i0 == 0) {
+       SLTU(r0, _ZERO_REGNO, r1);
+       XORI(r0, r0, 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ler_u(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_eqr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    subr(r0, r1, r2);
+    SLTU(r0, _ZERO_REGNO, r0);
+    XORI(r0, r0, 1);
+}
+
+static void
+_eqi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0) {
+       subi(r0, r1, i0);
+       SLTU(r0, _ZERO_REGNO, r0);
+    }
+    else
+       SLTU(r0, _ZERO_REGNO, r1);
+    XORI(r0, r0, 1);
+}
+
+static void
+_ger(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SLT(r0, r1, r2);
+    XORI(r0, r0, 1);
+}
+
+static void
+_gei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ger(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ger_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SLTU(r0, r1, r2);
+    XORI(r0, r0, 1);
+}
+
+static void
+_gei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ger_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_gti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    if (i0 == 0)
+       SLT(r0, _ZERO_REGNO, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       SLT(r0, rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_gti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    if (i0 == 0)
+       SLTU(r0, _ZERO_REGNO, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       SLTU(r0, rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ner(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    subr(r0, r1, r2);
+    SLTU(r0, _ZERO_REGNO, r0);
+}
+
+static void
+_nei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0) {
+       subi(r0, r1, i0);
+       SLTU(r0, _ZERO_REGNO, r0);
+    }
+    else
+       SLTU(r0, _ZERO_REGNO, r1);
+}
+
+static jit_word_t
+_bltr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr);
+    SLT(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_bltr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLTU(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BNE(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_blti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    jit_int32_t                reg;
+    jit_bool_t         zero_p;
+
+    if (!(zero_p = i1 == 0))
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    if (can_sign_extend_short_p(i1)) {
+       if (!zero_p)
+           SLTI(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 1;
+       if (!zero_p)
+           BNE(rn(reg), _ZERO_REGNO, d);
+       else
+           BLTZ(r0, d);
+       NOP(1);
+    }
+    else {
+       movi(rn(reg), i1);
+       w = bltr(i0, r0, rn(reg));
+    }
+    if (!zero_p)
+       jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_blti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    if (can_sign_extend_short_p(i1)) {
+       SLTIU(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BNE(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       movi(rn(reg), i1);
+       w = bltr_u(i0, r0, rn(reg));
+    }
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_bler(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLT(rn(reg), r1, r0);
+    w = _jit->pc.w;
+    BEQ(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_bler_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLTU(rn(reg), r1, r0);
+    w = _jit->pc.w;
+    BEQ(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_blei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BLEZ(r0, ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = bler(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    return (w);
+}
+
+static jit_word_t
+_blei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BEQ(r0, _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = bler_u(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    return (w);
+}
+
+static jit_word_t
+_beqr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+
+    w = _jit->pc.w;
+    BEQ(r0, r1, ((i0 - w) >> 2) - 1);
+    NOP(1);
+
+    return (w);
+}
+
+static jit_word_t
+_beqi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BEQ(r0, _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = beqr(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    return (w);
+}
+
+static jit_word_t
+_bger(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLT(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BEQ(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_bger_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLTU(rn(reg), r0, r1);
+    w = _jit->pc.w;
+    BEQ(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_bgei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_word_t         d;
+    jit_int32_t                reg;
+    jit_bool_t         zero_p;
+
+    if (!(zero_p = i1 == 0))
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    if (can_sign_extend_short_p(i1)) {
+       if (!zero_p)
+           SLTI(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       d = ((i0 - w) >> 2) - 1;
+       if (!zero_p)
+           BEQ(rn(reg), _ZERO_REGNO, d);
+       else
+           BGEZ(r0, d);
+       NOP(1);
+    }
+    else {
+       movi(rn(reg), i1);
+       w = bger(i0, r0, rn(reg));
+    }
+    if (!zero_p)
+       jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_bgei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    if (can_sign_extend_short_p(i1)) {
+       SLTIU(rn(reg), r0, i1);
+       w = _jit->pc.w;
+       BEQ(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       movi(rn(reg), i1);
+       w = bger_u(i0, r0, rn(reg));
+    }
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_bgtr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLT(rn(reg), r1, r0);
+    w = _jit->pc.w;
+    BNE(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_bgtr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLTU(rn(reg), r1, r0);
+    w = _jit->pc.w;
+    BNE(rn(reg), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(reg);
+
+    return (w);
+}
+
+static jit_word_t
+_bgti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BGTZ(r0, ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = bgtr(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    return (w);
+}
+
+static jit_word_t
+_bgti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BNE(r0, _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = bgtr_u(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    return (w);
+}
+
+static jit_word_t
+_bner(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+
+    w = _jit->pc.w;
+    BNE(r0, r1, ((i0 - w) >> 2) - 1);
+    NOP(1);
+
+    return (w);
+}
+
+static jit_word_t
+_bnei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    if (i1 == 0) {
+       w = _jit->pc.w;
+       BNE(r0, _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = bner(i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    return (w);
+}
+
+static void
+_jmpr(jit_state_t *_jit, jit_int32_t r0)
+{
+    JR(r0);
+    NOP(1);
+}
+
+static jit_word_t
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+
+    w = _jit->pc.w;
+    if (((w + sizeof(jit_int32_t)) & 0xf0000000) == (i0 & 0xf0000000)) {
+       J((i0 & ~0xf0000000) >> 2);
+       NOP(1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi_p(rn(reg), i0);
+       jmpr(rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    return (w);
+}
+
+static jit_word_t
+_boaddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+
+    /* t1 = r0 + r1;   overflow = r1 < 0 ? r0 < t1 : t1 < r0 */
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLT(rn(t0), r1, _ZERO_REGNO);      /* t0 = r1 < 0 */
+    addr(rn(t1), r0, r1);              /* t1 = r0 + r1 */
+    SLT(rn(t2), rn(t1), r0);           /* t2 = t1 < r0 */
+    SLT(rn(t1), r0, rn(t1));           /* t1 = r0 < t1 */
+    MOVZ(rn(t1), rn(t2), rn(t0));      /* if (r0 == 0) t1 = t2 */
+    w = _jit->pc.w;
+    BNE(rn(t1), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    /* delay slot */
+    addr(r0, r0, r1);
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+
+    return (w);
+}
+
+static jit_word_t
+_boaddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+
+    if (can_sign_extend_short_p(i1)) {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       SLTI(rn(t0), _ZERO_REGNO, i1);
+       addiu(rn(t1), r0, i1);
+       SLT(rn(t2), r0, rn(t1));
+       SLT(rn(t1), rn(t1), r0);
+       MOVZ(rn(t1), rn(t2), rn(t0));
+       w = _jit->pc.w;
+       BNE(rn(t1), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       /* delay slot */
+       addiu(r0, r0, i1);
+       jit_unget_reg(t2);
+       jit_unget_reg(t1);
+       jit_unget_reg(t0);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i1);
+       w = boaddr(i0, r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    return (w);
+}
+
+static jit_word_t
+_boaddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    addr(rn(t0), r0, r1);
+    SLTU(rn(t1), rn(t0), r0);
+    w = _jit->pc.w;
+    BNE(_ZERO_REGNO, rn(t1), ((i0 - w) >> 2) - 1);
+    /* delay slot */
+    movr(r0, rn(t0));
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_boaddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+
+    if (can_sign_extend_short_p(i0)) {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       addiu(rn(t0), r0, i1);
+       SLTU(rn(t1), rn(t0), r0);
+       w = _jit->pc.w;
+       BNE(_ZERO_REGNO, rn(t1), ((i0 - w) >> 2) - 1);
+       /* delay slot */
+       movr(r0, rn(t0));
+       jit_unget_reg(t1);
+       jit_unget_reg(t0);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(t0), i1);
+       w = boaddr_u(i0, r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bxaddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+
+    /* t1 = r0 + r1;   overflow = r1 < 0 ? r0 < t1 : t1 < r0 */
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLT(rn(t0), r1, _ZERO_REGNO);      /* t0 = r1 < 0 */
+    addr(rn(t1), r0, r1);              /* t1 = r0 + r1 */
+    SLT(rn(t2), rn(t1), r0);           /* t2 = t1 < r0 */
+    SLT(rn(t1), r0, rn(t1));           /* t1 = r0 < t1 */
+    MOVZ(rn(t1), rn(t2), rn(t0));      /* if (r0 == 0) t1 = t2 */
+    w = _jit->pc.w;
+    BEQ(rn(t1), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    /* delay slot */
+    addr(r0, r0, r1);
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+
+    return (w);
+}
+
+static jit_word_t
+_bxaddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+
+    if (can_sign_extend_short_p(i1)) {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       SLTI(rn(t0), _ZERO_REGNO, i1);
+       addiu(rn(t1), r0, i1);
+       SLT(rn(t2), r0, rn(t1));
+       SLT(rn(t1), rn(t1), r0);
+       MOVZ(rn(t1), rn(t2), rn(t0));
+       w = _jit->pc.w;
+       BEQ(rn(t1), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       /* delay slot */
+       addiu(r0, r0, i1);
+       jit_unget_reg(t2);
+       jit_unget_reg(t1);
+       jit_unget_reg(t0);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(t0), i1);
+       w = bxaddr(i0, r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bxaddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    addr(rn(t0), r0, r1);
+    SLTU(rn(t1), rn(t0), r0);
+    w = _jit->pc.w;
+    BEQ(_ZERO_REGNO, rn(t1), ((i0 - w) >> 2) - 1);
+    /* delay slot */
+    movr(r0, rn(t0));
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxaddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+
+    if (can_sign_extend_short_p(i0)) {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       addiu(rn(t0), r0, i1);
+       SLTU(rn(t1), rn(t0), r0);
+       w = _jit->pc.w;
+       BEQ(_ZERO_REGNO, rn(t1), ((i0 - w) >> 2) - 1);
+       /* delay slot */
+       movr(r0, rn(t0));
+       jit_unget_reg(t1);
+       jit_unget_reg(t0);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(t0), i1);
+       w = bxaddr_u(i0, r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bosubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+
+    /* t1 = r0 - r1;   overflow = 0 < r1 ? r0 < t1 : t1 < r0 */
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLT(rn(t0), _ZERO_REGNO, r1);      /* t0 = 0 < r1 */
+    subr(rn(t1), r0, r1);              /* t1 = r0 - r1 */
+    SLT(rn(t2), rn(t1), r0);           /* t2 = t1 < r0 */
+    SLT(rn(t1), r0, rn(t1));           /* t1 = r0 < t1 */
+    MOVZ(rn(t1), rn(t2), rn(t0));      /* if (r0 == 0) t1 = t2 */
+    w = _jit->pc.w;
+    BNE(rn(t1), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    /* delay slot */
+    subr(r0, r0, r1);
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+
+    return (w);
+}
+
+static jit_word_t
+_bosubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+
+    if (can_sign_extend_short_p(i1) && (i1 & 0xffff) != 0x8000) {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       SLTI(rn(t0), _ZERO_REGNO, i1);
+       addiu(rn(t1), r0, -i1);
+       SLT(rn(t2), rn(t1), r0);
+       SLT(rn(t1), r0, rn(t1));
+       MOVZ(rn(t1), rn(t2), rn(t0));
+       w = _jit->pc.w;
+       BNE(rn(t1), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       /* delay slot */
+       addiu(r0, r0, -i1);
+       jit_unget_reg(t2);
+       jit_unget_reg(t1);
+       jit_unget_reg(t0);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(t0), i1);
+       w = bosubr(i0, r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bosubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    subr(rn(t0), r0, r1);
+    SLTU(rn(t1), r0, rn(t0));
+    w = _jit->pc.w;
+    BNE(_ZERO_REGNO, rn(t1), ((i0 - w) >> 2) - 1);
+    /* delay slot */
+    movr(r0, rn(t0));
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bosubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+
+    if (can_sign_extend_short_p(i0) && (i0 & 0xffff) != 0x8000) {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       addiu(rn(t0), r0, -i1);
+       SLTU(rn(t1), r0, rn(t0));
+       w = _jit->pc.w;
+       BNE(_ZERO_REGNO, rn(t1), ((i0 - w) >> 2) - 1);
+       /* delay slot */
+       movr(r0, rn(t0));
+       jit_unget_reg(t1);
+       jit_unget_reg(t0);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(t0), i1);
+       w = bosubr_u(i0, r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bxsubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+
+    /* t1 = r0 - r1;   overflow = 0 < r1 ? r0 < t1 : t1 < r0 */
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    SLT(rn(t0), _ZERO_REGNO, r1);      /* t0 = 0 < r1 */
+    subr(rn(t1), r0, r1);              /* t1 = r0 - r1 */
+    SLT(rn(t2), rn(t1), r0);           /* t2 = t1 < r0 */
+    SLT(rn(t1), r0, rn(t1));           /* t1 = r0 < t1 */
+    MOVZ(rn(t1), rn(t2), rn(t0));      /* if (t0 == 0) t1 = t2 */
+    w = _jit->pc.w;
+    BEQ(rn(t1), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+    /* delay slot */
+    subr(r0, r0, r1);
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+
+    return (w);
+}
+
+static jit_word_t
+_bxsubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+
+    if (can_sign_extend_short_p(i1) && (i1 & 0xffff) != 0x8000) {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t2 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       SLTI(rn(t0), _ZERO_REGNO, i1);
+       addiu(rn(t1), r0, -i1);
+       SLT(rn(t2), rn(t1), r0);
+       SLT(rn(t1), r0, rn(t1));
+       MOVZ(rn(t1), rn(t2), rn(t0));
+       w = _jit->pc.w;
+       BEQ(rn(t1), _ZERO_REGNO, ((i0 - w) >> 2) - 1);
+       /* delay slot */
+       addiu(r0, r0, -i1);
+       jit_unget_reg(t2);
+       jit_unget_reg(t1);
+       jit_unget_reg(t0);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(t0), i1);
+       w = bxsubr(i0, r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bxsubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    subr(rn(t0), r0, r1);
+    SLTU(rn(t1), r0, rn(t0));
+    w = _jit->pc.w;
+    BEQ(_ZERO_REGNO, rn(t1), ((i0 - w) >> 2) - 1);
+    /* delay slot */
+    movr(r0, rn(t0));
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxsubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+
+    if (can_sign_extend_short_p(i0) && (i0 & 0xffff) != 0x8000) {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       addiu(rn(t0), r0, -i1);
+       SLTU(rn(t1), r0, rn(t0));
+       w = _jit->pc.w;
+       BEQ(_ZERO_REGNO, rn(t1), ((i0 - w) >> 2) - 1);
+       /* delay slot */
+       movr(r0, rn(t0));
+       jit_unget_reg(t1);
+       jit_unget_reg(t0);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(t0), i1);
+       w = bxsubr_u(i0, r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bmsr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    AND(rn(t0), r0, r1);
+    w = _jit->pc.w;
+    BNE(_ZERO_REGNO, rn(t0), ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bmsi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    if (can_zero_extend_short_p(i1)) {
+       ANDI(rn(t0), r0, i1);
+       w = _jit->pc.w;
+       BNE(_ZERO_REGNO, rn(t0), ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       movi(rn(t0), i1);
+       w = bmsr(i0, r0, rn(t0));
+    }
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bmcr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    AND(rn(t0), r0, r1);
+    w = _jit->pc.w;
+    BEQ(_ZERO_REGNO, rn(t0), ((i0 - w) >> 2) - 1);
+    NOP(1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bmci(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    if (can_zero_extend_short_p(i1)) {
+       ANDI(rn(t0), r0, i1);
+       w = _jit->pc.w;
+       BEQ(_ZERO_REGNO, rn(t0), ((i0 - w) >> 2) - 1);
+       NOP(1);
+    }
+    else {
+       movi(rn(t0), i1);
+       w = bmcr(i0, r0, rn(t0));
+    }
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static void
+_callr(jit_state_t *_jit, jit_int32_t r0)
+{
+    if (r0 != _T9_REGNO)
+       movr(_T9_REGNO, r0);
+    JALR(r0);
+    NOP(1);
+}
+
+static void
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    movi(_T9_REGNO, i0);
+    JALR(_T9_REGNO);
+    NOP(1);
+}
+
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         word;
+
+    word = _jit->pc.w;
+    movi_p(_T9_REGNO, i0);
+    JALR(_T9_REGNO);
+    NOP(1);
+
+    return (word);
+}
+
+static jit_int32_t fregs[] = {
+    _F30, _F28, _F26, _F24, _F22, _F20,
+#if !NEW_ABI
+    _F18, _F16,
+#endif
+};
+
+static jit_int32_t iregs[] = {
+    _S7, _S6, _S5, _S4, _S3, _S2, _S1, _S0,
+};
+
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                index;
+    jit_int32_t                offset;
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar)
+       _jitc->function->self.aoff &= -8;
+#if NEW_ABI
+    _jitc->function->stack = ((_jitc->function->self.alen -
+                             /* align stack at 16 bytes */
+                              _jitc->function->self.aoff) + 15) & -16;
+#else
+    _jitc->function->stack = ((/* first 16 bytes must be allocated */
+                             (_jitc->function->self.alen > 16 ?
+                              _jitc->function->self.alen : 16) -
+                             /* align stack at 8 bytes */
+                             _jitc->function->self.aoff) + 7) & -8;
+#endif
+    /* callee save registers */
+#if NEW_ABI
+    if ((_jitc->function->self.call & jit_call_varargs) &&
+       jit_arg_reg_p(_jitc->function->vagp))
+       subi(_SP_REGNO, _SP_REGNO, stack_framesize + 64);
+    else
+#endif
+       subi(_SP_REGNO, _SP_REGNO, stack_framesize);
+    offset = stack_framesize - (sizeof(jit_word_t) << 1);
+    for (index = 0; index < jit_size(fregs); index++, offset -= 8) {
+       if (jit_regset_tstbit(&_jitc->function->regset, fregs[index]))
+           stxi_d(offset, _SP_REGNO, rn(fregs[index]));
+    }
+    for (index = 0; index < jit_size(iregs);
+        index++, offset -= sizeof(jit_word_t)) {
+       if (jit_regset_tstbit(&_jitc->function->regset, iregs[index]))
+           stxi(offset, _SP_REGNO, rn(iregs[index]));
+    }
+    assert(offset >= sizeof(jit_word_t));
+    stxi(offset, _SP_REGNO, _RA_REGNO);
+    stxi(0, _SP_REGNO, _BP_REGNO);
+    movr(_BP_REGNO, _SP_REGNO);
+
+    /* alloca */
+    if (_jitc->function->stack)
+       subi(_SP_REGNO, _SP_REGNO, _jitc->function->stack);
+    if (_jitc->function->allocar) {
+       index = jit_get_reg(jit_class_gpr);
+       movi(rn(index), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, _BP_REGNO, rn(index));
+       jit_unget_reg(index);
+    }
+
+    if (_jitc->function->self.call & jit_call_varargs) {
+#if NEW_ABI
+       index = _jitc->function->vagp;
+#else
+       index = (_jitc->function->self.size - stack_framesize) >> STACK_SHIFT;
+#endif
+       offset = stack_framesize + index * STACK_SLOT;
+       for (; jit_arg_reg_p(index); ++index, offset += STACK_SLOT) {
+#if NEW_ABI
+           SD(rn(_A0 - index), offset, _BP_REGNO);
+#else
+           stxi(offset +  WORD_ADJUST, _BP_REGNO, rn(_A0 - index));
+#endif
+       }
+    }
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                index;
+    jit_int32_t                offset;
+    if (_jitc->function->assume_frame)
+       return;
+    /* callee save registers */
+    movr(_SP_REGNO, _BP_REGNO);
+    offset = stack_framesize - (sizeof(jit_word_t) << 1);
+    for (index = 0; index < jit_size(fregs); index++, offset -= 8) {
+       if (jit_regset_tstbit(&_jitc->function->regset, fregs[index]))
+           ldxi_d(rn(fregs[index]), _SP_REGNO, offset);
+    }
+    for (index = 0; index < jit_size(iregs);
+        index++, offset -= sizeof(jit_word_t)) {
+       if (jit_regset_tstbit(&_jitc->function->regset, iregs[index]))
+           ldxi(rn(iregs[index]), _SP_REGNO, offset);
+    }
+    assert(offset >= sizeof(jit_word_t));
+    ldxi(_RA_REGNO, _SP_REGNO, offset);
+    ldxi(_BP_REGNO, _SP_REGNO, 0);
+    JR(_RA_REGNO);
+    /* delay slot */
+#if NEW_ABI
+    if ((_jitc->function->self.call & jit_call_varargs) &&
+       jit_arg_reg_p(_jitc->function->vagp))
+       addi(_SP_REGNO, _SP_REGNO, stack_framesize + 64);
+    else
+#endif
+       addi(_SP_REGNO, _SP_REGNO, stack_framesize);
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Initialize va_list to the first stack argument. */
+#if NEW_ABI
+    if (jit_arg_reg_p(_jitc->function->vagp))
+       addi(r0, _BP_REGNO, stack_framesize + _jitc->function->vagp *
+            sizeof(jit_int64_t));
+    else
+#endif
+       addi(r0, _BP_REGNO, _jitc->function->self.size);
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    /* Load argument. */
+#if WORD_ADJUST
+    ldxi(r0, r1, WORD_ADJUST);
+#else
+    ldr(r0, r1);
+#endif
+
+    /* Update va_list. */
+    addi(r1, r1, STACK_SLOT);
+}
+
+static void
+_patch_abs(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
+{
+    jit_instr_t                i;
+    union {
+       jit_int32_t     *i;
+       jit_word_t       w;
+    } u;
+
+    u.w = instr;
+#if __WORDSIZE == 32
+    i.op = u.i[0];
+    assert(i.hc.b == MIPS_LUI);
+    i.is.b = label >> 16;
+    u.i[0] = i.op;
+    i.op = u.i[1];
+    assert(i.hc.b == MIPS_ORI);
+    i.is.b = label;
+    u.i[1] = i.op;
+#else
+    i.op = u.i[0];
+    assert(i.hc.b == MIPS_LUI);
+    i.is.b = label >> 48;
+    u.i[0] = i.op;
+    i.op = u.i[1];
+    assert(i.hc.b == MIPS_ORI);
+    i.is.b = label >> 32;
+    u.i[1] = i.op;
+    /* lshi */
+    i.op = u.i[3];
+    assert(i.hc.b == MIPS_ORI);
+    i.is.b = label >> 16;
+    u.i[3] = i.op;
+    /* lshi */
+    i.op = u.i[5];
+    assert(i.hc.b == MIPS_ORI);
+    i.is.b = label;
+    u.i[5] = i.op;
+#endif
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
+{
+    jit_instr_t                i;
+    union {
+       jit_int32_t     *i;
+       jit_word_t       w;
+    } u;
+
+    u.w = instr;
+    i.op = u.i[0];
+    switch (i.hc.b) {
+       /* 16 bit immediate opcodes */
+       case MIPS_REGIMM:
+           switch (i.rt.b) {
+               case MIPS_BLTZ:         case MIPS_BLTZL:
+               case MIPS_BLTZAL:       case MIPS_BLTZALL:
+               case MIPS_BGEZ:         case MIPS_BGEZAL:
+               case MIPS_BGEZALL:      case MIPS_BGEZL:
+               case MIPS_TEQI:         case MIPS_TGEI:
+               case MIPS_TGEIU:        case MIPS_TLTI:
+               case MIPS_TLTIU:        case MIPS_TNEI:
+                   i.is.b = ((label - instr) >> 2) - 1;
+                   u.i[0] = i.op;
+                   break;
+               default:
+                   assert(!"unhandled branch opcode");
+                   break;
+           }
+           break;
+
+       case MIPS_COP1:                 case MIPS_COP2:
+           assert(i.rs.b == MIPS_BC);
+           switch (i.rt.b) {
+               case MIPS_BCF:          case MIPS_BCFL:
+               case MIPS_BCT:          case MIPS_BCTL:
+                   i.is.b = ((label - instr) >> 2) - 1;
+                   u.i[0] = i.op;
+                   break;
+               default:
+                   assert(!"unhandled branch opcode");
+                   break;
+           }
+           break;
+
+       case MIPS_BLEZ:                 case MIPS_BLEZL:
+       case MIPS_BEQ:                  case MIPS_BEQL:
+       case MIPS_BGTZ:                 case MIPS_BGTZL:
+       case MIPS_BNE:                  case MIPS_BNEL:
+           i.is.b = ((label - instr) >> 2) - 1;
+           u.i[0] = i.op;
+           break;
+
+       case MIPS_LUI:
+           patch_abs(instr, label);
+           break;
+
+       case MIPS_J:                    case MIPS_JAL:
+       case MIPS_JALX:
+           assert(((instr + sizeof(jit_int32_t)) & 0xf0000000) ==
+                  (label & 0xf0000000));
+           i.ii.b = (label & ~0xf0000000) >> 2;
+           u.i[0] = i.op;
+           break;
+
+       default:
+           assert(!"unhandled branch opcode");
+           break;
+    }
+}
+#endif
diff --git a/deps/lightning/lib/jit_mips-fpu.c b/deps/lightning/lib/jit_mips-fpu.c
new file mode 100644 (file)
index 0000000..7513219
--- /dev/null
@@ -0,0 +1,1844 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  define BE_P                         (__BYTE_ORDER == __BIG_ENDIAN)
+#  define LE_P                         (__BYTE_ORDER == __LITTLE_ENDIAN)
+#  define MIPS_fmt_S                   0x10            /* float32 */
+#  define MIPS_fmt_D                   0x11            /* float64 */
+#  define MIPS_fmt_W                   0x14            /* int32 */
+#  define MIPS_fmt_L                   0x15            /* int64 */
+#  define MIPS_fmt_PS                  0x16            /* 2 x float32 */
+#  define MIPS_fmt_S_PU                        0x20
+#  define MIPS_fmt_S_PL                        0x26
+#  define MIPS_ADD_fmt                 0x00
+#  define MIPS_LWXC1                   0x00
+#  define MIPS_SUB_fmt                 0x01
+#  define MIPS_LDXC1                   0x01
+#  define MIPS_MUL_fmt                 0x02
+#  define MIPS_DIV_fmt                 0x03
+#  define MIPS_SQRT_fmt                        0x04
+#  define MIPS_ABS_fmt                 0x05
+#  define MIPS_LUXC1                   0x05
+#  define MIPS_MOV_fmt                 0x06
+#  define MIPS_NEG_fmt                 0x07
+#  define MIPS_SWXC1                   0x08
+#  define MIPS_ROUND_fmt_L             0x08
+#  define MIPS_TRUNC_fmt_L             0x09
+#  define MIPS_SDXC1                   0x09
+#  define MIPS_CEIL_fmt_L              0x0a
+#  define MIPS_FLOOR_fmt_L             0x0b
+#  define MIPS_ROUND_fmt_W             0x0c
+#  define MIPS_TRUNC_fmt_W             0x0d
+#  define MIPS_SUXC1                   0x0d
+#  define MIPS_CEIL_fmt_W              0x0e
+#  define MIPS_FLOOR_fmt_W             0x0f
+#  define MIPS_RECIP                   0x15
+#  define MIPS_RSQRT                   0x16
+#  define MIPS_ALNV_PS                 0x1e
+#  define MIPS_CVT_fmt_S               0x20
+#  define MIPS_CVT_fmt_D               0x21
+#  define MIPS_CVT_fmt_W               0x24
+#  define MIPS_CVT_fmt_L               0x25
+#  define MIPS_PLL                     0x2c
+#  define MIPS_PLU                     0x2d
+#  define MIPS_PUL                     0x2e
+#  define MIPS_PUU                     0x2f
+#  define MIPS_MADD_fmt_S              (0x20 | MIPS_fmt_S)
+#  define MIPS_MADD_fmt_D              (0x20 | MIPS_fmt_D)
+#  define MIPS_MADD_fmt_PS             (0x20 | MIPS_fmt_PS)
+#  define MIPS_MSUB_fmt_S              (0x28 | MIPS_fmt_S)
+#  define MIPS_MSUB_fmt_D              (0x28 | MIPS_fmt_D)
+#  define MIPS_MSUB_fmt_PS             (0x28 | MIPS_fmt_PS)
+#  define MIPS_NMADD_fmt_S             (0x30 | MIPS_fmt_S)
+#  define MIPS_NMADD_fmt_D             (0x30 | MIPS_fmt_D)
+#  define MIPS_NMADD_fmt_PS            (0x30 | MIPS_fmt_PS)
+#  define MIPS_NMSUB_fmt_S             (0x38 | MIPS_fmt_S)
+#  define MIPS_NMSUB_fmt_D             (0x38 | MIPS_fmt_D)
+#  define MIPS_NMSUB_fmt_PS            (0x38 | MIPS_fmt_PS)
+#  define MIPS_cond_F                  0x30
+#  define MIPS_cond_UN                 0x31
+#  define MIPS_cond_EQ                 0x32
+#  define MIPS_cond_UEQ                        0x33
+#  define MIPS_cond_OLT                        0x34
+#  define MIPS_cond_ULT                        0x35
+#  define MIPS_cond_OLE                        0x36
+#  define MIPS_cond_ULE                        0x37
+#  define MIPS_cond_SF                 0x38
+#  define MIPS_cond_NGLE               0x39
+#  define MIPS_cond_SEQ                        0x3a
+#  define MIPS_cond_NGL                        0x3b
+#  define MIPS_cond_LT                 0x3c
+#  define MIPS_cond_NGE                        0x3d
+#  define MIPS_cond_LE                 0x3e
+#  define MIPS_cond_UGT                        0x3f
+#  define ADD_S(fd,fs,ft)              hrrrit(MIPS_COP1,MIPS_fmt_S,ft,fs,fd,MIPS_ADD_fmt)
+#  define ADD_D(fd,fs,ft)              hrrrit(MIPS_COP1,MIPS_fmt_D,ft,fs,fd,MIPS_ADD_fmt)
+#  define SUB_S(fd,fs,ft)              hrrrit(MIPS_COP1,MIPS_fmt_S,ft,fs,fd,MIPS_SUB_fmt)
+#  define SUB_D(fd,fs,ft)              hrrrit(MIPS_COP1,MIPS_fmt_D,ft,fs,fd,MIPS_SUB_fmt)
+#  define MUL_S(fd,fs,ft)              hrrrit(MIPS_COP1,MIPS_fmt_S,ft,fs,fd,MIPS_MUL_fmt)
+#  define MUL_D(fd,fs,ft)              hrrrit(MIPS_COP1,MIPS_fmt_D,ft,fs,fd,MIPS_MUL_fmt)
+#  define DIV_S(fd,fs,ft)              hrrrit(MIPS_COP1,MIPS_fmt_S,ft,fs,fd,MIPS_DIV_fmt)
+#  define DIV_D(fd,fs,ft)              hrrrit(MIPS_COP1,MIPS_fmt_D,ft,fs,fd,MIPS_DIV_fmt)
+#  define ABS_S(fd,fs)                 hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_ABS_fmt)
+#  define ABS_D(fd,fs)                 hrrrit(MIPS_COP1,MIPS_fmt_D,0,fs,fd,MIPS_ABS_fmt)
+#  define NEG_S(fd,fs)                 hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_NEG_fmt)
+#  define NEG_D(fd,fs)                 hrrrit(MIPS_COP1,MIPS_fmt_D,0,fs,fd,MIPS_NEG_fmt)
+#  define SQRT_S(fd,fs)                        hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_SQRT_fmt)
+#  define SQRT_D(fd,fs)                        hrrrit(MIPS_COP1,MIPS_fmt_D,0,fs,fd,MIPS_SQRT_fmt)
+#  define MFC1(rt, fs)                 hrrrit(MIPS_COP1,MIPS_MF,rt,fs,0,0)
+#  define MTC1(rt, fs)                 hrrrit(MIPS_COP1,MIPS_MT,rt,fs,0,0)
+#  define DMFC1(rt, fs)                        hrrrit(MIPS_COP1,MIPS_DMF,rt,fs,0,0)
+#  define DMTC1(rt, fs)                        hrrrit(MIPS_COP1,MIPS_DMT,rt,fs,0,0)
+#  define CVT_D_S(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_CVT_fmt_D)
+#  define CVT_D_W(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_W,0,fs,fd,MIPS_CVT_fmt_D)
+#  define CVT_D_L(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_L,0,fs,fd,MIPS_CVT_fmt_D)
+#  define CVT_L_S(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_CVT_fmt_L)
+#  define CVT_L_D(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_D,0,fs,fd,MIPS_CVT_fmt_L)
+#  define CVT_PS_S(fd,fs)              hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_CVT_fmt_PS)
+#  define CVT_S_D(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_D,0,fs,fd,MIPS_CVT_fmt_S)
+#  define CVT_S_W(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_W,0,fs,fd,MIPS_CVT_fmt_S)
+#  define CVT_S_L(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_L,0,fs,fd,MIPS_CVT_fmt_S)
+#  define CVT_S_PL(fd,fs)              hrrrit(MIPS_COP1,MIPS_fmt_PS,0,fs,fd,MIPS_CVT_fmt_S_PL)
+#  define CVT_S_PU(fd,fs)              hrrrit(MIPS_COP1,MIPS_fmt_PS,0,fs,fd,MIPS_CVT_fmt_S_PU)
+#  define CVT_W_S(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_CVT_fmt_W)
+#  define CVT_W_D(fd,fs)               hrrrit(MIPS_COP1,MIPS_fmt_D,0,fs,fd,MIPS_CVT_fmt_W)
+#  define TRUNC_L_S(fd,fs)             hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_TRUNC_fmt_L)
+#  define TRUNC_L_D(fd,fs)             hrrrit(MIPS_COP1,MIPS_fmt_D,0,fs,fd,MIPS_TRUNC_fmt_L)
+#  define TRUNC_W_S(fd,fs)             hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_TRUNC_fmt_W)
+#  define TRUNC_W_D(fd,fs)             hrrrit(MIPS_COP1,MIPS_fmt_D,0,fs,fd,MIPS_TRUNC_fmt_W)
+#  define LWC1(rt, of, rb)             hrri(MIPS_LWC1, rb, rt, of)
+#  define SWC1(rt, of, rb)             hrri(MIPS_SWC1, rb, rt, of)
+#  define LDC1(rt, of, rb)             hrri(MIPS_LDC1, rb, rt, of)
+#  define SDC1(rt, of, rb)             hrri(MIPS_SDC1, rb, rt, of)
+#  define MOV_S(fd, fs)                        hrrrit(MIPS_COP1,MIPS_fmt_S,0,fs,fd,MIPS_MOV_fmt)
+#  define MOV_D(fd, fs)                        hrrrit(MIPS_COP1,MIPS_fmt_D,0,fs,fd,MIPS_MOV_fmt)
+#  define BC1F(im)                     hrri(MIPS_COP1,MIPS_BC,MIPS_BCF,im)
+#  define BC1T(im)                     hrri(MIPS_COP1,MIPS_BC,MIPS_BCT,im)
+#  define C_F_S(fs,ft)                 c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_F)
+#  define C_F_D(fs,ft)                 c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_F)
+#  define C_F_PS(fs,ft)                        c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_F)
+#  define C_UN_S(fs,ft)                        c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_UN)
+#  define C_UN_D(fs,ft)                        c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_UN)
+#  define C_UN_PS(fs,ft)               c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_UN)
+#  define C_EQ_S(fs,ft)                        c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_EQ)
+#  define C_EQ_D(fs,ft)                        c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_EQ)
+#  define C_EQ_PS(fs,ft)               c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_EQ)
+#  define C_UEQ_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_UEQ)
+#  define C_UEQ_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_UEQ)
+#  define C_UEQ_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_UEQ)
+#  define C_OLT_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_OLT)
+#  define C_OLT_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_OLT)
+#  define C_OLT_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_OLT)
+#  define C_ULT_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_ULT)
+#  define C_ULT_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_ULT)
+#  define C_ULT_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_ULT)
+#  define C_OLE_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_OLE)
+#  define C_OLE_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_OLE)
+#  define C_OLE_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_OLE)
+#  define C_ULE_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_ULE)
+#  define C_ULE_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_ULE)
+#  define C_ULE_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_ULE)
+#  define C_SF_S(fs,ft)                        c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_SF)
+#  define C_SF_D(fs,ft)                        c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_SF)
+#  define C_SF_PS(fs,ft)               c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_SF)
+#  define C_NGLE_S(fs,ft)              c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_NGLE)
+#  define C_NGLE_D(fs,ft)              c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_NGLE)
+#  define C_NGLE_PS(fs,ft)             c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_NGLE)
+#  define C_SEQ_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_SEQ)
+#  define C_SEQ_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_SEQ)
+#  define C_SEQ_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_SEQ)
+#  define C_NGL_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_NGL)
+#  define C_NGL_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_NGL)
+#  define C_NGL_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_NGL)
+#  define C_NLT_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_NLT)
+#  define C_NLT_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_NLT)
+#  define C_NLT_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_NLT)
+#  define C_NGE_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_NGE)
+#  define C_NGE_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_NGE)
+#  define C_NGE_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_NGE)
+#  define C_NLE_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_NLE)
+#  define C_NLE_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_NLE)
+#  define C_NLE_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_NLE)
+#  define C_UGT_S(fs,ft)               c_cond_fmt(MIPS_fmt_S,ft,fs,MIPS_cond_UGT)
+#  define C_UGT_D(fs,ft)               c_cond_fmt(MIPS_fmt_D,ft,fs,MIPS_cond_UGT)
+#  define C_UGT_PS(fs,ft)              c_cond_fmt(MIPS_fmt_PS,ft,fs,MIPS_cond_UGT)
+#  define c_cond_fmt(fm,ft,fs,cc)      _c_cond_fmt(_jit,fm,ft,fs,cc)
+static void
+_c_cond_fmt(jit_state_t *_jit, jit_int32_t fm,
+           jit_int32_t ft, jit_int32_t fs, jit_int32_t cc);
+#  define addr_f(r0,r1,r2)             ADD_S(r0,r1,r2)
+#  define addi_f(r0,r1,i0)             _addi_f(_jit,r0,r1,i0)
+static void _addi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define addr_d(r0,r1,r2)             ADD_D(r0,r1,r2)
+#  define addi_d(r0,r1,i0)             _addi_d(_jit,r0,r1,i0)
+static void _addi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define subr_f(r0,r1,r2)             SUB_S(r0,r1,r2)
+#  define subi_f(r0,r1,i0)             _subi_f(_jit,r0,r1,i0)
+static void _subi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define subr_d(r0,r1,r2)             SUB_D(r0,r1,r2)
+#  define subi_d(r0,r1,i0)             _subi_d(_jit,r0,r1,i0)
+static void _subi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define rsbr_f(r0,r1,r2)             subr_f(r0,r2,r1)
+#  define rsbi_f(r0,r1,i0)             _rsbi_f(_jit,r0,r1,i0)
+static void _rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define rsbr_d(r0,r1,r2)             subr_d(r0,r2,r1)
+#  define rsbi_d(r0,r1,i0)             _rsbi_d(_jit,r0,r1,i0)
+static void _rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define mulr_f(r0,r1,r2)             MUL_S(r0,r1,r2)
+#  define muli_f(r0,r1,i0)             _muli_f(_jit,r0,r1,i0)
+static void _muli_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define mulr_d(r0,r1,r2)             MUL_D(r0,r1,r2)
+#  define muli_d(r0,r1,i0)             _muli_d(_jit,r0,r1,i0)
+static void _muli_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define divr_f(r0,r1,r2)             DIV_S(r0,r1,r2)
+#  define divi_f(r0,r1,i0)             _divi_f(_jit,r0,r1,i0)
+static void _divi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define divr_d(r0,r1,r2)             DIV_D(r0,r1,r2)
+#  define divi_d(r0,r1,i0)             _divi_d(_jit,r0,r1,i0)
+static void _divi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define absr_f(r0,r1)                        ABS_S(r0,r1)
+#  define absr_d(r0,r1)                        ABS_D(r0,r1)
+#  define negr_f(r0,r1)                        NEG_S(r0,r1)
+#  define negr_d(r0,r1)                        NEG_D(r0,r1)
+#  define sqrtr_f(r0,r1)               SQRT_S(r0,r1)
+#  define sqrtr_d(r0,r1)               SQRT_D(r0,r1)
+#  define movr_w_f(r0, r1)             MTC1(r1, r0)
+#  define movr_f_w(r0, r1)             MFC1(r1, r0)
+#  define movi_f_w(r0, i0)             _movi_f_w(_jit, r0, i0)
+static void _movi_f_w(jit_state_t*,jit_int32_t,jit_float32_t*);
+#  define extr_f(r0, r1)               _extr_f(_jit, r0, r1)
+static void _extr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define truncr_f_i(r0, r1)           _truncr_f_i(_jit, r0, r1)
+static void _truncr_f_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#    define truncr_f_l(r0, r1)         _truncr_f_l(_jit, r0, r1)
+static void _truncr_f_l(jit_state_t*,jit_int32_t,jit_int32_t);
+#  endif
+#  define extr_d_f(r0, r1)             CVT_S_D(r0, r1)
+#  define ldr_f(r0, r1)                        LWC1(r0, 0, r1)
+#  define ldi_f(r0, i0)                        _ldi_f(_jit, r0, i0)
+static void _ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_f(r0, r1, r2)           _ldxr_f(_jit, r0, r1, r2)
+static void _ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_f(r0, r1, i0)           _ldxi_f(_jit, r0, r1, i0)
+static void _ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_f(r0, r1)                        SWC1(r1, 0, r0)
+#  define sti_f(i0, r0)                        _sti_f(_jit, i0, r0)
+static void _sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_f(r0, r1, r2)           _stxr_f(_jit, r0, r1, r2)
+static void _stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_f(i0, r0, r1)           _stxi_f(_jit, i0, r0, r1)
+static void _stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define movr_f(r0, r1)               _movr_f(_jit, r0, r1)
+static void _movr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi_f(r0, i0)               _movi_f(_jit, r0, i0)
+static void _movi_f(jit_state_t*,jit_int32_t,jit_float32_t*);
+#  if NEW_ABI
+#    if __WORDSIZE == 32
+#      define movi64(r0, i0)           _movi64(_jit, r0, i0)
+static void _movi64(jit_state_t*,jit_int32_t,jit_int64_t);
+#    else
+#      define movi64(r0, i0)           movi(r0, i0)
+#    endif
+#    define movr_w_d(r0, r1)           DMTC1(r1, r0)
+#    define movr_d_w(r0, r1)           DMFC1(r0, r1)
+#    define movi_d_w(r0, i0)           _movi_d_w(_jit,r0,i0)
+static void _movi_d_w(jit_state_t*,jit_int32_t,jit_float64_t*);
+#  else
+#    define movr_ww_d(r0, r1, r2)      _movr_ww_d(_jit, r0, r1, r2)
+static void _movr_ww_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define movr_d_ww(r0, r1, r2)      _movr_d_ww(_jit, r0, r1, r2)
+static void _movr_d_ww(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define movi_d_ww(r0, r1, i0)      _movi_d_ww(_jit, r0, r1, i0)
+static void _movi_d_ww(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  endif
+#  define extr_d(r0, r1)               _extr_d(_jit, r0, r1)
+static void _extr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define truncr_d_i(r0, r1)           _truncr_d_i(_jit, r0, r1)
+static void _truncr_d_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#    define truncr_d_l(r0, r1)         _truncr_d_l(_jit, r0, r1)
+static void _truncr_d_l(jit_state_t*,jit_int32_t,jit_int32_t);
+#  endif
+#  define ldr_d(r0, r1)                        _ldr_d(_jit, r0, r1)
+static void _ldr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_d(r0, i0)                        _ldi_d(_jit, r0, i0)
+static void _ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_d(r0, r1, r2)           _ldxr_d(_jit, r0, r1, r2)
+static void _ldxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_d(r0, r1, i0)           _ldxi_d(_jit, r0, r1, i0)
+static void _ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_d(r0, r1)                        _str_d(_jit, r0, r1)
+static void _str_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sti_d(i0, r0)                        _sti_d(_jit, i0, r0)
+static void _sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_d(r0, r1, r2)           _stxr_d(_jit, r0, r1, r2)
+static void _stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_d(i0, r0, r1)           _stxi_d(_jit, i0, r0, r1)
+static void _stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define movr_d(r0, r1)               _movr_d(_jit, r0, r1)
+static void _movr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi_d(r0, i0)               _movi_d(_jit, r0, i0)
+static void _movi_d(jit_state_t*,jit_int32_t,jit_float64_t*);
+#  define ltr_f(r0, r1, r2)            _ltr_f(_jit, r0, r1, r2)
+static void _ltr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lti_f(r0, r1, i2)            _lti_f(_jit, r0, r1, i2)
+static void _lti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ler_f(r0, r1, r2)            _ler_f(_jit, r0, r1, r2)
+static void _ler_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lei_f(r0, r1, i2)            _lei_f(_jit, r0, r1, i2)
+static void _lei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define eqr_f(r0, r1, r2)            _eqr_f(_jit, r0, r1, r2)
+static void _eqr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define eqi_f(r0, r1, i2)            _eqi_f(_jit, r0, r1, i2)
+static void _eqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ger_f(r0, r1, r2)            _ger_f(_jit, r0, r1, r2)
+static void _ger_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gei_f(r0, r1, i2)            _gei_f(_jit, r0, r1, i2)
+static void _gei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define gtr_f(r0, r1, r2)            _gtr_f(_jit, r0, r1, r2)
+static void _gtr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gti_f(r0, r1, i2)            _gti_f(_jit, r0, r1, i2)
+static void _gti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ner_f(r0, r1, r2)            _ner_f(_jit, r0, r1, r2)
+static void _ner_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nei_f(r0, r1, i2)            _nei_f(_jit, r0, r1, i2)
+static void _nei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unltr_f(r0, r1, r2)          _unltr_f(_jit, r0, r1, r2)
+static void _unltr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unlti_f(r0, r1, i2)          _unlti_f(_jit, r0, r1, i2)
+static void _unlti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unler_f(r0, r1, r2)          _unler_f(_jit, r0, r1, r2)
+static void _unler_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unlei_f(r0, r1, i2)          _unlei_f(_jit, r0, r1, i2)
+static void _unlei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define uneqr_f(r0, r1, r2)          _uneqr_f(_jit, r0, r1, r2)
+static void _uneqr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define uneqi_f(r0, r1, i2)          _uneqi_f(_jit, r0, r1, i2)
+static void _uneqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unger_f(r0, r1, r2)          _unger_f(_jit, r0, r1, r2)
+static void _unger_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ungei_f(r0, r1, i2)          _ungei_f(_jit, r0, r1, i2)
+static void _ungei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ungtr_f(r0, r1, r2)          _ungtr_f(_jit, r0, r1, r2)
+static void _ungtr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ungti_f(r0, r1, i2)          _ungti_f(_jit, r0, r1, i2)
+static void _ungti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ltgtr_f(r0, r1, r2)          _ltgtr_f(_jit, r0, r1, r2)
+static void _ltgtr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ltgti_f(r0, r1, i2)          _ltgti_f(_jit, r0, r1, i2)
+static void _ltgti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ordr_f(r0, r1, r2)           _ordr_f(_jit, r0, r1, r2)
+static void _ordr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ordi_f(r0, r1, i2)           _ordi_f(_jit, r0, r1, i2)
+static void _ordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unordr_f(r0, r1, r2)         _unordr_f(_jit, r0, r1, r2)
+static void _unordr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unordi_f(r0, r1, i2)         _unordi_f(_jit, r0, r1, i2)
+static void _unordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define bltr_f(i0, r0, r1)           _bltr_f(_jit, i0, r0, r1)
+static jit_word_t _bltr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti_f(i0, r0, i1)           _blti_f(_jit, i0, r0, i1)
+static jit_word_t
+_blti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bler_f(i0, r0, r1)           _bler_f(_jit, i0, r0, r1)
+static jit_word_t _bler_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei_f(i0, r0, i1)           _blei_f(_jit, i0, r0, i1)
+static jit_word_t
+_blei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define beqr_f(i0, r0, r1)           _beqr_f(_jit, i0, r0, r1)
+static jit_word_t _beqr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define beqi_f(i0, r0, i1)           _beqi_f(_jit, i0, r0, i1)
+static jit_word_t
+_beqi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bger_f(i0, r0, r1)           _bger_f(_jit, i0, r0, r1)
+static jit_word_t _bger_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei_f(i0, r0, i1)           _bgei_f(_jit, i0, r0, i1)
+static jit_word_t
+_bgei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bgtr_f(i0, r0, r1)           _bgtr_f(_jit, i0, r0, r1)
+static jit_word_t _bgtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti_f(i0, r0, i1)           _bgti_f(_jit, i0, r0, i1)
+static jit_word_t
+_bgti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bner_f(i0, r0, r1)           _bner_f(_jit, i0, r0, r1)
+static jit_word_t _bner_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bnei_f(i0, r0, i1)           _bnei_f(_jit, i0, r0, i1)
+static jit_word_t
+_bnei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bunltr_f(i0, r0, r1)         _bunltr_f(_jit, i0, r0, r1)
+static jit_word_t _bunltr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlti_f(i0, r0, i1)         _bunlti_f(_jit, i0, r0, i1)
+static jit_word_t
+_bunlti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bunler_f(i0, r0, r1)         _bunler_f(_jit, i0, r0, r1)
+static jit_word_t _bunler_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlei_f(i0, r0, i1)         _bunlei_f(_jit, i0, r0, i1)
+static jit_word_t
+_bunlei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define buneqr_f(i0, r0, r1)         _buneqr_f(_jit, i0, r0, r1)
+static jit_word_t _buneqr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define buneqi_f(i0, r0, i1)         _buneqi_f(_jit, i0, r0, i1)
+static jit_word_t
+_buneqi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bunger_f(i0, r0, r1)         _bunger_f(_jit, i0, r0, r1)
+static jit_word_t _bunger_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungei_f(i0, r0, i1)         _bungei_f(_jit, i0, r0, i1)
+static jit_word_t
+_bungei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bungtr_f(i0, r0, r1)         _bungtr_f(_jit, i0, r0, r1)
+static jit_word_t _bungtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungti_f(i0, r0, i1)         _bungti_f(_jit, i0, r0, i1)
+static jit_word_t
+_bungti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bltgtr_f(i0, r0, r1)         _bltgtr_f(_jit, i0, r0, r1)
+static jit_word_t _bltgtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bltgti_f(i0, r0, i1)         _bltgti_f(_jit, i0, r0, i1)
+static jit_word_t
+_bltgti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bordr_f(i0, r0, r1)          _bordr_f(_jit, i0, r0, r1)
+static jit_word_t _bordr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bordi_f(i0, r0, i1)          _bordi_f(_jit, i0, r0, i1)
+static jit_word_t
+_bordi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define bunordr_f(i0, r0, r1)                _bunordr_f(_jit, i0, r0, r1)
+static jit_word_t _bunordr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunordi_f(i0, r0, i1)                _bunordi_f(_jit, i0, r0, i1)
+static jit_word_t
+_bunordi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define extr_f_d(r0, r1)             CVT_D_S(r0, r1)
+#  define ltr_d(r0, r1, r2)            _ltr_d(_jit, r0, r1, r2)
+static void _ltr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lti_d(r0, r1, i2)            _lti_d(_jit, r0, r1, i2)
+static void _lti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ler_d(r0, r1, r2)            _ler_d(_jit, r0, r1, r2)
+static void _ler_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lei_d(r0, r1, i2)            _lei_d(_jit, r0, r1, i2)
+static void _lei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define eqr_d(r0, r1, r2)            _eqr_d(_jit, r0, r1, r2)
+static void _eqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define eqi_d(r0, r1, i2)            _eqi_d(_jit, r0, r1, i2)
+static void _eqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ger_d(r0, r1, r2)            _ger_d(_jit, r0, r1, r2)
+static void _ger_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gei_d(r0, r1, i2)            _gei_d(_jit, r0, r1, i2)
+static void _gei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define gtr_d(r0, r1, r2)            _gtr_d(_jit, r0, r1, r2)
+static void _gtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gti_d(r0, r1, i2)            _gti_d(_jit, r0, r1, i2)
+static void _gti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ner_d(r0, r1, r2)            _ner_d(_jit, r0, r1, r2)
+static void _ner_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nei_d(r0, r1, i2)            _nei_d(_jit, r0, r1, i2)
+static void _nei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unltr_d(r0, r1, r2)          _unltr_d(_jit, r0, r1, r2)
+static void _unltr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unlti_d(r0, r1, i2)          _unlti_d(_jit, r0, r1, i2)
+static void _unlti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unler_d(r0, r1, r2)          _unler_d(_jit, r0, r1, r2)
+static void _unler_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unlei_d(r0, r1, i2)          _unlei_d(_jit, r0, r1, i2)
+static void _unlei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define uneqr_d(r0, r1, r2)          _uneqr_d(_jit, r0, r1, r2)
+static void _uneqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define uneqi_d(r0, r1, i2)          _uneqi_d(_jit, r0, r1, i2)
+static void _uneqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unger_d(r0, r1, r2)          _unger_d(_jit, r0, r1, r2)
+static void _unger_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ungei_d(r0, r1, i2)          _ungei_d(_jit, r0, r1, i2)
+static void _ungei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ungtr_d(r0, r1, r2)          _ungtr_d(_jit, r0, r1, r2)
+static void _ungtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ungti_d(r0, r1, i2)          _ungti_d(_jit, r0, r1, i2)
+static void _ungti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ltgtr_d(r0, r1, r2)          _ltgtr_d(_jit, r0, r1, r2)
+static void _ltgtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ltgti_d(r0, r1, i2)          _ltgti_d(_jit, r0, r1, i2)
+static void _ltgti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ordr_d(r0, r1, r2)           _ordr_d(_jit, r0, r1, r2)
+static void _ordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ordi_d(r0, r1, i2)           _ordi_d(_jit, r0, r1, i2)
+static void _ordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unordr_d(r0, r1, r2)         _unordr_d(_jit, r0, r1, r2)
+static void _unordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unordi_d(r0, r1, i2)         _unordi_d(_jit, r0, r1, i2)
+static void _unordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define bltr_d(i0, r0, r1)           _bltr_d(_jit, i0, r0, r1)
+static jit_word_t _bltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti_d(i0, r0, i1)           _blti_d(_jit, i0, r0, i1)
+static jit_word_t
+_blti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bler_d(i0, r0, r1)           _bler_d(_jit, i0, r0, r1)
+static jit_word_t _bler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei_d(i0, r0, i1)           _blei_d(_jit, i0, r0, i1)
+static jit_word_t
+_blei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define beqr_d(i0, r0, r1)           _beqr_d(_jit, i0, r0, r1)
+static jit_word_t _beqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define beqi_d(i0, r0, i1)           _beqi_d(_jit, i0, r0, i1)
+static jit_word_t
+_beqi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bger_d(i0, r0, r1)           _bger_d(_jit, i0, r0, r1)
+static jit_word_t _bger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei_d(i0, r0, i1)           _bgei_d(_jit, i0, r0, i1)
+static jit_word_t
+_bgei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bgtr_d(i0, r0, r1)           _bgtr_d(_jit, i0, r0, r1)
+static jit_word_t _bgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti_d(i0, r0, i1)           _bgti_d(_jit, i0, r0, i1)
+static jit_word_t
+_bgti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bner_d(i0, r0, r1)           _bner_d(_jit, i0, r0, r1)
+static jit_word_t _bner_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bnei_d(i0, r0, i1)           _bnei_d(_jit, i0, r0, i1)
+static jit_word_t
+_bnei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bunltr_d(i0, r0, r1)         _bunltr_d(_jit, i0, r0, r1)
+static jit_word_t _bunltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlti_d(i0, r0, i1)         _bunlti_d(_jit, i0, r0, i1)
+static jit_word_t
+_bunlti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bunler_d(i0, r0, r1)         _bunler_d(_jit, i0, r0, r1)
+static jit_word_t _bunler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlei_d(i0, r0, i1)         _bunlei_d(_jit, i0, r0, i1)
+static jit_word_t
+_bunlei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define buneqr_d(i0, r0, r1)         _buneqr_d(_jit, i0, r0, r1)
+static jit_word_t _buneqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define buneqi_d(i0, r0, i1)         _buneqi_d(_jit, i0, r0, i1)
+static jit_word_t
+_buneqi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bunger_d(i0, r0, r1)         _bunger_d(_jit, i0, r0, r1)
+static jit_word_t _bunger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungei_d(i0, r0, i1)         _bungei_d(_jit, i0, r0, i1)
+static jit_word_t
+_bungei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bungtr_d(i0, r0, r1)         _bungtr_d(_jit, i0, r0, r1)
+static jit_word_t _bungtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungti_d(i0, r0, i1)         _bungti_d(_jit, i0, r0, i1)
+static jit_word_t
+_bungti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bltgtr_d(i0, r0, r1)         _bltgtr_d(_jit, i0, r0, r1)
+static jit_word_t _bltgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bltgti_d(i0, r0, i1)         _bltgti_d(_jit, i0, r0, i1)
+static jit_word_t
+_bltgti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bordr_d(i0, r0, r1)          _bordr_d(_jit, i0, r0, r1)
+static jit_word_t _bordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bordi_d(i0, r0, i1)          _bordi_d(_jit, i0, r0, i1)
+static jit_word_t
+_bordi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define bunordr_d(i0, r0, r1)                _bunordr_d(_jit, i0, r0, r1)
+static jit_word_t _bunordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunordi_d(i0, r0, i1)                _bunordi_d(_jit, i0, r0, i1)
+static jit_word_t
+_bunordi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define vaarg_d(r0, r1)              _vaarg_d(_jit, r0, r1)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif
+
+#if CODE
+static void
+_c_cond_fmt(jit_state_t *_jit, jit_int32_t fm,
+           jit_int32_t ft, jit_int32_t fs, jit_int32_t cc)
+{
+    jit_instr_t                i;
+    i.cc.b = cc;
+    i.fs.b = fs;
+    i.ft.b = ft;
+    i.fm.b = fm;
+    i.hc.b = MIPS_COP1;
+    ii(i.op);
+}
+
+#  define fpr_opi(name, type, size)                                    \
+static void                                                            \
+_##name##i_##type(jit_state_t *_jit,                                   \
+                 jit_int32_t r0, jit_int32_t r1,                       \
+                 jit_float##size##_t *i0)                              \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    movi_##type(rn(reg), i0);                                          \
+    name##r_##type(r0, r1, rn(reg));                                   \
+    jit_unget_reg(reg);                                                        \
+}
+#  define fpr_bopi(name, type, size)                                   \
+static jit_word_t                                                      \
+_b##name##i_##type(jit_state_t *_jit,                                  \
+                 jit_word_t i0, jit_int32_t r0,                        \
+                 jit_float##size##_t *i1)                              \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|                \
+                                         jit_class_nospill);           \
+    movi_##type(rn(reg), i1);                                          \
+    word = b##name##r_##type(i0, r0, rn(reg));                         \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+#  define fopi(name)                   fpr_opi(name, f, 32)
+#  define fbopi(name)                  fpr_bopi(name, f, 32)
+#  define dopi(name)                   fpr_opi(name, d, 64)
+#  define dbopi(name)                  fpr_bopi(name, d, 64)
+
+fopi(add)
+fopi(sub)
+fopi(rsb)
+fopi(mul)
+fopi(div)
+
+static void
+_movi_f_w(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+
+    data.f = *i0;
+    movi(r0, data.i);
+}
+
+static void
+_extr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_fpr);
+#  if __WORDSIZE == 32
+    MTC1(r1, rn(t0));
+    CVT_S_W(r0, rn(t0));
+#  else
+    DMTC1(r1, rn(t0));
+    CVT_S_L(r0, rn(t0));
+#  endif
+    jit_unget_reg(t0);
+}
+
+static void
+_truncr_f_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_fpr);
+    TRUNC_W_S(rn(t0), r1);
+    MFC1(r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+#  if __WORDSIZE == 64
+static void
+_truncr_f_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_fpr);
+    TRUNC_L_S(rn(t0), r1);
+    DMFC1(r0, rn(t0));
+    jit_unget_reg(t0);
+}
+#  endif
+
+static void
+_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LWC1(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_f(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       LWC1(r0, i0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SWC1(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_f(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_f(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       SWC1(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_f(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_movr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       MOV_S(r0, r1);
+}
+
+static void
+_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+    jit_int32_t                reg;
+
+    data.f = *i0;
+    if (data.i) {
+       if (_jitc->no_data) {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), data.i);
+           MTC1(rn(reg), r0);
+           jit_unget_reg(reg);
+       }
+       else
+           ldi_f(r0, (jit_word_t)i0);
+    }
+    else
+       MTC1(_ZERO_REGNO, r0);
+}
+
+dopi(add)
+dopi(sub)
+dopi(rsb)
+dopi(mul)
+dopi(div)
+
+#if NEW_ABI
+/* n32 abi requires 64 bit cpu */
+static void
+_movi64(jit_state_t *_jit, jit_int32_t r0, jit_int64_t i0)
+{
+    if (i0 == 0)
+       OR(r0, _ZERO_REGNO, _ZERO_REGNO);
+    else if (i0 >= -32678 && i0 <= 32767)
+       DADDIU(r0, _ZERO_REGNO, i0);
+    else if (i0 >= 0 && i0 <= 65535)
+       ORI(r0, _ZERO_REGNO, i0);
+    else {
+       if (i0 >= 0 && i0 <= 0x7fffffffLL)
+           LUI(r0, i0 >> 16);
+       else if (i0 >= 0 && i0 <= 0xffffffffLL) {
+           if (i0 & 0xffff0000LL) {
+               ORI(r0, _ZERO_REGNO, (jit_word_t)(i0 >> 16));
+               DSLL(r0, r0, 16);
+           }
+       }
+       else {
+           movi(r0, (jit_word_t)(i0 >> 32));
+           if (i0 & 0xffff0000LL) {
+               DSLL(r0, r0, 16);
+               ORI(r0, r0, (jit_word_t)(i0 >> 16));
+               DSLL(r0, r0, 16);
+           }
+           else
+               DSLL32(r0, r0, 0);
+       }
+       if ((jit_word_t)i0 & 0xffff)
+           ORI(r0, r0, (jit_word_t)i0 & 0xffff);
+    }
+}
+
+static void
+_movi_d_w(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    jit_word_t         w;
+    union {
+       jit_int64_t     l;
+       jit_float64_t   d;
+    } data;
+    if (_jitc->no_data) {
+       data.d = *i0;
+       movi64(r0, data.l);
+    }
+    else {
+       w = (jit_word_t)i0;
+       if (can_sign_extend_short_p(w))
+           LD(r0, w, _ZERO_REGNO);
+       else {
+           movi(r0, w);
+           LD(r0, 0, r0);
+       }
+    }
+}
+
+#else
+static void
+_movr_ww_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    assert(r1 == r2 - 1);
+    MTC1(r1, r0 + BE_P);
+    MTC1(r2, r0 + LE_P);
+}
+
+static void
+_movr_d_ww(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    assert(r0 == r1 - 1);
+    MFC1(r0, r2 + BE_P);
+    MFC1(r1, r2 + LE_P);
+}
+
+static void
+_movi_d_ww(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_float64_t *i0)
+{
+    union {
+       jit_int32_t     i[2];
+       jit_int64_t     l;
+       jit_float64_t   d;
+    } data;
+
+    data.d = *i0;
+    movi(r0, data.i[0]);
+    movi(r1, data.i[1]);
+}
+#endif
+
+static void
+_extr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_fpr);
+#  if __WORDSIZE == 32
+    MTC1(r1, rn(t0));
+    CVT_D_W(r0, rn(t0));
+#  else
+    DMTC1(r1, rn(t0));
+    CVT_D_L(r0, rn(t0));
+#  endif
+    jit_unget_reg(t0);
+}
+
+static void
+_truncr_d_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_fpr);
+    TRUNC_W_D(rn(t0), r1);
+    MFC1(r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+#  if __WORDSIZE == 64
+static void
+_truncr_d_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_fpr);
+    TRUNC_L_D(rn(t0), r1);
+    DMFC1(r0, rn(t0));
+    jit_unget_reg(t0);
+}
+#  endif
+
+static void
+_ldr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#  if __WORDSIZE == 64 || NEW_ABI
+    LDC1(r0, 0, r1);
+#  else
+    LWC1(r0 + BE_P, 0, r1);
+    LWC1(r0 + LE_P, 4, r1);
+#  endif
+}
+
+static void
+_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+#  if __WORDSIZE == 64 || NEW_ABI
+    if (can_sign_extend_short_p(i0))
+       LDC1(r0, i0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       LDC1(r0, 0, rn(reg));
+       jit_unget_reg(reg);
+    }
+#  else
+    if (can_sign_extend_short_p(i0) && can_sign_extend_short_p(i0 + 4)) {
+       LWC1(r0 + BE_P, i0, _ZERO_REGNO);
+       LWC1(r0 + LE_P, i0 + 4, _ZERO_REGNO);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       LWC1(r0 + BE_P, 0, rn(reg));
+       LWC1(r0 + LE_P, 4, rn(reg));
+       jit_unget_reg(reg);
+    }
+#  endif
+}
+
+static void
+_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    ldr_d(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+#  if __WORDSIZE == 64 || NEW_ABI
+    if (can_sign_extend_short_p(i0))
+       LDC1(r0, i0, r1);
+#  else
+    if (can_sign_extend_short_p(i0) && can_sign_extend_short_p(i0 + 4)) {
+       LWC1(r0 + BE_P, i0, r1);
+       LWC1(r0 + LE_P, i0 + 4, r1);
+    }
+#  endif
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ldr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_str_d(jit_state_t *_jit,jit_int32_t r0, jit_int32_t r1)
+{
+#  if __WORDSIZE == 64 || NEW_ABI
+    SDC1(r1, 0, r0);
+#  else
+    SWC1(r1 + BE_P, 0, r0);
+    SWC1(r1 + LE_P, 4, r0);
+#  endif
+}
+
+static void
+_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+#  if __WORDSIZE == 64 || NEW_ABI
+    if (can_sign_extend_short_p(i0))
+       SDC1(r0, i0, _ZERO_REGNO);
+#  else
+    if (can_sign_extend_short_p(i0) && can_sign_extend_short_p(i0 + 4)) {
+       SWC1(r0 + BE_P, i0, _ZERO_REGNO);
+       SWC1(r0 + LE_P, i0 + 4, _ZERO_REGNO);
+    }
+#  endif
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_d(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_d(rn(reg), r2);
+    jit_unget_reg(reg);
+}
+
+static void
+_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+#  if __WORDSIZE == 64 || NEW_ABI
+    if (can_sign_extend_short_p(i0))
+       SDC1(r1, i0, r0);
+#  else
+    if (can_sign_extend_short_p(i0) && can_sign_extend_short_p(i0 + 4)) {
+       SWC1(r1 + BE_P, i0, r0);
+       SWC1(r1 + LE_P, i0 + 4, r0);
+    }
+#  endif
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r0, i0);
+       str_d(rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       MOV_D(r0, r1);
+}
+
+static void
+_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+       jit_int32_t     i[2];
+       jit_int64_t     l;
+       jit_float64_t   d;
+    } data;
+    jit_int32_t                reg;
+
+    data.d = *i0;
+#  if __WORDSIZE == 64 || NEW_ABI
+    if (data.l) {
+       if (_jitc->no_data) {
+           reg = jit_get_reg(jit_class_gpr);
+           movi64(rn(reg), data.l);
+           DMTC1(rn(reg), r0);
+           jit_unget_reg(reg);
+       }
+       else
+           ldi_d(r0, (jit_word_t)i0);
+    }
+    else
+       DMTC1(_ZERO_REGNO, r0);
+#  else
+    if (_jitc->no_data)
+       reg = jit_get_reg(jit_class_gpr);
+    if (data.i[0]) {
+       if (_jitc->no_data) {
+           movi(rn(reg), data.i[0]);
+           MTC1(rn(reg), r0 + BE_P);
+       }
+       else
+           ldi_f(r0 + BE_P, (jit_word_t)i0);
+    }
+    else
+       MTC1(_ZERO_REGNO, r0 + BE_P);
+    if (data.i[1]) {
+       if (_jitc->no_data) {
+           movi(rn(reg), data.i[1]);
+           MTC1(rn(reg), r0 + LE_P);
+       }
+       else
+           ldi_f(r0 + LE_P, ((jit_word_t)i0) + 4);
+    }
+    else
+       MTC1(_ZERO_REGNO, r0 + LE_P);
+    if (_jitc->no_data)
+       jit_unget_reg(reg);
+#  endif
+}
+
+static void
+_ltr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLT_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(lt)
+
+static void
+_ler_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLE_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(le)
+
+static void
+_eqr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_EQ_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(eq)
+
+static void
+_ger_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULT_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(ge)
+
+static void
+_gtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULE_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(gt)
+
+static void
+_ner_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_EQ_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(ne)
+
+static void
+_unltr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULT_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(unlt)
+
+static void
+_unler_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULE_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(unle)
+
+static void
+_uneqr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UEQ_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(uneq)
+
+static void
+_unger_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLT_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(unge)
+
+static void
+_ungtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLE_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(ungt)
+
+static void
+_ltgtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UEQ_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(ltgt)
+
+static void
+_ordr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UN_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(ord)
+
+static void
+_unordr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UN_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+fopi(unord)
+
+static jit_word_t
+_bltr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLT_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(lt)
+
+static jit_word_t
+_bler_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLE_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(le)
+
+static jit_word_t
+_beqr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_EQ_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(eq)
+
+static jit_word_t
+_bger_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULT_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(ge)
+
+static jit_word_t
+_bgtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULE_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(gt)
+
+static jit_word_t
+_bner_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_EQ_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(ne)
+
+static jit_word_t
+_bunltr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULT_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(unlt)
+
+static jit_word_t
+_bunler_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULE_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(unle)
+
+static jit_word_t
+_buneqr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UEQ_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(uneq)
+
+static jit_word_t
+_bunger_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLT_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(unge)
+
+static jit_word_t
+_bungtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLE_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(ungt)
+
+static jit_word_t
+_bltgtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UEQ_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(ltgt)
+
+static jit_word_t
+_bordr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UN_S(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(ord)
+
+static jit_word_t
+_bunordr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UN_S(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+fbopi(unord)
+
+static void
+_ltr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLT_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(lt)
+
+static void
+_ler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLE_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(le)
+
+static void
+_eqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_EQ_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(eq)
+
+static void
+_ger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULT_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(ge)
+
+static void
+_gtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULE_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(gt)
+
+static void
+_ner_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_EQ_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(ne)
+
+static void
+_unltr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULT_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(unlt)
+
+static void
+_unler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULE_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(unle)
+
+static void
+_uneqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UEQ_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(uneq)
+
+static void
+_unger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLT_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(unge)
+
+static void
+_ungtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLE_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(ungt)
+
+static void
+_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UEQ_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(ltgt)
+
+static void
+_ordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UN_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(ord)
+
+static void
+_unordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UN_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(0);
+    /* delay slot */
+    movi(r0, 1);
+    movi(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+dopi(unord)
+
+static jit_word_t
+_bltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLT_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(lt)
+
+static jit_word_t
+_bler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLE_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(le)
+
+static jit_word_t
+_beqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_EQ_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(eq)
+
+static jit_word_t
+_bger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULT_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(ge)
+
+static jit_word_t
+_bgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULE_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(gt)
+
+static jit_word_t
+_bner_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_EQ_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(ne)
+
+static jit_word_t
+_bunltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULT_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(unlt)
+
+static jit_word_t
+_bunler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_ULE_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(unle)
+
+static jit_word_t
+_buneqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UEQ_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(uneq)
+
+static jit_word_t
+_bunger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLT_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(unge)
+
+static jit_word_t
+_bungtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_OLE_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(ungt)
+
+static jit_word_t
+_bltgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UEQ_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(ltgt)
+
+static jit_word_t
+_bordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UN_D(r1, r2);
+    w = _jit->pc.w;
+    BC1F(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(ord)
+
+static jit_word_t
+_bunordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    C_UN_D(r1, r2);
+    w = _jit->pc.w;
+    BC1T(((i0 - w) >> 2) - 1);
+    NOP(1);
+    return (w);
+}
+dbopi(unord)
+
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#if !NEW_ABI
+    jit_int32_t                reg;
+#endif
+    assert(_jitc->function->self.call & jit_call_varargs);
+#if !NEW_ABI
+    /* Align, if required. */
+    reg = jit_get_reg(jit_class_gpr);
+    andi(rn(reg), r1, 7);
+    addr(r1, r1, rn(reg));
+    jit_unget_reg(reg);
+#endif
+
+    /* Load argument. */
+    ldr_d(r0, r1);
+
+    /* Update va_list. */
+    addi(r1, r1, sizeof(jit_float64_t));
+}
+
+#  undef fopi
+#  undef fbopi
+#  undef dopi
+#  undef dbopi
+#  undef fpr_bopi
+#  undef fpr_opi
+#endif
diff --git a/deps/lightning/lib/jit_mips-sz.c b/deps/lightning/lib/jit_mips-sz.c
new file mode 100644 (file)
index 0000000..613aa00
--- /dev/null
@@ -0,0 +1,1210 @@
+
+#if __WORDSIZE == 32
+#if NEW_ABI
+#define JIT_INSTR_MAX 44
+    0, /* data */
+    0, /* live */
+    0, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    44,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    0, /* va_start */
+    0, /* va_arg */
+    0, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    12,        /* addi */
+    12,        /* addcr */
+    20,        /* addci */
+    28,        /* addxr */
+    28,        /* addxi */
+    4, /* subr */
+    12,        /* subi */
+    12,        /* subcr */
+    20,        /* subci */
+    28,        /* subxr */
+    28,        /* subxi */
+    16,        /* rsbi */
+    8, /* mulr */
+    16,        /* muli */
+    12,        /* qmulr */
+    20,        /* qmuli */
+    12,        /* qmulr_u */
+    20,        /* qmuli_u */
+    8, /* divr */
+    16,        /* divi */
+    8, /* divr_u */
+    16,        /* divi_u */
+    12,        /* qdivr */
+    16,        /* qdivi */
+    12,        /* qdivr_u */
+    16,        /* qdivi_u */
+    8, /* remr */
+    16,        /* remi */
+    8, /* remr_u */
+    16,        /* remi_u */
+    4, /* andr */
+    12,        /* andi */
+    4, /* orr */
+    12,        /* ori */
+    4, /* xorr */
+    12,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    8, /* comr */
+    4, /* ltr */
+    4, /* lti */
+    4, /* ltr_u */
+    4, /* lti_u */
+    8, /* ler */
+    12,        /* lei */
+    8, /* ler_u */
+    12,        /* lei_u */
+    12,        /* eqr */
+    12,        /* eqi */
+    8, /* ger */
+    12,        /* gei */
+    8, /* ger_u */
+    12,        /* gei_u */
+    4, /* gtr */
+    8, /* gti */
+    4, /* gtr_u */
+    8, /* gti_u */
+    8, /* ner */
+    8, /* nei */
+    4, /* movr */
+    8, /* movi */
+    8, /* extr_c */
+    4, /* extr_uc */
+    8, /* extr_s */
+    4, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    4, /* htonr_us */
+    4, /* htonr_ui */
+    0, /* htonr_ul */
+    4, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    12,        /* ldi_uc */
+    4, /* ldr_s */
+    12,        /* ldi_s */
+    4, /* ldr_us */
+    12,        /* ldi_us */
+    4, /* ldr_i */
+    12,        /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    8, /* ldxr_c */
+    4, /* ldxi_c */
+    8, /* ldxr_uc */
+    4, /* ldxi_uc */
+    8, /* ldxr_s */
+    4, /* ldxi_s */
+    8, /* ldxr_us */
+    4, /* ldxi_us */
+    8, /* ldxr_i */
+    4, /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    4, /* str_c */
+    12,        /* sti_c */
+    4, /* str_s */
+    12,        /* sti_s */
+    4, /* str_i */
+    12,        /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    8, /* stxr_c */
+    4, /* stxi_c */
+    8, /* stxr_s */
+    4, /* stxi_s */
+    8, /* stxr_i */
+    4, /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    12,        /* bltr */
+    12,        /* blti */
+    12,        /* bltr_u */
+    12,        /* blti_u */
+    12,        /* bler */
+    16,        /* blei */
+    12,        /* bler_u */
+    16,        /* blei_u */
+    8, /* beqr */
+    16,        /* beqi */
+    12,        /* bger */
+    12,        /* bgei */
+    12,        /* bger_u */
+    12,        /* bgei_u */
+    12,        /* bgtr */
+    16,        /* bgti */
+    12,        /* bgtr_u */
+    16,        /* bgti_u */
+    8, /* bner */
+    16,        /* bnei */
+    12,        /* bmsr */
+    12,        /* bmsi */
+    12,        /* bmcr */
+    12,        /* bmci */
+    28,        /* boaddr */
+    28,        /* boaddi */
+    16,        /* boaddr_u */
+    20,        /* boaddi_u */
+    28,        /* bxaddr */
+    28,        /* bxaddi */
+    16,        /* bxaddr_u */
+    20,        /* bxaddi_u */
+    28,        /* bosubr */
+    28,        /* bosubi */
+    16,        /* bosubr_u */
+    20,        /* bosubi_u */
+    28,        /* bxsubr */
+    28,        /* bxsubi */
+    16,        /* bxsubr_u */
+    20,        /* bxsubi_u */
+    0, /* jmpr */
+    8, /* jmpi */
+    12,        /* callr */
+    16,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    44,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    16,        /* addi_f */
+    4, /* subr_f */
+    16,        /* subi_f */
+    16,        /* rsbi_f */
+    4, /* mulr_f */
+    16,        /* muli_f */
+    4, /* divr_f */
+    16,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    16,        /* ltr_f */
+    28,        /* lti_f */
+    16,        /* ler_f */
+    28,        /* lei_f */
+    16,        /* eqr_f */
+    28,        /* eqi_f */
+    16,        /* ger_f */
+    28,        /* gei_f */
+    16,        /* gtr_f */
+    28,        /* gti_f */
+    16,        /* ner_f */
+    28,        /* nei_f */
+    16,        /* unltr_f */
+    28,        /* unlti_f */
+    16,        /* unler_f */
+    28,        /* unlei_f */
+    16,        /* uneqr_f */
+    28,        /* uneqi_f */
+    16,        /* unger_f */
+    28,        /* ungei_f */
+    16,        /* ungtr_f */
+    28,        /* ungti_f */
+    16,        /* ltgtr_f */
+    28,        /* ltgti_f */
+    16,        /* ordr_f */
+    28,        /* ordi_f */
+    16,        /* unordr_f */
+    28,        /* unordi_f */
+    8, /* truncr_f_i */
+    0, /* truncr_f_l */
+    8, /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    12,        /* movi_f */
+    4, /* ldr_f */
+    12,        /* ldi_f */
+    8, /* ldxr_f */
+    4, /* ldxi_f */
+    4, /* str_f */
+    12,        /* sti_f */
+    8, /* stxr_f */
+    4, /* stxi_f */
+    12,        /* bltr_f */
+    24,        /* blti_f */
+    12,        /* bler_f */
+    24,        /* blei_f */
+    12,        /* beqr_f */
+    24,        /* beqi_f */
+    12,        /* bger_f */
+    24,        /* bgei_f */
+    12,        /* bgtr_f */
+    24,        /* bgti_f */
+    12,        /* bner_f */
+    24,        /* bnei_f */
+    12,        /* bunltr_f */
+    24,        /* bunlti_f */
+    12,        /* bunler_f */
+    24,        /* bunlei_f */
+    12,        /* buneqr_f */
+    24,        /* buneqi_f */
+    12,        /* bunger_f */
+    24,        /* bungei_f */
+    12,        /* bungtr_f */
+    24,        /* bungti_f */
+    12,        /* bltgtr_f */
+    24,        /* bltgti_f */
+    12,        /* bordr_f */
+    24,        /* bordi_f */
+    12,        /* bunordr_f */
+    24,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    16,        /* addi_d */
+    4, /* subr_d */
+    16,        /* subi_d */
+    16,        /* rsbi_d */
+    4, /* mulr_d */
+    16,        /* muli_d */
+    4, /* divr_d */
+    16,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    16,        /* ltr_d */
+    28,        /* lti_d */
+    16,        /* ler_d */
+    28,        /* lei_d */
+    16,        /* eqr_d */
+    28,        /* eqi_d */
+    16,        /* ger_d */
+    28,        /* gei_d */
+    16,        /* gtr_d */
+    28,        /* gti_d */
+    16,        /* ner_d */
+    28,        /* nei_d */
+    16,        /* unltr_d */
+    28,        /* unlti_d */
+    16,        /* unler_d */
+    28,        /* unlei_d */
+    16,        /* uneqr_d */
+    28,        /* uneqi_d */
+    16,        /* unger_d */
+    28,        /* ungei_d */
+    16,        /* ungtr_d */
+    28,        /* ungti_d */
+    16,        /* ltgtr_d */
+    28,        /* ltgti_d */
+    16,        /* ordr_d */
+    28,        /* ordi_d */
+    16,        /* unordr_d */
+    28,        /* unordi_d */
+    8, /* truncr_d_i */
+    0, /* truncr_d_l */
+    8, /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    12,        /* movi_d */
+    4, /* ldr_d */
+    12,        /* ldi_d */
+    8, /* ldxr_d */
+    4, /* ldxi_d */
+    4, /* str_d */
+    12,        /* sti_d */
+    8, /* stxr_d */
+    4, /* stxi_d */
+    12,        /* bltr_d */
+    24,        /* blti_d */
+    12,        /* bler_d */
+    24,        /* blei_d */
+    12,        /* beqr_d */
+    24,        /* beqi_d */
+    12,        /* bger_d */
+    24,        /* bgei_d */
+    12,        /* bgtr_d */
+    24,        /* bgti_d */
+    12,        /* bner_d */
+    24,        /* bnei_d */
+    12,        /* bunltr_d */
+    24,        /* bunlti_d */
+    12,        /* bunler_d */
+    24,        /* bunlei_d */
+    12,        /* buneqr_d */
+    24,        /* buneqi_d */
+    12,        /* bunger_d */
+    24,        /* bungei_d */
+    12,        /* bungtr_d */
+    24,        /* bungti_d */
+    12,        /* bltgtr_d */
+    24,        /* bltgti_d */
+    12,        /* bordr_d */
+    24,        /* bordi_d */
+    12,        /* bunordr_d */
+    24,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    4, /* movr_d_w */
+    12,        /* movi_d_w */
+#endif /* NEW_ABI */
+#endif /* __WORDSIZE */
+
+#if __WORDSIZE == 32
+#if !NEW_ABI
+#define JIT_INSTR_MAX 116
+    0, /* data */
+    0, /* live */
+    0, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    116,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    4, /* va_start */
+    8, /* va_arg */
+    20,        /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    12,        /* addi */
+    12,        /* addcr */
+    20,        /* addci */
+    28,        /* addxr */
+    28,        /* addxi */
+    4, /* subr */
+    12,        /* subi */
+    12,        /* subcr */
+    20,        /* subci */
+    28,        /* subxr */
+    28,        /* subxi */
+    16,        /* rsbi */
+    8, /* mulr */
+    16,        /* muli */
+    12,        /* qmulr */
+    20,        /* qmuli */
+    12,        /* qmulr_u */
+    20,        /* qmuli_u */
+    8, /* divr */
+    16,        /* divi */
+    8, /* divr_u */
+    16,        /* divi_u */
+    12,        /* qdivr */
+    16,        /* qdivi */
+    12,        /* qdivr_u */
+    16,        /* qdivi_u */
+    8, /* remr */
+    16,        /* remi */
+    8, /* remr_u */
+    16,        /* remi_u */
+    4, /* andr */
+    12,        /* andi */
+    4, /* orr */
+    12,        /* ori */
+    4, /* xorr */
+    12,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    8, /* comr */
+    4, /* ltr */
+    4, /* lti */
+    4, /* ltr_u */
+    4, /* lti_u */
+    8, /* ler */
+    12,        /* lei */
+    8, /* ler_u */
+    12,        /* lei_u */
+    12,        /* eqr */
+    12,        /* eqi */
+    8, /* ger */
+    12,        /* gei */
+    8, /* ger_u */
+    12,        /* gei_u */
+    4, /* gtr */
+    8, /* gti */
+    4, /* gtr_u */
+    8, /* gti_u */
+    8, /* ner */
+    8, /* nei */
+    4, /* movr */
+    8, /* movi */
+    8, /* extr_c */
+    4, /* extr_uc */
+    8, /* extr_s */
+    4, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    20,        /* htonr_us */
+    52,        /* htonr_ui */
+    0, /* htonr_ul */
+    4, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    12,        /* ldi_uc */
+    4, /* ldr_s */
+    12,        /* ldi_s */
+    4, /* ldr_us */
+    12,        /* ldi_us */
+    4, /* ldr_i */
+    12,        /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    8, /* ldxr_c */
+    16,        /* ldxi_c */
+    8, /* ldxr_uc */
+    16,        /* ldxi_uc */
+    8, /* ldxr_s */
+    16,        /* ldxi_s */
+    8, /* ldxr_us */
+    16,        /* ldxi_us */
+    8, /* ldxr_i */
+    16,        /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    4, /* str_c */
+    12,        /* sti_c */
+    4, /* str_s */
+    12,        /* sti_s */
+    4, /* str_i */
+    12,        /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    8, /* stxr_c */
+    16,        /* stxi_c */
+    8, /* stxr_s */
+    16,        /* stxi_s */
+    8, /* stxr_i */
+    16,        /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    12,        /* bltr */
+    12,        /* blti */
+    12,        /* bltr_u */
+    12,        /* blti_u */
+    12,        /* bler */
+    16,        /* blei */
+    12,        /* bler_u */
+    16,        /* blei_u */
+    8, /* beqr */
+    16,        /* beqi */
+    12,        /* bger */
+    12,        /* bgei */
+    12,        /* bger_u */
+    12,        /* bgei_u */
+    12,        /* bgtr */
+    16,        /* bgti */
+    12,        /* bgtr_u */
+    16,        /* bgti_u */
+    8, /* bner */
+    16,        /* bnei */
+    12,        /* bmsr */
+    12,        /* bmsi */
+    12,        /* bmcr */
+    12,        /* bmci */
+    28,        /* boaddr */
+    28,        /* boaddi */
+    16,        /* boaddr_u */
+    20,        /* boaddi_u */
+    28,        /* bxaddr */
+    28,        /* bxaddi */
+    16,        /* bxaddr_u */
+    20,        /* bxaddi_u */
+    28,        /* bosubr */
+    28,        /* bosubi */
+    16,        /* bosubr_u */
+    20,        /* bosubi_u */
+    28,        /* bxsubr */
+    28,        /* bxsubi */
+    16,        /* bxsubr_u */
+    20,        /* bxsubi_u */
+    8, /* jmpr */
+    8, /* jmpi */
+    12,        /* callr */
+    16,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    116,       /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    16,        /* addi_f */
+    4, /* subr_f */
+    16,        /* subi_f */
+    16,        /* rsbi_f */
+    4, /* mulr_f */
+    16,        /* muli_f */
+    4, /* divr_f */
+    16,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    16,        /* ltr_f */
+    28,        /* lti_f */
+    16,        /* ler_f */
+    28,        /* lei_f */
+    16,        /* eqr_f */
+    28,        /* eqi_f */
+    16,        /* ger_f */
+    28,        /* gei_f */
+    16,        /* gtr_f */
+    28,        /* gti_f */
+    16,        /* ner_f */
+    28,        /* nei_f */
+    16,        /* unltr_f */
+    28,        /* unlti_f */
+    16,        /* unler_f */
+    28,        /* unlei_f */
+    16,        /* uneqr_f */
+    28,        /* uneqi_f */
+    16,        /* unger_f */
+    28,        /* ungei_f */
+    16,        /* ungtr_f */
+    28,        /* ungti_f */
+    16,        /* ltgtr_f */
+    28,        /* ltgti_f */
+    16,        /* ordr_f */
+    28,        /* ordi_f */
+    16,        /* unordr_f */
+    28,        /* unordi_f */
+    8, /* truncr_f_i */
+    0, /* truncr_f_l */
+    8, /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    12,        /* movi_f */
+    4, /* ldr_f */
+    12,        /* ldi_f */
+    8, /* ldxr_f */
+    16,        /* ldxi_f */
+    4, /* str_f */
+    12,        /* sti_f */
+    8, /* stxr_f */
+    16,        /* stxi_f */
+    12,        /* bltr_f */
+    24,        /* blti_f */
+    12,        /* bler_f */
+    24,        /* blei_f */
+    12,        /* beqr_f */
+    24,        /* beqi_f */
+    12,        /* bger_f */
+    24,        /* bgei_f */
+    12,        /* bgtr_f */
+    24,        /* bgti_f */
+    12,        /* bner_f */
+    24,        /* bnei_f */
+    12,        /* bunltr_f */
+    24,        /* bunlti_f */
+    12,        /* bunler_f */
+    24,        /* bunlei_f */
+    12,        /* buneqr_f */
+    24,        /* buneqi_f */
+    12,        /* bunger_f */
+    24,        /* bungei_f */
+    12,        /* bungtr_f */
+    24,        /* bungti_f */
+    12,        /* bltgtr_f */
+    24,        /* bltgti_f */
+    12,        /* bordr_f */
+    24,        /* bordi_f */
+    12,        /* bunordr_f */
+    24,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    20,        /* addi_d */
+    4, /* subr_d */
+    20,        /* subi_d */
+    20,        /* rsbi_d */
+    4, /* mulr_d */
+    20,        /* muli_d */
+    4, /* divr_d */
+    20,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    16,        /* ltr_d */
+    40,        /* lti_d */
+    16,        /* ler_d */
+    40,        /* lei_d */
+    16,        /* eqr_d */
+    40,        /* eqi_d */
+    16,        /* ger_d */
+    40,        /* gei_d */
+    16,        /* gtr_d */
+    40,        /* gti_d */
+    16,        /* ner_d */
+    40,        /* nei_d */
+    16,        /* unltr_d */
+    40,        /* unlti_d */
+    16,        /* unler_d */
+    40,        /* unlei_d */
+    16,        /* uneqr_d */
+    40,        /* uneqi_d */
+    16,        /* unger_d */
+    40,        /* ungei_d */
+    16,        /* ungtr_d */
+    40,        /* ungti_d */
+    16,        /* ltgtr_d */
+    40,        /* ltgti_d */
+    16,        /* ordr_d */
+    40,        /* ordi_d */
+    16,        /* unordr_d */
+    40,        /* unordi_d */
+    8, /* truncr_d_i */
+    0, /* truncr_d_l */
+    8, /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    24,        /* movi_d */
+    8, /* ldr_d */
+    16,        /* ldi_d */
+    12,        /* ldxr_d */
+    20,        /* ldxi_d */
+    8, /* str_d */
+    16,        /* sti_d */
+    12,        /* stxr_d */
+    20,        /* stxi_d */
+    12,        /* bltr_d */
+    28,        /* blti_d */
+    12,        /* bler_d */
+    28,        /* blei_d */
+    12,        /* beqr_d */
+    28,        /* beqi_d */
+    12,        /* bger_d */
+    28,        /* bgei_d */
+    12,        /* bgtr_d */
+    28,        /* bgti_d */
+    12,        /* bner_d */
+    36,        /* bnei_d */
+    12,        /* bunltr_d */
+    36,        /* bunlti_d */
+    12,        /* bunler_d */
+    36,        /* bunlei_d */
+    12,        /* buneqr_d */
+    36,        /* buneqi_d */
+    12,        /* bunger_d */
+    36,        /* bungei_d */
+    12,        /* bungtr_d */
+    36,        /* bungti_d */
+    12,        /* bltgtr_d */
+    28,        /* bltgti_d */
+    12,        /* bordr_d */
+    28,        /* bordi_d */
+    12,        /* bunordr_d */
+    36,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    4, /* movr_w_f */
+    8, /* movr_ww_d */
+    0, /* movr_w_d */
+    4, /* movr_f_w */
+    4, /* movi_f_w */
+    8, /* movr_d_ww */
+    8, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* NEW_ABI */
+#endif /* __WORDSIZE */
+
+#if __WORDSIZE == 64
+#define JIT_INSTR_MAX 44
+    0, /* data */
+    0, /* live */
+    4, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    44,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    0, /* va_start */
+    0, /* va_arg */
+    0, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    28,        /* addi */
+    12,        /* addcr */
+    36,        /* addci */
+    28,        /* addxr */
+    28,        /* addxi */
+    4, /* subr */
+    28,        /* subi */
+    12,        /* subcr */
+    36,        /* subci */
+    28,        /* subxr */
+    28,        /* subxi */
+    32,        /* rsbi */
+    8, /* mulr */
+    32,        /* muli */
+    12,        /* qmulr */
+    32,        /* qmuli */
+    12,        /* qmulr_u */
+    32,        /* qmuli_u */
+    8, /* divr */
+    32,        /* divi */
+    8, /* divr_u */
+    32,        /* divi_u */
+    12,        /* qdivr */
+    16,        /* qdivi */
+    12,        /* qdivr_u */
+    16,        /* qdivi_u */
+    8, /* remr */
+    32,        /* remi */
+    8, /* remr_u */
+    32,        /* remi_u */
+    4, /* andr */
+    28,        /* andi */
+    4, /* orr */
+    28,        /* ori */
+    4, /* xorr */
+    28,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    8, /* comr */
+    4, /* ltr */
+    4, /* lti */
+    4, /* ltr_u */
+    4, /* lti_u */
+    8, /* ler */
+    12,        /* lei */
+    8, /* ler_u */
+    12,        /* lei_u */
+    12,        /* eqr */
+    12,        /* eqi */
+    8, /* ger */
+    12,        /* gei */
+    8, /* ger_u */
+    12,        /* gei_u */
+    4, /* gtr */
+    8, /* gti */
+    4, /* gtr_u */
+    8, /* gti_u */
+    8, /* ner */
+    8, /* nei */
+    4, /* movr */
+    28,        /* movi */
+    8, /* extr_c */
+    4, /* extr_uc */
+    8, /* extr_s */
+    4, /* extr_us */
+    4, /* extr_i */
+    8, /* extr_ui */
+    4, /* htonr_us */
+    4, /* htonr_ui */
+    4, /* htonr_ul */
+    4, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    12,        /* ldi_uc */
+    4, /* ldr_s */
+    12,        /* ldi_s */
+    4, /* ldr_us */
+    12,        /* ldi_us */
+    4, /* ldr_i */
+    12,        /* ldi_i */
+    4, /* ldr_ui */
+    12,        /* ldi_ui */
+    4, /* ldr_l */
+    12,        /* ldi_l */
+    8, /* ldxr_c */
+    4, /* ldxi_c */
+    8, /* ldxr_uc */
+    4, /* ldxi_uc */
+    8, /* ldxr_s */
+    4, /* ldxi_s */
+    8, /* ldxr_us */
+    4, /* ldxi_us */
+    8, /* ldxr_i */
+    4, /* ldxi_i */
+    8, /* ldxr_ui */
+    4, /* ldxi_ui */
+    8, /* ldxr_l */
+    4, /* ldxi_l */
+    4, /* str_c */
+    12,        /* sti_c */
+    4, /* str_s */
+    12,        /* sti_s */
+    4, /* str_i */
+    12,        /* sti_i */
+    4, /* str_l */
+    12,        /* sti_l */
+    8, /* stxr_c */
+    4, /* stxi_c */
+    8, /* stxr_s */
+    4, /* stxi_s */
+    8, /* stxr_i */
+    4, /* stxi_i */
+    8, /* stxr_l */
+    4, /* stxi_l */
+    12,        /* bltr */
+    12,        /* blti */
+    12,        /* bltr_u */
+    12,        /* blti_u */
+    12,        /* bler */
+    16,        /* blei */
+    12,        /* bler_u */
+    16,        /* blei_u */
+    8, /* beqr */
+    36,        /* beqi */
+    12,        /* bger */
+    12,        /* bgei */
+    12,        /* bger_u */
+    12,        /* bgei_u */
+    12,        /* bgtr */
+    16,        /* bgti */
+    12,        /* bgtr_u */
+    16,        /* bgti_u */
+    8, /* bner */
+    32,        /* bnei */
+    12,        /* bmsr */
+    12,        /* bmsi */
+    12,        /* bmcr */
+    12,        /* bmci */
+    28,        /* boaddr */
+    28,        /* boaddi */
+    16,        /* boaddr_u */
+    20,        /* boaddi_u */
+    28,        /* bxaddr */
+    28,        /* bxaddi */
+    16,        /* bxaddr_u */
+    20,        /* bxaddi_u */
+    28,        /* bosubr */
+    28,        /* bosubi */
+    16,        /* bosubr_u */
+    20,        /* bosubi_u */
+    28,        /* bxsubr */
+    28,        /* bxsubi */
+    16,        /* bxsubr_u */
+    20,        /* bxsubi_u */
+    0, /* jmpr */
+    8, /* jmpi */
+    12,        /* callr */
+    32,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    44,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    16,        /* addi_f */
+    4, /* subr_f */
+    16,        /* subi_f */
+    16,        /* rsbi_f */
+    4, /* mulr_f */
+    16,        /* muli_f */
+    4, /* divr_f */
+    16,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    16,        /* ltr_f */
+    28,        /* lti_f */
+    16,        /* ler_f */
+    28,        /* lei_f */
+    16,        /* eqr_f */
+    28,        /* eqi_f */
+    16,        /* ger_f */
+    28,        /* gei_f */
+    16,        /* gtr_f */
+    28,        /* gti_f */
+    16,        /* ner_f */
+    28,        /* nei_f */
+    16,        /* unltr_f */
+    28,        /* unlti_f */
+    16,        /* unler_f */
+    28,        /* unlei_f */
+    16,        /* uneqr_f */
+    28,        /* uneqi_f */
+    16,        /* unger_f */
+    28,        /* ungei_f */
+    16,        /* ungtr_f */
+    28,        /* ungti_f */
+    16,        /* ltgtr_f */
+    28,        /* ltgti_f */
+    16,        /* ordr_f */
+    28,        /* ordi_f */
+    16,        /* unordr_f */
+    28,        /* unordi_f */
+    8, /* truncr_f_i */
+    8, /* truncr_f_l */
+    8, /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    12,        /* movi_f */
+    4, /* ldr_f */
+    12,        /* ldi_f */
+    8, /* ldxr_f */
+    4, /* ldxi_f */
+    4, /* str_f */
+    12,        /* sti_f */
+    8, /* stxr_f */
+    4, /* stxi_f */
+    12,        /* bltr_f */
+    24,        /* blti_f */
+    12,        /* bler_f */
+    24,        /* blei_f */
+    12,        /* beqr_f */
+    24,        /* beqi_f */
+    12,        /* bger_f */
+    24,        /* bgei_f */
+    12,        /* bgtr_f */
+    24,        /* bgti_f */
+    12,        /* bner_f */
+    24,        /* bnei_f */
+    12,        /* bunltr_f */
+    24,        /* bunlti_f */
+    12,        /* bunler_f */
+    24,        /* bunlei_f */
+    12,        /* buneqr_f */
+    24,        /* buneqi_f */
+    12,        /* bunger_f */
+    24,        /* bungei_f */
+    12,        /* bungtr_f */
+    24,        /* bungti_f */
+    12,        /* bltgtr_f */
+    24,        /* bltgti_f */
+    12,        /* bordr_f */
+    24,        /* bordi_f */
+    12,        /* bunordr_f */
+    24,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    16,        /* addi_d */
+    4, /* subr_d */
+    16,        /* subi_d */
+    16,        /* rsbi_d */
+    4, /* mulr_d */
+    16,        /* muli_d */
+    4, /* divr_d */
+    16,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    16,        /* ltr_d */
+    28,        /* lti_d */
+    16,        /* ler_d */
+    28,        /* lei_d */
+    16,        /* eqr_d */
+    28,        /* eqi_d */
+    16,        /* ger_d */
+    28,        /* gei_d */
+    16,        /* gtr_d */
+    28,        /* gti_d */
+    16,        /* ner_d */
+    28,        /* nei_d */
+    16,        /* unltr_d */
+    28,        /* unlti_d */
+    16,        /* unler_d */
+    28,        /* unlei_d */
+    16,        /* uneqr_d */
+    28,        /* uneqi_d */
+    16,        /* unger_d */
+    28,        /* ungei_d */
+    16,        /* ungtr_d */
+    28,        /* ungti_d */
+    16,        /* ltgtr_d */
+    28,        /* ltgti_d */
+    16,        /* ordr_d */
+    28,        /* ordi_d */
+    16,        /* unordr_d */
+    28,        /* unordi_d */
+    8, /* truncr_d_i */
+    8, /* truncr_d_l */
+    8, /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    12,        /* movi_d */
+    4, /* ldr_d */
+    12,        /* ldi_d */
+    8, /* ldxr_d */
+    4, /* ldxi_d */
+    4, /* str_d */
+    12,        /* sti_d */
+    8, /* stxr_d */
+    4, /* stxi_d */
+    12,        /* bltr_d */
+    24,        /* blti_d */
+    12,        /* bler_d */
+    24,        /* blei_d */
+    12,        /* beqr_d */
+    24,        /* beqi_d */
+    12,        /* bger_d */
+    24,        /* bgei_d */
+    12,        /* bgtr_d */
+    24,        /* bgti_d */
+    12,        /* bner_d */
+    24,        /* bnei_d */
+    12,        /* bunltr_d */
+    24,        /* bunlti_d */
+    12,        /* bunler_d */
+    24,        /* bunlei_d */
+    12,        /* buneqr_d */
+    24,        /* buneqi_d */
+    12,        /* bunger_d */
+    24,        /* bungei_d */
+    12,        /* bungtr_d */
+    24,        /* bungti_d */
+    12,        /* bltgtr_d */
+    24,        /* bltgti_d */
+    12,        /* bordr_d */
+    24,        /* bordi_d */
+    12,        /* bunordr_d */
+    24,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    4, /* movr_d_w */
+    12,        /* movi_d_w */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_mips.c b/deps/lightning/lib/jit_mips.c
new file mode 100644 (file)
index 0000000..dafade8
--- /dev/null
@@ -0,0 +1,1930 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if defined(__linux__)
+#  include <sys/cachectl.h>
+#endif
+
+#if NEW_ABI
+#  define NUM_WORD_ARGS                        8
+#  define STACK_SLOT                   8
+#  define STACK_SHIFT                  3
+#else
+#  define NUM_WORD_ARGS                        4
+#  define STACK_SLOT                   4
+#  define STACK_SHIFT                  2
+#endif
+#if NEW_ABI && __BYTE_ORDER == __BIG_ENDIAN && __WORDSIZE == 32
+#  define WORD_ADJUST                  4
+#else
+#  define WORD_ADJUST                  0
+#endif
+#define jit_arg_reg_p(i)               ((i) >= 0 && (i) < NUM_WORD_ARGS)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define C_DISP                       0
+#  define S_DISP                       0
+#  define I_DISP                       0
+#else
+#  define C_DISP                       STACK_SLOT - sizeof(jit_int8_t)
+#  define S_DISP                       STACK_SLOT - sizeof(jit_int16_t)
+#  define I_DISP                       STACK_SLOT - sizeof(jit_int32_t)
+#endif
+
+/*
+ * Types
+ */
+typedef struct jit_pointer_t jit_va_list_t;
+
+/*
+ * Prototypes
+ */
+#define jit_make_arg(node)             _jit_make_arg(_jit,node)
+static jit_node_t *_jit_make_arg(jit_state_t*,jit_node_t*);
+#define jit_make_arg_f(node)           _jit_make_arg_f(_jit,node)
+static jit_node_t *_jit_make_arg_f(jit_state_t*,jit_node_t*);
+#define jit_make_arg_d(node)           _jit_make_arg_d(_jit,node)
+static jit_node_t *_jit_make_arg_d(jit_state_t*,jit_node_t*);
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+#define PROTO                          1
+#  include "jit_rewind.c"
+#  include "jit_mips-cpu.c"
+#  include "jit_mips-fpu.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_register_t         _rvs[] = {
+    { rc(gpr) | 0x01,                  "at" },
+    { rc(gpr) | 0x02,                  "v0" },
+    { rc(gpr) | 0x03,                  "v1" },
+#if !NEW_ABI
+    { rc(gpr) | 0x08,                  "t0" },
+    { rc(gpr) | 0x09,                  "t1" },
+    { rc(gpr) | 0x0a,                  "t2" },
+    { rc(gpr) | 0x0b,                  "t3" },
+#endif
+    { rc(gpr) | 0x0c,                  "t4" },
+    { rc(gpr) | 0x0d,                  "t5" },
+    { rc(gpr) | 0x0e,                  "t6" },
+    { rc(gpr) | 0x0f,                  "t7" },
+    { rc(gpr) | 0x18,                  "t8" },
+    { rc(gpr) | 0x19,                  "t9" },
+    { rc(sav) | rc(gpr) | 0x10,                "s0" },
+    { rc(sav) | rc(gpr) | 0x11,                "s1" },
+    { rc(sav) | rc(gpr) | 0x12,                "s2" },
+    { rc(sav) | rc(gpr) | 0x13,                "s3" },
+    { rc(sav) | rc(gpr) | 0x14,                "s4" },
+    { rc(sav) | rc(gpr) | 0x15,                "s5" },
+    { rc(sav) | rc(gpr) | 0x16,                "s6" },
+    { rc(sav) | rc(gpr) | 0x17,                "s7" },
+    { 0x00,                            "zero" },
+    { 0x1a,                            "k0" },
+    { 0x1b,                            "k1" },
+    { rc(sav) | 0x1f,                  "ra" },
+    { rc(sav) | 0x1c,                  "gp" },
+    { rc(sav) | 0x1d,                  "sp" },
+    { rc(sav) | 0x1e,                  "fp" },
+#if NEW_ABI
+    { rc(gpr) | 0x0b,                  "a7" },
+    { rc(gpr) | 0x0a,                  "a6" },
+    { rc(gpr) | 0x09,                  "a5" },
+    { rc(gpr) | 0x08,                  "a4" },
+#endif
+    { rc(arg) | rc(gpr) | 0x07,                "a3" },
+    { rc(arg) | rc(gpr) | 0x06,                "a2" },
+    { rc(arg) | rc(gpr) | 0x05,                "a1" },
+    { rc(arg) | rc(gpr) | 0x04,                "a0" },
+    { rc(fpr) | 0x00,                  "$f0" },
+    { rc(fpr) | 0x02,                  "$f2" },
+    { rc(fpr) | 0x04,                  "$f4" },
+    { rc(fpr) | 0x06,                  "$f6" },
+    { rc(fpr) | 0x08,                  "$f8" },
+    { rc(fpr) | 0x0a,                  "$f10" },
+#if !NEW_ABI
+    { rc(sav) | rc(fpr) | 0x10,                "$f16" },
+    { rc(sav) | rc(fpr) | 0x12,                "$f18" },
+#endif
+    { rc(sav) | rc(fpr) | 0x14,                "$f20" },
+    { rc(sav) | rc(fpr) | 0x16,                "$f22" },
+    { rc(sav) | rc(fpr) | 0x18,                "$f24" },
+    { rc(sav) | rc(fpr) | 0x1a,                "$f26" },
+    { rc(sav) | rc(fpr) | 0x1c,                "$f28" },
+    { rc(sav) | rc(fpr) | 0x1e,                "$f30" },
+#if NEW_ABI
+    { rc(arg) | rc(fpr) | 0x13,                "$f19" },
+    { rc(arg) | rc(fpr) | 0x12,                "$f18" },
+    { rc(arg) | rc(fpr) | 0x11,                "$f17" },
+    { rc(arg) | rc(fpr) | 0x10,                "$f16" },
+    { rc(arg) | rc(fpr) | 0x0f,                "$f15" },
+    { rc(arg) | rc(fpr) | 0x0e,                "$f14" },
+    { rc(arg) | rc(fpr) | 0x0d,                "$f13" },
+    { rc(arg) | rc(fpr) | 0x0c,                "$f12" },
+#else
+    { rc(arg) | rc(fpr) | 0x0e,                "$f14" },
+    { rc(arg) | rc(fpr) | 0x0c,                "$f12" },
+#endif
+    { _NOREG,                          "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    _jitc->reglen = jit_size(_rvs) - 1;
+/* Could also:
+ *     o reserve a register for carry  (overkill)
+ *     o use MTLO/MFLO                 (performance hit)
+ * So, keep a register allocated after setting carry, and implicitly
+ * deallocate it if it can no longer be tracked
+ */
+    jit_carry = _NOREG;
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                 offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = stack_framesize;
+    _jitc->function->self.argi = _jitc->function->self.argf =
+       _jitc->function->self.aoff = _jitc->function->self.alen = 0;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    return (_jitc->function->self.aoff);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 reg;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    jit_negr(reg, v);
+    jit_andi(reg, reg, -8);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, reg);
+    jit_addr(JIT_SP, JIT_SP, reg);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(reg);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    if (JIT_RET != u)
+       jit_movr(JIT_RET, u);
+    jit_live(JIT_RET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    if (JIT_FRET != u)
+       jit_movr_f(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    if (JIT_FRET != u)
+       jit_movr_d(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    if (u->code == jit_code_arg)
+       return (jit_arg_reg_p(u->u.w));
+    assert(u->code == jit_code_arg_f || u->code == jit_code_arg_d);
+#if NEW_ABI
+    return (jit_arg_reg_p(u->u.w));
+#else
+    return (u->u.w < 8);
+#endif
+}
+
+static jit_node_t *
+_jit_make_arg(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                 offset;
+#if NEW_ABI
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += STACK_SLOT;
+    }
+#else
+    offset = (_jitc->function->self.size - stack_framesize) >> STACK_SHIFT;
+    _jitc->function->self.argi = 1;
+    if (offset >= 4)
+       offset = _jitc->function->self.size;
+    _jitc->function->self.size += STACK_SLOT;
+#endif
+    if (node == (jit_node_t *)0)
+       node = jit_new_node(jit_code_arg);
+    else
+       link_node(node);
+    node->u.w = offset;
+    node->v.w = ++_jitc->function->self.argn;
+    jit_link_prolog();
+    return (node);
+}
+
+static jit_node_t *
+_jit_make_arg_f(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                 offset;
+#if NEW_ABI
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi++;
+       if (_jitc->function->self.call & jit_call_varargs)
+           offset += 8;
+    }
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += STACK_SLOT;
+    }
+#else
+    offset = (_jitc->function->self.size - stack_framesize) >> STACK_SHIFT;
+    if (offset < NUM_WORD_ARGS) {
+       if (!_jitc->function->self.argi &&
+           !(_jitc->function->self.call & jit_call_varargs)) {
+           if (offset == 0)
+               offset = 4;
+           else {
+               offset = 6;
+               _jitc->function->self.argi = 1;
+           }
+           /* Use as flag to rewind in case of varargs function */
+           ++_jitc->function->self.argf;
+       }
+    }
+    else
+       offset = _jitc->function->self.size;
+    _jitc->function->self.size += STACK_SLOT;
+#endif
+    if (node == (jit_node_t *)0)
+       node = jit_new_node(jit_code_arg_f);
+    else
+       link_node(node);
+    node->u.w = offset;
+    node->v.w = ++_jitc->function->self.argn;
+    jit_link_prolog();
+    return (node);
+}
+
+static jit_node_t *
+_jit_make_arg_d(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                 offset;
+#if NEW_ABI
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi++;
+       if (_jitc->function->self.call & jit_call_varargs)
+           offset += 8;
+    }
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += STACK_SLOT;
+    }
+#else
+    if (_jitc->function->self.size & 7) {
+       _jitc->function->self.size += 4;
+       _jitc->function->self.argi = 1;
+    }
+    offset = (_jitc->function->self.size - stack_framesize) >> STACK_SHIFT;
+    if (offset < NUM_WORD_ARGS) {
+       if (!_jitc->function->self.argi &&
+           !(_jitc->function->self.call & jit_call_varargs)) {
+           offset += 4;
+           /* Use as flag to rewind in case of varargs function */
+           ++_jitc->function->self.argf;
+       }
+    }
+    else
+       offset = _jitc->function->self.size;
+    _jitc->function->self.size += sizeof(jit_float64_t);
+#endif
+    if (node == (jit_node_t *)0)
+       node = jit_new_node(jit_code_arg_d);
+    else
+       link_node(node);
+    node->u.w = offset;
+    node->v.w = ++_jitc->function->self.argn;
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    if (_jitc->prepare) {
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+#if !NEW_ABI
+       if (_jitc->function->call.argf)
+           rewind_prepare();
+#endif
+    }
+    else {
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+#if NEW_ABI
+       /* If varargs start in a register, allocate extra 64 bytes. */
+       if (jit_arg_reg_p(_jitc->function->self.argi))
+           rewind_prolog();
+       /* Do not set during possible rewind. */
+       _jitc->function->self.call |= jit_call_varargs;
+#else
+       _jitc->function->self.call |= jit_call_varargs;
+       if (_jitc->function->self.argf)
+           rewind_prolog();
+#endif
+       _jitc->function->vagp = _jitc->function->self.argi;
+    }
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare)
+       jit_link_prepare();
+    else
+       jit_link_prolog();
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    return (jit_make_arg((jit_node_t*)0));
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    return (jit_make_arg_f((jit_node_t*)0));
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    return (jit_make_arg_d((jit_node_t*)0));
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, _A0 - v->u.w);
+    else
+       jit_ldxi_c(u, _FP, v->u.w + C_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, _A0 - v->u.w);
+    else
+       jit_ldxi_uc(u, _FP, v->u.w + C_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, _A0 - v->u.w);
+    else
+       jit_ldxi_s(u, _FP, v->u.w + S_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, _A0 - v->u.w);
+    else
+       jit_ldxi_us(u, _FP, v->u.w + S_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w)) {
+#if __WORDSIZE == 64
+       jit_extr_i(u, _A0 - v->u.w);
+#else
+       jit_movr(u, _A0 - v->u.w);
+#endif
+    }
+    else
+       jit_ldxi_i(u, _FP, v->u.w + I_DISP);
+    jit_dec_synth();
+}
+
+#if __WORDSIZE == 64
+void
+_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_ui, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_ui(u, _A0 - v->u.w);
+    else
+       jit_ldxi_ui(u, _FP, v->u.w + I_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_l, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, _A0 - v->u.w);
+    else
+       jit_ldxi_l(u, _FP, v->u.w);
+    jit_dec_synth();
+}
+#endif
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    jit_inc_synth_wp(putargr, u, v);
+    assert(v->code == jit_code_arg);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(_A0 - v->u.w, u);
+    else
+       jit_stxi(v->u.w + WORD_ADJUST, _FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi(_A0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w + WORD_ADJUST, _FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+#if NEW_ABI
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_f(u, _F12 - v->u.w);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_w_f(u, _A0 - v->u.w - 8);
+#else
+    if (v->u.w < 4)
+       jit_movr_w_f(u, _A0 - v->u.w);
+    else if (v->u.w < 8)
+       jit_movr_f(u, _F12 - ((v->u.w - 4) >> 1));
+#endif
+    else
+       jit_ldxi_f(u, _FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+#if NEW_ABI
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_f(_F12 - v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_f_w(_A0 - v->u.w - 8, u);
+#else
+    if (v->u.w < 4)
+       jit_movr_f_w(_A0 - v->u.w, u);
+    else if (v->u.w < 8)
+       jit_movr_f(_F12 - ((v->u.w - 4) >> 1), u);
+#endif
+    else
+       jit_stxi_f(v->u.w, _FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+#if NEW_ABI
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi_f(_F12 - v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8)) {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_movr_f_w(_A0 - v->u.w - 8, u);
+       jit_unget_reg(regno);
+    }
+#else
+    if (v->u.w < 4) {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_movr_f_w(_A0 - ((v->u.w - 4) >> 1), regno);
+       jit_unget_reg(regno);
+    }
+    else if (v->u.w < 8)
+       jit_movi_f(_F12 - ((v->u.w - 4) >> 1), u);
+#endif
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(v->u.w, _FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+#if NEW_ABI
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_d(u, _F12 - v->u.w);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_d_w(_A0 - v->u.w - 8, u);
+#else
+    if (v->u.w < 4)
+       jit_movr_ww_d(u, _A0 - v->u.w, _A0 - (v->u.w + 1));
+    else if (v->u.w < 8)
+       jit_movr_d(u, _F12 - ((v->u.w - 4) >> 1));
+#endif
+    else
+       jit_ldxi_d(u, _FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+#if NEW_ABI
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_d(_F12 - v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_d_w(_A0 - v->u.w - 8, u);
+#else
+    if (v->u.w < 4)
+       jit_movr_d_ww(_A0 - v->u.w, _A0 - (v->u.w + 1), u);
+    else if (v->u.w < 8)
+       jit_movr_d(_F12 - ((v->u.w - 4) >> 1), u);
+#endif
+    else
+       jit_stxi_d(v->u.w, _FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+#if NEW_ABI
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi_d(_F12 - v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8)) {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_movr_d_w(_A0 - v->u.w - 8, u);
+       jit_unget_reg(regno);
+    }
+#else
+    if (v->u.w < 4) {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_movr_d_ww(_A0 - v->u.w, _A0 - (v->u.w + 1), regno);
+       jit_unget_reg(regno);
+    }
+    else if (v->u.w < 8)
+       jit_movi_d(_F12 - ((v->u.w - 4) >> 1), u);
+#endif
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, _FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+#if NEW_ABI
+    assert(_jitc->function);
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(_A0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi(_jitc->function->call.size + WORD_ADJUST, JIT_SP, u);
+       _jitc->function->call.size += STACK_SLOT;
+    }
+#else
+    jit_word_t         offset;
+    assert(_jitc->function);
+    offset = _jitc->function->call.size >> STACK_SHIFT;
+    _jitc->function->call.argi = 1;
+    if (jit_arg_reg_p(offset))
+       jit_movr(_A0 - offset, u);
+    else
+       jit_stxi(_jitc->function->call.size, JIT_SP, u);
+    _jitc->function->call.size += STACK_SLOT;
+#endif
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                regno;
+#if !NEW_ABI
+    jit_word_t         offset;
+#endif
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+#if NEW_ABI
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(_A0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size + WORD_ADJUST, JIT_SP, regno);
+       _jitc->function->call.size += STACK_SLOT;
+       jit_unget_reg(regno);
+    }
+#else
+    offset = _jitc->function->call.size >> STACK_SHIFT;
+    ++_jitc->function->call.argi;
+    if (jit_arg_reg_p(offset))
+       jit_movi(_A0 - offset, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+    }
+    _jitc->function->call.size += STACK_SLOT;
+#endif
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+#if !NEW_ABI
+    jit_word_t         offset;
+#endif
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+#if NEW_ABI
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       if (!(_jitc->function->call.call & jit_call_varargs))
+           jit_movr_f(_F12 - _jitc->function->call.argi, u);
+       else
+           jit_movr_f_w(_A0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += STACK_SLOT;
+    }
+#else
+    offset = _jitc->function->call.size >> STACK_SHIFT;
+    if (offset < 2 && !_jitc->function->call.argi &&
+       !(_jitc->function->call.call & jit_call_varargs)) {
+       ++_jitc->function->call.argf;
+       jit_movr_f(_F12 - offset, u);
+    }
+    else if (offset < 4) {
+       ++_jitc->function->call.argi;
+       jit_movr_f_w(_A0 - offset, u);
+    }
+    else
+       jit_stxi_f(_jitc->function->call.size, JIT_SP, u);
+    _jitc->function->call.size += STACK_SLOT;
+#endif
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                regno;
+#if !NEW_ABI
+    jit_word_t         offset;
+#endif
+    assert(_jitc->function);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+#if NEW_ABI
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       if (!(_jitc->function->call.call & jit_call_varargs))
+           jit_movi_f(_F12 - _jitc->function->call.argi, u);
+       else
+           jit_movi_f_w(_A0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(_jitc->function->call.size, JIT_SP, regno);
+       _jitc->function->call.size += STACK_SLOT;
+       jit_unget_reg(regno);
+    }
+#else
+    offset = _jitc->function->call.size >> STACK_SHIFT;
+    if (offset < 2 && !_jitc->function->call.argi &&
+       !(_jitc->function->call.call & jit_call_varargs)) {
+       ++_jitc->function->call.argf;
+       jit_movi_f(_F12 - offset, u);
+    }
+    else if (offset < 4) {
+       ++_jitc->function->call.argi;
+       jit_movi_f_w(_A0 - offset, u);
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+    }
+    _jitc->function->call.size += STACK_SLOT;
+#endif
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+#if !NEW_ABI
+    jit_bool_t         adjust;
+    jit_word_t         offset;
+#endif
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+#if NEW_ABI
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       if (!(_jitc->function->call.call & jit_call_varargs))
+           jit_movr_d(_F12 - _jitc->function->call.argi, u);
+       else
+           jit_movr_d_w(_A0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += STACK_SLOT;
+    }
+#else
+    adjust = !!_jitc->function->call.argi;
+    if (_jitc->function->call.size & 7) {
+       _jitc->function->call.size += 4;
+       adjust = 1;
+    }
+    offset = _jitc->function->call.size >> STACK_SHIFT;
+    if (offset < 3) {
+       if (adjust || (_jitc->function->call.call & jit_call_varargs)) {
+           jit_movr_d_ww(_A0 - offset, _A0 - (offset + 1), u);
+           _jitc->function->call.argi += 2;
+       }
+       else {
+           jit_movr_d(_F12 - (offset >> 1), u);
+           ++_jitc->function->call.argf;
+       }
+    }
+    else
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, u);
+    _jitc->function->call.size += sizeof(jit_float64_t);
+#endif
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                regno;
+#if !NEW_ABI
+    jit_bool_t         adjust;
+    jit_word_t         offset;
+#endif
+    assert(_jitc->function);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+#if NEW_ABI
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       if (!(_jitc->function->call.call & jit_call_varargs))
+           jit_movi_d(_F12 - _jitc->function->call.argi, u);
+       else
+           jit_movi_d_w(_A0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, regno);
+       _jitc->function->call.size += STACK_SLOT;
+       jit_unget_reg(regno);
+    }
+#else
+    adjust = !!_jitc->function->call.argi;
+    if (_jitc->function->call.size & 7) {
+       _jitc->function->call.size += 4;
+       adjust = 1;
+    }
+    offset = _jitc->function->call.size >> STACK_SHIFT;
+    if (offset < 3) {
+       if (adjust || (_jitc->function->call.call & jit_call_varargs)) {
+           jit_movi_d_ww(_A0 - offset, _A0 - (offset + 1), u);
+           _jitc->function->call.argi += 2;
+       }
+       else {
+           jit_movi_d(_F12 - (offset >> 1), u);
+           ++_jitc->function->call.argf;
+       }
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+    }
+    _jitc->function->call.size += sizeof(jit_float64_t);
+#endif
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_int32_t                spec;
+
+    spec = jit_class(_rvs[regno].spec);
+    if (spec & jit_class_arg) {
+       if (spec & jit_class_gpr) {
+           regno = _A0 - regno;
+           if (regno >= 0 && regno < node->v.w)
+               return (1);
+       }
+       else if (spec & jit_class_fpr) {
+           regno = _F12 - regno;
+           if (regno >= 0 && regno < node->w.w)
+               return (1);
+       }
+    }
+
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *call;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    jit_movr(_T9, r0);
+    call = jit_callr(_T9);
+    call->v.w = _jitc->function->self.argi;
+#if NEW_ABI
+    call->w.w = call->v.w;
+#else
+    call->w.w = _jitc->function->self.argf;
+#endif
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *call;
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_movi(_T9, (jit_word_t)i0);
+    call = jit_callr(_T9);
+    call->v.w = _jitc->function->call.argi;
+#if NEW_ABI
+    call->w.w = call->v.w;
+#else
+    call->w.w = _jitc->function->call.argf;
+#endif
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_extr_c(r0, JIT_RET);
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_extr_uc(r0, JIT_RET);
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_extr_s(r0, JIT_RET);
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_extr_us(r0, JIT_RET);
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+#if __WORDSIZE == 32
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+#else
+    jit_extr_i(r0, JIT_RET);
+#endif
+}
+
+#if __WORDSIZE == 64
+void
+_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_extr_ui(r0, JIT_RET);
+}
+
+void
+_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
+{
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+}
+#endif
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    if (r0 != JIT_FRET)
+       jit_movr_f(r0, JIT_FRET);
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    if (r0 != JIT_FRET)
+       jit_movr_d(r0, JIT_FRET);
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_int32_t                 value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_int32_t      patch_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.patch_offset = 0;
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_rrf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               assert(node->flag & jit_flag_data);                     \
+               name##i##type(rn(node->u.w), rn(node->v.w),             \
+                             (jit_float##size##_t *)node->w.n->u.w);   \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w, rn(node->v.w),             \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w, rn(node->v.w),     \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if (node->u.w == sizeof(jit_word_t) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rr(trunc, _f_i);
+               case_rr(trunc, _d_i);
+#if __WORDSIZE == 64
+               case_rr(trunc, _f_l);
+               case_rr(trunc, _d_l);
+#endif
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+#if __WORDSIZE == 64
+               case_rr(ld, _ui);
+               case_rw(ld, _ui);
+               case_rr(ld, _l);
+               case_rw(ld, _l);
+#endif
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+#if __WORDSIZE == 64
+               case_rrr(ldx, _ui);
+               case_rrw(ldx, _ui);
+               case_rrr(ldx, _l);
+               case_rrw(ldx, _l);
+#endif
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+#if __WORDSIZE == 64
+               case_rr(st, _l);
+               case_wr(st, _l);
+#endif
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+#if __WORDSIZE == 64
+               case_rrr(stx, _l);
+               case_wrr(stx, _l);
+#endif
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+#if __WORDSIZE == 64
+               case_rr(hton, _ul);
+#endif
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+#if __WORDSIZE == 64
+               case_rr(ext, _i);
+               case_rr(ext, _ui);
+#endif
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), node->v.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rr(neg,);
+               case_rr(com,);
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_rrr(add, _f);
+               case_rrf(add, _f, 32);
+               case_rrr(sub, _f);
+               case_rrf(sub, _f, 32);
+               case_rrf(rsb, _f, 32);
+               case_rrr(mul, _f);
+               case_rrf(mul, _f, 32);
+               case_rrr(div, _f);
+               case_rrf(div, _f, 32);
+               case_rr(abs, _f);
+               case_rr(neg, _f);
+               case_rr(sqrt, _f);
+               case_rr(ext, _f);
+               case_rr(ld, _f);
+               case_rw(ld, _f);
+               case_rrr(ldx, _f);
+               case_rrw(ldx, _f);
+               case_rr(st, _f);
+               case_wr(st, _f);
+               case_rrr(stx, _f);
+               case_wrr(stx, _f);
+               case_rr(mov, _f);
+           case jit_code_movi_f:
+               assert(node->flag & jit_flag_data);
+               movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _d_f);
+               case_rrr(lt, _f);
+               case_rrf(lt, _f, 32);
+               case_rrr(le, _f);
+               case_rrf(le, _f, 32);
+               case_rrr(eq, _f);
+               case_rrf(eq, _f, 32);
+               case_rrr(ge, _f);
+               case_rrf(ge, _f, 32);
+               case_rrr(gt, _f);
+               case_rrf(gt, _f, 32);
+               case_rrr(ne, _f);
+               case_rrf(ne, _f, 32);
+               case_rrr(unlt, _f);
+               case_rrf(unlt, _f, 32);
+               case_rrr(unle, _f);
+               case_rrf(unle, _f, 32);
+               case_rrr(uneq, _f);
+               case_rrf(uneq, _f, 32);
+               case_rrr(unge, _f);
+               case_rrf(unge, _f, 32);
+               case_rrr(ungt, _f);
+               case_rrf(ungt, _f, 32);
+               case_rrr(ltgt, _f);
+               case_rrf(ltgt, _f, 32);
+               case_rrr(ord, _f);
+               case_rrf(ord, _f, 32);
+               case_rrr(unord, _f);
+               case_rrf(unord, _f, 32);
+               case_brr(blt, _f);
+               case_brf(blt, _f, 32);
+               case_brr(ble, _f);
+               case_brf(ble, _f, 32);
+               case_brr(beq, _f);
+               case_brf(beq, _f, 32);
+               case_brr(bge, _f);
+               case_brf(bge, _f, 32);
+               case_brr(bgt, _f);
+               case_brf(bgt, _f, 32);
+               case_brr(bne, _f);
+               case_brf(bne, _f, 32);
+               case_brr(bunlt, _f);
+               case_brf(bunlt, _f, 32);
+               case_brr(bunle, _f);
+               case_brf(bunle, _f, 32);
+               case_brr(buneq, _f);
+               case_brf(buneq, _f, 32);
+               case_brr(bunge, _f);
+               case_brf(bunge, _f, 32);
+               case_brr(bungt, _f);
+               case_brf(bungt, _f, 32);
+               case_brr(bltgt, _f);
+               case_brf(bltgt, _f, 32);
+               case_brr(bord, _f);
+               case_brf(bord, _f, 32);
+               case_brr(bunord, _f);
+               case_brf(bunord, _f, 32);
+               case_rrr(add, _d);
+               case_rrf(add, _d, 64);
+               case_rrr(sub, _d);
+               case_rrf(sub, _d, 64);
+               case_rrf(rsb, _d, 64);
+               case_rrr(mul, _d);
+               case_rrf(mul, _d, 64);
+               case_rrr(div, _d);
+               case_rrf(div, _d, 64);
+               case_rr(abs, _d);
+               case_rr(neg, _d);
+               case_rr(sqrt, _d);
+               case_rr(ext, _d);
+               case_rr(ld, _d);
+               case_rw(ld, _d);
+               case_rrr(ldx, _d);
+               case_rrw(ldx, _d);
+               case_rr(st, _d);
+               case_wr(st, _d);
+               case_rrr(stx, _d);
+               case_wrr(stx, _d);
+               case_rr(mov, _d);
+           case jit_code_movi_d:
+               assert(node->flag & jit_flag_data);
+               movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _f_d);
+               case_rrr(lt, _d);
+               case_rrf(lt, _d, 64);
+               case_rrr(le, _d);
+               case_rrf(le, _d, 64);
+               case_rrr(eq, _d);
+               case_rrf(eq, _d, 64);
+               case_rrr(ge, _d);
+               case_rrf(ge, _d, 64);
+               case_rrr(gt, _d);
+               case_rrf(gt, _d, 64);
+               case_rrr(ne, _d);
+               case_rrf(ne, _d, 64);
+               case_rrr(unlt, _d);
+               case_rrf(unlt, _d, 64);
+               case_rrr(unle, _d);
+               case_rrf(unle, _d, 64);
+               case_rrr(uneq, _d);
+               case_rrf(uneq, _d, 64);
+               case_rrr(unge, _d);
+               case_rrf(unge, _d, 64);
+               case_rrr(ungt, _d);
+               case_rrf(ungt, _d, 64);
+               case_rrr(ltgt, _d);
+               case_rrf(ltgt, _d, 64);
+               case_rrr(ord, _d);
+               case_rrf(ord, _d, 64);
+               case_rrr(unord, _d);
+               case_rrf(unord, _d, 64);
+               case_brr(blt, _d);
+               case_brf(blt, _d, 64);
+               case_brr(ble, _d);
+               case_brf(ble, _d, 64);
+               case_brr(beq, _d);
+               case_brf(beq, _d, 64);
+               case_brr(bge, _d);
+               case_brf(bge, _d, 64);
+               case_brr(bgt, _d);
+               case_brf(bgt, _d, 64);
+               case_brr(bne, _d);
+               case_brf(bne, _d, 64);
+               case_brr(bunlt, _d);
+               case_brf(bunlt, _d, 64);
+               case_brr(bunle, _d);
+               case_brf(bunle, _d, 64);
+               case_brr(buneq, _d);
+               case_brf(buneq, _d, 64);
+               case_brr(bunge, _d);
+               case_brf(bunge, _d, 64);
+               case_brr(bungt, _d);
+               case_brf(bungt, _d, 64);
+               case_brr(bltgt, _d);
+               case_brf(bltgt, _d, 64);
+               case_brr(bord, _d);
+               case_brf(bord, _d, 64);
+               case_brr(bunord, _d);
+               case_brf(bunord, _d, 64);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   word = calli_p(temp->u.w);
+                   if (!(temp->flag & jit_flag_patch))
+                       patch(word, node);
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+           restart_function:
+               _jitc->again = 0;
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+                   goto restart_function;
+               }
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               break;
+#if !NEW_ABI
+           case jit_code_movr_w_f:
+               movr_w_f(rn(node->u.w), rn(node->v.w));
+               break;
+#endif
+           case jit_code_movr_f_w:
+               movr_f_w(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movi_f_w:
+               assert(node->flag & jit_flag_data);
+               movi_f_w(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               break;
+#if NEW_ABI
+           case jit_code_movr_d_w:
+               movr_d_w(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movi_d_w:
+               assert(node->flag & jit_flag_data);
+               movi_d_w(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               break;
+#else
+           case jit_code_movr_ww_d:
+               movr_ww_d(rn(node->u.w), rn(node->v.w), rn(node->w.w));
+               break;
+           case jit_code_movr_d_ww:
+               movr_d_ww(rn(node->u.w), rn(node->v.w), rn(node->w.w));
+               break;
+           case jit_code_movi_d_ww:
+               assert(node->flag & jit_flag_data);
+               movi_d_ww(rn(node->u.w), rn(node->v.w),
+                         (jit_float64_t *)node->w.n->u.w);
+               break;
+#endif
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:
+           case jit_code_arg:                  case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:
+#if __WORDSIZE == 64
+           case jit_code_getarg_ui:            case jit_code_getarg_l:
+#endif
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+#if __WORDSIZE == 64
+           case jit_code_retval_ui:            case jit_code_retval_l:
+#endif
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           default:
+               abort();
+       }
+       if (jit_carry != _NOREG) {
+           switch (node->code) {
+               case jit_code_note:
+               case jit_code_addcr:            case jit_code_addci:
+               case jit_code_addxr:            case jit_code_addxi:
+               case jit_code_subcr:            case jit_code_subci:
+               case jit_code_subxr:            case jit_code_subxi:
+                   break;
+               default:
+                   jit_unget_reg(jit_carry);
+                   jit_carry = _NOREG;
+                   break;
+           }
+       }
+       jit_regarg_clr(node, value);
+       assert(_jitc->regarg == 0 ||
+              (jit_carry != _NOREG && _jitc->regarg == (1 << jit_carry)));
+       assert(_jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+    }
+#undef case_brf
+#undef case_brw
+#undef case_brr
+#undef case_wrr
+#undef case_rrf
+#undef case_rrw
+#undef case_rrr
+#undef case_wr
+#undef case_rw
+#undef case_rr
+
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(_jitc->patches.ptr[offset].inst, word);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_rewind.c"
+#  include "jit_mips-cpu.c"
+#  include "jit_mips-fpu.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+#if defined(__linux__)
+    jit_word_t         f, t, s;
+
+    s = sysconf(_SC_PAGE_SIZE);
+    f = (jit_word_t)fptr & -s;
+    t = (((jit_word_t)tptr) + s - 1) & -s;
+    _flush_cache((void *)f, t - f, ICACHE);
+#endif
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi(i0, rn(r0), rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi_d(i0, rn(r0), rn(r1));
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                 flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+    assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_names.c b/deps/lightning/lib/jit_names.c
new file mode 100644 (file)
index 0000000..475bc96
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2014-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+static char *code_name[] = {
+    "data",
+    "live",            "align",
+    "save",            "load",
+    "#name",           "#note",
+    "label",
+    "prolog",
+    "ellipsis",                "va_push",
+    "allocai",         "allocar",
+    "arg",
+    "getarg_c",                "getarg_uc",
+    "getarg_s",                "getarg_us",
+    "getarg_i",                "getarg_ui",
+    "getarg_l",
+    "putargr",         "putargi",
+    "va_start",
+    "va_arg",          "va_arg_d",
+    "va_end",
+    "addr",            "addi",
+    "addcr",           "addci",
+    "addxr",           "addxi",
+    "subr",            "subi",
+    "subcr",           "subci",
+    "subxr",           "subxi",
+    "rsbi",
+    "mulr",            "muli",
+    "qmulr",           "qmuli",
+    "qmulr_u",         "qmuli_u",
+    "divr",            "divi",
+    "divr_u",          "divi_u",
+    "qdivr",           "qdivi",
+    "qdivr_u",         "qdivi_u",
+    "remr",            "remi",
+    "remr_u",          "remi_u",
+    "andr",            "andi",
+    "orr",             "ori",
+    "xorr",            "xori",
+    "lshr",            "lshi",
+    "rshr",            "rshi",
+    "rshr_u",          "rshi_u",
+    "negr",            "comr",
+    "ltr",             "lti",
+    "ltr_u",           "lti_u",
+    "ler",             "lei",
+    "ler_u",           "lei_u",
+    "eqr",             "eqi",
+    "ger",             "gei",
+    "ger_u",           "gei_u",
+    "gtr",             "gti",
+    "gtr_u",           "gti_u",
+    "ner",             "nei",
+    "movr",            "movi",
+    "extr_c",          "extr_uc",
+    "extr_s",          "extr_us",
+    "extr_i",          "extr_ui",
+    "htonr_us",
+    "htonr_ui",                "htonr_ul",
+    "ldr_c",           "ldi_c",
+    "ldr_uc",          "ldi_uc",
+    "ldr_s",           "ldi_s",
+    "ldr_us",          "ldi_us",
+    "ldr_i",           "ldi_i",
+    "ldr_ui",          "ldi_ui",
+    "ldr_l",           "ldi_l",
+    "ldxr_c",          "ldxi_c",
+    "ldxr_uc",         "ldxi_uc",
+    "ldxr_s",          "ldxi_s",
+    "ldxr_us",         "ldxi_us",
+    "ldxr_i",          "ldxi_i",
+    "ldxr_ui",         "ldxi_ui",
+    "ldxr_l",          "ldxi_l",
+    "str_c",           "sti_c",
+    "str_s",           "sti_s",
+    "str_i",           "sti_i",
+    "str_l",           "sti_l",
+    "stxr_c",          "stxi_c",
+    "stxr_s",          "stxi_s",
+    "stxr_i",          "stxi_i",
+    "stxr_l",          "stxi_l",
+    "bltr",            "blti",
+    "bltr_u",          "blti_u",
+    "bler",            "blei",
+    "bler_u",          "blei_u",
+    "beqr",            "beqi",
+    "bger",            "bgei",
+    "bger_u",          "bgei_u",
+    "bgtr",            "bgti",
+    "bgtr_u",          "bgti_u",
+    "bner",            "bnei",
+    "bmsr",            "bmsi",
+    "bmcr",            "bmci",
+    "boaddr",          "boaddi",
+    "boaddr_u",                "boaddi_u",
+    "bxaddr",          "bxaddi",
+    "bxaddr_u",                "bxaddi_u",
+    "bosubr",          "bosubi",
+    "bosubr_u",                "bosubi_u",
+    "bxsubr",          "bxsubi",
+    "bxsubr_u",                "bxsubi_u",
+    "jmpr",            "jmpi",
+    "callr",           "calli",
+    "prepare",
+    "pushargr",                "pushargi",
+    "finishr",         "finishi",
+    "ret",
+    "retr",            "reti",
+    "retval_c",                "retval_uc",
+    "retval_s",                "retval_us",
+    "retval_i",                "retval_ui",
+    "retval_l",
+    "epilog",
+    "arg_f",           "getarg_f",
+    "putargr_f",       "putargi_f",
+    "addr_f",          "addi_f",
+    "subr_f",          "subi_f",
+    "rsbi_f",
+    "mulr_f",          "muli_f",
+    "divr_f",          "divi_f",
+    "negr_f",          "absr_f",
+    "sqrtr_f",
+    "ltr_f",           "lti_f",
+    "ler_f",           "lei_f",
+    "eqr_f",           "eqi_f",
+    "ger_f",           "gei_f",
+    "gtr_f",           "gti_f",
+    "ner_f",           "nei_f",
+    "unltr_f",         "unlti_f",
+    "unler_f",         "unlei_f",
+    "uneqr_f",         "uneqi_f",
+    "unger_f",         "ungei_f",
+    "ungtr_f",         "ungti_f",
+    "ltgtr_f",         "ltgti_f",
+    "ordr_f",          "ordi_f",
+    "unordr_f",                "unordi_f",
+    "truncr_f_i",      "truncr_f_l",
+    "extr_f",          "extr_d_f",
+    "movr_f",          "movi_f",
+    "ldr_f",           "ldi_f",
+    "ldxr_f",          "ldxi_f",
+    "str_f",           "sti_f",
+    "stxr_f",          "stxi_f",
+    "bltr_f",          "blti_f",
+    "bler_f",          "blei_f",
+    "beqr_f",          "beqi_f",
+    "bger_f",          "bgei_f",
+    "bgtr_f",          "bgti_f",
+    "bner_f",          "bnei_f",
+    "bunltr_f",                "bunlti_f",
+    "bunler_f",                "bunlei_f",
+    "buneqr_f",                "buneqi_f",
+    "bunger_f",                "bungei_f",
+    "bungtr_f",                "bungti_f",
+    "bltgtr_f",                "bltgti_f",
+    "bordr_f",         "bordi_f",
+    "bunordr_f",       "bunordi_f",
+    "pushargr_f",      "pushargi_f",
+    "retr_f",          "reti_f",
+    "retval_f",
+    "arg_d",           "getarg_d",
+    "putargr_d",       "putargi_d",
+    "addr_d",          "addi_d",
+    "subr_d",          "subi_d",
+    "rsbi_d",
+    "mulr_d",          "muli_d",
+    "divr_d",          "divi_d",
+    "negr_d",          "absr_d",
+    "sqrtr_d",
+    "ltr_d",           "lti_d",
+    "ler_d",           "lei_d",
+    "eqr_d",           "eqi_d",
+    "ger_d",           "gei_d",
+    "gtr_d",           "gti_d",
+    "ner_d",           "nei_d",
+    "unltr_d",         "unlti_d",
+    "unler_d",         "unlei_d",
+    "uneqr_d",         "uneqi_d",
+    "unger_d",         "ungei_d",
+    "ungtr_d",         "ungti_d",
+    "ltgtr_d",         "ltgti_d",
+    "ordr_d",          "ordi_d",
+    "unordr_d",                "unordi_d",
+    "truncr_d_i",      "truncr_d_l",
+    "extr_d",          "extr_f_d",
+    "movr_d",          "movi_d",
+    "ldr_d",           "ldi_d",
+    "ldxr_d",          "ldxi_d",
+    "str_d",           "sti_d",
+    "stxr_d",          "stxi_d",
+    "bltr_d",          "blti_d",
+    "bler_d",          "blei_d",
+    "beqr_d",          "beqi_d",
+    "bger_d",          "bgei_d",
+    "bgtr_d",          "bgti_d",
+    "bner_d",          "bnei_d",
+    "bunltr_d",                "bunlti_d",
+    "bunler_d",                "bunlei_d",
+    "buneqr_d",                "buneqi_d",
+    "bunger_d",                "bungei_d",
+    "bungtr_d",                "bungti_d",
+    "bltgtr_d",                "bltgti_d",
+    "bordr_d",         "bordi_d",
+    "bunordr_d",       "bunordi_d",
+    "pushargr_d",      "pushargi_d",
+    "retr_d",          "reti_d",
+    "retval_d",
+    "movr_w_f",                "movr_ww_d",
+    "movr_w_d",
+    "movr_f_w",                "movi_f_w",
+    "movr_d_ww",       "movi_d_ww",
+    "movr_d_w",                "movi_d_w",
+};
diff --git a/deps/lightning/lib/jit_note.c b/deps/lightning/lib/jit_note.c
new file mode 100644 (file)
index 0000000..c79b818
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+
+/*
+ * Prototypes
+ */
+#define new_note(u, v)         _new_note(_jit, u, v)
+static jit_note_t *_new_note(jit_state_t *, jit_uint8_t*, char*);
+static void new_line(jit_int32_t,jit_note_t*,char*,jit_int32_t,jit_int32_t);
+#define note_search_index(u)   _note_search_index(_jit, u)
+static jit_int32_t _note_search_index(jit_state_t*, jit_uint8_t*);
+static jit_int32_t line_insert_index(jit_note_t*,jit_int32_t);
+static jit_int32_t line_search_index(jit_note_t*,jit_int32_t);
+static jit_int32_t offset_insert_index(jit_line_t*,jit_int32_t);
+static jit_int32_t offset_search_index(jit_line_t*,jit_int32_t);
+
+/*
+ * Implementation
+ */
+void
+jit_init_note(void)
+{
+}
+
+void
+jit_finish_note(void)
+{
+}
+
+jit_node_t *
+_jit_name(jit_state_t *_jit, const char *name)
+{
+    jit_node_t         *node;
+
+    node = jit_new_node(jit_code_name);
+    if (name)
+       node->v.n = jit_data(name, strlen(name) + 1, 1);
+    else
+       node->v.p = NULL;
+    if (_jitc->note.head == NULL)
+       _jitc->note.head = _jitc->note.tail = node;
+    else {
+       _jitc->note.tail->link = node;
+       _jitc->note.tail = node;
+    }
+    ++_jit->note.length;
+    _jitc->note.size += sizeof(jit_note_t);
+    /* remember previous note is invalid due to name change */
+    _jitc->note.note = NULL;
+    return (_jitc->note.name = node);
+}
+
+jit_node_t *
+_jit_note(jit_state_t *_jit, const char *name, int line)
+{
+    jit_node_t         *node;
+
+    node = jit_new_node(jit_code_note);
+    if (name)
+       node->v.n = jit_data(name, strlen(name) + 1, 1);
+    else
+       node->v.p = NULL;
+    node->w.w = line;
+    if (_jitc->note.head == NULL)
+       _jitc->note.head = _jitc->note.tail = node;
+    else {
+       _jitc->note.tail->link = node;
+       _jitc->note.tail = node;
+    }
+    if (_jitc->note.note == NULL ||
+       (name == NULL && _jitc->note.note != NULL) ||
+       (name != NULL && _jitc->note.note == NULL) ||
+       (name != NULL && _jitc->note.note != NULL &&
+        strcmp(name, (char *)_jitc->data.ptr + _jitc->note.note->v.n->u.w)))
+       _jitc->note.size += sizeof(jit_line_t);
+    _jitc->note.size += sizeof(jit_int32_t) * 2;
+    return (_jitc->note.note = node);
+}
+
+void
+_jit_annotate(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_note_t         *note;
+    jit_line_t         *line;
+    jit_word_t          length;
+    jit_word_t          note_offset;
+    jit_word_t          line_offset;
+
+    /* initialize pointers in mmaped data area */
+    _jit->note.ptr = (jit_note_t *)_jitc->note.base;
+    _jit->note.length = 0;
+
+    note = NULL;
+    for (node = _jitc->note.head; node; node = node->link) {
+       if (node->code == jit_code_name)
+           note = new_note(node->u.p, node->v.p ? node->v.n->u.p : NULL);
+       else if (node->v.p) {
+           if (note == NULL)
+               note = new_note(node->u.p, NULL);
+           jit_set_note(note, node->v.n->u.p, node->w.w,
+                        (jit_uint8_t *)node->u.p - note->code);
+       }
+    }
+    /* last note */
+    if (note)
+       note->size = _jit->pc.uc - note->code;
+
+    /* annotations may be very complex with conditions to extend
+     * or ignore redundant notes, as well as add entries to earlier
+     * notes, so, relocate the information to the data buffer,
+     * with likely over allocated reserved space */
+
+    /* relocate jit_line_t objects */
+    for (note_offset = 0; note_offset < _jit->note.length; note_offset++) {
+       note = _jit->note.ptr + note_offset;
+       if ((length = sizeof(jit_line_t) * note->length) == 0)
+           continue;
+       assert(_jitc->note.base + length < _jit->data.ptr + _jit->data.length);
+       jit_memcpy(_jitc->note.base, note->lines, length);
+       jit_free((jit_pointer_t *)&note->lines);
+       note->lines = (jit_line_t *)_jitc->note.base;
+       _jitc->note.base += length;
+    }
+
+    /* relocate offset and line number information */
+    for (note_offset = 0; note_offset < _jit->note.length; note_offset++) {
+       note = _jit->note.ptr + note_offset;
+       for (line_offset = 0; line_offset < note->length; line_offset++) {
+           line = note->lines + line_offset;
+           length = sizeof(jit_int32_t) * line->length;
+           assert(_jitc->note.base + length <
+                  _jit->data.ptr + _jit->data.length);
+           jit_memcpy(_jitc->note.base, line->linenos, length);
+           jit_free((jit_pointer_t *)&line->linenos);
+           line->linenos = (jit_int32_t *)_jitc->note.base;
+           _jitc->note.base += length;
+           assert(_jitc->note.base + length <
+                  _jit->data.ptr + _jit->data.length);
+           jit_memcpy(_jitc->note.base, line->offsets, length);
+           jit_free((jit_pointer_t *)&line->offsets);
+           line->offsets = (jit_int32_t *)_jitc->note.base;
+           _jitc->note.base += length;
+       }
+    }
+}
+
+void
+_jit_set_note(jit_state_t *_jit, jit_note_t *note,
+             char *file, int lineno, jit_int32_t offset)
+{
+    jit_line_t         *line;
+    jit_int32_t                 index;
+
+    index = line_insert_index(note, offset);
+    if (note->length && index == note->length &&
+       note->lines[index - 1].file == file)
+       --index;
+    if (index >= note->length || note->lines[index].file != file)
+       new_line(index, note, file, lineno, offset);
+    else {
+       line = note->lines + index;
+       index = offset_insert_index(line, offset);
+       if (index < line->length && line->offsets[index] == offset) {
+           /* common case if no code was generated for several source lines */
+           if (line->linenos[index] < lineno)
+               line->linenos[index] = lineno;
+       }
+       else if (index < line->length && line->linenos[index] == lineno) {
+           /* common case of extending entry */
+           if (line->offsets[index] > offset)
+               line->offsets[index] = offset;
+       }
+       else {
+           /* line or offset changed */
+           if ((line->length & 15) == 0) {
+               jit_realloc((jit_pointer_t *)&line->linenos,
+                           line->length * sizeof(jit_int32_t),
+                           (line->length + 17) * sizeof(jit_int32_t));
+               jit_realloc((jit_pointer_t *)&line->offsets,
+                           line->length * sizeof(jit_int32_t),
+                           (line->length + 17) * sizeof(jit_int32_t));
+           }
+           if (index < note->length) {
+               jit_memmove(line->linenos + index + 1, line->linenos + index,
+                           sizeof(jit_int32_t) * (line->length - index));
+               jit_memmove(line->offsets + index + 1, line->offsets + index,
+                           sizeof(jit_int32_t) * (line->length - index));
+           }
+           line->linenos[index] = lineno;
+           line->offsets[index] = offset;
+           ++line->length;
+       }
+    }
+}
+
+jit_bool_t
+_jit_get_note(jit_state_t *_jit, jit_pointer_t code,
+             char **name, char **file, jit_int32_t *lineno)
+{
+    jit_note_t         *note;
+    jit_line_t         *line;
+    jit_int32_t                 index;
+    jit_int32_t                 offset;
+
+    if ((index = note_search_index((jit_uint8_t *)code)) >= _jit->note.length)
+       return (0);
+    note = _jit->note.ptr + index;
+    if ((jit_uint8_t *)code < note->code ||
+       (jit_uint8_t *)code >= note->code + note->size)
+       return (0);
+    offset = (jit_uint8_t *)code - note->code;
+    if ((index = line_search_index(note, offset)) >= note->length)
+       return (0);
+    if (index == 0 && offset < note->lines[0].offsets[0])
+       return (0);
+    line = note->lines + index;
+    if ((index = offset_search_index(line, offset)) >= line->length)
+       return (0);
+
+    if (name)
+       *name = note->name;
+    if (file)
+       *file = line->file;
+    if (lineno)
+       *lineno = line->linenos[index];
+
+    return (1);
+}
+
+static jit_note_t *
+_new_note(jit_state_t *_jit, jit_uint8_t *code, char *name)
+{
+    jit_note_t         *note;
+    jit_note_t         *prev;
+
+    if (_jit->note.length) {
+       prev = _jit->note.ptr + _jit->note.length - 1;
+       assert(code >= prev->code);
+       prev->size = code - prev->code;
+    }
+    note = (jit_note_t *)_jitc->note.base;
+    _jitc->note.base += sizeof(jit_note_t);
+    ++_jit->note.length;
+    note->code = code;
+    note->name = name;
+
+    return (note);
+}
+
+static void
+new_line(jit_int32_t index, jit_note_t *note,
+         char *file, jit_int32_t lineno, jit_int32_t offset)
+{
+    jit_line_t         *line;
+
+    if (note->lines == NULL)
+       jit_alloc((jit_pointer_t *)&note->lines, 16 * sizeof(jit_line_t));
+    else if ((note->length & 15) == 15)
+       jit_realloc((jit_pointer_t *)&note->lines,
+                   note->length * sizeof(jit_line_t),
+                   (note->length + 17) * sizeof(jit_line_t));
+
+    if (index < note->length)
+       jit_memmove(note->lines + index + 1, note->lines + index,
+                   sizeof(jit_line_t) * (note->length - index));
+    line = note->lines + index;
+    ++note->length;
+
+    line->file = file;
+    line->length = 1;
+    jit_alloc((jit_pointer_t *)&line->linenos, 16 * sizeof(jit_int32_t));
+    line->linenos[0] = lineno;
+    jit_alloc((jit_pointer_t *)&line->offsets, 16 * sizeof(jit_int32_t));
+    line->offsets[0] = offset;
+}
+
+static jit_int32_t
+_note_search_index(jit_state_t *_jit, jit_uint8_t *code)
+{
+    jit_int32_t                 bot;
+    jit_int32_t                 top;
+    jit_int32_t                 index;
+    jit_note_t         *notes;
+
+    bot = 0;
+    top = _jit->note.length;
+    notes = _jit->note.ptr;
+    for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
+       if (code < notes[index].code)
+           top = index;
+       else if (code >= notes[index].code &&
+                code - notes[index].code < notes[index].size)
+           break;
+       else
+           bot = index + 1;
+    }
+
+    return (index);
+}
+
+static jit_int32_t
+line_insert_index(jit_note_t *note, jit_int32_t offset)
+{
+    jit_int32_t                 bot;
+    jit_int32_t                 top;
+    jit_int32_t                 index;
+    jit_line_t         *lines;
+
+    bot = 0;
+    top = note->length;
+    if ((lines = note->lines) == NULL)
+       return (0);
+    for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
+       if (offset < *lines[index].offsets)
+           top = index;
+       else
+           bot = index + 1;
+    }
+
+    return ((bot + top) >> 1);
+}
+
+static jit_int32_t
+line_search_index(jit_note_t *note, jit_int32_t offset)
+{
+    jit_int32_t                 bot;
+    jit_int32_t                 top;
+    jit_int32_t                 index;
+    jit_line_t         *lines;
+
+    bot = 0;
+    top = note->length;
+    if ((lines = note->lines) == NULL)
+       return (0);
+    for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
+       if (offset < *lines[index].offsets)
+           top = index;
+       /* offset should be already verified to be in range */
+       else if (index == note->length - 1 ||
+                (offset >= *lines[index].offsets &&
+                 offset < *lines[index + 1].offsets))
+           break;
+       else
+           bot = index + 1;
+    }
+
+    return (index);
+}
+
+static jit_int32_t
+offset_insert_index(jit_line_t *line, jit_int32_t offset)
+{
+    jit_int32_t                 bot;
+    jit_int32_t                 top;
+    jit_int32_t                 index;
+    jit_int32_t                *offsets;
+
+    bot = 0;
+    top = line->length;
+    offsets = line->offsets;
+    for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
+       if (offset < offsets[index])
+           top = index;
+       else
+           bot = index + 1;
+    }
+
+    return ((bot + top) >> 1);
+}
+
+static jit_int32_t
+offset_search_index(jit_line_t *line, jit_int32_t offset)
+{
+    jit_int32_t                 bot;
+    jit_int32_t                 top;
+    jit_int32_t                 index;
+    jit_int32_t                *offsets;
+
+    bot = 0;
+    top = line->length;
+    offsets = line->offsets;
+    for (index = (bot + top) >> 1; bot < top; index = (bot + top) >> 1) {
+       if (offset < offsets[index])
+           top = index;
+       /* offset should be already verified to be in range */
+       else if (index == line->length - 1 ||
+                (offset >= offsets[index] && offset < offsets[index + 1]))
+           break;
+       else
+           bot = index + 1;
+    }
+
+    return (index);
+}
diff --git a/deps/lightning/lib/jit_ppc-cpu.c b/deps/lightning/lib/jit_ppc-cpu.c
new file mode 100644 (file)
index 0000000..c4397ad
--- /dev/null
@@ -0,0 +1,3654 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  if __WORDSIZE == 32
+#    define gpr_save_area              72      /* r14~r31 = 18 * 4 */
+#    if _CALL_SYSV
+#      define params_offset            (sizeof(jit_word_t) << 1)
+#    else
+#      define params_offset            24
+#    endif
+#    define can_sign_extend_int_p(im)  1
+#    define can_zero_extend_int_p(im)  1
+#    define fits_uint32_p(im)          1
+#  else
+#    define gpr_save_area              144     /* r14~r31 = 18 * 8 */
+#    if _CALL_ELF == 2
+#      define params_offset            32
+#    else
+#      define params_offset            48
+#    endif
+#    define can_sign_extend_int_p(im)                                  \
+       (((im) >= 0 && (long)(im) <=  0x7fffffffL) ||                   \
+        ((im) <  0 && (long)(im) >= -0x80000000L))
+#    define can_zero_extend_int_p(im)                                  \
+       ((im) >= 0 && (im) < 0x80000000L)
+#    define fits_uint32_p(im)          ((im & 0xffffffff00000000L) == 0)
+#  endif
+#  define fpr_save_area                        64
+#  define alloca_offset                        -(gpr_save_area + fpr_save_area)
+#  define ii(i)                                *_jit->pc.ui++ = i
+#  if __WORDSIZE == 32
+#    define iw(i)                      *_jit->pc.ui++ = i
+#  else
+#    define iw(i)                      *_jit->pc.ul++ = i
+#  endif
+#  define can_sign_extend_short_p(im)  ((im) >= -32768 && (im) <= 32767)
+#  define can_zero_extend_short_p(im)  ((im) >= 0 && (im) <= 65535)
+#  define can_sign_extend_jump_p(im)   ((im) >= -33554432 && (im) <= 33554431)
+#  define _R0_REGNO                    0
+#  define _SP_REGNO                    1
+#  define _R2_REGNO                    2
+#  define _R11_REGNO                   11
+#  define _R12_REGNO                   12
+#  define _FP_REGNO                    31
+#  if __WORDSIZE == 32
+#    define ldr(r0,r1)                 ldr_i(r0,r1)
+#    define ldxi(r0,r1,i0)             ldxi_i(r0,r1,i0)
+#    define ldxr(r0,r1,r2)             ldxr_i(r0,r1,r2)
+#    define stxi(i0,r0,r1)             stxi_i(i0,r0,r1)
+#    define stxr(r0,r1,r2)             stxr_i(r0,r1,r2)
+#  else
+#    define ldr(r0,r1)                 ldr_l(r0,r1)
+#    define ldxi(r0,r1,i0)             ldxi_l(r0,r1,i0)
+#    define ldxr(r0,r1,r2)             ldxr_l(r0,r1,r2)
+#    define stxi(i0,r0,r1)             stxi_l(i0,r0,r1)
+#    define stxr(r0,r1,r2)             stxr_l(r0,r1,r2)
+#  endif
+#  define FXO(o,d,a,b,e,x)             _FXO(_jit,o,d,a,b,e,x,0)
+#  define FXO_(o,d,a,b,e,x)            _FXO(_jit,o,d,a,b,e,x,1)
+static void _FXO(jit_state_t*,int,int,int,int,int,int,int);
+#  define FDs(o,d,a,s)                 _FDs(_jit,o,d,a,s)
+static void _FDs(jit_state_t*,int,int,int,int);
+#  define FDu(o,d,a,s)                 _FDu(_jit,o,d,a,s)
+static void _FDu(jit_state_t*,int,int,int,int);
+#  define FX(o,d,a,b,x)                        _FX(_jit,o,d,a,b,x,0)
+#  define FX_(o,d,a,b,x)               _FX(_jit,o,d,a,b,x,1)
+static void _FX(jit_state_t*,int,int,int,int,int,int);
+#  define FI(o,t,a,k)                  _FI(_jit,o,t,a,k)
+static void _FI(jit_state_t*,int,int,int,int);
+#  define FB(o,bo,bi,t,a,k)            _FB(_jit,o,bo,bi,t,a,k)
+static void _FB(jit_state_t*,int,int,int,int,int,int);
+#  define FXL(o,bo,bi,x)               _FXL(_jit,o,bo,bi,x,0)
+#  define FXL_(o,bo,bi,x)              _FXL(_jit,o,bo,bi,x,1)
+static void _FXL(jit_state_t*,int,int,int,int,int);
+#  define FC(o,d,l,a,b,x)              _FC(_jit,o,d,l,a,b,x)
+static void _FC(jit_state_t*,int,int,int,int,int,int);
+#  define FCI(o,d,l,a,s)               _FCI(_jit,o,d,l,a,s)
+static void _FCI(jit_state_t*,int,int,int,int,int);
+#  define FXFX(o,s,x,f)                        _FXFX(_jit,o,s,x,f)
+static void _FXFX(jit_state_t*,int,int,int,int);
+#  define FM(o,s,a,h,b,e,r)            _FM(_jit,o,s,a,h,b,e,r)
+static void _FM(jit_state_t*,int,int,int,int,int,int,int);
+#  if __WORDSIZE == 64
+#    define FMDS(o,s,a,b,e,x)          _FMDS(_jit,o,s,a,b,e,x,0)
+#    define FMDS_(o,s,a,b,e,x)         _FMDS(_jit,o,s,a,b,e,x,1)
+static void _FMDS(jit_state_t*,int,int,int,int,int,int,int);
+#    define FMD(o,s,a,h,b,x,i)         _FMD(_jit,o,s,a,h,b,x,i,0)
+#    define FMD_(o,s,a,h,b,x,i)                _FMD(_jit,o,s,a,h,b,x,i,1)
+static void _FMD(jit_state_t*,int,int,int,int,int,int,int,int);
+#  define FXS(o,d,a,h,x,i)             _FXS(_jit,o,d,a,h,x,i,0)
+#  define FXS_(o,d,a,h,x,i)            _FXS(_jit,o,d,a,h,x,i,1)
+static void _FXS(jit_state_t*,int,int,int,int,int,int,int);
+#  endif
+#  define CR_0                         0
+#  define CR_1                         1
+#  define CR_2                         2
+#  define CR_3                         3
+#  define CR_4                         4
+#  define CR_5                         5
+#  define CR_6                         6
+#  define CR_7                         7
+#  define CR_LT                                0
+#  define CR_GT                                1
+#  define CR_EQ                                2
+#  define CR_SO                                3
+#  define CR_UN                                3
+#  define BCC_F                                4
+#  define BCC_T                                12
+#  define ADD(d,a,b)                   FXO(31,d,a,b,0,266)
+#  define ADD_(d,a,b)                  FXO_(31,d,a,b,0,266)
+#  define ADDO(d,a,b)                  FXO(31,d,a,b,1,266)
+#  define ADDO_(d,a,b)                 FXO_(31,d,a,b,1,266)
+#  define ADDC(d,a,b)                  FXO_(31,d,a,b,0,10)
+#  define ADDC_(d,a,b)                 FXO_(31,d,a,b,0,10)
+#  define ADDCO(d,a,b)                 FXO(31,d,a,b,1,10)
+#  define ADDCO_(d,a,b)                        FXO_(31,d,a,b,1,10)
+#  define ADDE(d,a,b)                  FXO(31,d,a,b,0,138)
+#  define ADDE_(d,a,b)                 FXO_(31,d,a,b,0,138)
+#  define ADDEO(d,a,b)                 FXO(31,d,a,b,1,138)
+#  define ADDEO_(d,a,b)                        FXO_(31,d,a,b,1,138)
+#  define ADDI(d,a,s)                  FDs(14,d,a,s)
+#  define ADDIC(d,a,s)                 FDs(12,d,a,s)
+#  define ADDIC_(d,a,s)                        FDs(13,d,a,s)
+#  define ADDIS(d,a,s)                 FDs(15,d,a,s)
+#  define LIS(d,s)                     ADDIS(d,0,s)
+#  define ADDME(d,a)                   FXO(31,d,a,0,0,234)
+#  define ADDME_(d,a)                  FXO_(31,d,a,0,0,234)
+#  define ADDMEO(d,a)                  FXO(31,d,a,0,1,234)
+#  define ADDMEO_(d,a)                 FXO_(31,d,a,0,1,234)
+#  define ADDZE(d,a)                   FXO(31,d,a,0,0,202)
+#  define ADDZE_(d,a)                  FXO_(31,d,a,0,0,202)
+#  define ADDZEO(d,a)                  FXO(31,d,a,0,1,202)
+#  define ADDZEO_(d,a)                 FXO_(31,d,a,0,1,202)
+#  define AND(d,a,b)                   FX(31,a,d,b,28)
+#  define ANDC(d,a,b)                  FXO(31,a,d,b,0,60)
+#  define ANDC_(d,a,b)                 FXO_(31,a,d,b,0,60)
+#  define AND_(d,a,b)                  FX_(31,a,b,d,28)
+#  define ANDI_(d,a,u)                 FDu(28,a,d,u)
+#  define ANDIS_(d,a,u)                        FDu(29,a,d,u)
+#  define B(t)                         FI(18,t,0,0)
+#  define BA(t)                                FI(18,t,1,0)
+#  define BL(t)                                FI(18,t,0,1)
+#  define BLA(t)                       FI(18,t,1,1)
+#  define BC(o,i,t)                    FB(16,o,i,t,0,0)
+#  define BCA(o,i,t)                   FB(16,o,i,t,1,0)
+#  define BCL(o,i,t)                   FB(16,o,i,t,0,1)
+#  define BCLA(o,i,t)                  FB(16,o,i,t,1,1)
+#  define BLT(t)                       BC(BCC_T,CR_LT,t)
+#  define BLE(t)                       BC(BCC_F,CR_GT,t)
+#  define BEQ(t)                       BC(BCC_T,CR_EQ,t)
+#  define BGE(t)                       BC(BCC_F,CR_LT,t)
+#  define BGT(t)                       BC(BCC_T,CR_GT,t)
+#  define BNE(t)                       BC(BCC_F,CR_EQ,t)
+#  define BUN(t)                       BC(BCC_T,CR_UN,t)
+#  define BNU(t)                       BC(BCC_F,CR_UN,t)
+#  define BCCTR(o,i)                   FXL(19,o,i,528)
+#  define BCCTRL(o,i)                  FXL_(19,o,i,528)
+#  define BLTCTR()                     BCCTR(BCC_T,CR_LT)
+#  define BLECTR()                     BCCTR(BCC_F,CR_GT)
+#  define BEQCTR()                     BCCTR(BCC_T,CR_EQ)
+#  define BGECTR()                     BCCTR(BCC_F,CR_LT)
+#  define BGTCTR()                     BCCTR(BCC_T,CR_GT)
+#  define BNECTR()                     BCCTR(BCC_F,CR_EQ)
+#  define BCTR()                       BCCTR(20,0)
+#  define BCTRL()                      BCCTRL(20,0)
+#  define BCLR(o,i)                    FXL(19,o,i,16)
+#  define BCLRL(o,i)                   FXL_(19,o,i,16)
+#  define BLTLR()                      BCLR(BCC_T,CR_LT)
+#  define BLELR()                      BCLR(BCC_F,CR_GT)
+#  define BEQLR()                      BCLR(BCC_T,CR_EQ)
+#  define BGELR()                      BCLR(BCC_F,CR_LT)
+#  define BGTLR()                      BCLR(BCC_T,CR_GT)
+#  define BNELR()                      BCLR(BCC_F,CR_EQ)
+#  define BLR()                                BCLR(20,0)
+#  define BLRL()                       BCLRL(20,0)
+#  define XCMP(cr,l,a,b)               FC(31,cr,l,a,b,0)
+#  define CMPD(a,b)                    XCMP(0,1,a,b)
+#  define CMPW(a,b)                    XCMP(0,0,a,b)
+#  define XCMPI(cr,l,a,s)              FCI(11,cr,l,a,s)
+#  define CMPDI(a,s)                   XCMPI(0,1,a,s)
+#  define CMPWI(a,s)                   XCMPI(0,0,a,s)
+#  define XCMPL(cr,l,a,b)              FC(31,cr,l,a,b,32)
+#  define CMPLD(a,b)                   XCMPL(0,1,a,b)
+#  define CMPLW(a,b)                   XCMPL(0,0,a,b)
+#  define XCMPLI(cr,l,a,u)             FCI(10,cr,l,a,u)
+#  define CMPLDI(a,s)                  XCMPLI(0,1,a,s)
+#  define CMPLWI(a,s)                  XCMPLI(0,0,a,s)
+#  define CNTLZW(a,s)                  FX(31,s,a,0,26)
+#  define CNTLZW_(a,s)                 FX_(31,s,a,0,26)
+#  define CRAND(d,a,b)                 FX(19,d,a,b,257)
+#  define CRANDC(d,a,b)                        FX(19,d,a,b,129)
+#  define CREQV(d,a,b)                 FX(19,d,a,b,289)
+#  define CRSET(d)                     CREQV(d,d,d)
+#  define CRNAND(d,a,b)                        FX(19,d,a,b,225)
+#  define CRNOR(d,a,b)                 FX(19,d,a,b,33)
+#  define CRNOT(d,a)                   CRNOR(d,a,a)
+#  define CROR(d,a,b)                  FX(19,d,a,b,449)
+#  define CRMOVE(d,a)                  CROR(d,a,a)
+#  define CRORC(d,a,b)                 FX(19,d,a,b,417)
+#  define CRXOR(d,a,b)                 FX(19,d,a,b,193)
+#  define CRCLR(d)                     CRXOR(d,d,d)
+#  define DCBA(a,b)                    FX(31,0,a,b,758)
+#  define DCBF(a,b)                    FX(31,0,a,b,86)
+#  define DCBI(a,b)                    FX(31,0,a,b,470)
+#  define DCBST(a,b)                   FX(31,0,a,b,54)
+#  define DCBT(a,b)                    FX(31,0,a,b,278)
+#  define DCBTST(a,b)                  FX(31,0,a,b,246)
+#  define DCBZ(a,b)                    FX(31,0,a,b,1014)
+#  define DIVW(d,a,b)                  FXO(31,d,a,b,0,491)
+#  define DIVW_(d,a,b)                 FXO_(31,d,a,b,0,491)
+#  define DIVWO(d,a,b)                 FXO(31,d,a,b,1,491)
+#  define DIVWO_(d,a,b)                        FXO_(31,d,a,b,1,491)
+#  define DIVWU(d,a,b)                 FXO(31,d,a,b,0,459)
+#  define DIVWU_(d,a,b)                        FXO_(31,d,a,b,0,459)
+#  define DIVWUO(d,a,b)                        FXO(31,d,a,b,1,459)
+#  define DIVWUO_(d,a,b)               FXO_(31,d,a,b,1,459)
+#  define DIVD(d,a,b)                  FXO(31,d,a,b,0,489)
+#  define DIVD_(d,a,b)                 FXO_(31,d,a,b,0,489)
+#  define DIVDO(d,a,b)                 FXO(31,d,a,b,1,489)
+#  define DIVDO_(d,a,b)                        FXO_(31,d,a,b,1,489)
+#  define DIVDU(d,a,b)                 FXO(31,d,a,b,0,457)
+#  define DIVDU_(d,a,b)                        FXO_(31,d,a,b,0,457)
+#  define DIVDUO(d,a,b)                        FXO(31,d,a,b,1,457)
+#  define DIVDUO_(d,a,b)               FXO_(31,d,a,b,1,457)
+#  define ECIWX(d,a,b)                 FX(31,d,a,b,310)
+#  define ECOWX(s,a,b)                 FX(31,s,a,b,438)
+#  define EIEIO()                      FX(31,0,0,0,854)
+#  define EQV(d,a,b)                   FX(31,a,d,b,284)
+#  define EQV_(d,a,b)                  FX_(31,a,d,b,284)
+#  define EXTSB(d,a)                   FX(31,a,d,0,954)
+#  define EXTSB_(d,a)                  FX_(31,a,d,0,954)
+#  define EXTSH(d,a)                   FX(31,a,d,0,922)
+#  define EXTSH_(d,a)                  FX_(31,a,d,0,922)
+#  define EXTSW(d,a)                   FX(31,a,d,0,986)
+#  define EXTSW_(d,a)                  FX_(31,a,d,0,986)
+#  define ICIB(a,b)                    FX(31,0,a,b,982)
+#  define ISYNC()                      FXL(19,0,0,150)
+#  define LBZ(d,a,s)                   FDs(34,d,a,s)
+#  define LBZU(d,a,s)                  FDs(35,d,a,s)
+#  define LBZUX(d,a,b)                 FX(31,d,a,b,119)
+#  define LBZX(d,a,b)                  FX(31,d,a,b,87)
+#  define LHA(d,a,s)                   FDs(42,d,a,s)
+#  define LHAU(d,a,s)                  FDs(43,d,a,s)
+#  define LHAUX(d,a,b)                 FX(31,d,a,b,375)
+#  define LHAX(d,a,b)                  FX(31,d,a,b,343)
+#  define LHRBX(d,a,b)                 FX(31,d,a,b,790)
+#  define LHZ(d,a,s)                   FDs(40,d,a,s)
+#  define LHZU(d,a,s)                  FDs(41,d,a,s)
+#  define LHZUX(d,a,b)                 FX(31,d,a,b,311)
+#  define LHZX(d,a,b)                  FX(31,d,a,b,279)
+#  define LA(d,a,s)                    ADDI(d,a,s)
+#  define LI(d,s)                      ADDI(d,0,s)
+#  define LMW(d,a,s)                   FDs(46,d,a,s)
+#  define LSWI(d,a,n)                  FX(31,d,a,n,597)
+#  define LSWX(d,a,b)                  FX(31,d,a,b,533)
+#  define LWARX(d,a,b)                 FX(31,d,a,b,20)
+#  define LWBRX(d,a,b)                 FX(31,d,a,b,534)
+#  define LWA(d,a,s)                   FDs(58,d,a,s|2)
+#  define LWAUX(d,a,b)                 FX(31,d,a,b,373)
+#  define LWAX(d,a,b)                  FX(31,d,a,b,341)
+#  define LWZ(d,a,s)                   FDs(32,d,a,s)
+#  define LWZU(d,a,s)                  FDs(33,d,a,s)
+#  define LWZUX(d,a,b)                 FX(31,d,a,b,55)
+#  define LWZX(d,a,b)                  FX(31,d,a,b,23)
+#  define LD(d,a,s)                    FDs(58,d,a,s)
+#  define LDX(d,a,b)                   FX(31,d,a,b,21)
+#  define MCRF(d,s)                    FXL(19,d<<2,(s)<<2,0)
+#  if DEBUG
+/* In case instruction is emulated, check the kernel can handle it.
+   Will only generate it if DEBUG is enabled.
+"""
+Chapter 6. Optional Facilities and Instructions that are being
+Phased Out of the Architecture
+...
+6.1 Move To Condition Register from XER
+The mcrxr instruction is being phased out of the archi-
+tecture. Its description is included here as an aid to
+constructing operating system code to emulate it.
+
+Move to Condition Register from XER
+X-form
+mcrxr BF
+31     BF      //      ///     ///     512     /
+0      6       9       11      16      21      31
+CR(4xBF:4xBF+3) <- XER(32:35)
+XER(32:35) <- 0b0000
+The contents of XER(32:35) are copied to Condition Reg-
+ister field BF. XER(32:35) are set to zero.
+Special Registers Altered:
+CR field BF XER(32:35)
+
+Programming Note
+Warning: This instruction has been phased out of
+the architecture. Attempting to execute this
+instruction will cause the system illegal instruction
+error handler to be invoked
+"""
+ */
+#    define MCRXR(d)                   FX(31,d<<2,0,0,512)
+#  else
+#    define MCRXR(cr)                  _MCRXR(_jit,cr);
+static void _MCRXR(jit_state_t*, jit_int32_t);
+#  endif
+#  define MFCR(d)                      FX(31,d,0,0,19)
+#  define MFMSR(d)                     FX(31,d,0,0,83)
+#  define MFSPR(d,s)                   FXFX(31,d,s<<5,339)
+#  define MFXER(d)                     MFSPR(d,1)
+#  define MFLR(d)                      MFSPR(d,8)
+#  define MFCTR(d)                     MFSPR(d,9)
+#  define MFSR(d,s)                    FX(31,d,s,0,595)
+#  define MFSRIN(d,b)                  FX(31,d,0,b,659)
+#  define MFTB(d,x,y)                  FXFX(31,d,(x)|((y)<<5),371)
+#  define MFTBL(d)                     MFTB(d,8,12)
+#  define MFTBU(d)                     MFTB(d,8,13)
+#  define MTCRF(c,s)                   FXFX(31,s,c<<1,144)
+#  define MTCR(s)                      MTCRF(0xff,s)
+#  define MTMSR(s)                     FX(31,s,0,0,146)
+#  define MTSPR(d,s)                   FXFX(31,d,s<<5,467)
+#  define MTXER(d)                     MTSPR(d,1)
+#  define MTLR(d)                      MTSPR(d,8)
+#  define MTCTR(d)                     MTSPR(d,9)
+#  define MTSR(r,s)                    FX(31,s<<1,r,0,210)
+#  define MTSRIN(r,b)                  FX(31,r<<1,0,b,242)
+#  define MULLI(d,a,s)                 FDs(07,d,a,s)
+#  define MULHW(d,a,b)                 FXO(31,d,a,b,0,75)
+#  define MULHW_(d,a,b)                        FXO_(31,d,a,b,0,75)
+#  define MULHWU(d,a,b)                        FXO(31,d,a,b,0,11)
+#  define MULHWU_(d,a,b)               FXO_(31,d,a,b,0,11)
+#  define MULLW(d,a,b)                 FXO(31,d,a,b,0,235)
+#  define MULLW_(d,a,b)                        FXO_(31,d,a,b,0,235)
+#  define MULLWO(d,a,b)                        FXO(31,d,a,b,1,235)
+#  define MULLWO_(d,a,b)               FXO_(31,d,a,b,1,235)
+#  define MULHD(d,a,b)                 FXO(31,d,a,b,0,73)
+#  define MULHD_(d,a,b)                        FXO_(31,d,a,b,0,73)
+#  define MULHDU(d,a,b)                        FXO(31,d,a,b,0,9)
+#  define MULHDU_(d,a,b)               FXO_(31,d,a,b,0,9)
+#  define MULLD(d,a,b)                 FXO(31,d,a,b,0,233)
+#  define MULLD_(d,a,b)                        FXO_(31,d,a,b,0,233)
+#  define MULLDO(d,a,b)                        FXO(31,d,a,b,1,233)
+#  define MULLDO_(d,a,b)               FXO_(31,d,a,b,1,233)
+#  define NAND(d,a,b)                  FX(31,a,d,b,476)
+#  define NAND_(d,a,b)                 FX_(31,a,d,b,476)
+#  define NEG(d,a)                     FXO(31,d,a,0,0,104)
+#  define NEG_(d,a)                    FXO_(31,d,a,0,0,104)
+#  define NEGO(d,a)                    FXO(31,d,a,0,1,104)
+#  define NEGO_(d,a)                   FXO_(31,d,a,0,1,104)
+#  define NOR(d,a,b)                   FX(31,a,d,b,124)
+#  define NOR_(d,a,b)                  FX_(31,a,d,b,124)
+#  define NOT(d,s)                     NOR(d,s,s)
+#  define OR(d,a,b)                    FX(31,a,d,b,444)
+#  define OR_(d,a,b)                   FX_(31,a,d,b,444)
+#  define MR(d,a)                      OR(d,a,a)
+#  define ORC(d,a,b)                   FX(31,a,d,b,412)
+#  define ORC_(d,a,b)                  FX_(31,a,d,b,412)
+#  define ORI(d,a,u)                   FDu(24,a,d,u)
+#  define NOP()                                ORI(0,0,0)
+#  define ORIS(d,a,u)                  FDu(25,a,d,u)
+#  define RFI()                                FXL(19,0,0,50)
+#  define RLWIMI(d,s,h,b,e)            FM(20,s,d,h,b,e,0)
+#  define RLWIMI_(d,s,h,b,e)           FM(20,s,d,h,b,e,1)
+#  define INSLWI(a,s,n,b)              RLWIMI(a,s,32-b,b,b+n-1)
+#  define INSRWI(a,s,n,b)              RLWIMI(a,s,32-(b+n),b,(b+n)-1)
+#  define RLWINM(a,s,h,b,e)            FM(21,s,a,h,b,e,0)
+#  define RLWINM_(a,s,h,b,e)           FM(21,s,a,h,b,e,1)
+#  define EXTLWI(a,s,n,b)              RLWINM(a,s,b,0,n-1)
+#  define EXTRWI(a,s,n,b)              RLWINM(a,s,b+n,32-n,31)
+#  define ROTLWI(a,s,n)                        RLWINM(a,s,n,0,31)
+#  define ROTRWI(a,s,n)                        RLWINM(a,s,32-n,0,31)
+#  define SLWI(a,s,n)                  RLWINM(a,s,n,0,31-n)
+#  define SRWI(a,s,n)                  RLWINM(a,s,32-n,n,31)
+#  define CLRLWI(a,s,n)                        RLWINM(a,s,0,n,31)
+#  define CLRRWI(a,s,n)                        RLWINM(a,s,0,0,31-n)
+#  define CLRLSWI(a,s,b,n)             RLWINM(a,s,n,b-n,31-n)
+#  define RLWNM(a,s,b,m,e)             FM(23,s,a,b,m,e,0)
+#  define RLWNM_(a,s,b,m,e)            FM(23,s,a,b,m,e,1)
+#  define ROTLW(a,s,b)                 RLWNM(a,s,b,0,31)
+#  define SC()                         FDu(17,0,0,2)
+#  define SLW(a,s,b)                   FX(31,s,a,b,24)
+#  define SLW_(a,s,b)                  FX_(31,s,a,b,24)
+#  define SRAW(a,s,b)                  FX(31,s,a,b,792)
+#  define SRAW_(a,s,b)                 FX_(31,s,a,b,792)
+#  define SRAWI(a,s,h)                 FX(31,s,a,h,824)
+#  define SRAWI_(a,s,h)                        FX_(31,s,a,h,824)
+#  define SRW(a,s,b)                   FX(31,s,a,b,536)
+#  define SRW_(a,s,b)                  FX_(31,s,a,b,536)
+#  if __WORDSIZE == 64
+#    define RLDICL(a,s,h,b)            FMD(30,s,a,h&~32,b,0,h>>5)
+#    define RLDICL_(a,s,h,b)           FMD_(30,s,a,h&~32,b,0,h>>5)
+#    define EXTRDI(x,y,n,b)            RLDICL(x,y,(b+n),(64-n))
+#    define SRDI(x,y,n)                        RLDICL(x,y,(64-n),n)
+#    define CLRLDI(x,y,n)              RLDICL(x,y,0,n)
+#    define RLDICR(a,s,h,e)            FMD(30,s,a,h&~32,e,1,h>>5)
+#    define RLDICR_(a,s,h,e)           FMD_(30,s,a,h&~32,e,1,h>>5)
+#    define EXTRLI(x,y,n,b)            RLDICR(x,y,b,(n-1))
+#    define SLDI(x,y,n)                        RLDICR(x,y,n,(63-n))
+#    define CLRRDI(x,y,n)              RLDICR(x,y,0,(63-n))
+#    define RLDIC(a,s,h,b)             FMD(30,s,a,h&~32,b,2,h>>5)
+#    define RLDIC_(a,s,h,b)            FMD_(30,s,a,h&~32,b,2,h>>5)
+#    define CLRLSLDI(x,y,b,n)          RLDIC(x,y,n,(b-n))
+#    define RLDCL(a,s,h,b)             FMDS(30,s,a,h,b,8)
+#    define RLDCL_(a,s,h,b)            FMDS_(30,s,a,h,b,8)
+#    define ROTLD(x,y,z)               RLDCL(x,y,z,0)
+#    define RLDCR(a,s,b,e)             FMDS(30,s,a,b,e,0)
+#    define RLDCR_(a,s,b,e)            FMDS_(30,s,a,b,e,0)
+#    define RLDIMI(a,s,h,b)            FMD(30,s,a,h&~32,b,3,h>>5)
+#    define RLDIMI_(a,s,h,b)           FMD_(30,s,a,h&~32,b,3,h>>5)
+#    define INSRDI(x,y,n,b)            RLDIMI(x,y,(64-(b+n)),b)
+#    define SLD(a,s,b)                 FX(31,s,a,b,27)
+#    define SLD_(a,s,b)                        FX_(31,s,a,b,27)
+#    define SRD(a,s,b)                 FX(31,s,a,b,539)
+#    define SRD_(a,s,b)                        FX_(31,s,a,b,539)
+#    define SRADI(a,s,h)               FXS(31,s,a,h&~32,413,h>>5)
+#    define SRADI_(a,s,h)              FXS_(31,s,a,h&~32,413,h>>5)
+#    define SRAD(a,s,b)                        FX(31,s,a,b,794)
+#    define SRAD_(a,s,b)               FX_(31,s,a,b,794)
+#  endif
+#  define STB(s,a,d)                   FDs(38,s,a,d)
+#  define STBU(s,a,d)                  FDs(39,s,a,d)
+#  define STBUX(s,a,b)                 FX(31,s,a,b,247)
+#  define STBX(s,a,b)                  FX(31,s,a,b,215)
+#  define STH(s,a,d)                   FDs(44,s,a,d)
+#  define STHBRX(s,a,b)                        FX(31,s,a,b,918)
+#  define STHU(s,a,d)                  FDs(45,s,a,d)
+#  define STHUX(s,a,b)                 FX(31,s,a,b,439)
+#  define STHX(s,a,b)                  FX(31,s,a,b,407)
+#  define STMW(s,a,d)                  FDs(47,s,a,d)
+#  define STWSI(s,a,nb)                        FX(31,s,a,nb,725)
+#  define STSWX(s,a,b)                 FX(31,s,a,b,661)
+#  define STW(s,a,d)                   FDs(36,s,a,d)
+#  define STWBRX(s,a,b)                        FX(31,s,a,b,662)
+#  define STWCX_(s,a,b)                        FX_(31,s,a,b,150)
+#  define STWU(s,a,d)                  FDs(37,s,a,d)
+#  define STWUX(s,a,b)                 FX(31,s,a,b,183)
+#  define STWX(s,a,b)                  FX(31,s,a,b,151)
+#  define STD(s,a,d)                   FDs(62,s,a,d)
+#  define STDX(s,a,b)                  FX(31,s,a,b,149)
+#  define STDU(s,a,d)                  FDs(62,s,a,d|1)
+#  define STDUX(s,a,b)                 FX(31,s,a,b,181)
+#  define SUBF(d,a,b)                  FXO(31,d,a,b,0,40)
+#  define SUBF_(d,a,b)                 FXO_(31,d,a,b,0,40)
+#  define SUBFO(d,a,b)                 FXO(31,d,a,b,1,40)
+#  define SUBFO_(d,a,b)                        FXO_(31,d,a,b,1,40)
+#  define SUB(d,a,b)                   SUBF(d,b,a)
+#  define SUB_(d,a,b)                  SUBF_(d,b,a)
+#  define SUBO(d,a,b)                  SUBFO(d,b,a)
+#  define SUBO_(d,a,b)                 SUBFO_(d,b,a)
+#  define SUBI(d,a,s)                  ADDI(d,a,-s)
+#  define SUBIS(d,a,s)                 ADDIS(d,a,-s)
+#  define SUBFC(d,a,b)                 FXO(31,d,a,b,0,8)
+#  define SUBFC_(d,a,b)                        FXO_(31,d,a,b,0,8)
+#  define SUBFCO(d,a,b)                        FXO(31,d,a,b,1,8)
+#  define SUBFCO_(d,a,b)               FXO_(31,d,a,b,1,8)
+#  define SUBC(d,a,b)                  SUBFC(d,b,a)
+#  define SUBIC(d,a,s)                 ADDIC(d,a,-s)
+#  define SUBIC_(d,a,s)                        ADDIC_(d,a,-s)
+#  define SUBFE(d,a,b)                 FXO(31,d,a,b,0,136)
+#  define SUBFE_(d,a,b)                        FXO_(31,d,a,b,0,136)
+#  define SUBFEO(d,a,b)                        FXO(31,d,a,b,1,136)
+#  define SUBFEO_(d,a,b)               FXO_(31,d,a,b,1,136)
+#  define SUBE(d,a,b)                  SUBFE(d,b,a)
+#  define SUBFIC(d,a,s)                        FDs(8,d,a,s)
+#  define SUBFME(d,a)                  FXO(31,d,a,0,0,232)
+#  define SUBFME_(d,a)                 FXO_(31,d,a,0,0,232)
+#  define SUBFMEO(d,a)                 FXO(31,d,a,0,1,232)
+#  define SUBFMEO_(d,a)                        FXO_(31,d,a,0,1,232)
+#  define SUBFZE(d,a)                  FXO(31,d,a,0,0,200)
+#  define SUBFZE_(d,a)                 FXO_(31,d,a,0,0,200)
+#  define SUBFZEO(d,a)                 FXO(31,d,a,0,1,200)
+#  define SUBFZEO_(d,a)                        FXO_(31,d,a,0,1,200)
+#  define SYNC()                       FX(31,0,0,0,598)
+#  define TLBIA()                      FX(31,0,0,0,370)
+#  define TLBIE(b)                     FX(31,0,0,b,306)
+#  define TLBSYNC()                    FX(31,0,0,0,566)
+#  define TW(t,a,b)                    FX(31,t,a,b,4)
+#  define TWEQ(a,b)                    FX(31,4,a,b,4)
+#  define TWLGE(a,b)                   FX(31,5,a,b,4)
+#  define TRAP()                       FX(31,31,0,0,4)
+#  define TWI(t,a,s)                   FDs(3,t,a,s)
+#  define TWGTI(a,s)                   TWI(8,a,s)
+#  define TWLLEI(a,s)                  TWI(6,a,s)
+#  define XOR(d,a,b)                   FX(31,a,d,b,316)
+#  define XOR_(d,a,b)                  FX_(31,a,d,b,316)
+#  define XORI(s,a,u)                  FDu(26,a,s,u)
+#  define XORIS(s,a,u)                 FDu(27,a,s,u)
+#  define nop(c)                       _nop(_jit,c)
+static void _nop(jit_state_t*,jit_int32_t);
+#  define movr(r0,r1)                  _movr(_jit,r0,r1)
+static void _movr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi(r0,i0)                  _movi(_jit,r0,i0)
+static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
+#  define movi_p(r0,i0)                        _movi_p(_jit,r0,i0)
+static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
+#  define negr(r0,r1)                  NEG(r0,r1)
+#  define comr(r0,r1)                  NOT(r0,r1)
+#  define extr_c(r0,r1)                        EXTSB(r0,r1)
+#  define extr_uc(r0,r1)               ANDI_(r0,r1,0xff)
+#  define extr_s(r0,r1)                        EXTSH(r0,r1)
+#  define extr_us(r0,r1)               ANDI_(r0,r1,0xffff)
+#  if __WORDSIZE == 64
+#    define extr_i(r0,r1)              EXTSW(r0,r1)
+#    define extr_ui(r0,r1)             CLRLDI(r0,r1,32)
+#  endif
+#  if __BYTE_ORDER == __BIG_ENDIAN
+#    define htonr_us(r0,r1)            extr_us(r0,r1)
+#    if __WORDSIZE == 32
+#      define htonr_ui(r0,r1)          movr(r0,r1)
+#    else
+#      define htonr_ui(r0,r1)          extr_ui(r0,r1)
+#      define htonr_ul(r0,r1)          movr(r0,r1)
+#    endif
+#  else
+#    define htonr_us(r0,r1)            _htonr_us(_jit,r0,r1)
+static void _htonr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#    define htonr_ui(r0,r1)            _htonr_ui(_jit,r0,r1)
+static void _htonr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#    if __WORDSIZE == 64
+#      define htonr_ul(r0,r1)          _htonr_ul(_jit,r0,r1)
+static void _htonr_ul(jit_state_t*,jit_int32_t,jit_int32_t);
+#    endif
+#  endif
+#  define addr(r0,r1,r2)               ADD(r0,r1,r2)
+#  define addi(r0,r1,i0)               _addi(_jit,r0,r1,i0)
+static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addcr(r0,r1,r2)              ADDC(r0,r1,r2)
+#  define addci(r0,r1,i0)              _addci(_jit,r0,r1,i0)
+static void _addci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addxr(r0,r1,r2)              ADDE(r0,r1,r2)
+#  define addxi(r0,r1,i0)              _addxi(_jit,r0,r1,i0)
+static void _addxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subr(r0,r1,r2)               SUB(r0,r1,r2)
+#  define subi(r0,r1,i0)               _subi(_jit,r0,r1,i0)
+static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subcr(r0,r1,r2)              SUBC(r0,r1,r2)
+#  define subci(r0,r1,i0)              _subci(_jit,r0,r1,i0)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subxr(r0,r1,r2)              SUBFE(r0,r2,r1)
+#  define subxi(r0,r1,i0)              _subxi(_jit,r0,r1,i0)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rsbi(r0, r1, i0)             _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define mulr(r0,r1,r2)             MULLW(r0,r1,r2)
+#    define mullr(r0,r1,r2)            MULLW(r0,r1,r2)
+#    define mulhr(r0,r1,r2)            MULHW(r0,r1,r2)
+#    define mulhr_u(r0,r1,r2)          MULHWU(r0,r1,r2)
+#  else
+#    define mulr(r0,r1,r2)             MULLD(r0,r1,r2)
+#    define mullr(r0,r1,r2)            MULLD(r0,r1,r2)
+#    define mulhr(r0,r1,r2)            MULHD(r0,r1,r2)
+#    define mulhr_u(r0,r1,r2)          MULHDU(r0,r1,r2)
+#  endif
+#  define muli(r0,r1,i0)               _muli(_jit,r0,r1,i0)
+static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr(r0,r1,r2,r3)           iqmulr(r0,r1,r2,r3,1)
+#  define qmulr_u(r0,r1,r2,r3)         iqmulr(r0,r1,r2,r3,0)
+#  define iqmulr(r0,r1,r2,r3,cc)       _iqmulr(_jit,r0,r1,r2,r3,cc)
+static void _iqmulr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#  define qmuli(r0,r1,r2,i0)           iqmuli(r0,r1,r2,i0,1)
+#  define qmuli_u(r0,r1,r2,i0)         iqmuli(r0,r1,r2,i0,0)
+#  define iqmuli(r0,r1,r2,i0,cc)       _iqmuli(_jit,r0,r1,r2,i0,cc)
+static void _iqmuli(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#  if __WORDSIZE == 32
+#    define divr(r0,r1,r2)             DIVW(r0,r1,r2)
+#  else
+#    define divr(r0,r1,r2)             DIVD(r0,r1,r2)
+#  endif
+#  define divi(r0,r1,i0)               _divi(_jit,r0,r1,i0)
+static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define divr_u(r0,r1,r2)           DIVWU(r0,r1,r2)
+#  else
+#    define divr_u(r0,r1,r2)           DIVDU(r0,r1,r2)
+#  endif
+#  define divi_u(r0,r1,i0)             _divi_u(_jit,r0,r1,i0)
+static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qdivr(r0,r1,r2,r3)           iqdivr(r0,r1,r2,r3,1)
+#  define qdivr_u(r0,r1,r2,r3)         iqdivr(r0,r1,r2,r3,0)
+#  define iqdivr(r0,r1,r2,r3,cc)       _iqdivr(_jit,r0,r1,r2,r3,cc)
+static void _iqdivr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#  define qdivi(r0,r1,r2,i0)           iqdivi(r0,r1,r2,i0,1)
+#  define qdivi_u(r0,r1,r2,i0)         iqdivi(r0,r1,r2,i0,0)
+#  define iqdivi(r0,r1,r2,i0,cc)       _iqdivi(_jit,r0,r1,r2,i0,cc)
+static void _iqdivi(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#  define remr(r0,r1,r2)               _remr(_jit,r0,r1,r2)
+static void _remr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi(r0,r1,i0)               _remi(_jit,r0,r1,i0)
+static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define remr_u(r0,r1,r2)             _remr_u(_jit,r0,r1,r2)
+static void _remr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi_u(r0,r1,i0)             _remi_u(_jit,r0,r1,i0)
+static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define andr(r0,r1,r2)               AND(r0,r1,r2)
+#  define andi(r0,r1,i0)               _andi(_jit,r0,r1,i0)
+static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define orr(r0,r1,r2)                        OR(r0,r1,r2)
+#  define ori(r0,r1,i0)                        _ori(_jit,r0,r1,i0)
+static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define xorr(r0,r1,r2)               XOR(r0,r1,r2)
+#  define xori(r0,r1,i0)               _xori(_jit,r0,r1,i0)
+static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define lshr(r0,r1,r2)             SLW(r0,r1,r2)
+#  else
+#    define lshr(r0,r1,r2)             SLD(r0,r1,r2)
+#  endif
+#  define lshi(r0,r1,i0)               _lshi(_jit,r0,r1,i0)
+static void _lshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define rshr(r0,r1,r2)             SRAW(r0,r1,r2)
+#  else
+#    define rshr(r0,r1,r2)             SRAD(r0,r1,r2)
+#  endif
+#  define rshi(r0,r1,i0)               _rshi(_jit,r0,r1,i0)
+static void _rshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define rshr_u(r0,r1,r2)           SRW(r0,r1,r2)
+#  else
+#    define rshr_u(r0,r1,r2)           SRD(r0,r1,r2)
+#  endif
+#  define rshi_u(r0,r1,i0)             _rshi_u(_jit,r0,r1,i0)
+static void _rshi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ltr(r0,r1,r2)                        _ltr(_jit,r0,r1,r2)
+static void _ltr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lti(r0,r1,i0)                        _lti(_jit,r0,r1,i0)
+static void _lti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ltr_u(r0,r1,r2)              _ltr_u(_jit,r0,r1,r2)
+static void _ltr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lti_u(r0,r1,i0)              _lti_u(_jit,r0,r1,i0)
+static void _lti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ler(r0,r1,r2)                        _ler(_jit,r0,r1,r2)
+static void _ler(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lei(r0,r1,i0)                        _lei(_jit,r0,r1,i0)
+static void _lei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ler_u(r0,r1,r2)              _ler_u(_jit,r0,r1,r2)
+static void _ler_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lei_u(r0,r1,i0)              _lei_u(_jit,r0,r1,i0)
+static void _lei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define eqr(r0,r1,r2)                        _eqr(_jit,r0,r1,r2)
+static void _eqr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define eqi(r0,r1,i0)                        _eqi(_jit,r0,r1,i0)
+static void _eqi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ger(r0,r1,r2)                        _ger(_jit,r0,r1,r2)
+static void _ger(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gei(r0,r1,i0)                        _gei(_jit,r0,r1,i0)
+static void _gei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ger_u(r0,r1,r2)              _ger_u(_jit,r0,r1,r2)
+static void _ger_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gei_u(r0,r1,i0)              _gei_u(_jit,r0,r1,i0)
+static void _gei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define gtr(r0,r1,r2)                        _gtr(_jit,r0,r1,r2)
+static void _gtr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gti(r0,r1,i0)                        _gti(_jit,r0,r1,i0)
+static void _gti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define gtr_u(r0,r1,r2)              _gtr_u(_jit,r0,r1,r2)
+static void _gtr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gti_u(r0,r1,i0)              _gti_u(_jit,r0,r1,i0)
+static void _gti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ner(r0,r1,r2)                        _ner(_jit,r0,r1,r2)
+static void _ner(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nei(r0,r1,i0)                        _nei(_jit,r0,r1,i0)
+static void _nei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#define bltr(i0,r0,r1)                 _bltr(_jit,i0,r0,r1)
+static jit_word_t _bltr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blti(i0,r0,i1)                 _blti(_jit,i0,r0,i1)
+static jit_word_t _blti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bltr_u(i0,r0,r1)               _bltr_u(_jit,i0,r0,r1)
+static jit_word_t _bltr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blti_u(i0,r0,i1)               _blti_u(_jit,i0,r0,i1)
+static jit_word_t _blti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bler(i0,r0,r1)                 _bler(_jit,i0,r0,r1)
+static jit_word_t _bler(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blei(i0,r0,i1)                 _blei(_jit,i0,r0,i1)
+static jit_word_t _blei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bler_u(i0,r0,r1)               _bler_u(_jit,i0,r0,r1)
+static jit_word_t _bler_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define blei_u(i0,r0,i1)               _blei_u(_jit,i0,r0,i1)
+static jit_word_t _blei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define beqr(i0,r0,r1)                 _beqr(_jit,i0,r0,r1)
+static jit_word_t _beqr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define beqi(i0,r0,i1)                 _beqi(_jit,i0,r0,i1)
+static jit_word_t _beqi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bger(i0,r0,r1)                 _bger(_jit,i0,r0,r1)
+static jit_word_t _bger(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgei(i0,r0,i1)                 _bgei(_jit,i0,r0,i1)
+static jit_word_t _bgei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bger_u(i0,r0,r1)               _bger_u(_jit,i0,r0,r1)
+static jit_word_t _bger_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgei_u(i0,r0,i1)               _bgei_u(_jit,i0,r0,i1)
+static jit_word_t _bgei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bgtr(i0,r0,r1)                 _bgtr(_jit,i0,r0,r1)
+static jit_word_t _bgtr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgti(i0,r0,i1)                 _bgti(_jit,i0,r0,i1)
+static jit_word_t _bgti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bgtr_u(i0,r0,r1)               _bgtr_u(_jit,i0,r0,r1)
+static jit_word_t _bgtr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bgti_u(i0,r0,i1)               _bgti_u(_jit,i0,r0,i1)
+static jit_word_t _bgti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bner(i0,r0,r1)                 _bner(_jit,i0,r0,r1)
+static jit_word_t _bner(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bnei(i0,r0,i1)                 _bnei(_jit,i0,r0,i1)
+static jit_word_t _bnei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bmsr(i0,r0,r1)                 _bmsr(_jit,i0,r0,r1)
+static jit_word_t _bmsr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bmsi(i0,r0,i1)                 _bmsi(_jit,i0,r0,i1)
+static jit_word_t _bmsi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bmcr(i0,r0,r1)                 _bmcr(_jit,i0,r0,r1)
+static jit_word_t _bmcr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bmci(i0,r0,i1)                 _bmci(_jit,i0,r0,i1)
+static jit_word_t _bmci(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define boaddr(i0,r0,r1)               _boaddr(_jit,i0,r0,r1)
+static jit_word_t _boaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define boaddi(i0,r0,i1)               _boaddi(_jit,i0,r0,i1)
+static jit_word_t _boaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bxaddr(i0,r0,r1)               _bxaddr(_jit,i0,r0,r1)
+static jit_word_t _bxaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bxaddi(i0,r0,i1)               _bxaddi(_jit,i0,r0,i1)
+static jit_word_t _bxaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bosubr(i0,r0,r1)               _bosubr(_jit,i0,r0,r1)
+static jit_word_t _bosubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bosubi(i0,r0,i1)               _bosubi(_jit,i0,r0,i1)
+static jit_word_t _bosubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bxsubr(i0,r0,r1)               _bxsubr(_jit,i0,r0,r1)
+static jit_word_t _bxsubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bxsubi(i0,r0,i1)               _bxsubi(_jit,i0,r0,i1)
+static jit_word_t _bxsubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define boaddr_u(i0,r0,r1)             _boaddr_u(_jit,i0,r0,r1)
+static jit_word_t _boaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define boaddi_u(i0,r0,i1)             _boaddi_u(_jit,i0,r0,i1)
+static jit_word_t _boaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bxaddr_u(i0,r0,r1)             _bxaddr_u(_jit,i0,r0,r1)
+static jit_word_t _bxaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bxaddi_u(i0,r0,i1)             _bxaddi_u(_jit,i0,r0,i1)
+static jit_word_t _bxaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bosubr_u(i0,r0,r1)             _bosubr_u(_jit,i0,r0,r1)
+static jit_word_t _bosubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bosubi_u(i0,r0,i1)             _bosubi_u(_jit,i0,r0,i1)
+static jit_word_t _bosubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#define bxsubr_u(i0,r0,r1)             _bxsubr_u(_jit,i0,r0,r1)
+static jit_word_t _bxsubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#define bxsubi_u(i0,r0,i1)             _bxsubi_u(_jit,i0,r0,i1)
+static jit_word_t _bxsubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define ldr_c(r0,r1)                 _ldr_c(_jit,r0,r1)
+static void _ldr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define ldi_c(r0,i0)                 _ldi_c(_jit,r0,i0)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_c(r0,r1,i0)             _ldxr_c(_jit,r0,r1,i0)
+static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_c(r0,r1,i0)             _ldxi_c(_jit,r0,r1,i0)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_uc(r0,r1)                        LBZX(r0, _R0_REGNO, r1)
+#  define ldi_uc(r0,i0)                        _ldi_uc(_jit,r0,i0)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_uc(r0,r1,r2)            _ldxr_uc(_jit,r0,r1,r2)
+static void _ldxr_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_uc(r0,r1,i0)            _ldxi_uc(_jit,r0,r1,i0)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_s(r0,r1)                 LHAX(r0, _R0_REGNO, r1)
+#  define ldi_s(r0,i0)                 _ldi_s(_jit,r0,i0)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_s(r0,r1,i0)             _ldxr_s(_jit,r0,r1,i0)
+static void _ldxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_s(r0,r1,i0)             _ldxi_s(_jit,r0,r1,i0)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_us(r0,r1)                        LHZX(r0, _R0_REGNO, r1)
+#  define ldi_us(r0,i0)                        _ldi_us(_jit,r0,i0)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_us(r0,r1,i0)            _ldxr_us(_jit,r0,r1,i0)
+static void _ldxr_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_us(r0,r1,i0)            _ldxi_us(_jit,r0,r1,i0)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define ldr_i(r0,r1)               LWZX(r0, _R0_REGNO, r1)
+#  else
+#    define ldr_i(r0,r1)               LWAX(r0, _R0_REGNO, r1)
+#  endif
+#  define ldi_i(r0,i0)                 _ldi_i(_jit,r0,i0)
+static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_i(r0,r1,i0)             _ldxr_i(_jit,r0,r1,i0)
+static void _ldxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_i(r0,r1,i0)             _ldxi_i(_jit,r0,r1,i0)
+static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 64
+#    define ldr_ui(r0,r1)              LWZX(r0, _R0_REGNO, r1)
+#    define ldi_ui(r0,i0)              _ldi_ui(_jit,r0,i0)
+static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
+#    define ldxr_ui(r0,r1,i0)          _ldxr_ui(_jit,r0,r1,i0)
+static void _ldxr_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define ldxi_ui(r0,r1,i0)          _ldxi_ui(_jit,r0,r1,i0)
+static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#    define ldr_l(r0,r1)               LDX(r0, _R0_REGNO, r1)
+#    define ldi_l(r0,i0)               _ldi_l(_jit,r0,i0)
+static void _ldi_l(jit_state_t*,jit_int32_t,jit_word_t);
+#    define ldxr_l(r0,r1,i0)           _ldxr_l(_jit,r0,r1,i0)
+static void _ldxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define ldxi_l(r0,r1,i0)           _ldxi_l(_jit,r0,r1,i0)
+static void _ldxi_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  endif
+#  define str_c(r0,r1)                 STBX(r1, _R0_REGNO, r0)
+#  define sti_c(i0,r0)                 _sti_c(_jit,i0,r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_c(r0,r1,r2)             _stxr_c(_jit,r0,r1,r2)
+static void _stxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_c(i0,r0,r1)             _stxi_c(_jit,i0,r0,r1)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define str_s(r0,r1)                 STHX(r1, _R0_REGNO, r0)
+#  define sti_s(i0,r0)                 _sti_s(_jit,i0,r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_s(r0,r1,r2)             _stxr_s(_jit,r0,r1,r2)
+static void _stxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_s(i0,r0,r1)             _stxi_s(_jit,i0,r0,r1)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define str_i(r0,r1)                 STWX(r1, _R0_REGNO, r0)
+#  define sti_i(i0,r0)                 _sti_i(_jit,i0,r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_i(r0,r1,r2)             _stxr_i(_jit,r0,r1,r2)
+static void _stxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_i(i0,r0,r1)             _stxi_i(_jit,i0,r0,r1)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#    define str_l(r0,r1)               STDX(r1, _R0_REGNO, r0)
+#    define sti_l(i0,r0)               _sti_l(_jit,i0,r0)
+static void _sti_l(jit_state_t*,jit_word_t,jit_int32_t);
+#    define stxr_l(r0,r1,r2)           _stxr_l(_jit,r0,r1,r2)
+static void _stxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define stxi_l(i0,r0,r1)           _stxi_l(_jit,i0,r0,r1)
+static void _stxi_l(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  endif
+#  define jmpr(r0)                     _jmpr(_jit,r0)
+static void _jmpr(jit_state_t*,jit_int32_t);
+#  define jmpi(i0)                     _jmpi(_jit,i0)
+static jit_word_t _jmpi(jit_state_t*,jit_word_t);
+#  define jmpi_p(i0)                   _jmpi_p(_jit,i0)
+static jit_word_t _jmpi_p(jit_state_t*,jit_word_t) maybe_unused;
+#  if _CALL_SYSV
+#    define callr(r0,i0)               _callr(_jit,r0,i0)
+static void _callr(jit_state_t*,jit_int32_t,jit_int32_t);
+#    define calli(i0,i1)               _calli(_jit,i0,i1)
+static void _calli(jit_state_t*,jit_word_t,jit_int32_t);
+#  define calli_p(i0,i1)               _calli_p(_jit,i0,i1)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t,jit_int32_t);
+#  else
+#    define callr(r0)                  _callr(_jit,r0)
+static void _callr(jit_state_t*,jit_int32_t);
+#    define calli(i0)                  _calli(_jit,i0)
+static void _calli(jit_state_t*,jit_word_t);
+#    define calli_p(i0)                        _calli_p(_jit,i0)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t);
+#endif
+#  define prolog(node)                 _prolog(_jit, node)
+static void _prolog(jit_state_t*, jit_node_t*);
+#  define epilog(node)                 _epilog(_jit, node)
+static void _epilog(jit_state_t*, jit_node_t*);
+#  define vastart(r0)                  _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#  define vaarg(r0, r1)                        _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define vaarg_d(r0, r1)              _vaarg_d(_jit, r0, r1)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define patch_at(i,l)                        _patch_at(_jit,i,l)
+static void _patch_at(jit_state_t*,jit_word_t,jit_word_t);
+#endif
+
+#if CODE
+#  define _u16(v)                      ((v) & 0xffff)
+#  define _u26(v)                      ((v) & 0x3ffffff)
+static void
+_FXO(jit_state_t *_jit, int o, int d, int a, int b, int e, int x, int r)
+{
+    assert(!(o & ~((1 << 6) - 1)));
+    assert(!(d & ~((1 << 5) - 1)));
+    assert(!(a & ~((1 << 5) - 1)));
+    assert(!(b & ~((1 << 5) - 1)));
+    assert(!(e & ~((1 << 1) - 1)));
+    assert(!(x & ~((1 << 9) - 1)));
+    assert(!(r & ~((1 << 1) - 1)));
+    ii((o<<26)|(d<<21)|(a<<16)|(b<<11)|(e<<10)|(x<<1)|r);
+}
+
+static void
+_FDs(jit_state_t *_jit, int o, int d, int a, int s)
+{
+    assert(!(o & ~((1 << 6) - 1)));
+    assert(!(d & ~((1 << 5) - 1)));
+    assert(!(a & ~((1 << 5) - 1)));
+    assert(can_sign_extend_short_p(s));
+    ii((o<<26)|(d<<21)|(a<<16)|_u16(s));
+}
+
+static void
+_FDu(jit_state_t *_jit, int o, int d, int a, int s)
+{
+    assert(!(o & ~((1 << 6) - 1)));
+    assert(!(d & ~((1 << 5) - 1)));
+    assert(!(a & ~((1 << 5) - 1)));
+    assert(can_zero_extend_short_p(s));
+    ii((o<<26)|(d<<21)|(a<<16)|_u16(s));
+}
+
+static void
+_FX(jit_state_t *_jit, int o, int s, int a, int b, int x, int r)
+{
+    assert(!(o & ~((1 <<  6) - 1)));
+    assert(!(s & ~((1 <<  5) - 1)));
+    assert(!(a & ~((1 <<  5) - 1)));
+    assert(!(b & ~((1 <<  5) - 1)));
+    assert(!(x & ~((1 << 10) - 1)));
+    assert(!(r & ~((1 <<  1) - 1)));
+    ii((o<<26)|(s<<21)|(a<<16)|(b<<11)|(x<<1)|r);
+}
+
+static void
+_FI(jit_state_t *_jit, int o, int t, int a, int k)
+{
+    assert(!(o & ~(( 1 <<  6) - 1)));
+    assert(!(t & 3) && can_sign_extend_jump_p(t));
+    assert(!(a & ~(( 1 <<  1) - 1)));
+    assert(!(k & ~(( 1 <<  1) - 1)));
+    ii((o<<26)|_u26(t)|(a<<1)|k);
+}
+
+static void
+_FB(jit_state_t *_jit, int o, int bo, int bi, int t, int a, int k)
+{
+    assert(!( o & ~((1 <<  6) - 1)));
+    assert(!(bo & ~((1 <<  5) - 1)));
+    assert(!(bi & ~((1 <<  5) - 1)));
+    assert(!(t & 3) && can_sign_extend_short_p(t));
+    assert(!(a & ~(( 1 <<  1) - 1)));
+    assert(!(k & ~(( 1 <<  1) - 1)));
+    ii((o<<26)|(bo<<21)|(bi<<16)|_u16(t)|(a<<1)|k);
+}
+
+static void
+_FXL(jit_state_t *_jit, int o, int bo, int bi, int x, int k)
+{
+    assert(!( o & ~((1 <<  6) - 1)));
+    assert(!(bo & ~((1 <<  5) - 1)));
+    assert(!(bi & ~((1 <<  5) - 1)));
+    assert(!(x & ~(( 1 << 10) - 1)));
+    assert(!(k & ~(( 1 <<  1) - 1)));
+    ii((o<<26)|(bo<<21)|(bi<<16)|(x<<1)|k);
+}
+
+static void
+_FC(jit_state_t *_jit, int o, int d, int l, int a, int b, int x)
+{
+    assert(!(o & ~((1 <<  6) - 1)));
+    assert(!(d & ~((1 <<  3) - 1)));
+    assert(!(l & ~((1 <<  1) - 1)));
+    assert(!(a & ~((1 <<  5) - 1)));
+    assert(!(b & ~((1 <<  5) - 1)));
+    assert(!(x & ~((1 << 10) - 1)));
+    ii((o<<26)|(d<<23)|(l<<21)|(a<<16)|(b<<11)|(x<<1));
+}
+
+static void
+_FCI(jit_state_t *_jit, int o, int d, int l, int a, int s)
+{
+    assert(!(o & ~((1 << 6) - 1)));
+    assert(!(d & ~((1 << 3) - 1)));
+    assert(!(l & ~((1 << 1) - 1)));
+    assert(!(a & ~((1 << 5) - 1)));
+    if (o == 11)       assert(can_sign_extend_short_p(s));
+    else if (o == 10)  assert(can_zero_extend_short_p(s));
+#if DEBUG
+    else               abort();
+#endif
+    ii((o<<26)|(d<<23)|(l<<21)|(a<<16)|_u16(s));
+}
+
+static void
+_FXFX(jit_state_t *_jit, int o, int d, int x, int f)
+{
+    assert(!(o & ~((1 <<  6) - 1)));
+    assert(!(d & ~((1 <<  5) - 1)));
+    assert(!(x & ~((1 << 10) - 1)));
+    assert(!(f & ~((1 << 10) - 1)));
+    ii((o<<26)|(d<<21)|(x<<11)|(f<<1));
+}
+
+static void
+_FM(jit_state_t *_jit, int o, int s, int a, int h, int b, int e, int r)
+{
+    assert(!(o & ~((1 << 6) - 1)));
+    assert(!(s & ~((1 << 5) - 1)));
+    assert(!(a & ~((1 << 5) - 1)));
+    assert(!(h & ~((1 << 5) - 1)));
+    assert(!(b & ~((1 << 5) - 1)));
+    assert(!(e & ~((1 << 5) - 1)));
+    assert(!(r & ~((1 << 1) - 1)));
+    ii((o<<26)|(s<<21)|(a<<16)|(h<<11)|(b<<6)|(e<<1)|r);
+}
+
+#  if __WORDSIZE == 64
+static void
+_FMDS(jit_state_t *_jit, int o, int s, int a, int b, int e, int x, int r)
+{
+    assert(!(o & ~((1 << 6) - 1)));
+    assert(!(s & ~((1 << 5) - 1)));
+    assert(!(a & ~((1 << 5) - 1)));
+    assert(!(b & ~((1 << 5) - 1)));
+    assert(!(e & ~((1 << 6) - 1)));
+    assert(!(x & ~((1 << 4) - 1)));
+    assert(!(r & ~((1 << 1) - 1)));
+    e = (e >> 5) | ((e << 1) & 63);
+    ii((o<<26)|(s<<21)|(a<<16)|(b<<11)|(e<<5)|(x<<1)|r);
+}
+
+static void
+_FMD(jit_state_t *_jit, int o, int s, int a, int h, int e, int x, int i, int r)
+{
+    assert(!(o & ~((1 << 6) - 1)));
+    assert(!(s & ~((1 << 5) - 1)));
+    assert(!(a & ~((1 << 5) - 1)));
+    assert(!(h & ~((1 << 5) - 1)));
+    assert(!(e & ~((1 << 6) - 1)));
+    assert(!(x & ~((1 << 3) - 1)));
+    assert(!(i & ~((1 << 1) - 1)));
+    assert(!(r & ~((1 << 1) - 1)));
+    e = (e >> 5) | ((e << 1) & 63);
+    ii((o<<26)|(s<<21)|(a<<16)|(h<<11)|(e<<5)|(x<<2)|(i<<1)|r);
+}
+
+static void
+_FXS(jit_state_t *_jit, int o, int s, int a, int h, int x, int i, int r)
+{
+    assert(!(o & ~((1 << 6) - 1)));
+    assert(!(s & ~((1 << 5) - 1)));
+    assert(!(a & ~((1 << 5) - 1)));
+    assert(!(h & ~((1 << 5) - 1)));
+    assert(!(x & ~((1 << 9) - 1)));
+    assert(!(i & ~((1 << 1) - 1)));
+    assert(!(r & ~((1 << 1) - 1)));
+    ii((o<<26)|(s<<21)|(a<<16)|(h<<11)|(x<<2)|(i<<1)|r);
+}
+#endif
+
+#if !DEBUG
+/*
+ * Use the sequence commented at
+ * http://tenfourfox.blogspot.com/2011/04/attention-g5-owners-your-javascript-no.html
+ */
+static void
+_MCRXR(jit_state_t *_jit, jit_int32_t cr)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    MFXER(rn(reg));
+    MTCRF(128, rn(reg));
+    RLWINM(rn(reg), rn(reg), 0, 0, 28);
+    MTXER(rn(reg));
+    jit_unget_reg(reg);
+}
+#endif
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t i0)
+{
+    for (; i0 > 0; i0 -= 4)
+       NOP();
+    assert(i0 == 0);
+}
+
+static void
+_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       MR(r0, r1);
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    if (can_sign_extend_short_p(i0))
+       LI(r0, i0);
+    else {
+       if (can_sign_extend_int_p(i0))
+           LIS(r0, (jit_int16_t)(i0 >> 16));
+       else if (can_zero_extend_int_p(i0)) {
+           if (i0 & 0xffff0000) {
+               ORI(r0, r0, (jit_uint16_t)(i0 >> 16));
+               SLWI(r0, r0, 16);
+           }
+       }
+#  if __WORDSIZE == 64
+       else {
+           movi(r0, (jit_uint32_t)(i0 >> 32));
+           if (i0 & 0xffff0000) {
+               SLDI(r0, r0, 16);
+               ORI(r0, r0, (jit_uint16_t)(i0 >> 16));
+               SLDI(r0, r0, 16);
+           }
+           else
+               SLDI(r0, r0, 32);
+       }
+#  endif
+       if (i0 & 0xffff)
+           ORI(r0, r0, (jit_uint16_t)i0);
+    }
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         word = _jit->pc.w;
+#  if __WORDSIZE == 32
+    LIS(r0, (jit_int16_t)(i0 >> 16));
+    ORI(r0, r0, (jit_uint16_t)i0);
+#  else
+    LIS(r0, (jit_int16_t)(i0 >> 48));
+    ORI(r0, r0, (jit_uint16_t)(i0 >> 32));
+    SLDI(r0, r0, 16);
+    ORI(r0, r0, (jit_uint16_t)(i0 >> 16));
+    SLDI(r0, r0, 16);
+    ORI(r0, r0, (jit_uint16_t)i0);
+#  endif
+    return (word);
+}
+
+#  if __BYTE_ORDER == __LITTLE_ENDIAN
+static void
+_htonr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    rshi(rn(t0), r1, 8);
+    andi(r0, r1, 0xff);
+    andi(rn(t0), rn(t0), 0xff);
+    lshi(r0, r0, 8);
+    orr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_htonr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    ROTLWI(rn(reg), r1, 8);
+    RLWIMI(rn(reg), r1, 24, 0, 7);
+    RLWIMI(rn(reg), r1, 24, 16, 23);
+    CLRLDI(r0, rn(reg), 32);
+    jit_unget_reg(reg);
+}
+
+#    if __WORDSIZE == 64
+static void
+_htonr_ul(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    rshi_u(rn(reg), r1, 32);
+    htonr_ui(r0, r1);
+    htonr_ui(rn(reg), rn(reg));
+    lshi(r0, r0, 32);
+    orr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+#    endif
+#  endif
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       ADDI(r0, r1, i0);
+    else if (can_zero_extend_int_p(i0) && !(i0 & 0x0000ffff))
+       ADDIS(r0, r1, i0 >> 16);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ADD(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       ADDIC(r0, r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ADDC(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    ADDE(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_word_t         ni0 = -i0;
+    if (can_sign_extend_short_p(ni0))
+       ADDI(r0, r1, ni0);
+    else if (can_zero_extend_int_p(ni0) && !(ni0 & 0x0000ffff))
+       ADDIS(r0, r1, ni0 >> 16);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       SUB(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    SUBC(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    SUBE(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    subi(r0, r1, i0);
+    negr(r0, r0);
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       MULLI(r0, r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       mulr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_iqmulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    if (r0 == r2 || r0 == r3) {
+       reg = jit_get_reg(jit_class_gpr);
+       mullr(rn(reg), r2, r3);
+    }
+    else
+       mullr(r0, r2, r3);
+    if (sign)
+       mulhr(r1, r2, r3);
+    else
+       mulhr_u(r1, r2, r3);
+    if (r0 == r2 || r0 == r3) {
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_iqmuli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    iqmulr(r0, r1, r2, rn(reg), sign);
+    jit_unget_reg(reg);
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    divr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_iqdivr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    jit_int32_t                sv0, rg0;
+    jit_int32_t                sv1, rg1;
+
+    if (r0 == r2 || r0 == r3) {
+       sv0 = jit_get_reg(jit_class_gpr);
+       rg0 = rn(sv0);
+    }
+    else
+       rg0 = r0;
+    if (r1 == r2 || r1 == r3) {
+       sv1 = jit_get_reg(jit_class_gpr);
+       rg1 = rn(sv1);
+    }
+    else
+       rg1 = r1;
+
+    if (sign)
+       divr(rg0, r2, r3);
+    else
+       divr_u(rg0, r2, r3);
+    mulr(rg1, r3, rg0);
+    subr(rg1, r2, rg1);
+    if (rg0 != r0) {
+       movr(r0, rg0);
+       jit_unget_reg(sv0);
+    }
+    if (rg1 != r1) {
+       movr(r1, rg1);
+       jit_unget_reg(sv1);
+    }
+}
+
+static void
+_iqdivi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    iqdivr(r0, r1, r2, rn(reg), sign);
+    jit_unget_reg(reg);
+}
+
+static void
+_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1 || r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       divr(rn(reg), r1, r2);
+       mulr(rn(reg), r2, rn(reg));
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       divr(r0, r1, r2);
+       mulr(r0, r2, r0);
+       subr(r0, r1, r0);
+    }
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1 || r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       divr_u(rn(reg), r1, r2);
+       mulr(rn(reg), r2, rn(reg));
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       divr_u(r0, r1, r2);
+       mulr(r0, r2, r0);
+       subr(r0, r1, r0);
+    }
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       ANDI_(r0, r1, i0);
+    else if (can_zero_extend_int_p(i0) && !(i0 & 0x0000ffff))
+       ANDIS_(r0, r1, (jit_uword_t)i0 >> 16);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       AND(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       ORI(r0, r1, i0);
+    else if (can_zero_extend_int_p(i0) && !(i0 & 0x0000ffff))
+       ORIS(r0, r1, (jit_uword_t)i0 >> 16);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       OR(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       XORI(r0, r1, i0);
+    else if (can_zero_extend_int_p(i0) && !(i0 & 0x0000ffff))
+       XORIS(r0, r1, (jit_uword_t)i0 >> 16);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       XOR(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else {
+#  if __WORDSIZE == 32
+       SLWI(r0, r1, i0);
+#  else
+       SLDI(r0, r1, i0);
+#  endif
+    }
+}
+
+static void
+_rshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else {
+#  if __WORDSIZE == 32
+       SRAWI(r0, r1, i0);
+#  else
+       SRADI(r0, r1, i0);
+#  endif
+    }
+}
+
+static void
+_rshi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else {
+#  if __WORDSIZE == 32
+       SRWI(r0, r1, i0);
+#  else
+       SRDI(r0, r1, i0);
+#  endif
+    }
+}
+
+static void
+_ltr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPW(r1, r2);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+
+static void
+_lti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       CMPWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+
+static void
+_ltr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPLW(r1, r2);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+
+static void
+_lti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       CMPLWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPLW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+
+static void
+_ler(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPW(r1, r2);
+    CRNOT(CR_GT, CR_GT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+
+static void
+_lei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       CMPWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    CRNOT(CR_GT, CR_GT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+
+static void
+_ler_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPLW(r1, r2);
+    CRNOT(CR_GT, CR_GT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+
+static void
+_lei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       CMPLWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPLW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    CRNOT(CR_GT, CR_GT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+
+static void
+_eqr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPW(r1, r2);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_EQ);
+}
+
+static void
+_eqi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       CMPWI(r1, i0);
+    else if (can_zero_extend_short_p(i0))
+       CMPLWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_EQ);
+}
+
+static void
+_ger(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPW(r1, r2);
+    CRNOT(CR_LT, CR_LT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+
+static void
+_gei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       CMPWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    CRNOT(CR_LT, CR_LT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+
+static void
+_ger_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPLW(r1, r2);
+    CRNOT(CR_LT, CR_LT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+
+static void
+_gei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       CMPLWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPLW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    CRNOT(CR_LT, CR_LT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+
+static void
+_gtr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPW(r1, r2);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+
+static void
+_gti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       CMPWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+
+static void
+_gtr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPLW(r1, r2);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+
+static void
+_gti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_short_p(i0))
+       CMPLWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPLW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+
+static void
+_ner(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMPW(r1, r2);
+    CRNOT(CR_EQ, CR_EQ);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_EQ);
+}
+
+static void
+_nei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_short_p(i0))
+       CMPWI(r1, i0);
+    else if (can_zero_extend_short_p(i0))
+       CMPLWI(r1, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       CMPW(r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    CRNOT(CR_EQ, CR_EQ);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_EQ);
+}
+
+static jit_word_t
+_bltr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLT(d);
+    return (w);
+}
+
+static jit_word_t
+_blti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_sign_extend_short_p(i1))
+       CMPWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLT(d);
+    return (w);
+}
+
+static jit_word_t
+_bltr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPLW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLT(d);
+    return (w);
+}
+
+static jit_word_t
+_blti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_zero_extend_short_p(i1))
+       CMPLWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPLW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLT(d);
+    return (w);
+}
+
+static jit_word_t
+_bler(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLE(d);
+    return (w);
+}
+
+static jit_word_t
+_blei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_sign_extend_short_p(i1))
+       CMPWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLE(d);
+    return (w);
+}
+
+static jit_word_t
+_bler_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPLW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLE(d);
+    return (w);
+}
+
+static jit_word_t
+_blei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_zero_extend_short_p(i1))
+       CMPLWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPLW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLE(d);
+    return (w);
+}
+
+static jit_word_t
+_beqr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BEQ(d);
+    return (w);
+}
+
+static jit_word_t
+_beqi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_sign_extend_short_p(i1))
+       CMPWI(r0, i1);
+    else if (can_zero_extend_short_p(i1))
+       CMPLWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BEQ(d);
+    return (w);
+}
+
+static jit_word_t
+_bger(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGE(d);
+    return (w);
+}
+
+static jit_word_t
+_bgei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_sign_extend_short_p(i1))
+       CMPWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGE(d);
+    return (w);
+}
+
+static jit_word_t
+_bger_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPLW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGE(d);
+    return (w);
+}
+
+static jit_word_t
+_bgei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_zero_extend_short_p(i1))
+       CMPLWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPLW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGE(d);
+    return (w);
+}
+
+static jit_word_t
+_bgtr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGT(d);
+    return (w);
+}
+
+static jit_word_t
+_bgti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_sign_extend_short_p(i1))
+       CMPWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGT(d);
+    return (w);
+}
+
+static jit_word_t
+_bgtr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPLW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGT(d);
+    return (w);
+}
+
+static jit_word_t
+_bgti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_zero_extend_short_p(i1))
+       CMPLWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPLW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGT(d);
+    return (w);
+}
+
+static jit_word_t
+_bner(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    CMPW(r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BNE(d);
+    return (w);
+}
+
+static jit_word_t
+_bnei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_sign_extend_short_p(i1))
+       CMPWI(r0, i1);
+    else if (can_zero_extend_short_p(i1))
+       CMPLWI(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       CMPW(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BNE(d);
+    return (w);
+}
+
+static jit_word_t
+_bmsr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    andr(rn(reg), r0, r1);
+    w = bnei(i0, rn(reg), 0);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bmsi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    andi(rn(reg), r0, i1);
+    w = bnei(i0, rn(reg), 0);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bmcr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    andr(rn(reg), r0, r1);
+    w = beqi(i0, rn(reg), 0);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bmci(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    andi(rn(reg), r0, i1);
+    w = beqi(i0, rn(reg), 0);
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_boaddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    ADDO(r0, r0, r1);
+    MCRXR(CR_0);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGT(d);                            /* GT = bit 1 of XER = OV */
+    return (w);
+}
+
+static jit_word_t
+_boaddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = boaddr(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bxaddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    ADDO(r0, r0, r1);
+    MCRXR(CR_0);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLE(d);
+    return (w);
+}
+
+static jit_word_t
+_bxaddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bxaddr(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bosubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    SUBO(r0, r0, r1);
+    MCRXR(CR_0);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGT(d);
+    return (w);
+}
+
+static jit_word_t
+_bosubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bosubr(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bxsubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    SUBO(r0, r0, r1);
+    MCRXR(CR_0);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLE(d);
+    return (w);
+}
+
+static jit_word_t
+_bxsubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bxsubr(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_boaddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    ADDC(r0, r0, r1);
+    MCRXR(CR_0);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BEQ(d);                            /* EQ = bit 2 of XER = CA */
+    return (w);
+}
+
+static jit_word_t
+_boaddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_sign_extend_short_p(i1)) {
+       ADDIC(r0, r0, i1);
+       MCRXR(CR_0);
+       w = _jit->pc.w;
+       d = (i0 - w) & ~3;
+       BEQ(d);
+       return (w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = boaddr_u(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bxaddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    ADDC(r0, r0, r1);
+    MCRXR(CR_0);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BNE(d);
+    return (w);
+}
+
+static jit_word_t
+_bxaddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    jit_word_t         d, w;
+    if (can_sign_extend_short_p(i1)) {
+       ADDIC(r0, r0, i1);
+       MCRXR(CR_0);
+       w = _jit->pc.w;
+       d = (i0 - w) & ~3;
+       BNE(d);
+       return (w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bxaddr_u(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bosubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    SUBC(r0, r0, r1);
+    MCRXR(CR_0);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BNE(d);                            /* PPC uses "carry" not "borrow" */
+    return (w);
+}
+
+static jit_word_t
+_bosubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bosubr_u(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bxsubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    SUBC(r0, r0, r1);
+    MCRXR(CR_0);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BEQ(d);
+    return (w);
+}
+
+static jit_word_t
+_bxsubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bxsubr_u(i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_ldr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ldr_uc(r0, r1);
+    extr_c(r0, r0);
+}
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    ldi_uc(r0, i0);
+    extr_c(r0, r0);
+}
+
+static void
+_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    ldxr_uc(r0, r1, r2);
+    extr_c(r0, r0);
+}
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi_uc(r0, r1, i0);
+    extr_c(r0, r0);
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       LBZ(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       LBZ(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_uc(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r1 == _R0_REGNO) {
+       if (r2 != _R0_REGNO)
+           LBZX(r0, r2, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LBZX(r0, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       LBZX(r0, r1, r2);
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       ldr_uc(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r1 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LBZ(r0, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           LBZ(r0, r1, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_uc(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       LHA(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       LHA(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_s(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r1 == _R0_REGNO) {
+       if (r2 != _R0_REGNO)
+           LHAX(r0, r2, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LHAX(r0, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       LHAX(r0, r1, r2);
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       ldr_s(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r1 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LHA(r0, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           LHA(r0, r1, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_s(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       LHZ(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       LHZ(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_us(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r1 == _R0_REGNO) {
+       if (r2 != _R0_REGNO)
+           LHZX(r0, r2, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LHZX(r0, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       LHZX(r0, r1, r2);
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       ldr_us(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r1 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LHZ(r0, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           LHZ(r0, r1, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_us(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 32
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       LWZ(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       LWZ(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r1 == _R0_REGNO) {
+       if (r2 != _R0_REGNO)
+           LWZX(r0, r2, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LWZX(r0, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       LWZX(r0, r1, r2);
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       ldr_i(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r1 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LWZ(r0, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           LWZ(r0, r1, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_i(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  else
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       LWA(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       LWA(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r1 == _R0_REGNO) {
+       if (r2 != _R0_REGNO)
+           LWZX(r0, r2, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LWAX(r0, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       LWZX(r0, r1, r2);
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       ldr_i(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r1 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LWA(r0, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           LWA(r0, r1, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_i(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       LWZ(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       LWZ(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_ui(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r1 == _R0_REGNO) {
+       if (r2 != _R0_REGNO)
+           LWZX(r0, r2, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LWZX(r0, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       LWZX(r0, r1, r2);
+}
+
+static void
+_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       ldr_i(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r1 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LWZ(r0, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           LWZ(r0, r1, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_ui(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_l(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       LD(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       LD(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_l(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r1 == _R0_REGNO) {
+       if (r2 != _R0_REGNO)
+           LDX(r0, r2, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LDX(r0, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       LDX(r0, r1, r2);
+}
+
+static void
+_ldxi_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       ldr_l(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r1 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LD(r0, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           LD(r0, r1, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_l(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+#  endif
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       STB(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       STB(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_c(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == _R0_REGNO) {
+       if (r1 != _R0_REGNO)
+           STBX(r2, r1, r0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r0);
+           STBX(r2, rn(reg), r1);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       STBX(r2, r0, r1);
+}
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       str_c(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r0 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), i0);
+           STB(r1, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           STB(r1, r0, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_c(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       STH(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       STH(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_s(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == _R0_REGNO) {
+       if (r1 != _R0_REGNO)
+           STHX(r2, r1, r0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r0);
+           STHX(r2, rn(reg), r1);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       STHX(r2, r0, r1);
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       str_s(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r0 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), i0);
+           STH(r1, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           STH(r1, r0, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_s(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       STW(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       STW(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_i(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == _R0_REGNO) {
+       if (r1 != _R0_REGNO)
+           STWX(r2, r1, r0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r0);
+           STWX(r2, rn(reg), r1);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       STWX(r2, r0, r1);
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       str_i(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r0 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), i0);
+           STW(r1, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           STW(r1, r0, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_i(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_sti_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       STD(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       STD(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_l(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == _R0_REGNO) {
+       if (r1 != _R0_REGNO)
+           STDX(r2, r1, r0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r0);
+           STDX(r2, rn(reg), r1);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       STDX(r2, r0, r1);
+}
+
+static void
+_stxi_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       str_l(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r0 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), i0);
+           STD(r1, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           STD(r1, r0, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_l(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+#  endif
+
+static void
+_jmpr(jit_state_t *_jit, jit_int32_t r0)
+{
+#if 0
+    MTLR(r0);
+    BLR();
+#else
+    MTCTR(r0);
+    BCTR();
+#endif
+}
+
+/* pc relative jump */
+static jit_word_t
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_word_t         w, d;
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    if (can_sign_extend_jump_p(d))
+       B(d);
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       w = movi_p(rn(reg), i0);
+       jmpr(rn(reg));
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+/* absolute jump */
+static jit_word_t
+_jmpi_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    w = movi_p(rn(reg), i0);
+    jmpr(rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_callr(jit_state_t *_jit, jit_int32_t r0
+#  if _CALL_SYSV
+       , jit_int32_t varargs
+#  endif
+       )
+{
+#  if _CALL_AIXDESC
+    stxi(sizeof(void*) * 5, _SP_REGNO, _R2_REGNO);
+    /* FIXME Pretend to not know about r11? */
+    if (r0 == _R0_REGNO) {
+       movr(_R11_REGNO, _R0_REGNO);
+       ldxi(_R2_REGNO, _R11_REGNO, sizeof(void*));
+       ldxi(_R11_REGNO, _R11_REGNO, sizeof(void*) * 2);
+    }
+    else {
+       ldxi(_R2_REGNO, r0, sizeof(void*));
+       ldxi(_R11_REGNO, r0, sizeof(void*) * 2);
+    }
+    ldr(r0, r0);
+#  else
+#    if _CALL_SYSV
+    /* Tell double arguments were passed in registers. */
+    if (varargs)
+       CREQV(6, 6, 6);
+#    endif
+    movr(_R12_REGNO, r0);
+#  endif
+
+    MTCTR(r0);
+    BCTRL();
+
+#  if _CALL_AIXDESC
+    ldxi(_R2_REGNO, _SP_REGNO, sizeof(void*) * 5);
+#  endif
+}
+
+/* assume fixed address or reachable address */
+static void
+_calli(jit_state_t *_jit, jit_word_t i0
+#  if _CALL_SYSV
+       , jit_int32_t varargs
+#  endif
+       )
+{
+#  if _CALL_SYSV
+    jit_word_t         d;
+    d = (i0 - _jit->pc.w) & ~3;
+    if (can_sign_extend_jump_p(d))
+       BL(d);
+    else
+#  endif
+    {
+       movi(_R12_REGNO, i0);
+       callr(_R12_REGNO
+#  if _CALL_SYSV
+             , varargs
+#  endif
+             );
+    }
+}
+
+/* absolute jump */
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0
+#  if _CALL_SYSV
+       , jit_int32_t varargs
+#  endif
+        )
+{
+    jit_word_t         w;
+    w = movi_p(_R12_REGNO, i0);
+    callr(_R12_REGNO
+#  if _CALL_SYSV
+         , varargs
+#  endif
+         );
+    return (w);
+}
+
+/* order is not guaranteed to be sequential */
+static jit_int32_t save[] = {
+    _R14, _R15, _R16, _R17, _R18, _R19, _R20, _R21, _R22,
+    _R23, _R24, _R25, _R26, _R27, _R28, _R29, _R30, _R31,
+};
+
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    unsigned long      regno;
+    jit_word_t         offset;
+
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar) {
+       _jitc->function->self.aoff -= 2 * sizeof(jit_word_t);
+       _jitc->function->self.aoff &= -16;
+    }
+    _jitc->function->stack = ((_jitc->function->self.alen +
+                             _jitc->function->self.size -
+                             _jitc->function->self.aoff) + 15) & -16;
+
+    /* return address */
+    MFLR(_R0_REGNO);
+
+    /* params >= %r31+params_offset+(8*sizeof(jit_word_t))
+     * alloca <  %r31-80 */
+
+#if _CALL_SYSV
+    stxi(sizeof(jit_word_t), _SP_REGNO, _R0_REGNO);
+#else
+    stxi(sizeof(void*) * 2, _SP_REGNO, _R0_REGNO);
+#endif
+    offset = -gpr_save_area;
+    for (regno = 0; regno < jit_size(save); regno++, offset += sizeof(void*)) {
+       if (jit_regset_tstbit(&_jitc->function->regset, save[regno]))
+           stxi(offset, _SP_REGNO, rn(save[regno]));
+    }
+    for (offset = 0; offset < 8; offset++) {
+       if (jit_regset_tstbit(&_jitc->function->regset, _F14 + offset))
+           stxi_d(-(gpr_save_area + 8 + offset * 8),
+                  _SP_REGNO, rn(_F14 + offset));
+    }
+
+    stxi(-(sizeof(void*)), _SP_REGNO, _FP_REGNO);
+
+    movr(_FP_REGNO, _SP_REGNO);
+#if __WORDSIZE == 32
+    STWU(_SP_REGNO, _SP_REGNO, -_jitc->function->stack);
+#else
+    STDU(_SP_REGNO, _SP_REGNO, -_jitc->function->stack);
+#endif
+
+    if (_jitc->function->allocar) {
+       regno = jit_get_reg(jit_class_gpr);
+       movi(rn(regno), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, _FP_REGNO, rn(regno));
+       jit_unget_reg(regno);
+    }
+
+#if !_CALL_SYSV
+    if (_jitc->function->self.call & jit_call_varargs) {
+       for (regno = _jitc->function->vagp; jit_arg_reg_p(regno); ++regno)
+           stxi(params_offset + regno * sizeof(jit_word_t),
+                _FP_REGNO, rn(JIT_RA0 - regno));
+    }
+#else
+    if (_jitc->function->self.call & jit_call_varargs) {
+       for (regno = _jitc->function->vagp; jit_arg_reg_p(regno); ++regno)
+           stxi(_jitc->function->vaoff + first_gp_offset +
+                regno * sizeof(jit_word_t), _FP_REGNO, rn(JIT_RA0 - regno));
+       for (regno = _jitc->function->vafp; jit_arg_f_reg_p(regno); ++regno)
+           stxi_d(_jitc->function->vaoff + first_fp_offset +
+                  regno * va_fp_increment, _FP_REGNO,
+                  rn(JIT_FA0 - regno));
+    }
+#endif
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    unsigned long      regno;
+    jit_word_t         offset;
+
+    if (_jitc->function->assume_frame)
+       return;
+    if (_jitc->function->allocar)
+       ldr(_SP_REGNO, _SP_REGNO);
+    else
+       addi(_SP_REGNO, _SP_REGNO, _jitc->function->stack);
+#if _CALL_SYSV
+    ldxi(_R0_REGNO, _SP_REGNO, sizeof(jit_word_t));
+#else
+    ldxi(_R0_REGNO, _SP_REGNO, sizeof(void*) * 2);
+#endif
+    offset = -gpr_save_area;
+    for (regno = 0; regno < jit_size(save); regno++, offset += sizeof(void*)) {
+       if (jit_regset_tstbit(&_jitc->function->regset, save[regno]))
+           ldxi(rn(save[regno]), _SP_REGNO, offset);
+    }
+    for (offset = 0; offset < 8; offset++) {
+       if (jit_regset_tstbit(&_jitc->function->regset, _F14 + offset))
+           ldxi_d(rn(_F14 + offset), _SP_REGNO,
+                  -(gpr_save_area + 8 + offset * 8));
+    }
+
+    MTLR(_R0_REGNO);
+    ldxi(_FP_REGNO, _SP_REGNO, -(sizeof(void*)));
+
+    BLR();
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+#if !_CALL_SYSV
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Initialize stack pointer to the first stack argument. */
+    addi(r0, _FP_REGNO, _jitc->function->self.size);
+#else
+    jit_int32_t                reg;
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Return jit_va_list_t in the register argument */
+    addi(r0, _FP_REGNO, _jitc->function->vaoff);
+    reg = jit_get_reg(jit_class_gpr);
+
+    /* Initialize the gp counter. */
+    movi(rn(reg), _jitc->function->vagp);
+    stxi_c(offsetof(jit_va_list_t, ngpr), r0, rn(reg));
+
+    /* Initialize the fp counter. */
+    movi(rn(reg), _jitc->function->vafp);
+    stxi_c(offsetof(jit_va_list_t, nfpr), r0, rn(reg));
+
+    /* Initialize overflow pointer to the first stack argument. */
+    addi(rn(reg), _FP_REGNO, _jitc->function->self.size);
+    stxi(offsetof(jit_va_list_t, over), r0, rn(reg));
+
+    /* Initialize register save area pointer. */
+    addi(rn(reg), r0, first_gp_offset);
+    stxi(offsetof(jit_va_list_t, save), r0, rn(reg));
+
+    jit_unget_reg(reg);
+#endif
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#if !_CALL_SYSV
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Load argument. */
+    ldr(r0, r1);
+    /* Update va_list. */
+    addi(r1, r1, sizeof(jit_word_t));
+#else
+    jit_int32_t                rg0;
+    jit_int32_t                rg1;
+    jit_word_t         ge_code;
+    jit_word_t         lt_code;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg(jit_class_gpr);
+    rg1 = jit_get_reg(jit_class_gpr);
+
+    /* Load the gp offset in save area in the first temporary. */
+    ldxi_uc(rn(rg0), r1, offsetof(jit_va_list_t, ngpr));
+
+    /* Jump over if there are no remaining arguments in the save area. */
+    ge_code = bgei(_jit->pc.w, rn(rg0), 8);
+
+    /* Update the gp counter. */
+    addi(rn(rg1), rn(rg0), 1);
+    stxi_c(offsetof(jit_va_list_t, ngpr), r1, rn(rg1));
+
+    /* Load the save area pointer in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, save));
+
+    /* Load the vararg argument in the first argument. */
+    lshi(rn(rg0), rn(rg0), va_gp_shift);
+    ldxr(r0, rn(rg1), rn(rg0));
+
+    /* Will only need one temporary register below. */
+    jit_unget_reg(rg1);
+
+    /* Jump over overflow code. */
+    lt_code = _jit->pc.w;
+    B(0);
+
+    /* Where to land if argument is in overflow area. */
+    patch_at(ge_code, _jit->pc.w);
+
+    /* Load overflow pointer. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, over));
+
+    /* Load argument. */
+    ldr(r0, rn(rg0));
+
+    /* Update overflow pointer. */
+    addi(rn(rg0), rn(rg0), va_gp_increment);
+    stxi(offsetof(jit_va_list_t, over), r1, rn(rg0));
+
+    /* Where to land if argument is in save area. */
+    patch_at(lt_code, _jit->pc.w);
+
+    jit_unget_reg(rg0);
+#endif
+}
+
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#if !_CALL_SYSV
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Load argument. */
+    ldr_d(r0, r1);
+    /* Update va_list. */
+    addi(r1, r1, sizeof(jit_float64_t));
+#else
+    jit_int32_t                rg0;
+    jit_int32_t                rg1;
+    jit_word_t         ge_code;
+    jit_word_t         lt_code;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg(jit_class_gpr);
+    rg1 = jit_get_reg(jit_class_gpr);
+
+    /* Load the fp offset in save area in the first temporary. */
+    ldxi_uc(rn(rg0), r1, offsetof(jit_va_list_t, nfpr));
+
+    /* Jump over if there are no remaining arguments in the save area. */
+    ge_code = bgei(_jit->pc.w, rn(rg0), 8);
+
+    /* Update the fp counter. */
+    addi(rn(rg1), rn(rg0), 1);
+    stxi_c(offsetof(jit_va_list_t, nfpr), r1, rn(rg1));
+
+    /* Load the save area pointer in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, save));
+
+    /* Load the vararg argument in the first argument. */
+    lshi(rn(rg0), rn(rg0), 3);
+    addi(rn(rg0), rn(rg0), offsetof(jit_va_list_t, first_fp_argument) -
+        offsetof(jit_va_list_t, first_gp_argument));
+    ldxr_d(r0, rn(rg1), rn(rg0));
+
+    /* Jump over overflow code. */
+    lt_code = _jit->pc.w;
+    B(0);
+
+    /* Where to land if argument is in overflow area. */
+    patch_at(ge_code, _jit->pc.w);
+
+    /* Load overflow pointer. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, over));
+
+#  if __WORDSIZE == 32
+    /* Align if required. */
+    andi(rn(rg1), rn(rg0), 7);
+    addr(rn(rg0), rn(rg0), rn(rg1));
+#  endif
+
+    /* Load argument. */
+    ldr_d(r0, rn(rg0));
+
+    /* Update overflow pointer. */
+    addi(rn(rg0), rn(rg0), va_fp_increment);
+    stxi(offsetof(jit_va_list_t, over), r1, rn(rg0));
+
+    /* Where to land if argument is in save area. */
+    patch_at(lt_code, _jit->pc.w);
+
+    jit_unget_reg(rg0);
+    jit_unget_reg(rg1);
+#endif
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
+{
+    jit_word_t          d;
+    union {
+       jit_int32_t     *i;
+       jit_word_t       w;
+    } u;
+    u.w = instr;
+    switch ((u.i[0] & 0xfc000000) >> 26) {
+       case 16:                                        /* BCx */
+           d = label - instr;
+           assert(!(d & 3));
+           if (!can_sign_extend_short_p(d)) {
+               /* use absolute address */
+               assert(can_sign_extend_short_p(label));
+               d |= 2;
+           }
+           u.i[0] = (u.i[0] & ~0xfffd) | (d & 0xfffe);
+           break;
+       case 18:                                        /* Bx */
+#if _CALL_AIXDESC
+           if (_jitc->jump && (!(u.i[0] & 1))) {       /* jmpi label */
+               /* zero is used for toc and env, so, quick check
+                * if this is a "jmpi main" like initial jit
+                * instruction */
+               if (((long *)label)[1] == 0 && ((long *)label)[2] == 0) {
+                   for (d = 0; d < _jitc->prolog.offset; d++) {
+                       /* not so pretty, but hides powerpc
+                        * specific abi intrinsics and/or
+                        * implementation from user */
+                       if (_jitc->prolog.ptr[d] == label) {
+                           label += sizeof(void*) * 3;
+                           break;
+                       }
+                   }
+               }
+           }
+#endif
+           d = label - instr;
+           assert(!(d & 3));
+           if (!can_sign_extend_jump_p(d)) {
+               /* use absolute address */
+               assert(can_sign_extend_jump_p(label));
+               d |= 2;
+           }
+           u.i[0] = (u.i[0] & ~0x3fffffd) | (d & 0x3fffffe);
+           break;
+       case 15:                                        /* LI */
+#if __WORDSIZE == 32
+#  define MTCTR_OFF            2
+#  define BCTR_OFF             3
+#else
+#  define MTCTR_OFF            6
+#  define BCTR_OFF             7
+#endif
+#if _CALL_AIXDESC
+           /* movi reg label; jmpr reg */
+           if (_jitc->jump &&
+#if 0
+               /* check for MLTR(reg) */
+               (u.i[MTCTR_OFF] >> 26) == 31 &&
+               ((u.i[MTCTR_OFF] >> 16) & 0x3ff) == 8 &&
+               ((u.i[MTCTR_OFF] >> 1) & 0x3ff) == 467 &&
+               /* check for BLR */
+               u.i[BCTR_OFF] == 0x4e800020) {
+#else
+               /* check for MTCTR(reg) */
+               (u.i[MTCTR_OFF] >> 26) == 31 &&
+               ((u.i[MTCTR_OFF] >> 16) & 0x3ff) == 9 &&
+               ((u.i[MTCTR_OFF] >> 1) & 0x3ff) == 467 &&
+               /* check for BCTR */
+               u.i[BCTR_OFF] == 0x4e800420) {
+#endif
+               /* zero is used for toc and env, so, quick check
+                * if this is a "jmpi main" like initial jit
+                * instruction */
+               if (((long *)label)[1] == 0 && ((long *)label)[2] == 0) {
+                   for (d = 0; d < _jitc->prolog.offset; d++) {
+                       /* not so pretty, but hides powerpc
+                        * specific abi intrinsics and/or
+                        * implementation from user */
+                       if (_jitc->prolog.ptr[d] == label) {
+                           label += sizeof(void*) * 3;
+                           break;
+                       }
+                   }
+               }
+           }
+#endif
+#undef BCTR_OFF
+#undef MTCTR_OFF
+#if __WORDSIZE == 32
+           assert(!(u.i[0] & 0x1f0000));
+           u.i[0] = (u.i[0] & ~0xffff) | ((label >> 16) & 0xffff);
+           assert((u.i[1] & 0xfc000000) >> 26 == 24);  /* ORI */
+           assert(((u.i[1] >> 16) & 0x1f) == ((u.i[1] >> 21) & 0x1f));
+           u.i[1] = (u.i[1] & ~0xffff) | (label & 0xffff);
+#else
+           assert(!(u.i[0] & 0x1f0000));
+           u.i[0] = (u.i[0] & ~0xffff) | ((label >> 48) & 0xffff);
+           assert((u.i[1] & 0xfc000000) >> 26 == 24);  /* ORI */
+           assert(((u.i[1] >> 16) & 0x1f) == ((u.i[1] >> 21) & 0x1f));
+           u.i[1] = (u.i[1] & ~0xffff) | ((label >> 32) & 0xffff);
+           /* not fully validating SLDI */
+           assert((u.i[2] & 0xfc000000) >> 26 == 30);  /* SLDI */
+           assert(((u.i[2] >> 16) & 0x1f) == ((u.i[2] >> 21) & 0x1f));
+           assert((u.i[3] & 0xfc000000) >> 26 == 24);  /* ORI */
+           assert(((u.i[3] >> 16) & 0x1f) == ((u.i[3] >> 21) & 0x1f));
+           u.i[3] = (u.i[3] & ~0xffff) | ((label >> 16) & 0xffff);
+           /* not fully validating SLDI */
+           assert((u.i[4] & 0xfc000000) >> 26 == 30);  /* SLDI */
+           assert(((u.i[4] >> 16) & 0x1f) == ((u.i[4] >> 21) & 0x1f));
+           assert((u.i[5] & 0xfc000000) >> 26 == 24);  /* ORI */
+           assert(((u.i[5] >> 16) & 0x1f) == ((u.i[5] >> 21) & 0x1f));
+           u.i[5] = (u.i[5] & ~0xffff) | (label & 0xffff);
+#endif
+           break;
+       default:
+           assert(!"unhandled branch opcode");
+    }
+}
+#endif
diff --git a/deps/lightning/lib/jit_ppc-fpu.c b/deps/lightning/lib/jit_ppc-fpu.c
new file mode 100644 (file)
index 0000000..1e84f8e
--- /dev/null
@@ -0,0 +1,1182 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#define FA(o,d,a,b,c,x)                        _FA(_jit,o,d,a,b,c,x,0)
+#define FA_(o,d,a,b,c,x)               _FA(_jit,o,d,a,b,c,x,1)
+static void _FA(jit_state_t*,int,int,int,int,int,int,int);
+#define FXFL(o,m,b,x)                  _FXFL(_jit,o,m,b,x,0)
+#define FXFL_(o,m,b,x)                 _FXFL(_jit,o,m,b,x,1)
+static void _FXFL(jit_state_t*,int,int,int,int,int) maybe_unused;
+#  define FABS(d,b)                    FX(63,d,0,b,264)
+#  define FABS_(d,b)                   FX_(63,d,0,b,264)
+#  define FADD(d,a,b)                  FA(63,d,a,b,0,21)
+#  define FADD_(d,a,b)                 FA_(63,d,a,b,0,21)
+#  define FADDS(d,a,b)                 FA(59,d,a,b,0,21)
+#  define FADDS_(d,a,b)                        FA_(59,d,a,b,0,21)
+#  define FCFID(d,b)                   FX(63,d,0,b,846)
+#  define FCMPO(cr,a,b)                        FC(63,cr,0,a,b,32)
+#  define FCMPU(cr,a,b)                        FC(63,cr,0,a,b,0)
+#  define FCTIW(d,b)                   FX(63,d,0,b,14)
+#  define FCTIW_(d,b)                  FX_(63,d,0,b,14)
+#  define FCTIWZ(d,b)                  FX(63,d,0,b,15)
+#  define FCTIWZ_(d,b)                 FX_(63,d,0,b,15)
+#  define FCTID(d,b)                   FX(63,d,0,b,814)
+#  define FCTID_(d,b)                  FX_(63,d,0,b,814)
+#  define FCTIDZ(d,b)                  FX(63,d,0,b,815)
+#  define FCTIDZ_(d,b)                 FX_(63,d,0,b,815)
+#  define FDIV(d,a,b)                  FA(63,d,a,b,0,18)
+#  define FDIV_(d,a,b)                 FA_(63,d,a,b,0,18)
+#  define FDIVS(d,a,b)                 FA(59,d,a,b,0,18)
+#  define FDIVS_(d,a,b)                        FA_(59,d,a,b,0,18)
+#  define FMADD(d,a,b,c)               FA(63,d,a,b,c,29)
+#  define FMADD_(d,a,b,c)              FA(63,d,a,b,c,29)
+#  define FMADDS(d,a,b,c)              FA(59,d,a,b,c,29)
+#  define FMADDS_(d,a,b,c)             FA(59,d,a,b,c,29)
+#  define FMR(d,b)                     FX(63,d,0,b,72)
+#  define FMR_(d,b)                    FX_(63,d,0,b,72)
+#  define FMSUB(d,a,b,c)               FA(63,d,a,b,c,28)
+#  define FMSUB_(d,a,b,c)              FA(63,d,a,b,c,28)
+#  define FMSUBS(d,a,b,c)              FA(59,d,a,b,c,28)
+#  define FMSUBS_(d,a,b,c)             FA(59,d,a,b,c,28)
+#  define FMUL(d,a,c)                  FA(63,d,a,0,c,25)
+#  define FMUL_(d,a,c)                 FA_(63,d,a,0,c,25)
+#  define FMULS(d,a,c)                 FA(59,d,a,0,c,25)
+#  define FMULS_(d,a,c)                        FA_(59,d,a,0,c,25)
+#  define FNABS(d,b)                   FX(63,d,0,b,136)
+#  define FNABS_(d,b)                  FX_(63,d,0,b,136)
+#  define FNEG(d,b)                    FX(63,d,0,b,40)
+#  define FNEG_(d,b)                   FX_(63,d,0,b,40)
+#  define FNMADD(d,a,b,c)              FA(63,d,a,b,c,31)
+#  define FNMADD_(d,a,b,c)             FA_(63,d,a,b,c,31)
+#  define FNMADDS(d,a,b,c)             FA(59,d,a,b,c,31)
+#  define FNMADDS_(d,a,b,c)            FA_(59,d,a,b,c,31)
+#  define FNMSUB(d,a,b,c)              FA(63,d,a,b,c,30)
+#  define FNMSUB_(d,a,b,c)             FA_(63,d,a,b,c,30)
+#  define FNMSUBS(d,a,b,c)             FA(59,d,a,b,c,30)
+#  define FNMSUBS_(d,a,b,c)            FA_(59,d,a,b,c,30)
+#  define FRES(d,b)                    FA(59,d,0,b,0,24)
+#  define FRES_(d,b)                   FA_(59,d,0,b,0,24)
+#  define FRSP(d,b)                    FA(63,d,0,b,0,12)
+#  define FRSP_(d,b)                   FA_(63,d,0,b,0,12)
+#  define FRSQTRE(d,b)                 FA(63,d,0,b,0,26)
+#  define FRSQTRE_(d,b)                        FA_(63,d,0,b,0,26)
+#  define FSEL(d,a,b,c)                        FA(63,d,a,b,c,23)
+#  define FSEL_(d,a,b,c)               FA_(63,d,a,b,c,23)
+#  define FSQRT(d,b)                   FA(63,d,0,b,0,22)
+#  define FSQRT_(d,b)                  FA_(63,d,0,b,0,22)
+#  define FSQRTS(d,b)                  FA(59,d,0,b,0,22)
+#  define FSQRTS_(d,b)                 FA_(59,d,0,b,0,22)
+#  define FSUB(d,a,b)                  FA(63,d,a,b,0,20)
+#  define FSUB_(d,a,b)                 FA(63,d,a,b,0,20)
+#  define FSUBS(d,a,b)                 FA(59,d,a,b,0,20)
+#  define FSUBS_(d,a,b)                        FA(59,d,a,b,0,20)
+#  define LFD(d,a,s)                   FDs(50,d,a,s)
+#  define LFDU(d,a,s)                  FDs(51,d,a,s)
+#  define LFDUX(d,a,b)                 FX(31,d,a,b,631)
+#  define LFDX(d,a,b)                  FX(31,d,a,b,599)
+#  define LFS(d,a,s)                   FDs(48,d,a,s)
+#  define LFSU(d,a,s)                  FDs(49,d,a,s)
+#  define LFSUX(d,a,b)                 FX(31,d,a,b,567)
+#  define LFSX(d,a,b)                  FX(31,d,a,b,535)
+#  define MCRFS(d,s)                   FXL(63,d<<2,(s)<<2,64)
+#  define MFFS(d)                      FX(63,d,0,0,583)
+#  define MFFS_(d)                     FX_(63,d,0,0,583)
+#  define MTFSB0(d)                    FX(63,d,0,0,70)
+#  define MTFSB0_(d)                   FX_(63,d,0,0,70)
+#  define MTFSB1(d)                    FX(63,d,0,0,38)
+#  define MTFSB1_(d)                   FX_(63,d,0,0,38)
+#  define MTFSF(m,b)                   FXFL(63,m,b,711)
+#  define MTFSF_(m,b)                  FXFL_(63,m,b,711)
+#  define MTFSFI(d,i)                  FX(63,d<<2,0,i<<1,134)
+#  define MTFSFI_(d,i)                 FX_(63,d<<2,0,i<<1,134)
+#  define STFD(s,a,d)                  FDs(54,s,a,d)
+#  define STFDU(s,a,d)                 FDs(55,s,a,d)
+#  define STFDUX(s,a,b)                        FX(31,s,a,b,759)
+#  define STFDX(s,a,b)                 FX(31,s,a,b,727)
+#  define STFIWX(s,a,b)                        FX(31,s,a,b,983)
+#  define STFS(s,a,d)                  FDs(52,s,a,d)
+#  define STFSU(s,a,d)                 FDs(53,s,a,d)
+#  define STFSUX(s,a,b)                        FX(31,s,a,b,695)
+#  define STFSX(s,a,b)                 FX(31,s,a,b,663)
+#  define movr_f(r0,r1)                        movr_d(r0,r1)
+#  define movr_d(r0,r1)                        _movr_d(_jit,r0,r1)
+static void _movr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi_f(r0,i0)                        _movi_f(_jit,r0,i0)
+static void _movi_f(jit_state_t*,jit_int32_t,jit_float32_t*);
+#  define movi_d(r0,i0)                        _movi_d(_jit,r0,i0)
+static void _movi_d(jit_state_t*,jit_int32_t,jit_float64_t*);
+#  define extr_f(r0,r1)                        extr_d(r0,r1)
+#  define extr_d(r0,r1)                        _extr_d(_jit,r0,r1)
+static void _extr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define truncr_f(r0,r1)              truncr_d(r0,r1)
+#  define truncr_f_i(r0,r1)            truncr_d_i(r0,r1)
+#  define truncr_d_i(r0,r1)            _truncr_d_i(_jit,r0,r1)
+static void _truncr_d_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 32
+#    define truncr_d(r0,r1)            truncr_d_i(r0,r1)
+#  else
+#    define truncr_d(r0,r1)            truncr_d_l(r0,r1)
+#    define truncr_f_l(r0,r1)          truncr_d_l(r0,r1)
+#    define truncr_d_l(r0,r1)          _truncr_d_l(_jit,r0,r1)
+static void _truncr_d_l(jit_state_t*,jit_int32_t,jit_int32_t);
+#  endif
+#  define extr_d_f(r0,r1)              FRSP(r0,r1)
+#  define extr_f_d(r0,r1)              movr_d(r0,r1)
+#  define absr_f(r0,r1)                        absr_d(r0,r1)
+#  define absr_d(r0,r1)                        FABS(r0,r1)
+#  define negr_f(r0,r1)                        negr_d(r0,r1)
+#  define negr_d(r0,r1)                        FNEG(r0,r1)
+#  define sqrtr_f(r0,r1)               FSQRTS(r0,r1)
+#  define sqrtr_d(r0,r1)               FSQRT(r0,r1)
+#  define addr_f(r0,r1,r2)             FADDS(r0,r1,r2)
+#  define addr_d(r0,r1,r2)             FADD(r0,r1,r2)
+#  define addi_f(r0,r1,i0)             _addi_f(_jit,r0,r1,i0)
+static void _addi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define addi_d(r0,r1,i0)             _addi_d(_jit,r0,r1,i0)
+static void _addi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define subr_f(r0,r1,r2)             FSUBS(r0,r1,r2)
+#  define subi_f(r0,r1,i0)             _subi_f(_jit,r0,r1,i0)
+static void _subi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define subr_d(r0,r1,r2)             FSUB(r0,r1,r2)
+#  define subi_d(r0,r1,i0)             _subi_d(_jit,r0,r1,i0)
+static void _subi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define rsbr_f(r0,r1,r2)             subr_f(r0,r2,r1)
+#  define rsbi_f(r0,r1,i0)             _rsbi_f(_jit,r0,r1,i0)
+static void _rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define rsbr_d(r0,r1,r2)             subr_d(r0,r2,r1)
+#  define rsbi_d(r0,r1,i0)             _rsbi_d(_jit,r0,r1,i0)
+static void _rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define mulr_f(r0,r1,r2)             FMULS(r0,r1,r2)
+#  define muli_f(r0,r1,i0)             _muli_f(_jit,r0,r1,i0)
+static void _muli_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define mulr_d(r0,r1,r2)             FMUL(r0,r1,r2)
+#  define muli_d(r0,r1,i0)             _muli_d(_jit,r0,r1,i0)
+static void _muli_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define divr_f(r0,r1,r2)             FDIVS(r0,r1,r2)
+#  define divi_f(r0,r1,i0)             _divi_f(_jit,r0,r1,i0)
+static void _divi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define divr_d(r0,r1,r2)             FDIV(r0,r1,r2)
+#  define divi_d(r0,r1,i0)             _divi_d(_jit,r0,r1,i0)
+static void _divi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ltr_f(r0,r1,r2)              ltr_d(r0,r1,r2)
+#  define ltr_d(r0,r1,r2)              _ltr_d(_jit,r0,r1,r2)
+static void _ltr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lti_f(r0,r1,i0)              _lti_f(_jit,r0,r1,i0)
+static void _lti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define lti_d(r0,r1,i0)              _lti_d(_jit,r0,r1,i0)
+static void _lti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ler_f(r0,r1,r2)              ler_d(r0,r1,r2)
+#  define ler_d(r0,r1,r2)              _ler_d(_jit,r0,r1,r2)
+static void _ler_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lei_f(r0,r1,i0)              _lei_f(_jit,r0,r1,i0)
+static void _lei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define lei_d(r0,r1,i0)              _lei_d(_jit,r0,r1,i0)
+static void _lei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define eqr_f(r0,r1,r2)              eqr_d(r0,r1,r2)
+#  define eqr_d(r0,r1,r2)              _eqr_d(_jit,r0,r1,r2)
+static void _eqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define eqi_f(r0,r1,i0)              _eqi_f(_jit,r0,r1,i0)
+static void _eqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define eqi_d(r0,r1,i0)              _eqi_d(_jit,r0,r1,i0)
+static void _eqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ger_f(r0,r1,r2)              ger_d(r0,r1,r2)
+#  define ger_d(r0,r1,r2)              _ger_d(_jit,r0,r1,r2)
+static void _ger_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gei_f(r0,r1,i0)              _gei_f(_jit,r0,r1,i0)
+static void _gei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define gei_d(r0,r1,i0)              _gei_d(_jit,r0,r1,i0)
+static void _gei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define gtr_f(r0,r1,r2)              gtr_d(r0,r1,r2)
+#  define gtr_d(r0,r1,r2)              _gtr_d(_jit,r0,r1,r2)
+static void _gtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gti_f(r0,r1,i0)              _gti_f(_jit,r0,r1,i0)
+static void _gti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define gti_d(r0,r1,i0)              _gti_d(_jit,r0,r1,i0)
+static void _gti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ner_f(r0,r1,r2)              ner_d(r0,r1,r2)
+#  define ner_d(r0,r1,r2)              _ner_d(_jit,r0,r1,r2)
+static void _ner_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nei_f(r0,r1,i0)              _nei_f(_jit,r0,r1,i0)
+static void _nei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define nei_d(r0,r1,i0)              _nei_d(_jit,r0,r1,i0)
+static void _nei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unltr_f(r0,r1,r2)            unltr_d(r0,r1,r2)
+#  define unltr_d(r0,r1,r2)            _unltr_d(_jit,r0,r1,r2)
+static void _unltr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unlti_f(r0,r1,i0)            _unlti_f(_jit,r0,r1,i0)
+static void _unlti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unlti_d(r0,r1,i0)            _unlti_d(_jit,r0,r1,i0)
+static void _unlti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unler_f(r0,r1,r2)            unler_d(r0,r1,r2)
+#  define unler_d(r0,r1,r2)            _unler_d(_jit,r0,r1,r2)
+static void _unler_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unlei_f(r0,r1,i0)            _unlei_f(_jit,r0,r1,i0)
+static void _unlei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unlei_d(r0,r1,i0)            _unlei_d(_jit,r0,r1,i0)
+static void _unlei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define uneqr_f(r0,r1,r2)            uneqr_d(r0,r1,r2)
+#  define uneqr_d(r0,r1,r2)            _uneqr_d(_jit,r0,r1,r2)
+static void _uneqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define uneqi_f(r0,r1,i0)            _uneqi_f(_jit,r0,r1,i0)
+static void _uneqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define uneqi_d(r0,r1,i0)            _uneqi_d(_jit,r0,r1,i0)
+static void _uneqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unger_f(r0,r1,r2)            unger_d(r0,r1,r2)
+#  define unger_d(r0,r1,r2)            _unger_d(_jit,r0,r1,r2)
+static void _unger_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ungei_f(r0,r1,i0)            _ungei_f(_jit,r0,r1,i0)
+static void _ungei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ungei_d(r0,r1,i0)            _ungei_d(_jit,r0,r1,i0)
+static void _ungei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ungtr_f(r0,r1,r2)            ungtr_d(r0,r1,r2)
+#  define ungtr_d(r0,r1,r2)            _ungtr_d(_jit,r0,r1,r2)
+static void _ungtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ungti_f(r0,r1,i0)            _ungti_f(_jit,r0,r1,i0)
+static void _ungti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ungti_d(r0,r1,i0)            _ungti_d(_jit,r0,r1,i0)
+static void _ungti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ltgtr_f(r0,r1,r2)            ltgtr_d(r0,r1,r2)
+#  define ltgtr_d(r0,r1,r2)            _ltgtr_d(_jit,r0,r1,r2)
+static void _ltgtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ltgti_f(r0,r1,i0)            _ltgti_f(_jit,r0,r1,i0)
+static void _ltgti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ltgti_d(r0,r1,i0)            _ltgti_d(_jit,r0,r1,i0)
+static void _ltgti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ordr_f(r0,r1,r2)             ordr_d(r0,r1,r2)
+#  define ordr_d(r0,r1,r2)             _ordr_d(_jit,r0,r1,r2)
+static void _ordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ordi_f(r0,r1,i0)             _ordi_f(_jit,r0,r1,i0)
+static void _ordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ordi_d(r0,r1,i0)             _ordi_d(_jit,r0,r1,i0)
+static void _ordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define unordr_f(r0,r1,r2)           unordr_d(r0,r1,r2)
+#  define unordr_d(r0,r1,r2)           _unordr_d(_jit,r0,r1,r2)
+static void _unordr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define unordi_f(r0,r1,i0)           _unordi_f(_jit,r0,r1,i0)
+static void _unordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define unordi_d(r0,r1,i0)           _unordi_d(_jit,r0,r1,i0)
+static void _unordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define bltr_f(i0,r0,r1)             bltr_d(i0,r0,r1)
+#  define bltr_d(i0,r0,r1)             _bltr_d(_jit,i0,r0,r1)
+static jit_word_t _bltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti_f(i0,r0,i1)             _blti_f(_jit,i0,r0,i1)
+static jit_word_t _blti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define blti_d(i0,r0,i1)             _blti_d(_jit,i0,r0,i1)
+static jit_word_t _blti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bler_f(i0,r0,r1)             bler_d(i0,r0,r1)
+#  define bler_d(i0,r0,r1)             _bler_d(_jit,i0,r0,r1)
+static jit_word_t _bler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei_f(i0,r0,i1)             _blei_f(_jit,i0,r0,i1)
+static jit_word_t _blei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define blei_d(i0,r0,i1)             _blei_d(_jit,i0,r0,i1)
+static jit_word_t _blei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define beqr_f(i0,r0,r1)             beqr_d(i0,r0,r1)
+#  define beqr_d(i0,r0,r1)             _beqr_d(_jit,i0,r0,r1)
+static jit_word_t _beqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define beqi_f(i0,r0,i1)             _beqi_f(_jit,i0,r0,i1)
+static jit_word_t _beqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define beqi_d(i0,r0,i1)             _beqi_d(_jit,i0,r0,i1)
+static jit_word_t _beqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bger_f(i0,r0,r1)             bger_d(i0,r0,r1)
+#  define bger_d(i0,r0,r1)             _bger_d(_jit,i0,r0,r1)
+static jit_word_t _bger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei_f(i0,r0,i1)             _bgei_f(_jit,i0,r0,i1)
+static jit_word_t _bgei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bgei_d(i0,r0,i1)             _bgei_d(_jit,i0,r0,i1)
+static jit_word_t _bgei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bgtr_f(i0,r0,r1)             bgtr_d(i0,r0,r1)
+#  define bgtr_d(i0,r0,r1)             _bgtr_d(_jit,i0,r0,r1)
+static jit_word_t _bgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti_f(i0,r0,i1)             _bgti_f(_jit,i0,r0,i1)
+static jit_word_t _bgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bgti_d(i0,r0,i1)             _bgti_d(_jit,i0,r0,i1)
+static jit_word_t _bgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bner_f(i0,r0,r1)             bner_d(i0,r0,r1)
+#  define bner_d(i0,r0,r1)             _bner_d(_jit,i0,r0,r1)
+static jit_word_t _bner_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bnei_f(i0,r0,i1)             _bnei_f(_jit,i0,r0,i1)
+static jit_word_t _bnei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bnei_d(i0,r0,i1)             _bnei_d(_jit,i0,r0,i1)
+static jit_word_t _bnei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bunltr_f(i0,r0,r1)           bunltr_d(i0,r0,r1)
+#  define bunltr_d(i0,r0,r1)           _bunltr_d(_jit,i0,r0,r1)
+static jit_word_t _bunltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlti_f(i0,r0,i1)           _bunlti_f(_jit,i0,r0,i1)
+static jit_word_t _bunlti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bunlti_d(i0,r0,i1)           _bunlti_d(_jit,i0,r0,i1)
+static jit_word_t _bunlti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bunler_f(i0,r0,r1)           bunler_d(i0,r0,r1)
+#  define bunler_d(i0,r0,r1)           _bunler_d(_jit,i0,r0,r1)
+static jit_word_t _bunler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlei_f(i0,r0,i1)           _bunlei_f(_jit,i0,r0,i1)
+static jit_word_t _bunlei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bunlei_d(i0,r0,i1)           _bunlei_d(_jit,i0,r0,i1)
+static jit_word_t _bunlei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define buneqr_f(i0,r0,r1)           buneqr_d(i0,r0,r1)
+#  define buneqr_d(i0,r0,r1)           _buneqr_d(_jit,i0,r0,r1)
+static jit_word_t _buneqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define buneqi_f(i0,r0,i1)           _buneqi_f(_jit,i0,r0,i1)
+static jit_word_t _buneqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define buneqi_d(i0,r0,i1)           _buneqi_d(_jit,i0,r0,i1)
+static jit_word_t _buneqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bunger_f(i0,r0,r1)           bunger_d(i0,r0,r1)
+#  define bunger_d(i0,r0,r1)           _bunger_d(_jit,i0,r0,r1)
+static jit_word_t _bunger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungei_f(i0,r0,i1)           _bungei_f(_jit,i0,r0,i1)
+static jit_word_t _bungei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bungei_d(i0,r0,i1)           _bungei_d(_jit,i0,r0,i1)
+static jit_word_t _bungei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bungtr_f(i0,r0,r1)           bungtr_d(i0,r0,r1)
+#  define bungtr_d(i0,r0,r1)           _bungtr_d(_jit,i0,r0,r1)
+static jit_word_t _bungtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungti_f(i0,r0,i1)           _bungti_f(_jit,i0,r0,i1)
+static jit_word_t _bungti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bungti_d(i0,r0,i1)           _bungti_d(_jit,i0,r0,i1)
+static jit_word_t _bungti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bltgtr_f(i0,r0,r1)           bltgtr_d(i0,r0,r1)
+#  define bltgtr_d(i0,r0,r1)           _bltgtr_d(_jit,i0,r0,r1)
+static jit_word_t _bltgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bltgti_f(i0,r0,i1)           _bltgti_f(_jit,i0,r0,i1)
+static jit_word_t _bltgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bltgti_d(i0,r0,i1)           _bltgti_d(_jit,i0,r0,i1)
+static jit_word_t _bltgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bordr_f(i0,r0,r1)            bordr_d(i0,r0,r1)
+#  define bordr_d(i0,r0,r1)            _bordr_d(_jit,i0,r0,r1)
+static jit_word_t _bordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bordi_f(i0,r0,i1)            _bordi_f(_jit,i0,r0,i1)
+static jit_word_t _bordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bordi_d(i0,r0,i1)            _bordi_d(_jit,i0,r0,i1)
+static jit_word_t _bordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bunordr_f(i0,r0,r1)          bunordr_d(i0,r0,r1)
+#  define bunordr_d(i0,r0,r1)          _bunordr_d(_jit,i0,r0,r1)
+static jit_word_t _bunordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunordi_f(i0,r0,i1)          _bunordi_f(_jit,i0,r0,i1)
+static jit_word_t _bunordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bunordi_d(i0,r0,i1)          _bunordi_d(_jit,i0,r0,i1)
+static jit_word_t _bunordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define ldr_f(r0,r1)                 LFSX(r0, _R0_REGNO, r1)
+#  define ldi_f(r0,i0)                 _ldi_f(_jit,r0,i0)
+static void _ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_f(r0,r1,r2)             _ldxr_f(_jit,r0,r1,r2)
+static void _ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_f(r0,r1,i0)             _ldxi_f(_jit,r0,r1,i0)
+static void _ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_f(r0,r1)                 STFSX(r1, _R0_REGNO, r0)
+#  define sti_f(i0,r0)                 _sti_f(_jit,i0,r0)
+static void _sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_f(r0,r1,r2)             _stxr_f(_jit,r0,r1,r2)
+static void _stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_f(i0,r0,r1)             _stxi_f(_jit,i0,r0,r1)
+static void _stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define ldr_d(r0,r1)                 LFDX(r0, _R0_REGNO, r1)
+#  define ldi_d(r0,i0)                 _ldi_d(_jit,r0,i0)
+static void _ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_d(r0,r1,r2)             _ldxr_d(_jit,r0,r1,r2)
+static void _ldxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_d(r0,r1,i0)             _ldxi_d(_jit,r0,r1,i0)
+static void _ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_d(r0,r1)                 STFDX(r1, _R0_REGNO, r0)
+#  define sti_d(i0,r0)                 _sti_d(_jit,i0,r0)
+static void _sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_d(r0,r1,r2)             _stxr_d(_jit,r0,r1,r2)
+static void _stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_d(i0,r0,r1)             _stxi_d(_jit,i0,r0,r1)
+static void _stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#endif
+
+#if CODE
+#  define _u16(v)                      ((v) & 0xffff)
+static void
+_FA(jit_state_t *_jit, int o, int d, int a, int b, int c, int x, int r)
+{
+    assert(!(o & ~((1 << 6) - 1)));
+    assert(!(d & ~((1 << 5) - 1)));
+    assert(!(a & ~((1 << 5) - 1)));
+    assert(!(b & ~((1 << 5) - 1)));
+    assert(!(c & ~((1 << 5) - 1)));
+    assert(!(x & ~((1 << 5) - 1)));
+    assert(!(r & ~((1 << 1) - 1)));
+    ii((o<<26)|(d<<21)|(a<<16)|(b<<11)|(c<<6)|(x<<1)|r);
+}
+
+static void
+_FXFL(jit_state_t *_jit, int o, int m, int b, int x, int r)
+{
+    assert(!(o & ~((1 <<  6) - 1)));
+    assert(!(m & ~((1 <<  8) - 1)));
+    assert(!(b & ~((1 <<  5) - 1)));
+    assert(!(x & ~((1 << 10) - 1)));
+    assert(!(r & ~((1 <<  1) - 1)));
+    ii((o<<26)|(m<<17)|(b<<11)|(x<<1)|r);
+}
+
+static void
+_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       FMR(r0,r1);
+}
+
+static void
+_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t      i;
+       jit_float32_t    f;
+    } data;
+    jit_int32_t                 reg;
+
+    if (_jitc->no_data) {
+       data.f = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.i & 0xffffffff);
+       stxi_i(alloca_offset - 4, _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+       ldxi_f(r0, _FP_REGNO, alloca_offset - 4);
+    }
+    else
+       ldi_f(r0, (jit_word_t)i0);
+}
+
+static void
+_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+       jit_int32_t      i[2];
+       jit_word_t       w;
+       jit_float64_t    d;
+    } data;
+    jit_int32_t                 reg;
+
+    if (_jitc->no_data) {
+       data.d = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+#  if __WORDSIZE == 32
+       movi(rn(reg), data.i[0]);
+       stxi(alloca_offset - 8, _FP_REGNO, rn(reg));
+       movi(rn(reg), data.i[1]);
+       stxi(alloca_offset - 4, _FP_REGNO, rn(reg));
+#  else
+       movi(rn(reg), data.w);
+       stxi(alloca_offset - 8, _FP_REGNO, rn(reg));
+#  endif
+       jit_unget_reg(reg);
+       ldxi_d(r0, _FP_REGNO, alloca_offset - 8);
+    }
+    else
+       ldi_d(r0, (jit_word_t)i0);
+}
+
+/* should only work on newer ppc (fcfid is a ppc64 instruction) */
+static void
+_extr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#  if __WORDSIZE == 32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    rshi(rn(reg), r1, 31);
+    /* use reserved 8 bytes area */
+    stxi(alloca_offset - 4, _FP_REGNO, r1);
+    stxi(alloca_offset - 8, _FP_REGNO, rn(reg));
+    jit_unget_reg(reg);
+#  else
+    stxi(alloca_offset - 8, _FP_REGNO, r1);
+#  endif
+    ldxi_d(r0, _FP_REGNO, alloca_offset - 8);
+    FCFID(r0, r0);
+}
+
+static void
+_truncr_d_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    FCTIWZ(rn(reg), r1);
+    /* use reserved 8 bytes area */
+    stxi_d(alloca_offset - 8, _FP_REGNO, rn(reg));
+    ldxi_i(r0, _FP_REGNO, alloca_offset - 4);
+    jit_unget_reg(reg);
+}
+
+#  if __WORDSIZE == 64
+static void
+_truncr_d_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    FCTIDZ(rn(reg), r1);
+    /* use reserved 8 bytes area */
+    stxi_d(alloca_offset - 8, _FP_REGNO, rn(reg));
+    ldxi(r0, _FP_REGNO, alloca_offset - 8);
+    jit_unget_reg(reg);
+}
+#  endif
+
+#  define fpr_opi(name, type, size)                                    \
+static void                                                            \
+_##name##i_##type(jit_state_t *_jit,                                   \
+                 jit_int32_t r0, jit_int32_t r1,                       \
+                 jit_float##size##_t *i0)                              \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    movi_##type(rn(reg), i0);                                          \
+    name##r_##type(r0, r1, rn(reg));                                   \
+    jit_unget_reg(reg);                                                        \
+}
+#  define fpr_bopi(name, type, size)                                   \
+static jit_word_t                                                      \
+_b##name##i_##type(jit_state_t *_jit,                                  \
+                 jit_word_t i0, jit_int32_t r0,                        \
+                 jit_float##size##_t *i1)                              \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|                \
+                                         jit_class_nospill);           \
+    movi_##type(rn(reg), i1);                                          \
+    word = b##name##r_##type(i0, r0, rn(reg));                         \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+#  define fopi(name)                   fpr_opi(name, f, 32)
+#  define fbopi(name)                  fpr_bopi(name, f, 32)
+#  define dopi(name)                   fpr_opi(name, d, 64)
+#  define dbopi(name)                  fpr_bopi(name, d, 64)
+
+fopi(add)
+dopi(add)
+fopi(sub)
+dopi(sub)
+fopi(rsb)
+dopi(rsb)
+fopi(mul)
+dopi(mul)
+fopi(div)
+dopi(div)
+
+static void
+_ltr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPO(CR_0, r1, r2);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+fopi(lt)
+dopi(lt)
+
+static void
+_ler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPO(CR_0, r1, r2);
+    CREQV(CR_GT, CR_GT, CR_UN);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+fopi(le)
+dopi(le)
+
+static void
+_eqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPO(CR_0, r1, r2);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_EQ);
+}
+fopi(eq)
+dopi(eq)
+
+static void
+_ger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPO(CR_0, r1, r2);
+    CREQV(CR_LT, CR_LT, CR_UN);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+fopi(ge)
+dopi(ge)
+
+static void
+_gtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPO(CR_0, r1, r2);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+fopi(gt)
+dopi(gt)
+
+static void
+_ner_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPO(CR_0, r1, r2);
+    CRNOT(CR_EQ, CR_EQ);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_EQ);
+}
+fopi(ne)
+dopi(ne)
+
+static void
+_unltr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPU(CR_0, r1, r2);
+    CROR(CR_LT, CR_LT, CR_UN);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+fopi(unlt)
+dopi(unlt)
+
+static void
+_unler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPU(CR_0, r1, r2);
+    CRNOT(CR_GT, CR_GT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+fopi(unle)
+dopi(unle)
+
+static void
+_uneqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPU(CR_0, r1, r2);
+    CROR(CR_EQ, CR_EQ, CR_UN);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_EQ);
+}
+fopi(uneq)
+dopi(uneq)
+
+static void
+_unger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPU(CR_0, r1, r2);
+    CRNOT(CR_LT, CR_LT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_LT);
+}
+fopi(unge)
+dopi(unge)
+
+static void
+_ungtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPU(CR_0, r1, r2);
+    CROR(CR_GT, CR_GT, CR_UN);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+fopi(ungt)
+dopi(ungt)
+
+static void
+_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPU(CR_0, r1, r2);
+    CROR(CR_GT, CR_GT, CR_LT);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_GT);
+}
+fopi(ltgt)
+dopi(ltgt)
+
+static void
+_ordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPU(CR_0, r1, r2);
+    CRNOT(CR_UN, CR_UN);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_UN);
+}
+fopi(ord)
+dopi(ord)
+
+static void
+_unordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPU(CR_0, r1, r2);
+    MFCR(r0);
+    EXTRWI(r0, r0, 1, CR_UN);
+}
+fopi(unord)
+dopi(unord)
+
+static jit_word_t
+_bltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPO(CR_0, r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLT(d);
+    return (w);
+}
+fbopi(lt)
+dbopi(lt)
+
+static jit_word_t
+_bler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPO(CR_0, r0, r1);
+    CREQV(CR_GT, CR_GT, CR_UN);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGT(d);
+    return (w);
+}
+fbopi(le)
+dbopi(le)
+
+static jit_word_t
+_beqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPO(CR_0, r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BEQ(d);
+    return (w);
+}
+fbopi(eq)
+dbopi(eq)
+
+static jit_word_t
+_bger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPO(CR_0, r0, r1);
+    CREQV(CR_LT, CR_LT, CR_UN);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLT(d);
+    return (w);
+}
+fbopi(ge)
+dbopi(ge)
+
+static jit_word_t
+_bgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPO(CR_0, r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGT(d);
+    return (w);
+}
+fbopi(gt)
+dbopi(gt)
+
+static jit_word_t
+_bner_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPO(CR_0, r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BNE(d);
+    return (w);
+}
+fbopi(ne)
+dbopi(ne)
+
+static jit_word_t
+_bunltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPU(CR_0, r0, r1);
+    CROR(CR_LT, CR_LT, CR_UN);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLT(d);
+    return (w);
+}
+fbopi(unlt)
+dbopi(unlt)
+
+static jit_word_t
+_bunler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPU(CR_0, r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BLE(d);
+    return (w);
+}
+fbopi(unle)
+dbopi(unle)
+
+static jit_word_t
+_buneqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPU(CR_0, r0, r1);
+    CROR(CR_EQ, CR_EQ, CR_UN);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BEQ(d);
+    return (w);
+}
+fbopi(uneq)
+dbopi(uneq)
+
+static jit_word_t
+_bunger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPU(CR_0, r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGE(d);
+    return (w);
+}
+fbopi(unge)
+dbopi(unge)
+
+static jit_word_t
+_bungtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPU(CR_0, r0, r1);
+    CROR(CR_GT, CR_GT, CR_UN);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BGT(d);
+    return (w);
+}
+fbopi(ungt)
+dbopi(ungt)
+
+static jit_word_t
+_bltgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPU(CR_0, r0, r1);
+    CROR(CR_EQ, CR_LT, CR_GT);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BEQ(d);
+    return (w);
+}
+fbopi(ltgt)
+dbopi(ltgt)
+
+static jit_word_t
+_bordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPU(CR_0, r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BNU(d);
+    return (w);
+}
+fbopi(ord)
+dbopi(ord)
+
+static jit_word_t
+_bunordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    FCMPU(CR_0, r0, r1);
+    w = _jit->pc.w;
+    d = (i0 - w) & ~3;
+    BUN(d);
+    return (w);
+}
+fbopi(unord)
+dbopi(unord)
+
+static void
+_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       LFS(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       LFS(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       LFD(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       LFD(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r1 == _R0_REGNO) {
+       if (r2 != _R0_REGNO)
+           LFSX(r0, r2, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LFSX(r0, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       LFSX(r0, r1, r2);
+}
+
+static void
+_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r1 == _R0_REGNO) {
+       if (r2 != _R0_REGNO)
+           LFDX(r0, r2, r1);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LFDX(r0, rn(reg), r2);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       LFDX(r0, r1, r2);
+}
+
+static void
+_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       ldr_f(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r1 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LFS(r0, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           LFS(r0, r1, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_f(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       ldr_d(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r1 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           LFD(r0, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           LFD(r0, r1, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_d(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       STFS(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       STFS(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_f(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_bool_t         inv;
+    jit_int32_t                reg;
+    jit_word_t         lo, hi;
+    if (can_sign_extend_short_p(i0))
+       STFD(r0, _R0_REGNO, i0);
+    else if (can_sign_extend_int_p(i0)) {
+       hi = (jit_int16_t)((i0 >> 16) + ((jit_uint16_t)i0 >> 15));
+       lo = (jit_int16_t)(i0 - (hi << 16));
+       reg = jit_get_reg(jit_class_gpr);
+       if ((inv = reg == _R0))         reg = jit_get_reg(jit_class_gpr);
+       LIS(rn(reg), hi);
+       STFD(r0, rn(reg), lo);
+       jit_unget_reg(reg);
+       if (inv)                        jit_unget_reg(_R0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_d(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == _R0_REGNO) {
+       if (r1 != _R0_REGNO)
+           STFSX(r2, r1, r0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r1);
+           STFSX(r2, rn(reg), r0);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       STFSX(r2, r0, r1);
+}
+
+static void
+_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == _R0_REGNO) {
+       if (r1 != _R0_REGNO)
+           STFDX(r2, r1, r0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), r0);
+           STFDX(r2, rn(reg), r1);
+           jit_unget_reg(reg);
+       }
+    }
+    else
+       STFDX(r2, r0, r1);
+}
+
+static void
+_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       str_f(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r0 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), i0);
+           STFS(r1, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           STFS(r1, r0, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_f(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       str_d(r0, r1);
+    else if (can_sign_extend_short_p(i0)) {
+       if (r0 == _R0_REGNO) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), i0);
+           STFD(r1, rn(reg), i0);
+           jit_unget_reg(reg);
+       }
+       else
+           STFD(r1, r0, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_d(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+#endif
diff --git a/deps/lightning/lib/jit_ppc-sz.c b/deps/lightning/lib/jit_ppc-sz.c
new file mode 100644 (file)
index 0000000..788ac45
--- /dev/null
@@ -0,0 +1,1627 @@
+#if __WORDSIZE == 32
+#if defined(__powerpc__)
+#if __BYTE_ORDER == __BIG_ENDIAN
+#if _CALL_SYSV
+#define JIT_INSTR_MAX 124
+    0, /* data */
+    0, /* live */
+    0, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    124,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    36,        /* va_start */
+    52,        /* va_arg */
+    64,        /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    12,        /* addi */
+    4, /* addcr */
+    12,        /* addci */
+    4, /* addxr */
+    8, /* addxi */
+    4, /* subr */
+    12,        /* subi */
+    4, /* subcr */
+    12,        /* subci */
+    4, /* subxr */
+    8, /* subxi */
+    16,        /* rsbi */
+    4, /* mulr */
+    12,        /* muli */
+    12,        /* qmulr */
+    16,        /* qmuli */
+    12,        /* qmulr_u */
+    16,        /* qmuli_u */
+    4, /* divr */
+    12,        /* divi */
+    4, /* divr_u */
+    12,        /* divi_u */
+    20,        /* qdivr */
+    16,        /* qdivi */
+    20,        /* qdivr_u */
+    16,        /* qdivi_u */
+    12,        /* remr */
+    20,        /* remi */
+    12,        /* remr_u */
+    20,        /* remi_u */
+    4, /* andr */
+    12,        /* andi */
+    4, /* orr */
+    12,        /* ori */
+    4, /* xorr */
+    12,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    12,        /* ltr */
+    12,        /* lti */
+    12,        /* ltr_u */
+    16,        /* lti_u */
+    16,        /* ler */
+    16,        /* lei */
+    16,        /* ler_u */
+    16,        /* lei_u */
+    12,        /* eqr */
+    12,        /* eqi */
+    16,        /* ger */
+    16,        /* gei */
+    16,        /* ger_u */
+    16,        /* gei_u */
+    12,        /* gtr */
+    12,        /* gti */
+    12,        /* gtr_u */
+    12,        /* gti_u */
+    16,        /* ner */
+    16,        /* nei */
+    4, /* movr */
+    8, /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    4, /* htonr_us */
+    4, /* htonr_ui */
+    0, /* htonr_ul */
+    8, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    8, /* ldi_uc */
+    4, /* ldr_s */
+    8, /* ldi_s */
+    4, /* ldr_us */
+    8, /* ldi_us */
+    4, /* ldr_i */
+    8, /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    8, /* ldxr_c */
+    16,        /* ldxi_c */
+    4, /* ldxr_uc */
+    12,        /* ldxi_uc */
+    4, /* ldxr_s */
+    12,        /* ldxi_s */
+    4, /* ldxr_us */
+    12,        /* ldxi_us */
+    4, /* ldxr_i */
+    12,        /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    4, /* str_c */
+    8, /* sti_c */
+    4, /* str_s */
+    8, /* sti_s */
+    4, /* str_i */
+    8, /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    4, /* stxr_c */
+    12,        /* stxi_c */
+    4, /* stxr_s */
+    12,        /* stxi_s */
+    4, /* stxr_i */
+    12,        /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    8, /* bltr */
+    8, /* blti */
+    8, /* bltr_u */
+    12,        /* blti_u */
+    8, /* bler */
+    8, /* blei */
+    8, /* bler_u */
+    12,        /* blei_u */
+    8, /* beqr */
+    16,        /* beqi */
+    8, /* bger */
+    8, /* bgei */
+    8, /* bger_u */
+    8, /* bgei_u */
+    8, /* bgtr */
+    8, /* bgti */
+    8, /* bgtr_u */
+    8, /* bgti_u */
+    8, /* bner */
+    16,        /* bnei */
+    12,        /* bmsr */
+    12,        /* bmsi */
+    12,        /* bmcr */
+    12,        /* bmci */
+    12,        /* boaddr */
+    16,        /* boaddi */
+    12,        /* boaddr_u */
+    12,        /* boaddi_u */
+    12,        /* bxaddr */
+    16,        /* bxaddi */
+    12,        /* bxaddr_u */
+    12,        /* bxaddi_u */
+    12,        /* bosubr */
+    16,        /* bosubi */
+    12,        /* bosubr_u */
+    16,        /* bosubi_u */
+    12,        /* bxsubr */
+    16,        /* bxsubi */
+    12,        /* bxsubr_u */
+    16,        /* bxsubi_u */
+    8, /* jmpr */
+    4, /* jmpi */
+    12,        /* callr */
+    20,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    124,       /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    16,        /* addi_f */
+    4, /* subr_f */
+    16,        /* subi_f */
+    16,        /* rsbi_f */
+    4, /* mulr_f */
+    16,        /* muli_f */
+    4, /* divr_f */
+    16,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    12,        /* ltr_f */
+    24,        /* lti_f */
+    16,        /* ler_f */
+    28,        /* lei_f */
+    12,        /* eqr_f */
+    24,        /* eqi_f */
+    16,        /* ger_f */
+    28,        /* gei_f */
+    12,        /* gtr_f */
+    24,        /* gti_f */
+    16,        /* ner_f */
+    28,        /* nei_f */
+    16,        /* unltr_f */
+    28,        /* unlti_f */
+    16,        /* unler_f */
+    28,        /* unlei_f */
+    16,        /* uneqr_f */
+    28,        /* uneqi_f */
+    16,        /* unger_f */
+    28,        /* ungei_f */
+    16,        /* ungtr_f */
+    28,        /* ungti_f */
+    16,        /* ltgtr_f */
+    28,        /* ltgti_f */
+    16,        /* ordr_f */
+    28,        /* ordi_f */
+    12,        /* unordr_f */
+    24,        /* unordi_f */
+    12,        /* truncr_f_i */
+    0, /* truncr_f_l */
+    20,        /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    12,        /* movi_f */
+    4, /* ldr_f */
+    8, /* ldi_f */
+    4, /* ldxr_f */
+    12,        /* ldxi_f */
+    4, /* str_f */
+    8, /* sti_f */
+    4, /* stxr_f */
+    12,        /* stxi_f */
+    8, /* bltr_f */
+    20,        /* blti_f */
+    12,        /* bler_f */
+    24,        /* blei_f */
+    8, /* beqr_f */
+    20,        /* beqi_f */
+    12,        /* bger_f */
+    24,        /* bgei_f */
+    8, /* bgtr_f */
+    20,        /* bgti_f */
+    8, /* bner_f */
+    20,        /* bnei_f */
+    12,        /* bunltr_f */
+    24,        /* bunlti_f */
+    8, /* bunler_f */
+    20,        /* bunlei_f */
+    12,        /* buneqr_f */
+    24,        /* buneqi_f */
+    8, /* bunger_f */
+    20,        /* bungei_f */
+    12,        /* bungtr_f */
+    24,        /* bungti_f */
+    12,        /* bltgtr_f */
+    24,        /* bltgti_f */
+    8, /* bordr_f */
+    20,        /* bordi_f */
+    8, /* bunordr_f */
+    20,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    24,        /* addi_d */
+    4, /* subr_d */
+    24,        /* subi_d */
+    24,        /* rsbi_d */
+    4, /* mulr_d */
+    24,        /* muli_d */
+    4, /* divr_d */
+    24,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    12,        /* ltr_d */
+    32,        /* lti_d */
+    16,        /* ler_d */
+    36,        /* lei_d */
+    12,        /* eqr_d */
+    32,        /* eqi_d */
+    16,        /* ger_d */
+    36,        /* gei_d */
+    12,        /* gtr_d */
+    32,        /* gti_d */
+    16,        /* ner_d */
+    36,        /* nei_d */
+    16,        /* unltr_d */
+    36,        /* unlti_d */
+    16,        /* unler_d */
+    36,        /* unlei_d */
+    16,        /* uneqr_d */
+    36,        /* uneqi_d */
+    16,        /* unger_d */
+    36,        /* ungei_d */
+    16,        /* ungtr_d */
+    36,        /* ungti_d */
+    16,        /* ltgtr_d */
+    36,        /* ltgti_d */
+    16,        /* ordr_d */
+    36,        /* ordi_d */
+    12,        /* unordr_d */
+    32,        /* unordi_d */
+    12,        /* truncr_d_i */
+    0, /* truncr_d_l */
+    20,        /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    24,        /* movi_d */
+    4, /* ldr_d */
+    8, /* ldi_d */
+    4, /* ldxr_d */
+    12,        /* ldxi_d */
+    4, /* str_d */
+    8, /* sti_d */
+    4, /* stxr_d */
+    12,        /* stxi_d */
+    8, /* bltr_d */
+    28,        /* blti_d */
+    12,        /* bler_d */
+    32,        /* blei_d */
+    8, /* beqr_d */
+    32,        /* beqi_d */
+    12,        /* bger_d */
+    32,        /* bgei_d */
+    8, /* bgtr_d */
+    28,        /* bgti_d */
+    8, /* bner_d */
+    28,        /* bnei_d */
+    12,        /* bunltr_d */
+    32,        /* bunlti_d */
+    8, /* bunler_d */
+    28,        /* bunlei_d */
+    12,        /* buneqr_d */
+    32,        /* buneqi_d */
+    8, /* bunger_d */
+    28,        /* bungei_d */
+    12,        /* bungtr_d */
+    32,        /* bungti_d */
+    12,        /* bltgtr_d */
+    32,        /* bltgti_d */
+    8, /* bordr_d */
+    28,        /* bordi_d */
+    8, /* bunordr_d */
+    28,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* _CALL_SYV */
+#endif /* __BYTE_ORDER */
+#endif /* __powerpc__ */
+#endif /* __WORDSIZE */
+
+#if __WORDSIZE == 32
+#if defined(__powerpc__)
+#if __BYTE_ORDER == __BIG_ENDIAN
+#if !_CALL_SYSV
+#define JIT_INSTR_MAX 136
+    0, /* data */
+    0, /* live */
+    0, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    136,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    4, /* va_start */
+    8, /* va_arg */
+    8, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    12,        /* addi */
+    4, /* addcr */
+    12,        /* addci */
+    4, /* addxr */
+    8, /* addxi */
+    4, /* subr */
+    12,        /* subi */
+    4, /* subcr */
+    12,        /* subci */
+    4, /* subxr */
+    8, /* subxi */
+    16,        /* rsbi */
+    4, /* mulr */
+    12,        /* muli */
+    12,        /* qmulr */
+    16,        /* qmuli */
+    12,        /* qmulr_u */
+    16,        /* qmuli_u */
+    4, /* divr */
+    12,        /* divi */
+    4, /* divr_u */
+    12,        /* divi_u */
+    20,        /* qdivr */
+    16,        /* qdivi */
+    20,        /* qdivr_u */
+    16,        /* qdivi_u */
+    12,        /* remr */
+    20,        /* remi */
+    12,        /* remr_u */
+    20,        /* remi_u */
+    4, /* andr */
+    12,        /* andi */
+    4, /* orr */
+    12,        /* ori */
+    4, /* xorr */
+    12,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    12,        /* ltr */
+    12,        /* lti */
+    12,        /* ltr_u */
+    16,        /* lti_u */
+    16,        /* ler */
+    16,        /* lei */
+    16,        /* ler_u */
+    16,        /* lei_u */
+    12,        /* eqr */
+    12,        /* eqi */
+    16,        /* ger */
+    16,        /* gei */
+    16,        /* ger_u */
+    16,        /* gei_u */
+    12,        /* gtr */
+    12,        /* gti */
+    12,        /* gtr_u */
+    12,        /* gti_u */
+    16,        /* ner */
+    16,        /* nei */
+    4, /* movr */
+    8, /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    4, /* htonr_us */
+    4, /* htonr_ui */
+    0, /* htonr_ul */
+    8, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    8, /* ldi_uc */
+    4, /* ldr_s */
+    8, /* ldi_s */
+    4, /* ldr_us */
+    8, /* ldi_us */
+    4, /* ldr_i */
+    8, /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    8, /* ldxr_c */
+    16,        /* ldxi_c */
+    4, /* ldxr_uc */
+    12,        /* ldxi_uc */
+    4, /* ldxr_s */
+    12,        /* ldxi_s */
+    4, /* ldxr_us */
+    12,        /* ldxi_us */
+    4, /* ldxr_i */
+    12,        /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    4, /* str_c */
+    8, /* sti_c */
+    4, /* str_s */
+    8, /* sti_s */
+    4, /* str_i */
+    8, /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    4, /* stxr_c */
+    12,        /* stxi_c */
+    4, /* stxr_s */
+    12,        /* stxi_s */
+    4, /* stxr_i */
+    12,        /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    8, /* bltr */
+    8, /* blti */
+    8, /* bltr_u */
+    12,        /* blti_u */
+    8, /* bler */
+    8, /* blei */
+    8, /* bler_u */
+    12,        /* blei_u */
+    8, /* beqr */
+    16,        /* beqi */
+    8, /* bger */
+    8, /* bgei */
+    8, /* bger_u */
+    8, /* bgei_u */
+    8, /* bgtr */
+    8, /* bgti */
+    8, /* bgtr_u */
+    8, /* bgti_u */
+    8, /* bner */
+    16,        /* bnei */
+    12,        /* bmsr */
+    12,        /* bmsi */
+    12,        /* bmcr */
+    12,        /* bmci */
+    12,        /* boaddr */
+    16,        /* boaddi */
+    12,        /* boaddr_u */
+    12,        /* boaddi_u */
+    12,        /* bxaddr */
+    16,        /* bxaddi */
+    12,        /* bxaddr_u */
+    12,        /* bxaddi_u */
+    12,        /* bosubr */
+    16,        /* bosubi */
+    12,        /* bosubr_u */
+    16,        /* bosubi_u */
+    12,        /* bxsubr */
+    16,        /* bxsubi */
+    12,        /* bxsubr_u */
+    16,        /* bxsubi_u */
+    8, /* jmpr */
+    4, /* jmpi */
+    28,        /* callr */
+    40,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    124,       /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    16,        /* addi_f */
+    4, /* subr_f */
+    16,        /* subi_f */
+    16,        /* rsbi_f */
+    4, /* mulr_f */
+    16,        /* muli_f */
+    4, /* divr_f */
+    16,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    12,        /* ltr_f */
+    24,        /* lti_f */
+    16,        /* ler_f */
+    28,        /* lei_f */
+    12,        /* eqr_f */
+    24,        /* eqi_f */
+    16,        /* ger_f */
+    28,        /* gei_f */
+    12,        /* gtr_f */
+    24,        /* gti_f */
+    16,        /* ner_f */
+    28,        /* nei_f */
+    16,        /* unltr_f */
+    28,        /* unlti_f */
+    16,        /* unler_f */
+    28,        /* unlei_f */
+    16,        /* uneqr_f */
+    28,        /* uneqi_f */
+    16,        /* unger_f */
+    28,        /* ungei_f */
+    16,        /* ungtr_f */
+    28,        /* ungti_f */
+    16,        /* ltgtr_f */
+    28,        /* ltgti_f */
+    16,        /* ordr_f */
+    28,        /* ordi_f */
+    12,        /* unordr_f */
+    24,        /* unordi_f */
+    12,        /* truncr_f_i */
+    0, /* truncr_f_l */
+    20,        /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    12,        /* movi_f */
+    4, /* ldr_f */
+    8, /* ldi_f */
+    4, /* ldxr_f */
+    12,        /* ldxi_f */
+    4, /* str_f */
+    8, /* sti_f */
+    4, /* stxr_f */
+    12,        /* stxi_f */
+    8, /* bltr_f */
+    20,        /* blti_f */
+    12,        /* bler_f */
+    24,        /* blei_f */
+    8, /* beqr_f */
+    20,        /* beqi_f */
+    12,        /* bger_f */
+    24,        /* bgei_f */
+    8, /* bgtr_f */
+    20,        /* bgti_f */
+    8, /* bner_f */
+    20,        /* bnei_f */
+    12,        /* bunltr_f */
+    24,        /* bunlti_f */
+    8, /* bunler_f */
+    20,        /* bunlei_f */
+    12,        /* buneqr_f */
+    24,        /* buneqi_f */
+    8, /* bunger_f */
+    20,        /* bungei_f */
+    12,        /* bungtr_f */
+    24,        /* bungti_f */
+    12,        /* bltgtr_f */
+    24,        /* bltgti_f */
+    8, /* bordr_f */
+    20,        /* bordi_f */
+    8, /* bunordr_f */
+    20,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    24,        /* addi_d */
+    4, /* subr_d */
+    24,        /* subi_d */
+    24,        /* rsbi_d */
+    4, /* mulr_d */
+    24,        /* muli_d */
+    4, /* divr_d */
+    24,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    12,        /* ltr_d */
+    32,        /* lti_d */
+    16,        /* ler_d */
+    36,        /* lei_d */
+    12,        /* eqr_d */
+    32,        /* eqi_d */
+    16,        /* ger_d */
+    36,        /* gei_d */
+    12,        /* gtr_d */
+    32,        /* gti_d */
+    16,        /* ner_d */
+    36,        /* nei_d */
+    16,        /* unltr_d */
+    36,        /* unlti_d */
+    16,        /* unler_d */
+    36,        /* unlei_d */
+    16,        /* uneqr_d */
+    36,        /* uneqi_d */
+    16,        /* unger_d */
+    36,        /* ungei_d */
+    16,        /* ungtr_d */
+    36,        /* ungti_d */
+    16,        /* ltgtr_d */
+    36,        /* ltgti_d */
+    16,        /* ordr_d */
+    36,        /* ordi_d */
+    12,        /* unordr_d */
+    32,        /* unordi_d */
+    12,        /* truncr_d_i */
+    0, /* truncr_d_l */
+    20,        /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    24,        /* movi_d */
+    4, /* ldr_d */
+    8, /* ldi_d */
+    4, /* ldxr_d */
+    12,        /* ldxi_d */
+    4, /* str_d */
+    8, /* sti_d */
+    4, /* stxr_d */
+    12,        /* stxi_d */
+    8, /* bltr_d */
+    28,        /* blti_d */
+    12,        /* bler_d */
+    32,        /* blei_d */
+    8, /* beqr_d */
+    32,        /* beqi_d */
+    12,        /* bger_d */
+    32,        /* bgei_d */
+    8, /* bgtr_d */
+    28,        /* bgti_d */
+    8, /* bner_d */
+    28,        /* bnei_d */
+    12,        /* bunltr_d */
+    32,        /* bunlti_d */
+    8, /* bunler_d */
+    28,        /* bunlei_d */
+    12,        /* buneqr_d */
+    32,        /* buneqi_d */
+    8, /* bunger_d */
+    28,        /* bungei_d */
+    12,        /* bungtr_d */
+    32,        /* bungti_d */
+    12,        /* bltgtr_d */
+    32,        /* bltgti_d */
+    8, /* bordr_d */
+    28,        /* bordi_d */
+    8, /* bunordr_d */
+    28,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* _CALL_AIX */
+#endif /* __BYTEORDER */
+#endif /* __powerpc__ */
+#endif /* __WORDSIZE */
+
+#if __WORDSIZE == 64
+#if defined(__powerpc__)
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define JIT_INSTR_MAX 148
+    0, /* data */
+    0, /* live */
+    4, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    148,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    4, /* va_start */
+    8, /* va_arg */
+    8, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    28,        /* addi */
+    4, /* addcr */
+    28,        /* addci */
+    4, /* addxr */
+    8, /* addxi */
+    4, /* subr */
+    28,        /* subi */
+    4, /* subcr */
+    28,        /* subci */
+    4, /* subxr */
+    8, /* subxi */
+    44,        /* rsbi */
+    4, /* mulr */
+    28,        /* muli */
+    12,        /* qmulr */
+    28,        /* qmuli */
+    12,        /* qmulr_u */
+    28,        /* qmuli_u */
+    4, /* divr */
+    28,        /* divi */
+    4, /* divr_u */
+    28,        /* divi_u */
+    20,        /* qdivr */
+    16,        /* qdivi */
+    20,        /* qdivr_u */
+    16,        /* qdivi_u */
+    12,        /* remr */
+    36,        /* remi */
+    12,        /* remr_u */
+    36,        /* remi_u */
+    4, /* andr */
+    28,        /* andi */
+    4, /* orr */
+    28,        /* ori */
+    4, /* xorr */
+    28,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    12,        /* ltr */
+    12,        /* lti */
+    12,        /* ltr_u */
+    16,        /* lti_u */
+    16,        /* ler */
+    16,        /* lei */
+    16,        /* ler_u */
+    16,        /* lei_u */
+    12,        /* eqr */
+    12,        /* eqi */
+    16,        /* ger */
+    16,        /* gei */
+    16,        /* ger_u */
+    16,        /* gei_u */
+    12,        /* gtr */
+    12,        /* gti */
+    12,        /* gtr_u */
+    12,        /* gti_u */
+    16,        /* ner */
+    16,        /* nei */
+    4, /* movr */
+    36,        /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    4, /* extr_i */
+    4, /* extr_ui */
+    4, /* htonr_us */
+    4, /* htonr_ui */
+    4, /* htonr_ul */
+    8, /* ldr_c */
+    28,        /* ldi_c */
+    4, /* ldr_uc */
+    24,        /* ldi_uc */
+    4, /* ldr_s */
+    24,        /* ldi_s */
+    4, /* ldr_us */
+    24,        /* ldi_us */
+    4, /* ldr_i */
+    24,        /* ldi_i */
+    4, /* ldr_ui */
+    24,        /* ldi_ui */
+    4, /* ldr_l */
+    24,        /* ldi_l */
+    8, /* ldxr_c */
+    16,        /* ldxi_c */
+    4, /* ldxr_uc */
+    12,        /* ldxi_uc */
+    4, /* ldxr_s */
+    12,        /* ldxi_s */
+    4, /* ldxr_us */
+    12,        /* ldxi_us */
+    4, /* ldxr_i */
+    12,        /* ldxi_i */
+    4, /* ldxr_ui */
+    12,        /* ldxi_ui */
+    4, /* ldxr_l */
+    12,        /* ldxi_l */
+    4, /* str_c */
+    24,        /* sti_c */
+    4, /* str_s */
+    24,        /* sti_s */
+    4, /* str_i */
+    24,        /* sti_i */
+    4, /* str_l */
+    24,        /* sti_l */
+    4, /* stxr_c */
+    12,        /* stxi_c */
+    4, /* stxr_s */
+    12,        /* stxi_s */
+    4, /* stxr_i */
+    12,        /* stxi_i */
+    4, /* stxr_l */
+    12,        /* stxi_l */
+    8, /* bltr */
+    8, /* blti */
+    8, /* bltr_u */
+    12,        /* blti_u */
+    8, /* bler */
+    8, /* blei */
+    8, /* bler_u */
+    12,        /* blei_u */
+    8, /* beqr */
+    44,        /* beqi */
+    8, /* bger */
+    8, /* bgei */
+    8, /* bger_u */
+    8, /* bgei_u */
+    8, /* bgtr */
+    8, /* bgti */
+    8, /* bgtr_u */
+    8, /* bgti_u */
+    8, /* bner */
+    36,        /* bnei */
+    12,        /* bmsr */
+    12,        /* bmsi */
+    12,        /* bmcr */
+    12,        /* bmci */
+    12,        /* boaddr */
+    16,        /* boaddi */
+    12,        /* boaddr_u */
+    12,        /* boaddi_u */
+    12,        /* bxaddr */
+    16,        /* bxaddi */
+    12,        /* bxaddr_u */
+    12,        /* bxaddi_u */
+    12,        /* bosubr */
+    16,        /* bosubi */
+    12,        /* bosubr_u */
+    16,        /* bosubi_u */
+    12,        /* bxsubr */
+    16,        /* bxsubi */
+    12,        /* bxsubr_u */
+    16,        /* bxsubi_u */
+    8, /* jmpr */
+    4, /* jmpi */
+    28,        /* callr */
+    56,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    124,       /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    28,        /* addi_f */
+    4, /* subr_f */
+    28,        /* subi_f */
+    28,        /* rsbi_f */
+    4, /* mulr_f */
+    28,        /* muli_f */
+    4, /* divr_f */
+    28,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    12,        /* ltr_f */
+    36,        /* lti_f */
+    16,        /* ler_f */
+    40,        /* lei_f */
+    12,        /* eqr_f */
+    36,        /* eqi_f */
+    16,        /* ger_f */
+    40,        /* gei_f */
+    12,        /* gtr_f */
+    36,        /* gti_f */
+    16,        /* ner_f */
+    40,        /* nei_f */
+    16,        /* unltr_f */
+    40,        /* unlti_f */
+    16,        /* unler_f */
+    40,        /* unlei_f */
+    16,        /* uneqr_f */
+    40,        /* uneqi_f */
+    16,        /* unger_f */
+    40,        /* ungei_f */
+    16,        /* ungtr_f */
+    40,        /* ungti_f */
+    16,        /* ltgtr_f */
+    40,        /* ltgti_f */
+    16,        /* ordr_f */
+    40,        /* ordi_f */
+    12,        /* unordr_f */
+    36,        /* unordi_f */
+    12,        /* truncr_f_i */
+    12,        /* truncr_f_l */
+    12,        /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    24,        /* movi_f */
+    4, /* ldr_f */
+    24,        /* ldi_f */
+    4, /* ldxr_f */
+    12,        /* ldxi_f */
+    4, /* str_f */
+    24,        /* sti_f */
+    4, /* stxr_f */
+    12,        /* stxi_f */
+    8, /* bltr_f */
+    32,        /* blti_f */
+    12,        /* bler_f */
+    36,        /* blei_f */
+    8, /* beqr_f */
+    32,        /* beqi_f */
+    12,        /* bger_f */
+    36,        /* bgei_f */
+    8, /* bgtr_f */
+    32,        /* bgti_f */
+    8, /* bner_f */
+    32,        /* bnei_f */
+    12,        /* bunltr_f */
+    36,        /* bunlti_f */
+    8, /* bunler_f */
+    32,        /* bunlei_f */
+    12,        /* buneqr_f */
+    36,        /* buneqi_f */
+    8, /* bunger_f */
+    32,        /* bungei_f */
+    12,        /* bungtr_f */
+    36,        /* bungti_f */
+    12,        /* bltgtr_f */
+    36,        /* bltgti_f */
+    8, /* bordr_f */
+    32,        /* bordi_f */
+    8, /* bunordr_f */
+    32,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    28,        /* addi_d */
+    4, /* subr_d */
+    28,        /* subi_d */
+    32,        /* rsbi_d */
+    4, /* mulr_d */
+    28,        /* muli_d */
+    4, /* divr_d */
+    28,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    12,        /* ltr_d */
+    40,        /* lti_d */
+    16,        /* ler_d */
+    44,        /* lei_d */
+    12,        /* eqr_d */
+    40,        /* eqi_d */
+    16,        /* ger_d */
+    44,        /* gei_d */
+    12,        /* gtr_d */
+    40,        /* gti_d */
+    16,        /* ner_d */
+    44,        /* nei_d */
+    16,        /* unltr_d */
+    44,        /* unlti_d */
+    16,        /* unler_d */
+    44,        /* unlei_d */
+    16,        /* uneqr_d */
+    44,        /* uneqi_d */
+    16,        /* unger_d */
+    44,        /* ungei_d */
+    16,        /* ungtr_d */
+    44,        /* ungti_d */
+    16,        /* ltgtr_d */
+    44,        /* ltgti_d */
+    16,        /* ordr_d */
+    44,        /* ordi_d */
+    12,        /* unordr_d */
+    40,        /* unordi_d */
+    12,        /* truncr_d_i */
+    12,        /* truncr_d_l */
+    12,        /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    32,        /* movi_d */
+    4, /* ldr_d */
+    24,        /* ldi_d */
+    4, /* ldxr_d */
+    12,        /* ldxi_d */
+    4, /* str_d */
+    24,        /* sti_d */
+    4, /* stxr_d */
+    12,        /* stxi_d */
+    8, /* bltr_d */
+    32,        /* blti_d */
+    12,        /* bler_d */
+    36,        /* blei_d */
+    8, /* beqr_d */
+    40,        /* beqi_d */
+    12,        /* bger_d */
+    40,        /* bgei_d */
+    8, /* bgtr_d */
+    36,        /* bgti_d */
+    8, /* bner_d */
+    36,        /* bnei_d */
+    12,        /* bunltr_d */
+    36,        /* bunlti_d */
+    8, /* bunler_d */
+    32,        /* bunlei_d */
+    12,        /* buneqr_d */
+    36,        /* buneqi_d */
+    8, /* bunger_d */
+    36,        /* bungei_d */
+    12,        /* bungtr_d */
+    40,        /* bungti_d */
+    12,        /* bltgtr_d */
+    40,        /* bltgti_d */
+    8, /* bordr_d */
+    36,        /* bordi_d */
+    8, /* bunordr_d */
+    32,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __BYTEORDER */
+#endif /* __powerpc__ */
+#endif /* __WORDSIZE */
+
+#if __WORDSIZE == 64
+#if defined(__powerpc__)
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define JIT_INSTR_MAX 124
+    0, /* data */
+    0, /* live */
+    4, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    124,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    4, /* va_start */
+    8, /* va_arg */
+    8, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    28,        /* addi */
+    4, /* addcr */
+    28,        /* addci */
+    4, /* addxr */
+    8, /* addxi */
+    4, /* subr */
+    28,        /* subi */
+    4, /* subcr */
+    28,        /* subci */
+    4, /* subxr */
+    8, /* subxi */
+    44,        /* rsbi */
+    4, /* mulr */
+    28,        /* muli */
+    12,        /* qmulr */
+    28,        /* qmuli */
+    12,        /* qmulr_u */
+    28,        /* qmuli_u */
+    4, /* divr */
+    28,        /* divi */
+    4, /* divr_u */
+    28,        /* divi_u */
+    20,        /* qdivr */
+    16,        /* qdivi */
+    20,        /* qdivr_u */
+    16,        /* qdivi_u */
+    12,        /* remr */
+    36,        /* remi */
+    12,        /* remr_u */
+    36,        /* remi_u */
+    4, /* andr */
+    28,        /* andi */
+    4, /* orr */
+    28,        /* ori */
+    4, /* xorr */
+    28,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    12,        /* ltr */
+    12,        /* lti */
+    12,        /* ltr_u */
+    16,        /* lti_u */
+    16,        /* ler */
+    16,        /* lei */
+    16,        /* ler_u */
+    16,        /* lei_u */
+    12,        /* eqr */
+    12,        /* eqi */
+    16,        /* ger */
+    16,        /* gei */
+    16,        /* ger_u */
+    16,        /* gei_u */
+    12,        /* gtr */
+    12,        /* gti */
+    12,        /* gtr_u */
+    12,        /* gti_u */
+    16,        /* ner */
+    16,        /* nei */
+    4, /* movr */
+    36,        /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    4, /* extr_i */
+    4, /* extr_ui */
+    20,        /* htonr_us */
+    16,        /* htonr_ui */
+    44,        /* htonr_ul */
+    8, /* ldr_c */
+    28,        /* ldi_c */
+    4, /* ldr_uc */
+    24,        /* ldi_uc */
+    4, /* ldr_s */
+    24,        /* ldi_s */
+    4, /* ldr_us */
+    24,        /* ldi_us */
+    4, /* ldr_i */
+    24,        /* ldi_i */
+    4, /* ldr_ui */
+    24,        /* ldi_ui */
+    4, /* ldr_l */
+    24,        /* ldi_l */
+    8, /* ldxr_c */
+    16,        /* ldxi_c */
+    4, /* ldxr_uc */
+    12,        /* ldxi_uc */
+    4, /* ldxr_s */
+    12,        /* ldxi_s */
+    4, /* ldxr_us */
+    12,        /* ldxi_us */
+    4, /* ldxr_i */
+    12,        /* ldxi_i */
+    4, /* ldxr_ui */
+    12,        /* ldxi_ui */
+    4, /* ldxr_l */
+    12,        /* ldxi_l */
+    4, /* str_c */
+    24,        /* sti_c */
+    4, /* str_s */
+    24,        /* sti_s */
+    4, /* str_i */
+    24,        /* sti_i */
+    4, /* str_l */
+    24,        /* sti_l */
+    4, /* stxr_c */
+    12,        /* stxi_c */
+    4, /* stxr_s */
+    12,        /* stxi_s */
+    4, /* stxr_i */
+    12,        /* stxi_i */
+    4, /* stxr_l */
+    12,        /* stxi_l */
+    8, /* bltr */
+    8, /* blti */
+    8, /* bltr_u */
+    12,        /* blti_u */
+    8, /* bler */
+    8, /* blei */
+    8, /* bler_u */
+    12,        /* blei_u */
+    8, /* beqr */
+    44,        /* beqi */
+    8, /* bger */
+    8, /* bgei */
+    8, /* bger_u */
+    8, /* bgei_u */
+    8, /* bgtr */
+    8, /* bgti */
+    8, /* bgtr_u */
+    8, /* bgti_u */
+    8, /* bner */
+    36,        /* bnei */
+    12,        /* bmsr */
+    12,        /* bmsi */
+    12,        /* bmcr */
+    12,        /* bmci */
+    12,        /* boaddr */
+    16,        /* boaddi */
+    12,        /* boaddr_u */
+    12,        /* boaddi_u */
+    12,        /* bxaddr */
+    16,        /* bxaddi */
+    12,        /* bxaddr_u */
+    12,        /* bxaddi_u */
+    12,        /* bosubr */
+    16,        /* bosubi */
+    12,        /* bosubr_u */
+    16,        /* bosubi_u */
+    12,        /* bxsubr */
+    16,        /* bxsubi */
+    12,        /* bxsubr_u */
+    16,        /* bxsubi_u */
+    8, /* jmpr */
+    4, /* jmpi */
+    12,        /* callr */
+    36,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    124,       /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    28,        /* addi_f */
+    4, /* subr_f */
+    28,        /* subi_f */
+    28,        /* rsbi_f */
+    4, /* mulr_f */
+    28,        /* muli_f */
+    4, /* divr_f */
+    28,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    12,        /* ltr_f */
+    36,        /* lti_f */
+    16,        /* ler_f */
+    40,        /* lei_f */
+    12,        /* eqr_f */
+    36,        /* eqi_f */
+    16,        /* ger_f */
+    40,        /* gei_f */
+    12,        /* gtr_f */
+    36,        /* gti_f */
+    16,        /* ner_f */
+    40,        /* nei_f */
+    16,        /* unltr_f */
+    40,        /* unlti_f */
+    16,        /* unler_f */
+    40,        /* unlei_f */
+    16,        /* uneqr_f */
+    40,        /* uneqi_f */
+    16,        /* unger_f */
+    40,        /* ungei_f */
+    16,        /* ungtr_f */
+    40,        /* ungti_f */
+    16,        /* ltgtr_f */
+    40,        /* ltgti_f */
+    16,        /* ordr_f */
+    40,        /* ordi_f */
+    12,        /* unordr_f */
+    36,        /* unordi_f */
+    12,        /* truncr_f_i */
+    12,        /* truncr_f_l */
+    12,        /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    24,        /* movi_f */
+    4, /* ldr_f */
+    24,        /* ldi_f */
+    4, /* ldxr_f */
+    12,        /* ldxi_f */
+    4, /* str_f */
+    24,        /* sti_f */
+    4, /* stxr_f */
+    12,        /* stxi_f */
+    8, /* bltr_f */
+    32,        /* blti_f */
+    12,        /* bler_f */
+    36,        /* blei_f */
+    8, /* beqr_f */
+    32,        /* beqi_f */
+    12,        /* bger_f */
+    36,        /* bgei_f */
+    8, /* bgtr_f */
+    32,        /* bgti_f */
+    8, /* bner_f */
+    32,        /* bnei_f */
+    12,        /* bunltr_f */
+    36,        /* bunlti_f */
+    8, /* bunler_f */
+    32,        /* bunlei_f */
+    12,        /* buneqr_f */
+    36,        /* buneqi_f */
+    8, /* bunger_f */
+    32,        /* bungei_f */
+    12,        /* bungtr_f */
+    36,        /* bungti_f */
+    12,        /* bltgtr_f */
+    36,        /* bltgti_f */
+    8, /* bordr_f */
+    32,        /* bordi_f */
+    8, /* bunordr_f */
+    32,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    28,        /* addi_d */
+    4, /* subr_d */
+    28,        /* subi_d */
+    32,        /* rsbi_d */
+    4, /* mulr_d */
+    28,        /* muli_d */
+    4, /* divr_d */
+    28,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    12,        /* ltr_d */
+    40,        /* lti_d */
+    16,        /* ler_d */
+    44,        /* lei_d */
+    12,        /* eqr_d */
+    40,        /* eqi_d */
+    16,        /* ger_d */
+    44,        /* gei_d */
+    12,        /* gtr_d */
+    40,        /* gti_d */
+    16,        /* ner_d */
+    44,        /* nei_d */
+    16,        /* unltr_d */
+    44,        /* unlti_d */
+    16,        /* unler_d */
+    44,        /* unlei_d */
+    16,        /* uneqr_d */
+    44,        /* uneqi_d */
+    16,        /* unger_d */
+    44,        /* ungei_d */
+    16,        /* ungtr_d */
+    44,        /* ungti_d */
+    16,        /* ltgtr_d */
+    44,        /* ltgti_d */
+    16,        /* ordr_d */
+    44,        /* ordi_d */
+    12,        /* unordr_d */
+    40,        /* unordi_d */
+    12,        /* truncr_d_i */
+    12,        /* truncr_d_l */
+    12,        /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    32,        /* movi_d */
+    4, /* ldr_d */
+    24,        /* ldi_d */
+    4, /* ldxr_d */
+    12,        /* ldxi_d */
+    4, /* str_d */
+    24,        /* sti_d */
+    4, /* stxr_d */
+    12,        /* stxi_d */
+    8, /* bltr_d */
+    32,        /* blti_d */
+    12,        /* bler_d */
+    36,        /* blei_d */
+    8, /* beqr_d */
+    40,        /* beqi_d */
+    12,        /* bger_d */
+    40,        /* bgei_d */
+    8, /* bgtr_d */
+    36,        /* bgti_d */
+    8, /* bner_d */
+    36,        /* bnei_d */
+    12,        /* bunltr_d */
+    36,        /* bunlti_d */
+    8, /* bunler_d */
+    32,        /* bunlei_d */
+    12,        /* buneqr_d */
+    36,        /* buneqi_d */
+    8, /* bunger_d */
+    36,        /* bungei_d */
+    12,        /* bungtr_d */
+    40,        /* bungti_d */
+    12,        /* bltgtr_d */
+    40,        /* bltgti_d */
+    8, /* bordr_d */
+    36,        /* bordi_d */
+    8, /* bunordr_d */
+    32,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __BYTE_ORDER */
+#endif /* __powerpc__ */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_ppc.c b/deps/lightning/lib/jit_ppc.c
new file mode 100644 (file)
index 0000000..0826f4e
--- /dev/null
@@ -0,0 +1,1912 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#define jit_arg_reg_p(i)               ((i) >= 0 && (i) < 8)
+#if !_CALL_SYSV
+#  define jit_arg_f_reg_p(i)           ((i) >= 0 && (i) < 13)
+#else
+#  define jit_arg_f_reg_p(i)           ((i) >= 0 && (i) < 8)
+#  if __WORDSIZE == 32
+#    define va_gp_shift                        2
+#  else
+#    define va_gp_shift                        3
+#  endif
+#  define va_gp_increment              sizeof(jit_word_t)
+#  define first_gp_argument            r3
+#  define first_gp_offset              offsetof(jit_va_list_t,         \
+                                                first_gp_argument)
+#  define va_fp_increment              sizeof(jit_float64_t)
+#  define first_fp_argument            f1
+#  define first_fp_offset              offsetof(jit_va_list_t,         \
+                                                first_fp_argument)
+#endif
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define C_DISP                       0
+#  define S_DISP                       0
+#  define I_DISP                       0
+#  define F_DISP                       0
+#else
+#  define C_DISP                       (__WORDSIZE >> 3) - sizeof(jit_int8_t)
+#  define S_DISP                       (__WORDSIZE >> 3) - sizeof(jit_int16_t)
+#  define I_DISP                       (__WORDSIZE >> 3) - sizeof(jit_int32_t)
+#  define F_DISP                       (__WORDSIZE >> 3) - sizeof(jit_float32_t)
+#endif
+
+/*
+ * Types
+ */
+#if _CALL_SYSV
+typedef struct jit_va_list {
+    jit_uint8_t                ngpr;
+    jit_uint8_t                nfpr;
+    jit_uint16_t       _pad;
+#  if __WORDSIZE == 64
+    jit_uint32_t       _pad2;
+#  endif
+    jit_pointer_t      over;
+    jit_pointer_t      save;
+#  if __WORDSIZE == 32
+    jit_word_t         _pad2;
+#  endif
+    jit_word_t         r3;
+    jit_word_t         r4;
+    jit_word_t         r5;
+    jit_word_t         r6;
+    jit_word_t         r7;
+    jit_word_t         r8;
+    jit_word_t         r9;
+    jit_word_t         r10;
+    jit_float64_t      f1;
+    jit_float64_t      f2;
+    jit_float64_t      f3;
+    jit_float64_t      f4;
+    jit_float64_t      f5;
+    jit_float64_t      f6;
+    jit_float64_t      f7;
+    jit_float64_t      f8;
+} jit_va_list_t;
+#else
+typedef jit_pointer_t jit_va_list_t;
+#endif
+
+/*
+ * Prototypes
+ */
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+/* libgcc */
+extern void __clear_cache(void *, void *);
+
+#define PROTO                          1
+#  include "jit_ppc-cpu.c"
+#  include "jit_ppc-fpu.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_register_t         _rvs[] = {
+    { rc(sav) | 0,                     "r0" },
+    { rc(sav) | 11,                    "r11" },        /* env */
+    { rc(sav) | 12,                    "r12" },        /* exception */
+    { rc(sav) | 13,                    "r13" },        /* thread */
+    { rc(sav) | 2,                     "r2" },         /* toc */
+    { rc(sav) | rc(gpr) | 14,          "r14" },
+    { rc(sav) | rc(gpr) | 15,          "r15" },
+    { rc(sav) | rc(gpr) | 16,          "r16" },
+    { rc(sav) | rc(gpr) | 17,          "r17" },
+    { rc(sav) | rc(gpr) | 18,          "r18" },
+    { rc(sav) | rc(gpr) | 19,          "r19" },
+    { rc(sav) | rc(gpr) | 20,          "r20" },
+    { rc(sav) | rc(gpr) | 21,          "r21" },
+    { rc(sav) | rc(gpr) | 22,          "r22" },
+    { rc(sav) | rc(gpr) | 23,          "r23" },
+    { rc(sav) | rc(gpr) | 24,          "r24" },
+    { rc(sav) | rc(gpr) | 25,          "r25" },
+    { rc(sav) | rc(gpr) | 26,          "r26" },
+    { rc(sav) | rc(gpr) | 27,          "r27" },
+    { rc(sav) | rc(gpr) | 28,          "r28" },
+    { rc(sav) | rc(gpr) | 29,          "r29" },
+    { rc(sav) | rc(gpr) | 30,          "r30" },
+    { rc(sav) | 1,                     "r1" },
+    { rc(sav) | 31,                    "r31" },
+    { rc(arg) | rc(gpr) | 10,          "r10" },
+    { rc(arg) | rc(gpr) | 9,           "r9" },
+    { rc(arg) | rc(gpr) | 8,           "r8" },
+    { rc(arg) | rc(gpr) | 7,           "r7" },
+    { rc(arg) | rc(gpr) | 6,           "r6" },
+    { rc(arg) | rc(gpr) | 5,           "r5" },
+    { rc(arg) | rc(gpr) | 4,           "r4" },
+    { rc(arg) | rc(gpr) | 3,           "r3" },
+    { rc(fpr) | 0,                     "f0" },
+    { rc(sav) | rc(fpr) | 14,          "f14" },
+    { rc(sav) | rc(fpr) | 15,          "f15" },
+    { rc(sav) | rc(fpr) | 16,          "f16" },
+    { rc(sav) | rc(fpr) | 17,          "f17" },
+    { rc(sav) | rc(fpr) | 18,          "f18" },
+    { rc(sav) | rc(fpr) | 19,          "f19" },
+    { rc(sav) | rc(fpr) | 20,          "f20" },
+    { rc(sav) | rc(fpr) | 21,          "f21" },
+    { rc(sav) | rc(fpr) | 22,          "f22" },
+    { rc(sav) | rc(fpr) | 23,          "f23" },
+    { rc(sav) | rc(fpr) | 24,          "f24" },
+    { rc(sav) | rc(fpr) | 25,          "f25" },
+    { rc(sav) | rc(fpr) | 26,          "f26" },
+    { rc(sav) | rc(fpr) | 27,          "f27" },
+    { rc(sav) | rc(fpr) | 28,          "f28" },
+    { rc(sav) | rc(fpr) | 29,          "f29" },
+    { rc(sav) | rc(fpr) | 30,          "f30" },
+    { rc(sav) | rc(fpr) | 31,          "f31" },
+#if !_CALL_SYSV
+    { rc(arg) | rc(fpr) | 13,          "f13" },
+    { rc(arg) | rc(fpr) | 12,          "f12" },
+    { rc(arg) | rc(fpr) | 11,          "f11" },
+    { rc(arg) | rc(fpr) | 10,          "f10" },
+    { rc(arg) | rc(fpr) | 9,           "f9" },
+#else
+    { rc(fpr) | 13,                    "f13" },
+    { rc(fpr) | 12,                    "f12" },
+    { rc(fpr) | 11,                    "f11" },
+    { rc(fpr) | 10,                    "f10" },
+    { rc(fpr) | 9,                     "f9" },
+#endif
+    { rc(arg) | rc(fpr) | 8,           "f8" },
+    { rc(arg) | rc(fpr) | 7,           "f7" },
+    { rc(arg) | rc(fpr) | 6,           "f6" },
+    { rc(arg) | rc(fpr) | 5,           "f5" },
+    { rc(arg) | rc(fpr) | 4,           "f4" },
+    { rc(arg) | rc(fpr) | 3,           "f3" },
+    { rc(arg) | rc(fpr) | 2,           "f2" },
+    { rc(arg) | rc(fpr) | 1,           "f1" },
+    { _NOREG,                          "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    _jitc->reglen = jit_size(_rvs) - 1;
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                 offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = params_offset;
+    _jitc->function->self.argi = _jitc->function->self.argf =
+       _jitc->function->self.alen = 0;
+    /* float conversion */
+    _jitc->function->self.aoff = alloca_offset - 8;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    return (_jitc->function->self.aoff);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 r0, r1;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    r0 = jit_get_reg(jit_class_gpr);
+    r1 = jit_get_reg(jit_class_gpr);
+    jit_ldr(r0, JIT_SP);
+    jit_negr(r1, v);
+    jit_andi(r1, r1, -16);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, r1);
+    jit_addr(JIT_SP, JIT_SP, r1);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_str(JIT_SP, r0);
+    jit_unget_reg(r1);
+    jit_unget_reg(r0);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    if (JIT_RET != u)
+       jit_movr(JIT_RET, u);
+    jit_live(JIT_RET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    if (JIT_RET != u)
+       jit_movr_f(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    if (JIT_FRET != u)
+       jit_movr_d(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    if (u->code == jit_code_arg)
+       return (jit_arg_reg_p(u->u.w));
+    assert(u->code == jit_code_arg_f || u->code == jit_code_arg_d);
+    return (jit_arg_f_reg_p(u->u.w));
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare) {
+       jit_link_prepare();
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+    }
+    else {
+       jit_link_prolog();
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+#if _CALL_SYSV
+       /* Allocate va_list like object in the stack.
+        * If applicable, with enough space to save all argument
+        * registers, and use fixed offsets for them. */
+       _jitc->function->vaoff = jit_allocai(sizeof(jit_va_list_t));
+#endif
+       _jitc->function->vagp = _jitc->function->self.argi;
+       _jitc->function->vafp = _jitc->function->self.argf;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    jit_bool_t          incr = 1;
+    assert(_jitc->function);
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi++;
+#if _CALL_SYSV
+       incr = 0;
+#endif
+    }
+    else
+       offset = _jitc->function->self.size;
+    if (incr)
+       _jitc->function->self.size += sizeof(jit_word_t);
+    node = jit_new_node_ww(jit_code_arg, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    jit_bool_t          incr = 1;
+    assert(_jitc->function);
+    if (jit_arg_f_reg_p(_jitc->function->self.argf)) {
+       offset = _jitc->function->self.argf++;
+#if _CALL_SYSV
+       incr = 0;
+#endif
+    }
+    else
+       offset = _jitc->function->self.size + F_DISP;
+#if !_CALL_SYSV
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+#  if __WORDSIZE == 32
+       _jitc->function->self.argi += 2;
+#  else
+       _jitc->function->self.argi++;
+#  endif
+    }
+#endif
+    if (incr)
+       _jitc->function->self.size += sizeof(jit_word_t);
+    node = jit_new_node_ww(jit_code_arg_f, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    jit_bool_t          incr = 1;
+    assert(_jitc->function);
+    if (jit_arg_f_reg_p(_jitc->function->self.argf)) {
+       offset = _jitc->function->self.argf++;
+#if _CALL_SYSV
+       incr = 0;
+#endif
+    }
+    else {
+#if _CALL_SYSV
+       if (_jitc->function->self.size & 7)
+           _jitc->function->self.size += 4;
+#endif
+       offset = _jitc->function->self.size;
+    }
+#if !_CALL_SYSV
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+#  if __WORDSIZE == 32
+       _jitc->function->self.argi += 2;
+#  else
+       _jitc->function->self.argi++;
+#  endif
+    }
+#endif
+    if (incr)
+       _jitc->function->self.size += sizeof(jit_float64_t);
+    node = jit_new_node_ww(jit_code_arg_d, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_c(u, JIT_FP, v->u.w + C_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_uc(u, JIT_FP, v->u.w + C_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_s(u, JIT_FP, v->u.w + S_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_us(u, JIT_FP, v->u.w + S_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w)) {
+#if __WORDSIZE == 32
+       jit_movr(u, JIT_RA0 - v->u.w);
+#else
+       jit_extr_i(u, JIT_RA0 - v->u.w);
+#endif
+    }
+    else
+       jit_ldxi_i(u, JIT_FP, v->u.w + I_DISP);
+    jit_dec_synth();
+}
+
+#if __WORDSIZE == 64
+void
+_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_ui, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_ui(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_ui(u, JIT_FP, v->u.w + I_DISP);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_l, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_l(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+#endif
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(JIT_RA0 - v->u.w, u);
+    else
+       jit_stxi(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    jit_inc_synth_wp(putargi, u, v);
+    assert(v->code == jit_code_arg);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi(JIT_RA0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(u, JIT_FA0 - v->u.w);
+    else
+       jit_ldxi_f(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(JIT_FA0 - v->u.w, u);
+    else
+       jit_stxi_f(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movi_d(JIT_FA0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_f(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(u, JIT_FA0 - v->u.w);
+    else
+       jit_ldxi_d(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(JIT_FA0 - v->u.w, u);
+    else
+       jit_stxi_d(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movi_d(JIT_FA0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_bool_t         incr = 1;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+#if _CALL_SYSV
+       incr = 0;
+#endif
+    }
+    else
+       jit_stxi(_jitc->function->call.size + params_offset, JIT_SP, u);
+    if (incr)
+       _jitc->function->call.size += sizeof(jit_word_t);
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                 regno;
+    jit_bool_t          incr = 1;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+#if _CALL_SYSV
+       incr = 0;
+#endif
+    }
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size + params_offset, JIT_SP, regno);
+       jit_unget_reg(regno);
+    }
+    if (incr)
+       _jitc->function->call.size += sizeof(jit_word_t);
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_bool_t         incr = 1;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)
+#if !_CALL_SYSV
+       && !(_jitc->function->call.call & jit_call_varargs)
+#endif
+       ) {
+       jit_movr_d(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+#if !_CALL_SYSV
+       /* in case of excess arguments */
+       if (jit_arg_reg_p(_jitc->function->call.argi)) {
+#  if __WORDSIZE == 32
+           _jitc->function->call.argi += 2;
+           if (!jit_arg_reg_p(_jitc->function->call.argi - 1))
+               --_jitc->function->call.argi;
+#  else
+           _jitc->function->call.argi++;
+#  endif
+       }
+#elif _CALL_SYSV
+       incr = 0;
+#endif
+    }
+#if !_CALL_SYSV
+    else if (jit_arg_reg_p(_jitc->function->call.argi
+#  if __WORDSIZE == 32
+                         + 1
+#  endif
+                          )) {
+       /* use reserved 8 bytes area */
+       jit_stxi_d(alloca_offset - 8, JIT_FP, u);
+       jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_FP,
+                alloca_offset - 8);
+       _jitc->function->call.argi++;
+#  if __WORDSIZE == 32
+       jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_FP,
+                alloca_offset - 4);
+       _jitc->function->call.argi++;
+#  endif
+    }
+#endif
+    else
+       jit_stxi_f(_jitc->function->call.size + params_offset + F_DISP,
+                  JIT_SP, u);
+    if (incr)
+       _jitc->function->call.size += sizeof(jit_word_t);
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_bool_t          incr = 1;
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)
+#if !_CALL_SYSV
+       && !(_jitc->function->call.call & jit_call_varargs)
+#endif
+       ) {
+       jit_movi_d(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+#if !_CALL_SYSV
+           /* in case of excess arguments */
+#  if __WORDSIZE == 32
+       _jitc->function->call.argi += 2;
+       if (!jit_arg_reg_p(_jitc->function->call.argi - 1))
+           --_jitc->function->call.argi;
+#  else
+       _jitc->function->call.argi++;
+#  endif
+#elif _CALL_SYSV
+       incr = 0;
+#endif
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+#if !_CALL_SYSV
+       if (jit_arg_reg_p(_jitc->function->call.argi
+#  if __WORDSIZE == 32
+                         + 1
+#  endif
+                         )) {
+           /* use reserved 8 bytes area */
+           jit_stxi_d(alloca_offset - 8, JIT_FP, regno);
+           jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_FP,
+                    alloca_offset - 8);
+           _jitc->function->call.argi++;
+#  if __WORDSIZE == 32
+           jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_FP,
+                    alloca_offset - 4);
+           _jitc->function->call.argi++;
+#  endif
+       }
+       else
+#endif
+           jit_stxi_f(_jitc->function->call.size + params_offset + F_DISP,
+                      JIT_SP, regno);
+       jit_unget_reg(regno);
+    }
+    if (incr)
+       _jitc->function->call.size += sizeof(jit_word_t);
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_bool_t         incr = 1;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)
+#if !_CALL_SYSV
+       && !(_jitc->function->call.call & jit_call_varargs)
+#endif
+       ) {
+       jit_movr_d(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+#if !_CALL_SYSV
+           /* in case of excess arguments */
+#  if __WORDSIZE == 32
+       _jitc->function->call.argi += 2;
+       if (!jit_arg_reg_p(_jitc->function->call.argi - 1))
+           --_jitc->function->call.argi;
+#  else
+       _jitc->function->call.argi++;
+#  endif
+#else /* _CALL_SYSV */
+       incr = 0;
+#endif
+    }
+#if !_CALL_SYSV
+    else if (jit_arg_reg_p(_jitc->function->call.argi
+#  if __WORDSIZE == 32
+                         + 1
+#  endif
+                          )) {
+       /* use reserved 8 bytes area */
+       jit_stxi_d(alloca_offset - 8, JIT_FP, u);
+       jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_FP,
+                alloca_offset - 8);
+       _jitc->function->call.argi++;
+#  if __WORDSIZE == 32
+       jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_FP,
+                alloca_offset - 4);
+       _jitc->function->call.argi++;
+#  endif
+    }
+    else
+#endif /* !_CALL_SYSV */
+    {
+#if _CALL_SYSV
+       if (_jitc->function->call.size & 7)
+           _jitc->function->call.size += 4;
+#endif
+       jit_stxi_d(_jitc->function->call.size + params_offset, JIT_SP, u);
+#if !_CALL_SYSV && __WORDSIZE == 32
+       if (jit_arg_reg_p(_jitc->function->call.argi)) {
+           jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_SP,
+                    _jitc->function->call.size + params_offset);
+           _jitc->function->call.argi++;
+       }
+#endif
+    }
+    if (incr)
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                 regno;
+    jit_bool_t          incr = 1;
+    assert(_jitc->function);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)
+#if !_CALL_SYSV
+       && !(_jitc->function->call.call & jit_call_varargs)
+#endif
+       ) {
+       jit_movi_d(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+#if !_CALL_SYSV
+       /* in case of excess arguments */
+       if (jit_arg_reg_p(_jitc->function->call.argi)) {
+#  if __WORDSIZE == 32
+           _jitc->function->call.argi += 2;
+           if (!jit_arg_reg_p(_jitc->function->call.argi - 1))
+               --_jitc->function->call.argi;
+#  else
+           _jitc->function->call.argi++;
+#  endif
+       }
+#else /* _CALL_SYSV */
+           incr = 0;
+#endif
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+#if !_CALL_SYSV
+       if (jit_arg_reg_p(_jitc->function->call.argi
+#  if __WORDSIZE == 32
+                         + 1
+#  endif
+                         )) {
+           /* use reserved 8 bytes area */
+           jit_stxi_d(alloca_offset - 8, JIT_FP, regno);
+           jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_FP,
+                    alloca_offset - 8);
+           _jitc->function->call.argi++;
+#  if __WORDSIZE == 32
+           jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_FP,
+                    alloca_offset - 4);
+           _jitc->function->call.argi++;
+#  endif
+       }
+       else
+#endif /* !_CALL_SYSV */
+       {
+#if _CALL_SYSV
+           if (_jitc->function->call.size & 7)
+               _jitc->function->call.size += 4;
+#endif
+           jit_stxi_d(_jitc->function->call.size + params_offset,
+                      JIT_SP, regno);
+#if !_CALL_SYSV && __WORDSIZE == 32
+           if (jit_arg_reg_p(_jitc->function->call.argi)) {
+               jit_ldxi(JIT_RA0 - _jitc->function->call.argi, JIT_SP,
+                        _jitc->function->call.size + params_offset);
+               _jitc->function->call.argi++;
+           }
+#endif
+       }
+       jit_unget_reg(regno);
+    }
+    if (incr)
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_int32_t                spec;
+    spec = jit_class(_rvs[regno].spec);
+    if (spec & jit_class_arg) {
+       if (spec & jit_class_gpr) {
+           regno = JIT_RA0 - regno;
+           if (regno >= 0 && regno < node->v.w)
+               return (1);
+       }
+       else if (spec & jit_class_fpr) {
+           regno = JIT_FA0 - regno;
+           if (regno >= 0 && regno < node->w.w)
+               return (1);
+       }
+    }
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *call;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    call = jit_callr(r0);
+    call->v.w = _jitc->function->call.argi;
+    call->w.w = _jitc->function->call.argf;
+#if _CALL_SYSV
+    /* If passing float arguments in registers */
+    if ((_jitc->function->call.call & jit_call_varargs) && call->w.w)
+       call->flag |= jit_flag_varargs;
+#endif
+    _jitc->function->call.argi = _jitc->function->call.argf = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_calli(i0);
+    node->v.w = _jitc->function->call.argi;
+    node->w.w = _jitc->function->call.argf;
+#if _CALL_SYSV
+    if ((_jitc->function->call.call & jit_call_varargs) && node->w.w)
+       node->flag |= jit_flag_varargs;
+#endif
+    _jitc->function->call.argi = _jitc->function->call.argf = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth(retval_c);
+    jit_extr_c(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth(retval_uc);
+    jit_extr_uc(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth(retval_s);
+    jit_extr_s(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth(retval_us);
+    jit_extr_us(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth(retval_i);
+#if __WORDSIZE == 32
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+#else
+    jit_extr_i(r0, JIT_RET);
+#endif
+    jit_dec_synth();
+}
+
+#if __WORDSIZE == 64
+void
+_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth(retval_ui);
+    jit_extr_ui(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth(retval_l);
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+    jit_dec_synth();
+}
+#endif
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth(retval_f);
+    jit_retval_d(r0);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth(retval_d);
+    if (r0 != JIT_FRET)
+       jit_movr_d(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_int32_t                 value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_word_t       patch_offset;
+#if _CALL_AIXDESC
+       jit_word_t       prolog_offset;
+#endif
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.patch_offset = 0;
+
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+#if _CALL_AIXDESC
+    undo.prolog_offset = 0;
+    for (node = _jitc->head; node; node = node->next)
+       if (node->code != jit_code_label &&
+           node->code != jit_code_note &&
+           node->code != jit_code_name)
+           break;
+    if (node && (node->code != jit_code_prolog ||
+                !(_jitc->functions.ptr + node->w.w)->assume_frame)) {
+       /* code may start with a jump so add an initial function descriptor */
+       word = _jit->pc.w + sizeof(void*) * 3;
+       iw(word);                       /* addr */
+       iw(0);                          /* toc */
+       iw(0);                          /* env */
+    }
+#endif
+
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_rrf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               assert(node->flag & jit_flag_data);                     \
+               name##i##type(rn(node->u.w), rn(node->v.w),             \
+                             (jit_float##size##_t *)node->w.n->u.w);   \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w, rn(node->v.w),             \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w, rn(node->v.w),     \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if (node->u.w == sizeof(jit_word_t) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+#  if __WORDSIZE == 64
+               case_rr(ext, _i);
+               case_rr(ext, _ui);
+#  endif
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+#  if __WORDSIZE == 64
+               case_rr(hton, _ul);
+#  endif
+               case_rr(neg,);
+               case_rr(com,);
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), node->v.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rr(trunc, _f_i);
+               case_rr(trunc, _d_i);
+#  if __WORDSIZE == 64
+               case_rr(trunc, _f_l);
+               case_rr(trunc, _d_l);
+#  endif
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+#if __WORDSIZE == 64
+               case_rr(ld, _ui);
+               case_rw(ld, _ui);
+               case_rrr(ldx, _ui);
+               case_rrw(ldx, _ui);
+               case_rr(ld, _l);
+               case_rw(ld, _l);
+               case_rrr(ldx, _l);
+               case_rrw(ldx, _l);
+#endif
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+#if __WORDSIZE == 64
+               case_rr(st, _l);
+               case_wr(st, _l);
+               case_rrr(stx, _l);
+               case_wrr(stx, _l);
+#endif
+               case_rr(mov, _f);
+           case jit_code_movi_f:
+               assert(node->flag & jit_flag_data);
+               movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _f);
+               case_rr(ext, _d_f);
+               case_rr(abs, _f);
+               case_rr(neg, _f);
+               case_rr(sqrt, _f);
+               case_rrr(add, _f);
+               case_rrf(add, _f, 32);
+               case_rrr(sub, _f);
+               case_rrf(sub, _f, 32);
+               case_rrf(rsb, _f, 32);
+               case_rrr(mul, _f);
+               case_rrf(mul, _f, 32);
+               case_rrr(div, _f);
+               case_rrf(div, _f, 32);
+               case_rrr(lt, _f);
+               case_rrf(lt, _f, 32);
+               case_rrr(le, _f);
+               case_rrf(le, _f, 32);
+               case_rrr(eq, _f);
+               case_rrf(eq, _f, 32);
+               case_rrr(ge, _f);
+               case_rrf(ge, _f, 32);
+               case_rrr(gt, _f);
+               case_rrf(gt, _f, 32);
+               case_rrr(ne, _f);
+               case_rrf(ne, _f, 32);
+               case_rrr(unlt, _f);
+               case_rrf(unlt, _f, 32);
+               case_rrr(unle, _f);
+               case_rrf(unle, _f, 32);
+               case_rrr(uneq, _f);
+               case_rrf(uneq, _f, 32);
+               case_rrr(unge, _f);
+               case_rrf(unge, _f, 32);
+               case_rrr(ungt, _f);
+               case_rrf(ungt, _f, 32);
+               case_rrr(ltgt, _f);
+               case_rrf(ltgt, _f, 32);
+               case_rrr(ord, _f);
+               case_rrf(ord, _f, 32);
+               case_rrr(unord, _f);
+               case_rrf(unord, _f, 32);
+               case_brr(blt, _f);
+               case_brf(blt, _f, 32);
+               case_brr(ble, _f);
+               case_brf(ble, _f, 32);
+               case_brr(beq, _f);
+               case_brf(beq, _f, 32);
+               case_brr(bge, _f);
+               case_brf(bge, _f, 32);
+               case_brr(bgt, _f);
+               case_brf(bgt, _f, 32);
+               case_brr(bne, _f);
+               case_brf(bne, _f, 32);
+               case_brr(bunlt, _f);
+               case_brf(bunlt, _f, 32);
+               case_brr(bunle, _f);
+               case_brf(bunle, _f, 32);
+               case_brr(buneq, _f);
+               case_brf(buneq, _f, 32);
+               case_brr(bunge, _f);
+               case_brf(bunge, _f, 32);
+               case_brr(bungt, _f);
+               case_brf(bungt, _f, 32);
+               case_brr(bltgt, _f);
+               case_brf(bltgt, _f, 32);
+               case_brr(bord, _f);
+               case_brf(bord, _f, 32);
+               case_brr(bunord, _f);
+               case_brf(bunord, _f, 32);
+               case_rr(ld, _f);
+               case_rw(ld, _f);
+               case_rrr(ldx, _f);
+               case_rrw(ldx, _f);
+               case_rr(st, _f);
+               case_wr(st, _f);
+               case_rrr(stx, _f);
+               case_wrr(stx, _f);
+               case_rr(mov, _d);
+           case jit_code_movi_d:
+               assert(node->flag & jit_flag_data);
+               movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _d);
+               case_rr(ext, _f_d);
+               case_rr(abs, _d);
+               case_rr(neg, _d);
+               case_rr(sqrt, _d);
+               case_rrr(add, _d);
+               case_rrf(add, _d, 64);
+               case_rrr(sub, _d);
+               case_rrf(sub, _d, 64);
+               case_rrf(rsb, _d, 64);
+               case_rrr(mul, _d);
+               case_rrf(mul, _d, 64);
+               case_rrr(div, _d);
+               case_rrf(div, _d, 64);
+               case_rrr(lt, _d);
+               case_rrf(lt, _d, 64);
+               case_rrr(le, _d);
+               case_rrf(le, _d, 64);
+               case_rrr(eq, _d);
+               case_rrf(eq, _d, 64);
+               case_rrr(ge, _d);
+               case_rrf(ge, _d, 64);
+               case_rrr(gt, _d);
+               case_rrf(gt, _d, 64);
+               case_rrr(ne, _d);
+               case_rrf(ne, _d, 64);
+               case_rrr(unlt, _d);
+               case_rrf(unlt, _d, 64);
+               case_rrr(unle, _d);
+               case_rrf(unle, _d, 64);
+               case_rrr(uneq, _d);
+               case_rrf(uneq, _d, 64);
+               case_rrr(unge, _d);
+               case_rrf(unge, _d, 64);
+               case_rrr(ungt, _d);
+               case_rrf(ungt, _d, 64);
+               case_rrr(ltgt, _d);
+               case_rrf(ltgt, _d, 64);
+               case_rrr(ord, _d);
+               case_rrf(ord, _d, 64);
+               case_rrr(unord, _d);
+               case_rrf(unord, _d, 64);
+               case_brr(blt, _d);
+               case_brf(blt, _d, 64);
+               case_brr(ble, _d);
+               case_brf(ble, _d, 64);
+               case_brr(beq, _d);
+               case_brf(beq, _d, 64);
+               case_brr(bge, _d);
+               case_brf(bge, _d, 64);
+               case_brr(bgt, _d);
+               case_brf(bgt, _d, 64);
+               case_brr(bne, _d);
+               case_brf(bne, _d, 64);
+               case_brr(bunlt, _d);
+               case_brf(bunlt, _d, 64);
+               case_brr(bunle, _d);
+               case_brf(bunle, _d, 64);
+               case_brr(buneq, _d);
+               case_brf(buneq, _d, 64);
+               case_brr(bunge, _d);
+               case_brf(bunge, _d, 64);
+               case_brr(bungt, _d);
+               case_brf(bungt, _d, 64);
+               case_brr(bltgt, _d);
+               case_brf(bltgt, _d, 64);
+               case_brr(bord, _d);
+               case_brf(bord, _d, 64);
+               case_brr(bunord, _d);
+               case_brf(bunord, _d, 64);
+               case_rr(ld, _d);
+               case_rw(ld, _d);
+               case_rrr(ldx, _d);
+               case_rrw(ldx, _d);
+               case_rr(st, _d);
+               case_wr(st, _d);
+               case_rrr(stx, _d);
+               case_wrr(stx, _d);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+#if _CALL_AIXDESC
+                   if (_jit->pc.uc == _jit->code.ptr + sizeof(void*) * 3)
+                       _jitc->jump = 1;
+#endif
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   (void)jmpi_p(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w)
+#if _CALL_SYSV
+                     , !!(node->flag & jit_flag_varargs)
+#endif
+                     );
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   word = calli_p(temp->u.w
+#if _CALL_SYSV
+                                  , !!(node->flag & jit_flag_varargs)
+#endif
+                                  );
+                   if (!(temp->flag & jit_flag_patch))
+                       patch(word, node);
+               }
+               else
+                   calli(node->u.w
+#if _CALL_SYSV
+                         , !!(node->flag & jit_flag_varargs)
+#endif
+                         );
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+#if _CALL_AIXDESC
+               undo.prolog_offset = _jitc->prolog.offset;
+#endif
+           restart_function:
+               _jitc->again = 0;
+#if _CALL_AIXDESC
+               if (_jitc->jump && !_jitc->function->assume_frame) {
+                   /* remember prolog to hide offset adjustment for a jump
+                    * to the start of a function, what is expected to be
+                    * a common practice as first jit instruction */
+                   if (_jitc->prolog.offset >= _jitc->prolog.length) {
+                       _jitc->prolog.length += 16;
+                       jit_realloc((jit_pointer_t *)&_jitc->prolog.ptr,
+                                   (_jitc->prolog.length - 16) *
+                                   sizeof(jit_word_t),
+                                   _jitc->prolog.length * sizeof(jit_word_t));
+                   }
+                   _jitc->prolog.ptr[_jitc->prolog.offset++] = _jit->pc.w;
+                   /* function descriptor */
+                   word = _jit->pc.w + sizeof(void*) * 3;
+                   iw(word);                           /* addr */
+                   iw(0);                              /* toc */
+                   iw(0);                              /* env */
+               }
+#endif
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+#if _CALL_AIXDESC
+                   _jitc->prolog.offset = undo.prolog_offset;
+#endif
+                   goto restart_function;
+               }
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:
+           case jit_code_arg:                  case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:
+#if __WORDSIZE == 64
+           case jit_code_getarg_ui:            case jit_code_getarg_l:
+#endif
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+#if __WORDSIZE == 64
+           case jit_code_retval_ui:            case jit_code_retval_l:
+#endif
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           default:
+               abort();
+       }
+       jit_regarg_clr(node, value);
+       assert(_jitc->regarg == 0 && _jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+    }
+#undef case_brf
+#undef case_brw
+#undef case_brr
+#undef case_wrr
+#undef case_rrf
+#undef case_rrw
+#undef case_rrr
+#undef case_wr
+#undef case_rw
+#undef case_rr
+
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(_jitc->patches.ptr[offset].inst, word);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_ppc-cpu.c"
+#  include "jit_ppc-fpu.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+#if defined(__GNUC__)
+    jit_word_t         f, t, s;
+
+    s = sysconf(_SC_PAGE_SIZE);
+    f = (jit_word_t)fptr & -s;
+    t = (((jit_word_t)tptr) + s - 1) & -s;
+    __clear_cache((void *)f, (void *)t);
+#endif
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+#if __WORDSIZE == 32
+    ldxi_i(rn(r0), rn(r1), i0);
+#else
+    ldxi_l(rn(r0), rn(r1), i0);
+#endif
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+#if __WORDSIZE == 32
+    stxi_i(i0, rn(r0), rn(r1));
+#else
+    stxi_l(i0, rn(r0), rn(r1));
+#endif
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi_d(i0, rn(r0), rn(r1));
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                 flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+    assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_print.c b/deps/lightning/lib/jit_print.c
new file mode 100644 (file)
index 0000000..fc4ab87
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+
+#define print_chr(value)               fputc(value, stdout)
+#define print_hex(value)               fprintf(stdout, "0x%lx", value)
+#define print_dec(value)               fprintf(stdout, "%ld", value)
+#define print_flt(value)               fprintf(stdout, "%g", value)
+#define print_str(value)               fprintf(stdout, "%s", value)
+#define print_ptr(value)               fprintf(stdout, "%p", value)
+#define print_reg(value)                                               \
+    do {                                                               \
+       if ((value) & jit_regno_patch)                                  \
+           print_chr('?');                                             \
+       print_str(_rvs[jit_regno(value)].name);                         \
+    } while (0)
+#define print_arg(value)                                               \
+    do {                                                               \
+       print_chr('#');                                                 \
+       if (value)                                                      \
+           print_dec((value)->v.w);                                    \
+       else                                                            \
+           print_chr('?');                                             \
+    } while (0)
+
+/*
+ * Initialization
+ */
+#include "jit_names.c"
+
+/*
+ * Implementation
+ */
+void
+_jit_print(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+
+    if ((node = _jitc->head)) {
+       jit_print_node(node);
+       for (node = node->next; node; node = node->next) {
+           print_chr('\n');
+           jit_print_node(node);
+       }
+       print_chr('\n');
+    }
+}
+
+void
+_jit_print_node(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_block_t                *block;
+    jit_int32_t                 value;
+    jit_int32_t                 offset;
+
+    if (node->code == jit_code_label ||
+       node->code == jit_code_prolog || node->code == jit_code_epilog) {
+       print_chr('L');
+       print_dec(node->v.w);
+       print_chr(':');
+       block = _jitc->blocks.ptr + node->v.w;
+       for (offset = 0; offset < _jitc->reglen; offset++) {
+           if (jit_regset_tstbit(&block->reglive, offset)) {
+               print_chr(' ');
+               print_reg(offset);
+           }
+       }
+       if (node->code == jit_code_prolog ||
+           node->code == jit_code_epilog) {
+           print_str(" /* ");
+           print_str(code_name[node->code]);
+           print_str(" */");
+       }
+       return;
+    }
+    value = jit_classify(node->code) &
+       (jit_cc_a0_int|jit_cc_a0_flt|jit_cc_a0_dbl|jit_cc_a0_jmp|
+        jit_cc_a0_reg|jit_cc_a0_rlh|jit_cc_a0_arg|
+        jit_cc_a1_reg|jit_cc_a1_int|jit_cc_a1_flt|jit_cc_a1_dbl|jit_cc_a1_arg|
+        jit_cc_a2_reg|jit_cc_a2_int|jit_cc_a2_flt|jit_cc_a2_dbl);
+    if (!(node->flag & jit_flag_synth) && ((value & jit_cc_a0_jmp) ||
+                                          node->code == jit_code_finishr ||
+                                          node->code == jit_code_finishi))
+       print_str("    ");
+    else
+       print_chr('\t');
+    if (node->flag & jit_flag_synth)
+       print_str(" \\__ ");
+    print_str(code_name[node->code]);
+    switch (node->code) {
+       r:
+           print_chr(' ');     print_reg(node->u.w);   return;
+       w:
+           print_chr(' ');     print_hex(node->u.w);   return;
+       f:
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float32_t *)node->u.n->u.w);
+           else
+               print_flt(node->u.f);
+           return;
+       d:
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float64_t *)node->u.n->u.w);
+           else
+               print_flt(node->u.d);
+           return;
+       n:
+           print_chr(' ');
+           if (!(node->flag & jit_flag_node))
+               print_ptr(node->u.p);
+           else {
+               print_chr('L');
+               print_dec(node->u.n->v.w);
+           }
+           return;
+       a:
+           print_chr(' ');     print_arg(node);        return;
+       r_r:
+           print_chr(' ');     print_reg(node->u.w);
+           print_chr(' ');     print_reg(node->v.w);   return;
+       r_w:
+           print_chr(' ');     print_reg(node->u.w);
+           print_chr(' ');     print_hex(node->v.w);   return;
+       r_f:
+           print_chr(' ');     print_reg(node->u.w);
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float32_t *)node->v.n->u.w);
+           else
+               print_flt(node->v.f);
+           return;
+       r_d:
+           print_chr(' ');     print_reg(node->u.w);
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float64_t *)node->v.n->u.w);
+           else
+               print_flt(node->v.d);
+           return;
+       r_a:
+           print_chr(' ');     print_reg(node->u.w);
+           print_chr(' ');     print_arg(node->v.n);
+           return;
+       w_r:
+           print_chr(' ');     print_hex(node->u.w);
+           print_chr(' ');     print_reg(node->v.w);   return;
+       w_w:
+           print_chr(' ');     print_hex(node->u.w);
+           print_chr(' ');     print_hex(node->v.w);   return;
+       w_a:
+           print_chr(' ');     print_hex(node->u.w);
+           print_chr(' ');     print_arg(node->v.n);
+           return;
+       f_a:
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float32_t *)node->u.n->u.w);
+           else
+               print_flt(node->u.f);
+           print_chr(' ');     print_arg(node->v.n);
+           return;
+       d_a:
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float64_t *)node->u.n->u.w);
+           else
+               print_flt(node->u.d);
+           print_chr(' ');     print_arg(node->v.n);
+           return;
+       r_r_r:
+           print_chr(' ');     print_reg(node->u.w);
+           print_chr(' ');     print_reg(node->v.w);
+           print_chr(' ');     print_reg(node->w.w);   return;
+       r_r_w:
+           print_chr(' ');     print_reg(node->u.w);
+           print_chr(' ');     print_reg(node->v.w);
+           print_chr(' ');     print_hex(node->w.w);   return;
+       q_r_r:
+           print_str(" (");    print_reg(node->u.q.l);
+           print_chr(' ');     print_reg(node->u.q.h);
+           print_str(") ");    print_reg(node->v.w);
+           print_chr(' ');     print_reg(node->w.w);   return;
+       q_r_w:
+           print_str(" (");    print_reg(node->u.q.l);
+           print_chr(' ');     print_reg(node->u.q.h);
+           print_str(") ");    print_reg(node->v.w);
+           print_chr(' ');     print_hex(node->w.w);   return;
+       r_r_f:
+           print_chr(' ');     print_reg(node->u.w);
+           print_chr(' ');     print_reg(node->v.w);
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float32_t *)node->w.n->u.w);
+           else
+               print_flt(node->w.f);
+           return;
+       r_r_d:
+           print_chr(' ');     print_reg(node->u.w);
+           print_chr(' ');     print_reg(node->v.w);
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float64_t *)node->w.n->u.w);
+           else
+               print_flt(node->w.d);
+           return;
+       w_r_r:
+           print_chr(' ');     print_hex(node->u.w);
+           print_chr(' ');     print_reg(node->v.w);
+           print_chr(' ');     print_reg(node->w.w);   return;
+       n_r_r:
+           print_chr(' ');
+           if (!(node->flag & jit_flag_node))
+               print_ptr(node->u.p);
+           else {
+               print_chr('L');
+               print_dec(node->u.n->v.w);
+           }
+           print_chr(' ');     print_reg(node->v.w);
+           print_chr(' ');     print_reg(node->w.w);   return;
+       n_r_w:
+           print_chr(' ');
+           if (!(node->flag & jit_flag_node))
+               print_ptr(node->u.p);
+           else {
+               print_chr('L');
+               print_dec(node->u.n->v.w);
+           }
+           print_chr(' ');     print_reg(node->v.w);
+           print_chr(' ');     print_hex(node->w.w);   return;
+       n_r_f:
+           print_chr(' ');
+           if (!(node->flag & jit_flag_node))
+               print_ptr(node->u.p);
+           else{
+               print_chr('L');
+               print_dec(node->u.n->v.w);
+           }
+           print_chr(' ');     print_reg(node->v.w);
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float32_t *)node->w.n->u.w);
+           else
+               print_flt(node->w.f);
+           return;
+       n_r_d:
+           print_chr(' ');
+           if (!(node->flag & jit_flag_node))
+               print_ptr(node->u.p);
+           else {
+               print_chr('L');
+               print_dec(node->u.n->v.w);
+           }
+           print_chr(' ');     print_reg(node->v.w);
+           print_chr(' ');
+           if (node->flag & jit_flag_data)
+               print_flt(*(jit_float64_t *)node->w.n->u.w);
+           else
+               print_flt(node->w.d);
+           return;
+       case jit_code_name:
+           print_chr(' ');
+           if (node->v.p && _jitc->emit)
+               print_ptr(node->v.n->u.p);
+           break;
+       case jit_code_note:
+           print_chr(' ');
+           if (node->v.p && _jitc->emit)
+               print_ptr(node->v.n->u.p);
+           if (node->v.p && _jitc->emit && node->w.w)
+               print_chr(':');
+           if (node->w.w)
+               print_dec(node->w.w);
+           break;
+       case jit_code_data:
+       case jit_code_label:
+       case jit_code_ellipsis:
+       case jit_code_prolog:   case jit_code_epilog:
+       case jit_code_ret:      case jit_code_prepare:
+           break;
+       case jit_code_save:     case jit_code_load:
+           goto r;
+       default:
+           switch (value) {
+               case jit_cc_a0_reg:
+               case jit_cc_a0_reg|jit_cc_a0_chg:
+               case jit_cc_a0_reg|jit_cc_a0_jmp:
+                   goto r;
+               case jit_cc_a0_int:
+                   goto w;
+               case jit_cc_a0_flt:
+                   goto f;
+               case jit_cc_a0_dbl:
+                   goto d;
+               case jit_cc_a0_jmp:
+                   goto n;
+               case jit_cc_a0_int|jit_cc_a0_arg:
+                   goto a;
+               case jit_cc_a0_reg|jit_cc_a1_reg:
+                   goto r_r;
+               case jit_cc_a0_reg|jit_cc_a1_int:
+                   goto r_w;
+               case jit_cc_a0_reg|jit_cc_a1_flt:
+                   goto r_f;
+               case jit_cc_a0_reg|jit_cc_a1_dbl:
+                   goto r_d;
+               case jit_cc_a0_reg|jit_cc_a1_arg:
+                   goto r_a;
+               case jit_cc_a0_int|jit_cc_a1_reg:
+                   goto w_r;
+               case jit_cc_a0_int|jit_cc_a1_int:
+                   goto w_w;
+               case jit_cc_a0_int|jit_cc_a1_arg:
+                   goto w_a;
+               case jit_cc_a0_flt|jit_cc_a1_arg:
+                   goto f_a;
+               case jit_cc_a0_dbl|jit_cc_a1_arg:
+                   goto d_a;
+               case jit_cc_a0_reg|jit_cc_a1_reg|jit_cc_a2_reg:
+                   goto r_r_r;
+               case jit_cc_a0_reg|jit_cc_a1_reg|jit_cc_a2_int:
+                   goto r_r_w;
+               case jit_cc_a0_reg|jit_cc_a0_rlh|
+                    jit_cc_a1_reg|jit_cc_a2_reg:
+                   goto q_r_r;
+               case jit_cc_a0_reg|jit_cc_a0_rlh|
+                    jit_cc_a1_reg|jit_cc_a2_int:
+                   goto q_r_w;
+               case jit_cc_a0_reg|jit_cc_a1_reg|jit_cc_a2_flt:
+                   goto r_r_f;
+               case jit_cc_a0_reg|jit_cc_a1_reg|jit_cc_a2_dbl:
+                   goto r_r_d;
+               case jit_cc_a0_int|jit_cc_a1_reg|jit_cc_a2_reg:
+                   goto w_r_r;
+               case jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a2_reg:
+                   goto n_r_r;
+               case jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a2_int:
+                   goto n_r_w;
+               case jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a2_flt:
+                   goto n_r_f;
+               case jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a2_dbl:
+                   goto n_r_d;
+               default:
+                   abort();
+           }
+           break;
+    }
+}
diff --git a/deps/lightning/lib/jit_rewind.c b/deps/lightning/lib/jit_rewind.c
new file mode 100644 (file)
index 0000000..5ef1be5
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2015-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+
+#if PROTO
+#  define free_synth_list(node)                _free_synth_list(_jit,node)
+static jit_node_t *_free_synth_list(jit_state_t*,jit_node_t*);
+#define rewind_prolog()                        _rewind_prolog(_jit)
+static void _rewind_prolog(jit_state_t*);
+#define rewind_prepare()               _rewind_prepare(_jit)
+static void _rewind_prepare(jit_state_t*);
+#endif
+
+#if CODE
+/*
+ * Implementation
+ */
+static jit_node_t *
+_free_synth_list(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_node_t         *next;
+    next = node->next;
+    free_node(node);
+    for (node = next; node && (node->flag & jit_flag_synth); node = next) {
+       next = node->next;
+       free_node(node);
+    }
+    return (next);
+}
+
+static void
+_rewind_prolog(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *next;
+    _jitc->function->self.size = stack_framesize;
+#if __arm__
+    assert(jit_cpu.abi);
+    _jitc->function->self.size += 64;
+#endif
+#if __mips__ && NEW_ABI
+    /* Only add extra stack space if there are varargs
+     * arguments in registers. */
+    assert(jit_arg_reg_p(_jitc->function->self.argi));
+    _jitc->function->self.size += 64;
+#endif
+    _jitc->function->self.argi =
+       _jitc->function->self.argf = _jitc->function->self.argn = 0;
+    _jitc->tail = _jitc->function->prolog;
+    node = _jitc->tail->next;
+    _jitc->tail->next = (jit_node_t *)0;
+    _jitc->tail->link = (jit_node_t *)0;
+    for (; node; node = next) {
+       next = node->next;
+       switch (node->code) {
+           case jit_code_arg:
+               node->next = (jit_node_t *)0;
+               jit_make_arg(node);
+               break;
+           case jit_code_arg_f:
+               node->next = (jit_node_t *)0;
+               jit_make_arg_f(node);
+               break;
+           case jit_code_arg_d:
+               node->next = (jit_node_t *)0;
+               jit_make_arg_d(node);
+               break;
+           case jit_code_getarg_c:
+               jit_getarg_c(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_getarg_uc:
+               jit_getarg_uc(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_getarg_s:
+               jit_getarg_s(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_getarg_us:
+               jit_getarg_us(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_getarg_i:
+               jit_getarg_i(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_getarg_f:
+               jit_getarg_f(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_getarg_d:
+               jit_getarg_d(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_putargr:
+               jit_putargr(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_putargi:
+               jit_putargi(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_putargr_f:
+               jit_putargr_f(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_putargi_f:
+               jit_putargi_f(node->u.f, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_putargr_d:
+               jit_putargr_d(node->u.w, node->v.n);
+               next = free_synth_list(node);
+               break;
+           case jit_code_putargi_d:
+               jit_putargi_d(node->u.d, node->v.n);
+               next = free_synth_list(node);
+               break;
+           default:
+               node->next = (jit_node_t *)0;
+               link_node(node);
+               break;
+       }
+    }
+}
+
+static void
+_rewind_prepare(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *next;
+    _jitc->function->call.argi =
+       _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->tail = _jitc->prepare;
+    node = _jitc->tail->next;
+    _jitc->tail->next = (jit_node_t *)0;
+    _jitc->tail->link = (jit_node_t *)0;
+    for (; node; node = next) {
+       next = node->next;
+       switch (node->code) {
+           case jit_code_pushargr:
+               jit_pushargr(node->u.w);
+               next = free_synth_list(node);
+               break;
+           case jit_code_pushargi:
+               jit_pushargi(node->u.w);
+               next = free_synth_list(node);
+               break;
+           case jit_code_pushargr_f:
+               jit_pushargr_f(node->u.w);
+               next = free_synth_list(node);
+               break;
+           case jit_code_pushargi_f:
+               jit_pushargi_f(node->u.f);
+               next = free_synth_list(node);
+               break;
+           case jit_code_pushargr_d:
+               jit_pushargr_d(node->u.w);
+               next = free_synth_list(node);
+               break;
+           case jit_code_pushargi_d:
+               jit_pushargi_d(node->u.d);
+               next = free_synth_list(node);
+               break;
+           default:
+               node->next = (jit_node_t *)0;
+               link_node(node);
+               break;
+       }
+    }
+}
+#endif
diff --git a/deps/lightning/lib/jit_riscv-cpu.c b/deps/lightning/lib/jit_riscv-cpu.c
new file mode 100644 (file)
index 0000000..388489f
--- /dev/null
@@ -0,0 +1,2378 @@
+/*
+ * Copyright (C) 2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#define _ZERO_REGNO            0
+#define _RA_REGNO              1
+#define _SP_REGNO              2
+#define _FP_REGNO              8
+typedef union {
+#  define ui                   jit_uint32_t
+    struct  {
+       ui opcode       : 7;
+       ui rd           : 5;
+       ui funct3       : 3;
+       ui rs1          : 5;
+       ui rs2          : 5;
+       ui funct7       : 7;
+    } R;
+    struct  {
+       ui opcode       : 7;
+       ui rd           : 5;
+       ui funct3       : 3;
+       ui rs1          : 5;
+       ui rs2          : 5;
+       ui funct2       : 2;
+       ui rs3          : 5;
+    } R4;
+    struct  {
+       ui opcode       : 7;
+       ui rd           : 5;
+       ui funct3       : 3;
+       ui rs1          : 5;
+       ui imm11_0      : 12;
+    } I;
+#  if __WORDSIZE == 64
+    struct  {
+       ui opcode       : 7;
+       ui rd           : 5;
+       ui funct3       : 3;
+       ui rs1          : 5;
+       ui shamt        : 6;
+       ui imm6_0       : 6;
+    } IS;
+#  endif
+    struct  {
+       ui opcode       : 7;
+       ui imm4_0       : 5;
+       ui funct3       : 3;
+       ui rs1          : 5;
+       ui rs2          : 5;
+       ui imm11_5      : 7;
+    } S;
+    struct  {
+       ui opcode       : 7;
+       ui imm11        : 1;
+       ui imm4_1       : 4;
+       ui funct3       : 3;
+       ui rs1          : 5;
+       ui rs2          : 5;
+       ui imm10_5      : 6;
+       ui imm12        : 1;
+    } B;
+    struct  {
+       ui opcode       : 7;
+       ui rd           : 5;
+       ui imm12_31     : 20;
+    } U;
+    struct  {
+       ui opcode       : 7;
+       ui rd           : 5;
+       ui imm19_12     : 8;
+       ui imm11        : 1;
+       ui imm10_1      : 10;
+       ui imm20        : 1;
+    } J;
+    jit_int32_t                w;
+#  undef ui
+} instr_t;
+#  define ii(i)                                *_jit->pc.ui++ = i
+/* FIXME could jit_rewind_prolog() to only use extra 64 bytes
+ * if a variadic jit function that have variadic arguments in
+ * registers */
+#  define stack_framesize              (200 + 64)
+#  define ldr(r0, r1)                  ldr_l(r0, r1)
+#  define ldi(r0, im)                  ldi_l(r0, im)
+#  define ldxr(r0, r1, r2)             ldxr_l(r0, r1, r2)
+#  define ldxi(r0, r1, im)             ldxi_l(r0, r1, im)
+#  define str(r0, r1)                  str_l(r0, r1)
+#  define sti(im, r0)                  sti_l(im, r0)
+#  define stxr(r0, r1, r2)             stxr_l(r0, r1, r2)
+#  define stxi(im, r0, r1)             stxi_l(im, r0, r1)
+#  define simm6_p(im)                  ((im) <= 31 && (im) >= -32)
+#  define simm12_p(im)                 ((im) <= 2047 && (im) >= -2048)
+#  define simm20_p(im)                 ((im) <= 524287 && (im) >= -524288)
+#  define simm32_p(im)                 ((im) <= 2147483647LL && (im) >= -2147483648LL)
+
+/*
+ * RV32I Base Instruction Set
+ */
+#  define LUI(rd, imm)                 Utype(55, rd, imm)
+#  define AUIPC(rd, imm)               Utype(23, rd, imm)
+#  define JAL(rd, imm)                 Jtype(111, rd, imm)
+#  define JALR(rd, rs1, imm)           Itype(103, rd, 0, rs1, imm)
+#  define BEQ(rs1, rs2, imm)           Btype(99, 0, rs1, rs2, imm)
+#  define BNE(rs1, rs2, imm)           Btype(99, 1, rs1, rs2, imm)
+#  define BLT(rs1, rs2, imm)           Btype(99, 4, rs1, rs2, imm)
+#  define BGE(rs1, rs2, imm)           Btype(99, 5, rs1, rs2, imm)
+#  define BLTU(rs1, rs2, imm)          Btype(99, 6, rs1, rs2, imm)
+#  define BGEU(rs1, rs2, imm)          Btype(99, 7, rs1, rs2, imm)
+#  define LB(rd, rs1, imm)             Itype(3, rd, 0, rs1, imm)
+#  define LH(rd, rs1, imm)             Itype(3, rd, 1, rs1, imm)
+#  define LW(rd, rs1, imm)             Itype(3, rd, 2, rs1, imm)
+#  define LBU(rd, rs1, imm)            Itype(3, rd, 4, rs1, imm)
+#  define LHU(rd, rs1, imm)            Itype(3, rd, 5, rs1, imm)
+#  define SB(rs1, rs2, imm)            Stype(35, 0, rs1, rs2, imm)
+#  define SH(rs1, rs2, imm)            Stype(35, 1, rs1, rs2, imm)
+#  define SW(rs1, rs2, imm)            Stype(35, 2, rs1, rs2, imm)
+#  define ADDI(rd, rs1, imm)           Itype(19, rd, 0, rs1, imm)
+#  define SLTI(rd, rs1, imm)           Itype(19, rd, 2, rs1, imm)
+#  define SLTIU(rd, rs1, imm)          Itype(19, rd, 3, rs1, imm)
+#  define XORI(rd, rs1, imm)           Itype(19, rd, 4, rs1, imm)
+#  define ORI(rd, rs1, imm)            Itype(19, rd, 6, rs1, imm)
+#  define ANDI(rd, rs1, imm)           Itype(19, rd, 7, rs1, imm)
+#  if __WORDSIZE == 32
+#    define SLLI(rd, rs1, imm)         Rtype(19, rd, 1, rs1, imm, 0)
+#    define SRLI(rd, rs1, imm)         Rtype(19, rd, 5, rs1, imm, 0)
+#    define SRAI(rd, rs1, imm)         Rtype(19, rd, 5, rs1, imm, 32)
+#  endif
+#  define ADD(rd, rs1, rs2)            Rtype(51, rd, 0, rs1, rs2, 0)
+#  define SUB(rd, rs1, rs2)            Rtype(51, rd, 0, rs1, rs2, 32)
+#  define SLL(rd, rs1, rs2)            Rtype(51, rd, 1, rs1, rs2, 0)
+#  define SLT(rd, rs1, rs2)            Rtype(51, rd, 2, rs1, rs2, 0)
+#  define SLTU(rd, rs1, rs2)           Rtype(51, rd, 3, rs1, rs2, 0)
+#  define XOR(rd, rs1, rs2)            Rtype(51, rd, 4, rs1, rs2, 0)
+#  define SRL(rd, rs1, rs2)            Rtype(51, rd, 5, rs1, rs2, 0)
+#  define SRA(rd, rs1, rs2)            Rtype(51, rd, 5, rs1, rs2, 32)
+#  define OR(rd, rs1, rs2)             Rtype(51, rd, 6, rs1, rs2, 0)
+#  define AND(rd, rs1, rs2)            Rtype(51, rd, 7, rs1, rs2, 0)
+#  define FENCE(imm)                   Itype(15, 0, 0, 0, im)
+#  define FENCE_I(imm)                 Itype(15, 0, 1, 0, im)
+#  define ECALL()                      Itype(115, 0, 0, 0, 0)
+#  define EBREAK()                     Itype(115, 0, 0, 0, 1)
+#  define CSRRW(rd, rs1, csr)          Itype(115, rd, 1, rs1, csr)
+#  define CSRRS(rd, rs1, csr)          Itype(115, rd, 2, rs1, csr)
+#  define CSRRC(rd, rs1, csr)          Itype(115, rd, 3, rs1, csr)
+#  define CSRRWI(rd, zimm, csr)                Itype(115, rd, 5, zimm, csr)
+#  define CSRRSI(rd, zimm, csr)                Itype(115, rd, 6, zimm, csr)
+#  define CSRRCI(rd, zimm, csr)                Itype(115, rd, 7, zimm, csr)
+/*
+ * RV64I Base Instruction Set (in addition to RV32I)
+ */
+#  define LWU(rd, rs1, imm)            Itype(3, rd, 6, rs1, imm)
+#  define LD(rd, rs1, imm)             Itype(3, rd, 3, rs1, imm)
+#  define SD(rs1, rs2, imm)            Stype(35, 3, rs1, rs2, imm)
+#  if __WORDSIZE == 64
+#    define SLLI(rd, rs1, sh)          IStype(19, rd, 1, rs1, sh, 0)
+#    define SRLI(rd, rs1, sh)          IStype(19, rd, 5, rs1, sh, 0)
+#    define SRAI(rd, rs1, sh)          IStype(19, rd, 5, rs1, sh, 16)
+#  endif
+#  define ADDIW(rd, rs1, imm)          Itype(27, rd, 0, rs1, imm)
+#  define SLLIW(rd, rs1, imm)          Rtype(27, rd, 1, rs1, imm, 0)
+#  define SRLIW(rd, rs1, imm)          Rtype(27, rd, 3, rs1, imm, 0)
+#  define SRAIW(rd, rs1, imm)          Rtype(27, rd, 3, rs1, imm, 32)
+#  define ADDW(rd, rs1, imm)           Rtype(59, rd, 0, rs1, imm, 0)
+#  define SUBW(rd, rs1, imm)           Rtype(59, rd, 0, rs1, imm, 32)
+#  define SLLW(rd, rs1, imm)           Rtype(59, rd, 1, rs1, imm, 0)
+#  define SRLW(rd, rs1, imm)           Rtype(59, rd, 5, rs1, imm, 0)
+#  define SRAW(rd, rs1, imm)           Rtype(59, rd, 5, rs1, imm, 32)
+/*
+ * RV32M Standard Extension
+ */
+#  define MUL(rd, rs1, rs2)            Rtype(51, rd, 0, rs1, rs2, 1)
+#  define MULH(rd, rs1, rs2)           Rtype(51, rd, 1, rs1, rs2, 1)
+#  define MULHSU(rd, rs1, rs2)         Rtype(51, rd, 2, rs1, rs2, 1)
+#  define MULHU(rd, rs1, rs2)          Rtype(51, rd, 3, rs1, rs2, 1)
+#  define DIV(rd, rs1, rs2)            Rtype(51, rd, 4, rs1, rs2, 1)
+#  define DIVU(rd, rs1, rs2)           Rtype(51, rd, 5, rs1, rs2, 1)
+#  define REM(rd, rs1, rs2)            Rtype(51, rd, 6, rs1, rs2, 1)
+#  define REMU(rd, rs1, rs2)           Rtype(51, rd, 7, rs1, rs2, 1)
+/*
+ * RV64M Standard Extension (in addition to RV32M)
+ */
+#  define MULW(rd, rs1, rs2)           Rtype(59, rd, 0, rs1, rs2, 1)
+#  define DIVW(rd, rs1, rs2)           Rtype(59, rd, 4, rs1, rs2, 1)
+#  define DIVUW(rd, rs1, rs2)          Rtype(59, rd, 5, rs1, rs2, 1)
+#  define REMW(rd, rs1, rs2)           Rtype(59, rd, 6, rs1, rs2, 1)
+#  define REMUW(rd, rs1, rs2)          Rtype(59, rd, 7, rs1, rs2, 1)
+/*
+ * RV32A Standard Extension
+ */
+#  define LR_W(rd, rs1)                        R4type(47, rd, 2, rs1, 0, 0, 2)
+#  define SC_W(rd, rs1, rs2)           R4type(47, rd, 2, rs1, rs2, 0, 3)
+#  define AMOSWAP_W(rd, rs1, rs2)      R4type(47, rd, 2, rs1, rs2, 0, 1)
+#  define AMOADD_W(rd, rs1, rs2)       R4type(47, rd, 2, rs1, rs2, 0, 0)
+#  define AMOXOR_W(rd, rs1, rs2)       R4type(47, rd, 2, rs1, rs2, 0, 4)
+#  define AMOAND_W(rd, rs1, rs2)       R4type(47, rd, 2, rs1, rs2, 0, 12)
+#  define AMOOR_W(rd, rs1, rs2)                R4type(47, rd, 2, rs1, rs2, 0, 8)
+#  define AMOMIN_W(rd, rs1, rs2)       R4type(47, rd, 2, rs1, rs2, 0, 16)
+#  define AMOMAX_W(rd, rs1, rs2)       R4type(47, rd, 2, rs1, rs2, 0, 20)
+#  define AMOMINU_W(rd, rs1, rs2)      R4type(47, rd, 2, rs1, rs2, 0, 24)
+#  define AMOMAXU_W(rd, rs1, rs2)      R4type(47, rd, 2, rs1, rs2, 0, 28)
+/*
+ * RV64A Standard Extension (in addition to RV32A)
+ */
+#  define LR_D(rd, rs1)                        R4type(47, rd, 3, rs1, 0, 0, 2)
+#  define SC_D(rd, rs1, rs2)           R4type(47, rd, 3, rs1, rs2, 0, 3)
+#  define AMOSWAP_D(rd, rs1, rs2)      R4type(47, rd, 3, rs1, rs2, 0, 1)
+#  define AMOADD_D(rd, rs1, rs2)       R4type(47, rd, 3, rs1, rs2, 0, 0)
+#  define AMOXOR_D(rd, rs1, rs2)       R4type(47, rd, 3, rs1, rs2, 0, 4)
+#  define AMOAND_D(rd, rs1, rs2)       R4type(47, rd, 3, rs1, rs2, 0, 12)
+#  define AMOOR_D(rd, rs1, rs2)                R4type(47, rd, 3, rs1, rs2, 0, 8)
+#  define AMOMIN_D(rd, rs1, rs2)       R4type(47, rd, 3, rs1, rs2, 0, 16)
+#  define AMOMAX_D(rd, rs1, rs2)       R4type(47, rd, 3, rs1, rs2, 0, 20)
+#  define AMOMINU_D(rd, rs1, rs2)      R4type(47, rd, 3, rs1, rs2, 0, 24)
+#  define AMOMAXU_D(rd, rs1, rs2)      R4type(47, rd, 3, rs1, rs2, 0, 28)
+/*
+ * Pseudo Instructions
+ */
+#  define NOP()                                ADDI(_ZERO_REGNO, _ZERO_REGNO, 0)
+#  define MV(r0, r1)                   ADDI(r0, r1, 0)
+#  define NOT(r0, r1)                  XORI(r0, r1, -1)
+#  define NEG(r0, r1)                  SUB(r0, _ZERO_REGNO, r1)
+#  define NEGW(r0, r1)                 SUBW(r0, _ZERO_REGNO, r1)
+#  define SEXT_W(r0, r1)               ADDIW(r0, r1, 0)
+#  define RET()                                JALR(0, 1, 0)
+
+/*
+ * Enconding functions
+ */
+#  define Rtype(op, rd, fct, rs1, rs2, fct2)                   \
+       _Rtype(_jit, op, rd, fct, rs1, rs2, fct2)
+static void _Rtype(jit_state_t*, jit_int32_t, jit_int32_t,
+                  jit_int32_t, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define R4type(op, rd, fct, rs1,rs2,fct2,rs3)                        \
+       _R4type(_jit, op, rd, fct, rs1, rs2, fct2, rs3)
+static void _R4type(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t,
+                   jit_int32_t, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define Itype(op, rd, fct, rs1, imm)                         \
+       _Itype(_jit, op, rd, fct, rs1, imm)
+static void _Itype(jit_state_t*, jit_int32_t, jit_int32_t,
+                  jit_int32_t, jit_int32_t, jit_int32_t);
+#  if __WORDSIZE == 64
+#  define IStype(op, rd, fct, rs1, sh, imm)                    \
+       _IStype(_jit, op, rd, fct, rs1, sh, imm)
+static void _IStype(jit_state_t*, jit_int32_t, jit_int32_t,
+                  jit_int32_t, jit_int32_t, jit_int32_t,jit_int32_t);
+#  endif
+#  define Stype(op, fct, rs1, rs2, imm)                                \
+       _Stype(_jit, op, fct, rs1, rs2, imm)
+static void _Stype(jit_state_t*, jit_int32_t, jit_int32_t,
+                  jit_int32_t, jit_int32_t, jit_int32_t);
+#  define Btype(op, fct, rs1, rs2, imm)                                \
+       _Btype(_jit, op, fct, rs1, rs2, imm)
+static void _Btype(jit_state_t*, jit_int32_t, jit_int32_t,
+                  jit_int32_t, jit_int32_t, jit_int32_t);
+#  define Utype(op, rd, imm)           _Utype(_jit, op, rd, imm)
+static void _Utype(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define Jtype(op, rd, imm)           _Jtype(_jit, op, rd, imm)
+static void _Jtype(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+/*
+ * Lightning instructions
+ */
+#  define nop(im)                      _nop(_jit, im)
+static void _nop(jit_state_t*, jit_int32_t);
+#  define addr(r0, r1, r2)             ADD(r0, r1, r2)
+#  define addi(r0, r1, im)             _addi(_jit, r0, r1, im)
+static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addcr(r0, r1, r2)            _addcr(_jit, r0, r1, r2)
+static void _addcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addci(r0, r1, im)            _addci(_jit, r0, r1, im)
+static void _addci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addxr(r0, r1, r2)            _addxr(_jit, r0, r1, r2)
+static void _addxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addxi(r0, r1, im)            _addxi(_jit, r0, r1, im)
+static void _addxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subr(r0, r1, r2)             SUB(r0, r1, r2)
+#  define subi(r0, r1, im)             _subi(_jit, r0, r1, im)
+static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subcr(r0, r1, r2)            _subcr(_jit, r0, r1, r2)
+static void _subcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subci(r0, r1, im)            _subci(_jit, r0, r1, im)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subxr(r0, r1, r2)            _subxr(_jit, r0, r1, r2)
+static void _subxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subxi(r0, r1, im)            _subxi(_jit, r0, r1, im)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rsbi(r0, r1, im)             _rsbi(_jit, r0, r1, im)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define mulr(r0, r1, r2)             MUL(r0, r1, r2)
+#  define muli(r0, r1, im)             _muli(_jit, r0, r1, im)
+static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define divr(r0, r1, r2)             DIV(r0, r1, r2)
+#  define divi(r0, r1, im)             _divi(_jit, r0, r1, im)
+static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define divr_u(r0, r1, r2)           DIVU(r0, r1, r2)
+#  define divi_u(r0, r1, im)           _divi_u(_jit, r0, r1, im)
+static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define remr(r0, r1, r2)             REM(r0, r1, r2)
+#  define remi(r0, r1, im)             _remi(_jit, r0, r1, im)
+static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define remr_u(r0, r1, r2)           REMU(r0, r1, r2)
+#  define remi_u(r0, r1, im)           _remi_u(_jit, r0, r1, im)
+static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr(r0, r1, r2, r3)                _qmulr(_jit,r0,r1,r2,r3)
+static void _qmulr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qmuli(r0, r1, r2, i0)                _qmuli(_jit,r0,r1,r2,i0)
+static void _qmuli(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr_u(r0, r1, r2, r3)      _qmulr_u(_jit,r0,r1,r2,r3)
+static void _qmulr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qmuli_u(r0, r1, r2, i0)      _qmuli_u(_jit,r0,r1,r2,i0)
+static void _qmuli_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+static void _iqdivr(jit_state_t*,jit_bool_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qdivr(r0,r1,r2,r3)           _iqdivr(_jit,1,r0,r1,r2,r3)
+#  define qdivr_u(r0,r1,r2,r3)         _iqdivr(_jit,0,r0,r1,r2,r3)
+static void _iqdivr(jit_state_t*,jit_bool_t,
+                   jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qdivi(r0,r1,r2,i0)           _qdivi(_jit,r0,r1,r2,i0)
+static void _qdivi(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_word_t);
+#  define qdivi_u(r0,r1,r2,i0)         _qdivi_u(_jit,r0,r1,r2,i0)
+static void _qdivi_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_word_t);
+#  define lshr(r0, r1, r2)             SLL(r0, r1, r2)
+#  define lshi(r0, r1, im)             _lshi(_jit, r0, r1, im)
+static void _lshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rshr(r0, r1, r2)             SRA(r0, r1, r2)
+#  define rshi(r0, r1, im)             _rshi(_jit, r0, r1, im)
+static void _rshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rshr_u(r0, r1, r2)           SRL(r0, r1, r2)
+#  define rshi_u(r0, r1, im)           _rshi_u(_jit, r0, r1, im)
+static void _rshi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define negr(r0, r1)                 NEG(r0, r1)
+#  define comr(r0, r1)                 NOT(r0, r1)
+#  define andr(r0, r1, r2)             AND(r0, r1, r2)
+#  define andi(r0, r1, im)             _andi(_jit, r0, r1, im)
+static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define orr(r0, r1, r2)              OR(r0, r1, r2)
+#  define ori(r0, r1, im)              _ori(_jit, r0, r1, im)
+static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define xorr(r0, r1, r2)             XOR(r0, r1, r2)
+#  define xori(r0, r1, im)             _xori(_jit, r0, r1, im)
+static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_c(r0, r1)                        LB(r0, r1, 0)
+#  define ldi_c(r0, im)                        _ldi_c(_jit, r0, im)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_uc(r0, r1)               LBU(r0, r1, 0)
+#  define ldi_uc(r0, im)               _ldi_uc(_jit, r0, im)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_s(r0, r1)                        LH(r0, r1, 0)
+#  define ldi_s(r0, im)                        _ldi_s(_jit, r0, im)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_us(r0, r1)               LHU(r0, r1, 0)
+#  define ldi_us(r0, im)               _ldi_us(_jit, r0, im)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_i(r0, r1)                        LW(r0, r1, 0)
+#  define ldi_i(r0, im)                        _ldi_i(_jit, r0, im)
+static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_ui(r0, r1)               LWU(r0, r1, 0)
+#  define ldi_ui(r0, im)               _ldi_ui(_jit, r0, im)
+static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_l(r0, r1)                        LD(r0, r1, 0)
+#  define ldi_l(r0, im)                        _ldi_l(_jit, r0, im)
+static void _ldi_l(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_c(r0, r1, r2)           _ldxr_c(_jit, r0, r1, r2)
+static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_c(r0, r1, im)           _ldxi_c(_jit, r0, r1, im)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_uc(r0, r1, r2)          _ldxr_uc(_jit, r0, r1, r2)
+static void _ldxr_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_uc(r0, r1, im)          _ldxi_uc(_jit, r0, r1, im)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_s(r0, r1, r2)           _ldxr_s(_jit, r0, r1, r2)
+static void _ldxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_s(r0, r1, im)           _ldxi_s(_jit, r0, r1, im)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_us(r0, r1, r2)          _ldxr_us(_jit, r0, r1, r2)
+static void _ldxr_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_us(r0, r1, im)          _ldxi_us(_jit, r0, r1, im)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_i(r0, r1, r2)           _ldxr_i(_jit, r0, r1, r2)
+static void _ldxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_i(r0, r1, im)           _ldxi_i(_jit, r0, r1, im)
+static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_ui(r0, r1, r2)          _ldxr_ui(_jit, r0, r1, r2)
+static void _ldxr_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_ui(r0, r1, im)          _ldxi_ui(_jit, r0, r1, im)
+static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_l(r0, r1, r2)           _ldxr_l(_jit, r0, r1, r2)
+static void _ldxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_l(r0, r1, im)           _ldxi_l(_jit, r0, r1, im)
+static void _ldxi_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_c(r0, r1)                        SB(r0, r1, 0)
+#  define sti_c(im, r0)                        _sti_c(_jit, im, r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_s(r0, r1)                        SH(r0, r1, 0)
+#  define sti_s(im, r0)                        _sti_s(_jit, im, r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_i(r0, r1)                        SW(r0, r1, 0)
+#  define sti_i(im, r0)                        _sti_i(_jit, im, r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_l(r0, r1)                        SD(r0, r1, 0)
+#  define sti_l(im, r0)                        _sti_l(_jit, im, r0)
+static void _sti_l(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_c(r0, r1, r2)           _stxr_c(_jit, r0, r1, r2)
+static void _stxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_c(i0, r0, r1)           _stxi_c(_jit, i0, r0, r1)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_s(r0, r1, r2)           _stxr_s(_jit, r0, r1, r2)
+static void _stxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_s(i0, r0, r1)           _stxi_s(_jit, i0, r0, r1)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_i(r0, r1, r2)           _stxr_i(_jit, r0, r1, r2)
+static void _stxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_i(i0, r0, r1)           _stxi_i(_jit, i0, r0, r1)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_l(r0, r1, r2)           _stxr_l(_jit, r0, r1, r2)
+static void _stxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_l(i0, r0, r1)           _stxi_l(_jit, i0, r0, r1)
+static void _stxi_l(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define htonr_us(r0, r1)             _htonr_us(_jit, r0, r1)
+static void _htonr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define htonr_ui(r0, r1)             _htonr_ui(_jit, r0, r1)
+static void _htonr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define htonr_ul(r0, r1)             _htonr_ul(_jit, r0, r1)
+static void _htonr_ul(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_c(r0, r1)               _extr_c(_jit, r0, r1)
+static void _extr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_uc(r0, r1)              andi(r0, r1, 0xff)
+#  define extr_s(r0, r1)               _extr_s(_jit, r0, r1)
+static void _extr_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_us(r0, r1)              _extr_us(_jit, r0, r1)
+static void _extr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_i(r0, r1)               SEXT_W(r0, r1)
+#  define extr_ui(r0, r1)              _extr_ui(_jit, r0, r1)
+static void _extr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movr(r0, r1)                 MV(r0, r1)
+#  define movi(r0, im)                 _movi(_jit, r0, im)
+static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
+#  define movi_p(r0, im)               _movi_p(_jit, r0, im)
+static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ltr(r0, r1, r2)              SLT(r0, r1, r2)
+#  define lti(r0, r1, im)              _lti(_jit, r0, r1, im)
+static void _lti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ltr_u(r0, r1, r2)            SLTU(r0, r1, r2)
+#  define lti_u(r0, r1, im)            _lti_u(_jit, r0, r1, im)
+static void _lti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ler(r0, r1, r2)              _ler(_jit, r0, r1, r2)
+static void _ler(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lei(r0, r1, im)              _lei(_jit, r0, r1, im)
+static void _lei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ler_u(r0, r1, r2)            _ler_u(_jit, r0, r1, r2)
+static void _ler_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define lei_u(r0, r1, im)            _lei_u(_jit, r0, r1, im)
+static void _lei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define eqr(r0, r1, r2)              _eqr(_jit, r0, r1, r2)
+static void _eqr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define eqi(r0, r1, im)              _eqi(_jit, r0, r1, im)
+static void _eqi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ger(r0, r1, r2)              _ger(_jit, r0, r1, r2)
+static void _ger(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gei(r0, r1, r2)              _gei(_jit, r0, r1, r2)
+static void _gei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ger_u(r0, r1, r2)            _ger_u(_jit, r0, r1, r2)
+static void _ger_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define gei_u(r0, r1, im)            _gei_u(_jit, r0, r1, im)
+static void _gei_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define gtr(r0, r1, r2)              SLT(r0, r2, r1)
+#  define gti(r0, r1, im)              _gti(_jit, r0, r1, im)
+static void _gti(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define gtr_u(r0, r1, r2)            SLTU(r0, r2, r1)
+#  define gti_u(r0, r1, im)            _gti_u(_jit, r0, r1, im)
+static void _gti_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ner(r0, r1, r2)              _ner(_jit, r0, r1, r2)
+static void _ner(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nei(r0, r1, im)              _nei(_jit, r0, r1, im)
+static void _nei(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define bltr(br, r0, r1)             _bltr(_jit, br, r0, r1)
+static jit_word_t _bltr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti(br, r0, im)             _blti(_jit, br, r0, im)
+static jit_word_t _blti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bltr_u(br, r0, r1)           _bltr_u(_jit, br, r0, r1)
+static jit_word_t _bltr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti_u(br, r0, im)           _blti_u(_jit, br, r0, im)
+static jit_word_t _blti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bler(br, r0, r1)             _bler(_jit, br, r0, r1)
+static jit_word_t _bler(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei(br, r0, im)             _blei(_jit, br, r0, im)
+static jit_word_t _blei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bler_u(br, r0, r1)           _bler_u(_jit, br, r0, r1)
+static jit_word_t _bler_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei_u(br, r0, im)           _blei_u(_jit, br, r0, im)
+static jit_word_t _blei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define beqr(br, r0, r1)             _beqr(_jit, br, r0, r1)
+static jit_word_t _beqr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define beqi(br, r0, im)             _beqi(_jit, br, r0, im)
+static jit_word_t _beqi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bger(br, r0, r1)             _bger(_jit, br, r0, r1)
+static jit_word_t _bger(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei(br, r0, im)             _bgei(_jit, br, r0, im)
+static jit_word_t _bgei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bger_u(br, r0, r1)           _bger_u(_jit, br, r0, r1)
+static jit_word_t _bger_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei_u(br, r0, im)           _bgei_u(_jit, br, r0, im)
+static jit_word_t _bgei_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bgtr(br, r0, r1)             _bgtr(_jit, br, r0, r1)
+static jit_word_t _bgtr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti(br, r0, im)             _bgti(_jit, br, r0, im)
+static jit_word_t _bgti(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bgtr_u(br, r0, r1)           _bgtr_u(_jit, br, r0, r1)
+static jit_word_t _bgtr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti_u(br, r0, im)           _bgti_u(_jit, br, r0, im)
+static jit_word_t _bgti_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bner(br, r0, r1)             _bner(_jit, br, r0, r1)
+static jit_word_t _bner(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bnei(br, r0, im)             _bnei(_jit, br, r0, im)
+static jit_word_t _bnei(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define boaddr(br, r0, r1)           _boaddr(_jit, br, r0, r1)
+#  define boaddi(br, r0, im)           _boaddi(_jit, br, r0, im)
+static jit_word_t _boaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _boaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define boaddr_u(br, r0, r1)         _boaddr_u(_jit, br, r0, r1)
+#  define boaddi_u(br, r0, im)         _boaddi_u(_jit, br, r0, im)
+static jit_word_t _boaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _boaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxaddr(br, r0, r1)           _bxaddr(_jit, br, r0, r1)
+#  define bxaddi(br, r0, im)           _bxaddi(_jit, br, r0, im)
+static jit_word_t _bxaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _bxaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxaddr_u(br, r0, r1)         _bxaddr_u(_jit, br, r0, r1)
+#  define bxaddi_u(br, r0, im)         _bxaddi_u(_jit, br, r0, im)
+static jit_word_t _bxaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _bxaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bosubr(br, r0, r1)           _bosubr(_jit, br, r0, r1)
+#  define bosubi(br, r0, im)           _bosubi(_jit, br, r0, im)
+static jit_word_t _bosubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _bosubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bosubr_u(br, r0, r1)         _bosubr_u(_jit, br, r0, r1)
+#  define bosubi_u(br, r0, im)         _bosubi_u(_jit, br, r0, im)
+static jit_word_t _bosubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _bosubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxsubr(br, r0, r1)           _bxsubr(_jit, br, r0, r1)
+#  define bxsubi(br, r0, im)           _bxsubi(_jit, br, r0, im)
+static jit_word_t _bxsubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _bxsubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxsubr_u(br, r0, r1)         _bxsubr_u(_jit, br, r0, r1)
+#  define bxsubi_u(br, r0, im)         _bxsubi_u(_jit, br, r0, im)
+static jit_word_t _bxsubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _bxsubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bmsr(br, r0, r1)             _bmsr(_jit, br, r0, r1)
+#  define bmsi(br, r0, im)             _bmsi(_jit, br, r0, im)
+static jit_word_t _bmsr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _bmsi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bmcr(br, r0, r1)             _bmcr(_jit, br, r0, r1)
+#  define bmci(br, r0, im)             _bmci(_jit, br, r0, im)
+static jit_word_t _bmcr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _bmci(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define jmpr(r0)                     JALR(_ZERO_REGNO, r0, 0)
+#  define jmpi(im)                     _jmpi(_jit, im)
+static void _jmpi(jit_state_t*,jit_word_t);
+#  define jmpi_p(im)                   _jmpi_p(_jit, im)
+static jit_word_t _jmpi_p(jit_state_t*,jit_word_t);
+#  define callr(r0)                    JALR(_RA_REGNO, r0, 0)
+#  define calli(im)                    _calli(_jit, im)
+static void _calli(jit_state_t*,jit_word_t);
+#  define calli_p(im)          _calli_p(_jit, im)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t);
+#  define prolog(i0)                   _prolog(_jit,i0)
+static void _prolog(jit_state_t*,jit_node_t*);
+#  define epilog(i0)                   _epilog(_jit,i0)
+static void _epilog(jit_state_t*,jit_node_t*);
+#  define vastart(r0)                  _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#  define vaarg(r0, r1)                        _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#define patch_abs(instr,label)         _patch_at(_jit,instr,label)
+#define patch_at(instr,label)          _patch_at(_jit,instr,label)
+static void _patch_at(jit_state_t*,jit_word_t,jit_word_t);
+#endif         /* PROTO */
+
+#if CODE
+static void
+_Rtype(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd,
+       jit_int32_t fct, jit_int32_t rs1, jit_int32_t rs2, jit_int32_t fct2)
+{
+    instr_t    i;
+    assert(!(op   & ~0x7f));
+    assert(!(rd   & ~0x1f));
+    assert(!(fct  & ~0x07));
+    assert(!(rs1  & ~0x1f));
+    assert(!(rs2  & ~0x1f));
+    assert(!(fct2 & ~0x7f));
+    i.R.opcode = op;
+    i.R.rd     = rd;
+    i.R.funct3 = fct;
+    i.R.rs1    = rs1;
+    i.R.rs2    = rs2;
+    i.R.funct7 = fct2;
+    ii(i.w);
+}
+
+static void
+_R4type(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd, jit_int32_t fct,
+       jit_int32_t rs1, jit_int32_t rs2, jit_int32_t fct2, jit_int32_t rs3)
+{
+    instr_t    i;
+    assert(!(op   & ~0x7f));
+    assert(!(rd   & ~0x1f));
+    assert(!(fct  & ~0x07));
+    assert(!(rs1  & ~0x1f));
+    assert(!(rs2  & ~0x1f));
+    assert(!(fct2 & ~0x03));
+    assert(!(rs3  & ~0x1f));
+    i.R4.opcode        = op;
+    i.R4.rd    = rd;
+    i.R4.funct3        = fct;
+    i.R4.rs1   = rs1;
+    i.R4.rs2   = rs2;
+    i.R4.funct2        = fct2;
+    i.R4.rs3   = rs3;
+    ii(i.w);
+}
+
+static void
+_Itype(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd,
+       jit_int32_t fct, jit_int32_t rs1, jit_int32_t imm)
+{
+    instr_t    i;
+    assert(!(op  &  ~0x7f));
+    assert(!(rd  &  ~0x1f));
+    assert(!(fct &  ~0x07));
+    assert(!(rs1 &  ~0x1f));
+    assert(simm12_p(imm));
+    i.I.opcode = op;
+    i.I.rd     = rd;
+    i.I.funct3 = fct;
+    i.I.rs1    = rs1;
+    i.I.imm11_0        = imm;
+    ii(i.w);
+}
+
+#  if __WORDSIZE == 64
+static void
+_IStype(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd,
+       jit_int32_t fct, jit_int32_t rs1, jit_int32_t sh, jit_int32_t imm)
+{
+    instr_t    i;
+    assert(!(op  &  ~0x7f));
+    assert(!(rd  &  ~0x1f));
+    assert(!(fct &  ~0x07));
+    assert(!(rs1 &  ~0x1f));
+    assert(!(sh  &  ~0x3f));
+    assert(simm6_p(imm));
+    i.IS.opcode        = op;
+    i.IS.rd    = rd;
+    i.IS.funct3        = fct;
+    i.IS.rs1   = rs1;
+    i.IS.shamt = sh;
+    i.IS.imm6_0 = imm;
+    ii(i.w);
+}
+#  endif
+
+static void
+_Stype(jit_state_t *_jit, jit_int32_t op, jit_int32_t fct,
+       jit_int32_t rs1, jit_int32_t rs2, jit_int32_t imm)
+{
+    instr_t    i;
+    assert(!(op  &  ~0x7f));
+    assert(!(fct &  ~0x07));
+    assert(!(rs1 &  ~0x1f));
+    assert(!(rs2 &  ~0x1f));
+    assert(simm12_p(imm));
+    i.S.opcode = op;
+    i.S.imm4_0 = imm & 0x1f;
+    i.S.funct3 = fct;
+    i.S.rs1    = rs1;
+    i.S.rs2    = rs2;
+    i.S.imm11_5        = (imm >> 5) & 0x7f;
+    ii(i.w);
+}
+
+static void
+_Btype(jit_state_t *_jit, jit_int32_t op, jit_int32_t fct,
+       jit_int32_t rs1, jit_int32_t rs2, jit_int32_t imm)
+{
+    instr_t    i;
+    assert(!(op  & ~0x7f));
+    assert(!(fct & ~0x07));
+    assert(!(rs1 & ~0x1f));
+    assert(!(rs2 & ~0x1f));
+    assert(!(imm & 1) && simm12_p(imm));
+    i.B.opcode = op;
+    i.B.imm11  = (imm >> 11) & 0x1;
+    i.B.imm4_1 = (imm >>  1) & 0xf;
+    i.B.funct3 = fct;
+    i.B.rs1    = rs1;
+    i.B.rs2    = rs2;
+    i.B.imm10_5        = (imm >>  5) & 0x3f;
+    i.B.imm12  = (imm >> 12) & 0x1;
+    ii(i.w);
+}
+
+static void
+_Utype(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd, jit_int32_t imm)
+{
+    instr_t    i;
+    assert(!(op        & ~0x7f));
+    assert(!(rd        & ~0x1f));
+    assert(simm20_p(imm));
+    i.U.opcode = op;
+    i.U.rd     = rd;
+    i.U.imm12_31= imm;
+    ii(i.w);
+}
+
+static void
+_Jtype(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd, jit_int32_t imm)
+{
+    instr_t    i;
+    assert(!(op & ~0x7f));
+    assert(!(rd & ~0x1f));
+    assert(!(imm & 1) && imm <= 1048575 && imm >= -1048576);
+    i.J.opcode = op;
+    i.J.rd     = rd;
+    i.J.imm19_12= (imm >> 12) &  0xff;
+    i.J.imm11  = (imm >> 11) &   0x1;
+    i.J.imm10_1        = (imm >>  1) & 0x3ff;
+    i.J.imm20  = (imm >> 20) &   0x1;
+    ii(i.w);
+}
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t im)
+{
+    for (; im > 0; im -= 4)
+       NOP();
+    assert(im == 0);
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (simm12_p(i0))
+       ADDI(r0, r1, i0);
+    else {
+       jit_int32_t     t0;
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       addr(r0, r1, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_addcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       t0 = jit_get_reg(jit_class_gpr);
+       addr(rn(t0), r1, r2);
+       SLTU(rn(jit_carry), rn(t0), r1);
+       movr(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    else {
+       addr(r0, r1, r2);
+       SLTU(rn(jit_carry), r0, r1);
+    }
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       t0 = jit_get_reg(jit_class_gpr);
+       addi(rn(t0), r1, i0);
+       SLTU(rn(jit_carry), rn(t0), r1);
+       movr(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    else {
+       addi(r0, r1, i0);
+       SLTU(rn(jit_carry), r0, r1);
+    }
+}
+
+static void
+_addxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+    assert(jit_carry != _NOREG);
+    t0 = jit_get_reg(jit_class_gpr);
+    movr(rn(t0), rn(jit_carry));
+    addcr(r0, r1, r2);
+    addcr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    assert(jit_carry != _NOREG);
+    t0 = jit_get_reg(jit_class_gpr);
+    movr(rn(t0), rn(jit_carry));
+    addci(r0, r1, i0);
+    addcr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (simm12_p(-i0))
+       ADDI(r0, r1, -i0);
+    else {
+       jit_int32_t     t0;
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       subr(r0, r1, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_subcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       t0 = jit_get_reg(jit_class_gpr);
+       subr(rn(t0), r1, r2);
+       SLTU(rn(jit_carry), r1, rn(t0));
+       movr(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    else {
+       subr(r0, r1, r2);
+       SLTU(rn(jit_carry), r1, r0);
+    }
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       t0 = jit_get_reg(jit_class_gpr);
+       subi(rn(t0), r1, i0);
+       SLTU(rn(jit_carry), r1, rn(t0));
+       movr(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+    else {
+       subi(r0, r1, i0);
+       SLTU(rn(jit_carry), r1, r0);
+    }
+}
+
+static void
+_subxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+    assert(jit_carry != _NOREG);
+    t0 = jit_get_reg(jit_class_gpr);
+    movr(rn(t0), rn(jit_carry));
+    subcr(r0, r1, r2);
+    subcr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    assert(jit_carry != _NOREG);
+    t0 = jit_get_reg(jit_class_gpr);
+    movr(rn(t0), rn(jit_carry));
+    subci(r0, r1, i0);
+    subcr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    subi(r0, r1, i0);
+    negr(r0, r0);
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    mulr(r0, r1, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    divr(r0, r1, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    divr_u(r0, r1, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    remr(r0, r1, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    remr_u(r0, r1, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_qmulr(jit_state_t *_jit, jit_int32_t r0,
+       jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                t0;
+    if (r0 == r2 || r0 == r3) {
+       t0 = jit_get_reg(jit_class_gpr);
+       mulr(rn(t0), r2, r3);
+    }
+    else
+       mulr(r0, r2, r3);
+    MULH(r1, r2, r3);
+    if (r0 == r2 || r0 == r3) {
+       movr(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_qmuli(jit_state_t *_jit, jit_int32_t r0,
+       jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    qmulr(r0, r1, r2, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_qmulr_u(jit_state_t *_jit, jit_int32_t r0,
+        jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                t0;
+    if (r0 == r2 || r0 == r3) {
+       t0 = jit_get_reg(jit_class_gpr);
+       mulr(rn(t0), r2, r3);
+    }
+    else
+       mulr(r0, r2, r3);
+    MULHU(r1, r2, r3);
+    if (r0 == r2 || r0 == r3) {
+       movr(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_qmuli_u(jit_state_t *_jit, jit_int32_t r0,
+        jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    qmulr_u(r0, r1, r2, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_iqdivr(jit_state_t *_jit, jit_bool_t sign,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                sv0, rg0;
+    jit_int32_t                sv1, rg1;
+    if (r0 == r2 || r0 == r3) {
+       sv0 = jit_get_reg(jit_class_gpr);
+       rg0 = rn(sv0);
+    }
+    else
+       rg0 = r0;
+    if (r1 == r2 || r1 == r3) {
+       sv1 = jit_get_reg(jit_class_gpr);
+       rg1 = rn(sv1);
+    }
+    else
+       rg1 = r1;
+    if (sign)
+       divr(rg0, r2, r3);
+    else
+       divr_u(rg0, r2, r3);
+    mulr(rg1, r3, rg0);
+    subr(rg1, r2, rg1);
+    if (rg0 != r0) {
+       movr(r0, rg0);
+       jit_unget_reg(sv0);
+    }
+    if (rg1 != r1) {
+       movr(r1, rg1);
+       jit_unget_reg(sv1);
+    }
+}
+
+static void
+_qdivi(jit_state_t *_jit, jit_int32_t r0,
+       jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    qdivr(r0, r1, r2, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_qdivi_u(jit_state_t *_jit, jit_int32_t r0,
+        jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    qdivr_u(r0, r1, r2, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else {
+       assert(i0 > 0 && i0 < 64);
+       SLLI(r0, r1, i0);
+    }
+}
+
+static void
+_rshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else {
+       assert(i0 > 0 && i0 < 64);
+       SRAI(r0, r1, i0);
+    }
+}
+
+static void
+_rshi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else {
+       assert(i0 > 0 && i0 < 64);
+       SRLI(r0, r1, i0);
+    }
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (simm12_p(i0))
+       ANDI(r0, r1, i0);
+    else {
+       jit_int32_t     t0;
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       andr(r0, r1, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (simm12_p(i0))
+       ORI(r0, r1, i0);
+    else {
+       jit_int32_t     t0;
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       orr(r0, r1, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (simm12_p(i0))
+       XORI(r0, r1, i0);
+    else {
+       jit_int32_t     t0;
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       xorr(r0, r1, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+#  define DEFLD(T,O)                                                   \
+static void                                                            \
+_ldi_##T(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)             \
+{                                                                      \
+    if (simm12_p(i0))                                                  \
+       L##O(r0, _ZERO_REGNO, i0);                                      \
+    else {                                                             \
+       jit_int32_t     t0;                                             \
+       t0 = jit_get_reg(jit_class_gpr);                                \
+       movi(rn(t0), i0);                                               \
+       ldr_##T(r0, rn(t0));                                            \
+       jit_unget_reg(t0);                                              \
+    }                                                                  \
+}                                                                      \
+                                                                       \
+static void                                                            \
+_ldxr_##T(jit_state_t *_jit,jit_int32_t r0,jit_int32_t r1,jit_int32_t r2)\
+{                                                                      \
+    jit_int32_t        t0;                                                     \
+    t0 = jit_get_reg(jit_class_gpr);                                   \
+    addr(rn(t0), r1, r2);                                              \
+    ldr_##T(r0, rn(t0));                                               \
+    jit_unget_reg(t0);                                                 \
+}                                                                      \
+                                                                       \
+static void                                                            \
+_ldxi_##T(jit_state_t *_jit,jit_int32_t r0,jit_int32_t r1,jit_word_t i0)\
+{                                                                      \
+    if (simm12_p(i0))                                                  \
+       L##O(r0, r1, i0);                                               \
+    else {                                                             \
+       jit_int32_t     t0;                                             \
+       t0 = jit_get_reg(jit_class_gpr);                                \
+       addi(rn(t0), r1, i0);                                           \
+       ldr_##T(r0, rn(t0));                                            \
+       jit_unget_reg(t0);                                              \
+    }                                                                  \
+}
+
+DEFLD(c,B)
+DEFLD(uc,BU)
+DEFLD(s,H)
+DEFLD(us,HU)
+DEFLD(i,W)
+DEFLD(ui,WU)
+DEFLD(l,D)
+
+#  define DEFST(T, O)                                                  \
+static void                                                            \
+_sti_##T(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)             \
+{                                                                      \
+    if (simm12_p(i0))                                                  \
+       S##O(_ZERO_REGNO, r0, i0);                                      \
+    else {                                                             \
+       jit_int32_t     t0;                                             \
+       t0 = jit_get_reg(jit_class_gpr);                                \
+       movi(rn(t0), i0);                                               \
+       str_##T(rn(t0), r0);                                            \
+       jit_unget_reg(t0);                                              \
+    }                                                                  \
+}                                                                      \
+                                                                       \
+static void                                                            \
+_stxr_##T(jit_state_t *_jit,jit_int32_t r0,jit_int32_t r1,jit_int32_t r2)\
+{                                                                      \
+    jit_int32_t        t0;                                                     \
+    t0 = jit_get_reg(jit_class_gpr);                                   \
+    addr(rn(t0), r0, r1);                                              \
+    str_##T(rn(t0), r2);                                               \
+    jit_unget_reg(t0);                                                 \
+}                                                                      \
+                                                                       \
+static void                                                            \
+_stxi_##T(jit_state_t *_jit,jit_word_t i0,jit_int32_t r0,jit_int32_t r1)\
+{                                                                      \
+    if (simm12_p(i0))                                                  \
+       S##O(r0, r1, i0);                                               \
+    else {                                                             \
+       jit_int32_t     t0;                                             \
+       t0 = jit_get_reg(jit_class_gpr);                                \
+       addi(rn(t0), r0, i0);                                           \
+       str_##T(rn(t0), r1);                                            \
+       jit_unget_reg(t0);                                              \
+    }                                                                  \
+}
+
+DEFST(c, B)
+DEFST(s, H)
+DEFST(i, W)
+DEFST(l, D)
+
+static void
+_htonr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    rshi(rn(t0), r1, 8);
+    andi(r0, r1, 0xff);
+    andi(rn(t0), rn(t0), 0xff);
+    lshi(r0, r0, 8);
+    orr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_htonr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    jit_int32_t                t1;
+    jit_int32_t                t2;
+    t0 = jit_get_reg(jit_class_gpr);
+    t1 = jit_get_reg(jit_class_gpr);
+    t2 = jit_get_reg(jit_class_gpr);
+    rshi(rn(t0), r1, 24);
+    rshi(rn(t1), r1, 16);
+    rshi(rn(t2), r1,  8);
+    andi(rn(t0), rn(t0), 0xff);
+    andi(rn(t1), rn(t1), 0xff);
+    andi(rn(t2), rn(t2), 0xff);
+    andi(r0, r1, 0xff);
+    lshi(r0, r0, 24);
+    lshi(rn(t1), rn(t1), 8);
+    orr(r0, r0, rn(t0));
+    lshi(rn(t2), rn(t2), 16);
+    orr(r0, r0, rn(t1));
+    orr(r0, r0, rn(t2));
+    jit_unget_reg(t2);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+}
+
+static void
+_htonr_ul(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    rshi_u(rn(t0), r1, 32);
+    htonr_ui(r0, r1);
+    htonr_ui(rn(t0), rn(t0));
+    lshi(r0, r0, 32);
+    orr(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_extr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 56);
+    rshi(r0, r0, 56);
+}
+
+static void
+_extr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 48);
+    rshi(r0, r0, 48);
+}
+
+static void
+_extr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 48);
+    rshi_u(r0, r0, 48);
+}
+
+static void
+_extr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, 32);
+    rshi_u(r0, r0, 32);
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    if (simm32_p(i0)) {
+       jit_int32_t     lo = (jit_int32_t)i0 << 20 >> 20;
+       jit_int32_t     hi = i0 - lo;
+       if (hi) {
+           LUI(r0, hi >> 12);
+           if (lo)
+               ADDIW(r0, r0, lo);
+       }
+       else
+           ADDIW(r0, _ZERO_REGNO, lo);
+    }
+    else {
+       jit_int32_t     lo = i0 << 32 >> 32;
+       jit_word_t      hi = i0 - lo;
+       jit_int32_t     t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), (jit_int32_t)(hi >> 32));
+       movi(r0, lo);
+       lshi(rn(t0), rn(t0), 32);
+       addr(r0, r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    jit_int32_t                ww = i0 << 32 >> 32;
+    jit_int32_t                lo = ww << 20 >> 20;
+    jit_int32_t                hi = ww - lo;
+    w = _jit->pc.w;
+    t0 = jit_get_reg(jit_class_gpr);
+    LUI(r0, hi >> 12);
+    ADDIW(r0, r0, lo);
+    ww = i0 >> 32;
+    lo = ww << 20 >> 20;
+    hi = ww - lo;
+    LUI(rn(t0), hi >> 12);
+    ADDIW(rn(t0), rn(t0), lo);
+    SLLI(rn(t0), rn(t0), 32);
+    ADD(r0, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static void
+_lti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (simm12_p(i0))
+       SLTI(r0, r1, i0);
+    else {
+       jit_int32_t     t0;
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(r0, i0);
+       ltr(r0, r1, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_lti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (simm12_p(i0))
+       SLTIU(r0, r1, i0);
+    else {
+       jit_int32_t     t0;
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(r0, i0);
+       ltr_u(r0, r1, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_ler(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SLT(r0, r2, r1);
+    XORI(r0, r0, 1);
+}
+
+static void
+_lei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    if (i0 == 0) {
+       SLT(r0, _ZERO_REGNO, r1);
+       XORI(r0, r0, 1);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       ler(r0, r1, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_ler_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SLTU(r0, r2, r1);
+    XORI(r0, r0, 1);
+}
+
+static void
+_lei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    if (i0 == 0) {
+       SLTU(r0, _ZERO_REGNO, r1);
+       XORI(r0, r0, 1);
+    }
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       ler_u(r0, r1, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_eqr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    subr(r0, r1, r2);
+    SLTU(r0, _ZERO_REGNO, r0);
+    XORI(r0, r0, 1);
+}
+
+static void
+_eqi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0) {
+       subi(r0, r1, i0);
+       SLTU(r0, _ZERO_REGNO, r0);
+    }
+    else
+       SLTU(r0, _ZERO_REGNO, r1);
+    XORI(r0, r0, 1);
+}
+
+static void
+_ger(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SLT(r0, r1, r2);
+    XORI(r0, r0, 1);
+}
+
+static void
+_gei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    ger(r0, r1, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_ger_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    SLTU(r0, r1, r2);
+    XORI(r0, r0, 1);
+}
+
+static void
+_gei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(rn(t0), i0);
+    ger_u(r0, r1, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_gti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t        t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(r0, i0);
+    ltr(r0, rn(t0), r1);
+    jit_unget_reg(t0);
+}
+
+static void
+_gti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t        t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    movi(r0, i0);
+    ltr_u(r0, rn(t0), r1);
+    jit_unget_reg(t0);
+}
+
+static void
+_ner(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    subr(r0, r1, r2);
+    SLTU(r0, _ZERO_REGNO, r0);
+}
+
+static void
+_nei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0) {
+       subi(r0, r1, i0);
+       SLTU(r0, _ZERO_REGNO, r0);
+    }
+    else
+       SLTU(r0, _ZERO_REGNO, r1);
+}
+
+static jit_word_t
+_bltr(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BLT(r0, r1, br - w);
+    return (w);
+}
+
+static jit_word_t
+_blti(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bltr(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bltr_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BLTU(r0, r1, br - w);
+    return (w);
+}
+
+static jit_word_t
+_blti_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bltr_u(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bler(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BGE(r1, r0, br - w);
+    return (w);
+}
+
+static jit_word_t
+_blei(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bler(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bler_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BGEU(r1, r0, br - w);
+    return (w);
+}
+
+static jit_word_t
+_blei_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bler_u(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_beqr(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BEQ(r1, r0, br - w);
+    return (w);
+}
+
+static jit_word_t
+_beqi(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = beqr(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bger(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BGE(r0, r1, br - w);
+    return (w);
+}
+
+static jit_word_t
+_bgei(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bger(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bger_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BGEU(r0, r1, br - w);
+    return (w);
+}
+
+static jit_word_t
+_bgei_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bger_u(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bgtr(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BLT(r1, r0, br - w);
+    return (w);
+}
+
+static jit_word_t
+_bgti(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bgtr(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bgtr_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BLTU(r1, r0, br - w);
+    return (w);
+}
+
+static jit_word_t
+_bgti_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bgtr_u(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bner(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+    BNE(r1, r0, br - w);
+    return (w);
+}
+
+static jit_word_t
+_bnei(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_reg_t          t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bner(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_boaddr(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, jal;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    /* t0 = r1 < 0; */
+    SLT(rn(t0), r1, _ZERO_REGNO);
+    /* t1 = r0 */
+    movr(rn(t1), r0);
+    /* r0 = r0 + r1 */
+    addr(r0, r0, r1);
+    /* overflow = r1 < 0 ? t1 < r0 : r0 < t1 */
+    w = _jit->pc.w;
+    BNE(rn(t0), _ZERO_REGNO, 0);
+    /* r1 >= 0 */
+    SLT(rn(t1), r0, rn(t1));
+    jal = _jit->pc.w;
+    JAL(_ZERO_REGNO, 0);
+    /* r1 < 0 */
+    patch_at(w, _jit->pc.w);
+    SLT(rn(t1), rn(t1), r0);
+    /**/
+    patch_at(jal, _jit->pc.w);
+    w = _jit->pc.w;
+    BNE(rn(t1), _ZERO_REGNO, br - w);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_boaddi(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = boaddr(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_boaddr_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    addr(rn(t0), r0, r1);
+    SLTU(rn(t1), rn(t0), r0);
+    movr(r0, rn(t0));
+    w = _jit->pc.w;
+    BNE(_ZERO_REGNO, rn(t1), br - w);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_boaddi_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = boaddr_u(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxaddr(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, jal;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    /* t0 = r1 < 0; */
+    SLT(rn(t0), r1, _ZERO_REGNO);
+    /* t1 = r0 */
+    movr(rn(t1), r0);
+    /* r0 = r0 + r1 */
+    addr(r0, r0, r1);
+    /* overflow = r1 < 0 ? t1 < r0 : r0 < t1 */
+    w = _jit->pc.w;
+    BNE(rn(t0), _ZERO_REGNO, 0);
+    /* r1 >= 0 */
+    SLT(rn(t1), r0, rn(t1));
+    jal = _jit->pc.w;
+    JAL(_ZERO_REGNO, 0);
+    /* r1 < 0 */
+    patch_at(w, _jit->pc.w);
+    SLT(rn(t1), rn(t1), r0);
+    /**/
+    patch_at(jal, _jit->pc.w);
+    w = _jit->pc.w;
+    BEQ(rn(t1), _ZERO_REGNO, br - w);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxaddi(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bxaddr(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxaddr_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    addr(rn(t0), r0, r1);
+    SLTU(rn(t1), rn(t0), r0);
+    movr(r0, rn(t0));
+    w = _jit->pc.w;
+    BEQ(_ZERO_REGNO, rn(t1), br - w);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxaddi_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bxaddr_u(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bosubr(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, jal;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    /* t0 = 0 < r1; */
+    SLT(rn(t0), _ZERO_REGNO, r1);
+    /* t1 = r0 */
+    movr(rn(t1), r0);
+    /* r0 = r0 - r1 */
+    subr(r0, r0, r1);
+    /* overflow = r1 < 0 ? t1 < r0 : r0 < t1 */
+    w = _jit->pc.w;
+    BNE(rn(t0), _ZERO_REGNO, 0);
+    /* r1 >= 0 */
+    SLT(rn(t1), r0, rn(t1));
+    jal = _jit->pc.w;
+    JAL(_ZERO_REGNO, 0);
+    /* r1 < 0 */
+    patch_at(w, _jit->pc.w);
+    SLT(rn(t1), rn(t1), r0);
+    /**/
+    patch_at(jal, _jit->pc.w);
+    w = _jit->pc.w;
+    BNE(rn(t1), _ZERO_REGNO, br - w);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bosubi(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bosubr(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bosubr_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    subr(rn(t0), r0, r1);
+    SLTU(rn(t1), r0, rn(t0));
+    movr(r0, rn(t0));
+    w = _jit->pc.w;
+    BNE(_ZERO_REGNO, rn(t1), br - w);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bosubi_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bosubr_u(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxsubr(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w, jal;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    /* t0 = r1 < 0; */
+    SLT(rn(t0), _ZERO_REGNO, r1);
+    /* t1 = r0 */
+    movr(rn(t1), r0);
+    /* r0 = r0 - r1 */
+    subr(r0, r0, r1);
+    /* overflow = r1 < 0 ? t1 < r0 : r0 < t1 */
+    w = _jit->pc.w;
+    BNE(rn(t0), _ZERO_REGNO, 0);
+    /* r1 >= 0 */
+    SLT(rn(t1), r0, rn(t1));
+    jal = _jit->pc.w;
+    JAL(_ZERO_REGNO, 0);
+    /* r1 < 0 */
+    patch_at(w, _jit->pc.w);
+    SLT(rn(t1), rn(t1), r0);
+    /**/
+    patch_at(jal, _jit->pc.w);
+    w = _jit->pc.w;
+    BEQ(rn(t1), _ZERO_REGNO, br - w);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxsubi(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bxsubr(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxsubr_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    t1 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    subr(rn(t0), r0, r1);
+    SLTU(rn(t1), r0, rn(t0));
+    movr(r0, rn(t0));
+    w = _jit->pc.w;
+    BEQ(_ZERO_REGNO, rn(t1), br - w);
+    jit_unget_reg(t1);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bxsubi_u(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bxsubr_u(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bmsr(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    AND(rn(t0), r0, r1);
+    w = _jit->pc.w;
+    BNE(_ZERO_REGNO, rn(t0), br - w);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bmsi(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bmsr(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bmcr(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    AND(rn(t0), r0, r1);
+    w = _jit->pc.w;
+    BEQ(_ZERO_REGNO, rn(t0), br - w);
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static jit_word_t
+_bmci(jit_state_t *_jit, jit_word_t br, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(t0), i0);
+    w = bmcr(br, r0, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static void
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    jit_word_t         dsp;
+    dsp = i0 - _jit->pc.w;
+    if (simm20_p(dsp))
+       JAL(_ZERO_REGNO, dsp);
+    else {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(t0), i0);
+       jmpr(rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static jit_word_t
+_jmpi_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    w = movi_p(rn(t0), i0);
+    jmpr(rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static void
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    jit_word_t         dsp;
+    dsp = i0 - _jit->pc.w;
+    if (simm20_p(dsp))
+       JAL(_RA_REGNO, dsp);
+    else {
+       t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(t0), i0);
+       callr(rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    w = movi_p(rn(t0), i0);
+    callr(rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                reg;
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar)
+       _jitc->function->self.aoff &= -16;
+    _jitc->function->stack = ((_jitc->function->self.alen -
+                             /* align stack at 16 bytes */
+                             _jitc->function->self.aoff) + 15) & -16;
+    subi(_SP_REGNO, _SP_REGNO, stack_framesize);
+    stxi(0, _SP_REGNO, _RA_REGNO);
+    stxi(8, _SP_REGNO, _FP_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S1))
+       stxi(16, _SP_REGNO, 9);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S2))
+       stxi(24, _SP_REGNO, 18);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S3))
+       stxi(32, _SP_REGNO, 19);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S4))
+       stxi(40, _SP_REGNO, 20);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S5))
+       stxi(48, _SP_REGNO, 21);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S6))
+       stxi(56, _SP_REGNO, 22);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S7))
+       stxi(64, _SP_REGNO, 23);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S8))
+       stxi(72, _SP_REGNO, 24);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S9))
+       stxi(80, _SP_REGNO, 25);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S10))
+       stxi(88, _SP_REGNO, 26);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S11))
+       stxi(96, _SP_REGNO, 27);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS0))
+       stxi_d(104, _SP_REGNO, 8);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS1))
+       stxi_d(112, _SP_REGNO, 9);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS2))
+       stxi_d(120, _SP_REGNO, 18);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS3))
+       stxi_d(128, _SP_REGNO, 19);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS4))
+       stxi_d(136, _SP_REGNO, 20);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS5))
+       stxi_d(144, _SP_REGNO, 21);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS6))
+       stxi_d(152, _SP_REGNO, 22);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS7))
+       stxi_d(160, _SP_REGNO, 23);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS8))
+       stxi_d(168, _SP_REGNO, 24);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS9))
+       stxi_d(176, _SP_REGNO, 25);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS10))
+       stxi_d(184, _SP_REGNO, 26);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS11))
+       stxi_d(192, _SP_REGNO, 27);
+    movr(_FP_REGNO, _SP_REGNO);
+    if (_jitc->function->stack)
+       subi(_SP_REGNO, _SP_REGNO, _jitc->function->stack);
+    if (_jitc->function->allocar) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+    }
+    if (_jitc->function->self.call & jit_call_varargs) {
+       for (reg = _jitc->function->vagp; jit_arg_reg_p(reg); ++reg)
+           stxi(stack_framesize - ((8 - reg) * 8),
+                _FP_REGNO, rn(JIT_RA0 - reg));
+    }
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    if (_jitc->function->assume_frame)
+       return;
+    movr(_SP_REGNO, _FP_REGNO);
+    ldxi(_RA_REGNO, _SP_REGNO, 0);
+    ldxi(_FP_REGNO, _SP_REGNO, 8);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S1))
+       ldxi(9, _SP_REGNO, 16);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S2))
+       ldxi(18, _SP_REGNO, 24);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S3))
+       ldxi(19, _SP_REGNO, 32);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S4))
+       ldxi(20, _SP_REGNO, 40);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S5))
+       ldxi(21, _SP_REGNO, 48);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S6))
+       ldxi(22, _SP_REGNO, 56);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S7))
+       ldxi(23, _SP_REGNO, 64);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S8))
+       ldxi(24, _SP_REGNO, 72);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S9))
+       ldxi(25, _SP_REGNO, 80);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S10))
+       ldxi(26, _SP_REGNO, 88);
+    if (jit_regset_tstbit(&_jitc->function->regset, _S11))
+       ldxi(27, _SP_REGNO, 96);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS0))
+       ldxi_d(8, _SP_REGNO, 104);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS1))
+       ldxi_d(9, _SP_REGNO, 112);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS2))
+       ldxi_d(18, _SP_REGNO, 120);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS3))
+       ldxi_d(19, _SP_REGNO, 128);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS4))
+       ldxi_d(20, _SP_REGNO, 136);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS5))
+       ldxi_d(21, _SP_REGNO, 144);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS6))
+       ldxi_d(22, _SP_REGNO, 152);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS7))
+       ldxi_d(23, _SP_REGNO, 160);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS8))
+       ldxi_d(24, _SP_REGNO, 168);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS9))
+       ldxi_d(25, _SP_REGNO, 176);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS10))
+       ldxi_d(26, _SP_REGNO, 184);
+    if (jit_regset_tstbit(&_jitc->function->regset, _FS11))
+       ldxi_d(27, _SP_REGNO, 192);
+    addi(_SP_REGNO, _SP_REGNO, stack_framesize);
+    RET();
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Initialize va_list to the first stack argument. */
+    if (jit_arg_reg_p(_jitc->function->vagp))
+       addi(r0, _FP_REGNO, stack_framesize - ((8 - _jitc->function->vagp) * 8));
+    else
+       addi(r0, _FP_REGNO, _jitc->function->self.size);
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Load argument. */
+    ldr(r0, r1);
+    /* Update va_list. */
+    addi(r1, r1, sizeof(jit_word_t));
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
+{
+    instr_t             i;
+    union {
+       jit_int32_t     *i;
+       jit_word_t       w;
+    } u;
+    u.w = instr;
+    i.w = u.i[0];
+    /* movi_p? */
+    if (i.U.opcode == 55) {                                    /* LUI */
+       jit_int32_t     ww = label << 32 >> 32;
+       jit_int32_t     lo = ww << 20 >> 20;
+       jit_int32_t     hi = ww - lo;
+       i.U.imm12_31 = hi >> 12;
+       u.i[0] = i.w;
+       i.w = u.i[1];
+       if (i.I.opcode == 27 && i.I.funct3 == 0) {              /* ADDIW */
+           i.I.imm11_0 = lo & 0xfff;
+           u.i[1] = i.w;
+           i.w = u.i[2];
+           if (i.U.opcode == 55) {                             /* LUI */
+               ww = label >> 32;
+               lo = ww << 20 >> 20;
+               hi = ww - lo;
+               i.U.imm12_31 = hi >> 12;
+               u.i[2] = i.w;
+               i.w = u.i[3];
+               if (i.I.opcode == 27 && i.I.funct3 == 0) {      /* ADDIW */
+                   i.I.imm11_0 = lo & 0xfff;
+                   u.i[3] = i.w;
+                   i.w = u.i[4];
+                   assert(i.IS.opcode == 19);                  /* SLLI */
+                   assert(i.IS.shamt == 32);
+                   i.w = u.i[5];
+                   assert(i.R.opcode == 51);                   /* ADD */
+               }
+               else
+                   abort();
+           }
+           else
+               abort();
+       }
+       else
+           abort();
+    }
+    /* b{lt,le,eq,ge,gt,ne}{,_u}? */
+    else if (i.B.opcode == 99) {               /* B{EQ,NE,LT,GE,LTU,GEU} */
+       jit_word_t jmp = label - instr;
+       assert(simm12_p(jmp));
+       i.B.imm11       = (jmp >> 11) & 0x1;
+       i.B.imm4_1      = (jmp >> 1) & 0xf;
+       i.B.imm10_5     = (jmp >> 5) & 0x3f;
+       i.B.imm12       = (jmp >> 12) & 0x1;
+       u.i[0] = i.w;
+    }
+    else if (i.J.opcode == 111) {              /* JAL */
+       jit_word_t jmp = label - instr;
+       i.J.imm19_12    = (jmp >> 12) &  0xff;
+       i.J.imm11       = (jmp >> 11) &   0x1;
+       i.J.imm10_1     = (jmp >>  1) & 0x3ff;
+       i.J.imm20       = (jmp >> 20) &   0x1;
+       u.i[0] = i.w;
+    }
+    else
+       abort();
+}
+#endif         /* CODE */
diff --git a/deps/lightning/lib/jit_riscv-fpu.c b/deps/lightning/lib/jit_riscv-fpu.c
new file mode 100644 (file)
index 0000000..367975e
--- /dev/null
@@ -0,0 +1,1271 @@
+/*
+ * Copyright (C) 2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+/*
+ * RV32F Standard Extension
+ */
+#  define FLW(rd, rs1, im)             Itype(7, rd, 2, rs1, im)
+#  define FSW(rs1, rs2, imm)           Stype(39, 2, rs1, rs2, imm)
+#  define FMADD_S(rd, rs1, rs2, rs3)   R4type(67, rd, 0, rs1, rs2, 0, rs3)
+#  define FMSUB_S(rd, rs1, rs2, rs3)   R4type(71, rd, 0, rs1, rs2, 0, rs3)
+#  define FNMSUB_S(rd, rs1, rs2, rs3)  R4type(75, rd, 0, rs1, rs2, 0, rs3)
+#  define FNMADD_S(rd, rs1, rs2, rs3)  R4type(79, rd, 0, rs1, rs2, 0, rs3)
+#  define FADD_S(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 0)
+#  define FSUB_S(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 4)
+#  define FMUL_S(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 8)
+#  define FDIV_S(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 12)
+#  define FSQRT_S(rd, rs1)             Rtype(83, rd, 0, rs1, 0, 44)
+#  define FSGNJ_S(rd, rs1, rs2)                Rtype(83, rd, 0, rs1, rs2, 16)
+#  define FSGNJN_S(rd, rs1, rs2)       Rtype(83, rd, 1, rs1, rs2, 16)
+#  define FSGNJX_S(rd, rs1, rs2)       Rtype(83, rd, 2, rs1, rs2, 16)
+#  define FMIN_S(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 20)
+#  define FMAX_S(rd, rs1, rs2)         Rtype(83, rd, 1, rs1, rs2, 20)
+#  define FCVT_W_S(rd, rs1)            Rtype(83, rd, 0, rs1, 0, 96)
+#  define FCVT_WU_S(rd, rs1)           Rtype(83, rd, 1, rs1, 1, 96)
+#  define FMV_X_W(rd, rs1)             Rtype(83, rd, 0, rs1, 0, 112)
+#  define FEQ_S(rd, rs1, rs2)          Rtype(83, rd, 2, rs1, rs2, 80)
+#  define FLT_S(rd, rs1, rs2)          Rtype(83, rd, 1, rs1, rs2, 80)
+#  define FLE_S(rd, rs1, rs2)          Rtype(83, rd, 0, rs1, rs2, 80)
+#  define FCLASS_S(rd, rs1)            Rtype(83, rd, 1, rs1, 0, 112)
+#  define FCVT_S_W(rd, rs1)            Rtype(83, rd, 0, rs1, 0, 104)
+#  define FCVT_S_WU(rd, rs1)           Rtype(83, rd, 0, rs1, 1, 104)
+#  define FMV_W_X(rd, rs1)             Rtype(83, rd, 0, rs1, 0, 120)
+/*
+ * RV64F Standard Extension (in addition to RV32F)
+ */
+#  define FCVT_L_S(rd, rs1)            Rtype(83, rd, 0, rs1, 2, 96)
+#  define FCVT_LU_S(rd, rs1)           Rtype(83, rd, 0, rs1, 3, 96)
+#  define FCVT_S_L(rd, rs1)            Rtype(83, rd, 0, rs1, 2, 104)
+#  define FCVT_S_LU(rd, rs1)           Rtype(83, rd, 0, rs1, 3, 104)
+/*
+ * RV32D Standard Extension
+ */
+#  define FLD(rd, rs1, im)             Itype(7, rd, 3, rs1, im)
+#  define FSD(rs1, rs2, imm)           Stype(39, 3, rs1, rs2, imm)
+#  define FMADD_D(rd, rs1, rs2, rs3)   R4type(67, rd, 0, rs1, rs2, 1, rs3)
+#  define FMSUB_D(rd, rs1, rs2, rs3)   R4type(71, rd, 0, rs1, rs2, 1, rs3)
+#  define FNMSUB_D(rd, rs1, rs2, rs3)  R4type(75, rd, 0, rs1, rs2, 1, rs3)
+#  define FNMADD_D(rd, rs1, rs2, rs3)  R4type(79, rd, 0, rs1, rs2, 1, rs3)
+#  define FADD_D(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 1)
+#  define FSUB_D(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 5)
+#  define FMUL_D(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 9)
+#  define FDIV_D(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 13)
+#  define FSQRT_D(rd, rs1)             Rtype(83, rd, 0, rs1, 0, 45)
+#  define FSGNJ_D(rd, rs1, rs2)                Rtype(83, rd, 0, rs1, rs2, 17)
+#  define FSGNJN_D(rd, rs1, rs2)       Rtype(83, rd, 1, rs1, rs2, 17)
+#  define FSGNJX_D(rd, rs1, rs2)       Rtype(83, rd, 2, rs1, rs2, 17)
+#  define FMIN_D(rd, rs1, rs2)         Rtype(83, rd, 0, rs1, rs2, 21)
+#  define FMAX_D(rd, rs1, rs2)         Rtype(83, rd, 1, rs1, rs2, 21)
+#  define FCVT_S_D(rd, rs1)            Rtype(83, rd, 0, rs1, 1, 32)
+#  define FCVT_D_S(rd, rs1)            Rtype(83, rd, 0, rs1, 0, 33)
+#  define FEQ_D(rd, rs1, rs2)          Rtype(83, rd, 2, rs1, rs2, 81)
+#  define FLT_D(rd, rs1, rs2)          Rtype(83, rd, 1, rs1, rs2, 81)
+#  define FLE_D(rd, rs1, rs2)          Rtype(83, rd, 0, rs1, rs2, 81)
+#  define FCLASS_D(rd, rs1)            Rtype(83, rd, 1, rs1, 0, 113)
+#  define FCVT_W_D(rd, rs1)            Rtype(83, rd, 0, rs1, 0, 97)
+#  define FCVT_WU_D(rd, rs1)           Rtype(83, rd, 0, rs1, 1, 97)
+#  define FCVT_D_W(rd, rs1)            Rtype(83, rd, 0, rs1, 0, 105)
+#  define FCVT_D_WU(rd, rs1)           Rtype(83, rd, 0, rs1, 1, 105)
+/*
+ * RV64D Standard Extension (in addition to RV32D)
+ */
+#  define FCVT_L_D(rd, rs1)            Rtype(83, rd, 0, rs1, 2, 97)
+#  define FCVT_LU_D(rd, rs1)           Rtype(83, rd, 0, rs1, 3, 97)
+#  define FMV_X_D(rd, rs1)             Rtype(83, rd, 0, rs1, 0, 113)
+#  define FCVT_D_L(rd, rs1)            Rtype(83, rd, 0, rs1, 2, 105)
+#  define FCVT_D_LU(rd, rs1)           Rtype(83, rd, 0, rs1, 3, 105)
+#  define FMV_D_X(rd, rs1)             Rtype(83, rd, 0, rs1, 0, 121)
+/*
+ * Pseudo instructions
+ */
+#  define FMV_S(r0, r1)                        FSGNJ_S(r0, r1, r1)
+#  define FABS_S(r0, r1)               FSGNJX_S(r0, r1, r1)
+#  define FNEG_S(r0, r1)               FSGNJN_S(r0, r1, r1)
+#  define FMV_D(r0, r1)                        FSGNJ_D(r0, r1, r1)
+#  define FABS_D(r0, r1)               FSGNJX_D(r0, r1, r1)
+#  define FNEG_D(r0, r1)               FSGNJN_D(r0, r1, r1)
+
+/*
+ * Lightning instructions
+ */
+#  define truncr_f_i(r0, r1)           FCVT_W_S(r0, r1)
+#  define truncr_d_i(r0, r1)           FCVT_W_D(r0, r1)
+#  define truncr_f_l(r0, r1)           FCVT_L_S(r0, r1)
+#  define truncr_d_l(r0, r1)           FCVT_L_D(r0, r1)
+#  define addr_f(r0, r1, r2)           FADD_S(r0, r1, r2)
+#  define addi_f(r0, r1, im)           _addi_f(_jit, r0, r1, im)
+static void _addi_f(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define subr_f(r0, r1, r2)           FSUB_S(r0, r1, r2)
+#  define subi_f(r0, r1, im)           _subi_f(_jit, r0, r1, im)
+static void _subi_f(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define rsbr_f(r0, r1, r2)           FSUB_S(r0, r2, r1)
+#  define rsbi_f(r0, r1, im)           _rsbi_f(_jit, r0, r1, im)
+static void _rsbi_f(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define mulr_f(r0, r1, r2)           FMUL_S(r0, r1, r2)
+#  define muli_f(r0, r1, im)           _muli_f(_jit, r0, r1, im)
+static void _muli_f(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define divr_f(r0, r1, r2)           FDIV_S(r0, r1, r2)
+#  define divi_f(r0, r1, im)           _divi_f(_jit, r0, r1, im)
+static void _divi_f(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float32_t);
+#  define absr_f(r0, r1)               FABS_S(r0, r1)
+#  define negr_f(r0, r1)               FNEG_S(r0, r1)
+#  define sqrtr_f(r0, r1)              FSQRT_S(r0, r1)
+#  define extr_f(r0, r1)               FCVT_S_L(r0, r1)
+#  define ldr_f(r0, r1)                        FLW(r0, r1, 0)
+#  define ldi_f(r0, im)                        _ldi_f(_jit, r0, im)
+static void _ldi_f(jit_state_t*, jit_int32_t, jit_word_t);
+#  define ldxr_f(r0, r1, r2)           _ldxr_f(_jit, r0, r1, r2)
+static void _ldxr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ldxi_f(r0, r1, i0)           _ldxi_f(_jit, r0, r1, i0)
+static void _ldxi_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define str_f(r0, r1)                        FSW(r0, r1, 0)
+#  define sti_f(im, r0)                        _sti_f(_jit, im, r0)
+static void _sti_f(jit_state_t*, jit_word_t, jit_int32_t);
+#  define stxr_f(r0, r1, r2)           _stxr_f(_jit, r0, r1, r2)
+static void _stxr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define stxi_f(im, r0, r1)           _stxi_f(_jit, im, r0, r1)
+static void _stxi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define movr_f(r0, r1)               FMV_S(r0, r1)
+#  define movi_f(r0, im)               _movi_f(_jit, r0, im)
+static void _movi_f(jit_state_t*, jit_int32_t, jit_float32_t);
+#  define movr_f_w(r0, r1)             FMV_X_W(r0, r1)
+#  define movi_f_w(r0, im)             _movi_f_w(_jit, r0, im)
+static void _movi_f_w(jit_state_t*, jit_int32_t, jit_float32_t);
+#  define movr_w_f(r0, r1)             FMV_W_X(r0, r1)
+#  define extr_d_f(r0, r1)             FCVT_S_D(r0, r1)
+#  define ltr_f(r0, r1, r2)            FLT_S(r0, r1, r2)
+#  define lti_f(r0, r1, im)            _lti_f(_jit, r0, r1, im)
+static void _lti_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define ler_f(r0, r1, r2)            FLE_S(r0, r1, r2)
+#  define lei_f(r0, r1, im)            _lei_f(_jit, r0, r1, im)
+static void _lei_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define eqr_f(r0, r1, r2)            FEQ_S(r0, r1, r2)
+#  define eqi_f(r0, r1, im)            _eqi_f(_jit, r0, r1, im)
+static void _eqi_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define ger_f(r0, r1, r2)            FLE_S(r0, r2, r1)
+#  define gei_f(r0, r1, im)            _gei_f(_jit, r0, r1, im)
+static void _gei_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define gtr_f(r0, r1, r2)            FLT_S(r0, r2, r1)
+#  define gti_f(r0, r1, im)            _gti_f(_jit, r0, r1, im)
+static void _gti_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define ner_f(r0, r1, r2)            _ner_f(_jit, r0, r1, r2)
+static void _ner_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define nei_f(r0, r1, im)            _nei_f(_jit, r0, r1, im)
+static void _nei_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define unltr_f(r0, r1, r2)          _unltr_f(_jit, r0, r1, r2)
+static void _unltr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define unlti_f(r0, r1, im)          _unlti_f(_jit, r0, r1, im)
+static void _unlti_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define unler_f(r0, r1, r2)          _unler_f(_jit, r0, r1, r2)
+static void _unler_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define unlei_f(r0, r1, im)          _unlei_f(_jit, r0, r1, im)
+static void _unlei_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define uneqr_f(r0, r1, r2)          _uneqr_f(_jit, r0, r1, r2)
+static void _uneqr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define uneqi_f(r0, r1, im)          _uneqi_f(_jit, r0, r1, im)
+static void _uneqi_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define unger_f(r0, r1, r2)          _unger_f(_jit, r0, r1, r2)
+static void _unger_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ungei_f(r0, r1, im)          _ungei_f(_jit, r0, r1, im)
+static void _ungei_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define ungtr_f(r0, r1, r2)          _ungtr_f(_jit, r0, r1, r2)
+static void _ungtr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ungti_f(r0, r1, im)          _ungti_f(_jit, r0, r1, im)
+static void _ungti_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define ltgtr_f(r0, r1, r2)          _ltgtr_f(_jit, r0, r1, r2)
+static void _ltgtr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ltgti_f(r0, r1, im)          _ltgti_f(_jit, r0, r1, im)
+static void _ltgti_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define ordr_f(r0, r1, r2)           _ordr_f(_jit, r0, r1, r2)
+static void _ordr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ordi_f(r0, r1, im)           _ordi_f(_jit, r0, r1, im)
+static void _ordi_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define unordr_f(r0, r1, r2)         _unordr_f(_jit, r0, r1, r2)
+static void _unordr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define unordi_f(r0, r1, im)         _unordi_f(_jit, r0, r1, im)
+static void _unordi_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_float32_t);
+#  define bltr_f(br, r0, r1)           _bltr_f(_jit,br,r0,r1)
+static jit_word_t _bltr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti_f(br, r0, im)           _blti_f(_jit,br,r0,im)
+static jit_word_t _blti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bler_f(br, r0, r1)           _bler_f(_jit,br,r0,r1)
+static jit_word_t _bler_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei_f(br, r0, im)           _blei_f(_jit,br,r0,im)
+static jit_word_t _blei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define beqr_f(br, r0, r1)           _beqr_f(_jit,br,r0,r1)
+static jit_word_t _beqr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define beqi_f(br, r0, im)           _beqi_f(_jit,br,r0,im)
+static jit_word_t _beqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bger_f(br, r0, r1)           _bger_f(_jit,br,r0,r1)
+static jit_word_t _bger_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei_f(br, r0, im)           _bgei_f(_jit,br,r0,im)
+static jit_word_t _bgei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bgtr_f(br, r0, r1)           _bgtr_f(_jit,br,r0,r1)
+static jit_word_t _bgtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti_f(br, r0, im)           _bgti_f(_jit,br,r0,im)
+static jit_word_t _bgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bner_f(br, r0, r1)           _bner_f(_jit,br,r0,r1)
+static jit_word_t _bner_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bnei_f(br, r0, im)           _bnei_f(_jit,br,r0,im)
+static jit_word_t _bnei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bunltr_f(br, r0, r1)         _bunltr_f(_jit,br,r0,r1)
+static jit_word_t _bunltr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlti_f(br, r0, im)         _bunlti_f(_jit,br,r0,im)
+static jit_word_t _bunlti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bunler_f(br, r0, r1)         _bunler_f(_jit,br,r0,r1)
+static jit_word_t _bunler_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlei_f(br, r0, im)         _bunlei_f(_jit,br,r0,im)
+static jit_word_t _bunlei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define buneqr_f(br, r0, r1)         _buneqr_f(_jit,br,r0,r1)
+static jit_word_t _buneqr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define buneqi_f(br, r0, im)         _buneqi_f(_jit,br,r0,im)
+static jit_word_t _buneqi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bunger_f(br, r0, r1)         _bunger_f(_jit,br,r0,r1)
+static jit_word_t _bunger_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungei_f(br, r0, im)         _bungei_f(_jit,br,r0,im)
+static jit_word_t _bungei_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bungtr_f(br, r0, r1)         _bungtr_f(_jit,br,r0,r1)
+static jit_word_t _bungtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungti_f(br, r0, im)         _bungti_f(_jit,br,r0,im)
+static jit_word_t _bungti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bltgtr_f(br, r0, r1)         _bltgtr_f(_jit,br,r0,r1)
+static jit_word_t _bltgtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bltgti_f(br, r0, im)         _bltgti_f(_jit,br,r0,im)
+static jit_word_t _bltgti_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bordr_f(br, r0, r1)          _bordr_f(_jit,br,r0,r1)
+static jit_word_t _bordr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bordi_f(br, r0, im)          _bordi_f(_jit,br,r0,im)
+static jit_word_t _bordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define bunordr_f(br, r0, r1)                _bunordr_f(_jit,br,r0,r1)
+static jit_word_t _bunordr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunordi_f(br, r0, im)                _bunordi_f(_jit,br,r0,im)
+static jit_word_t _bunordi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_float32_t);
+#  define addr_d(r0, r1, r2)           FADD_D(r0, r1, r2)
+#  define addi_d(r0, r1, im)           _addi_d(_jit, r0, r1, im)
+static void _addi_d(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define subr_d(r0, r1, r2)           FSUB_D(r0, r1, r2)
+#  define subi_d(r0, r1, im)           _subi_d(_jit, r0, r1, im)
+static void _subi_d(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define rsbr_d(r0, r1, r2)           FSUB_D(r0, r2, r1)
+#  define rsbi_d(r0, r1, im)           _rsbi_d(_jit, r0, r1, im)
+static void _rsbi_d(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define mulr_d(r0, r1, r2)           FMUL_D(r0, r1, r2)
+#  define muli_d(r0, r1, im)           _muli_d(_jit, r0, r1, im)
+static void _muli_d(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define divr_d(r0, r1, r2)           FDIV_D(r0, r1, r2)
+#  define divi_d(r0, r1, im)           _divi_d(_jit, r0, r1, im)
+static void _divi_d(jit_state_t *_jit,jit_int32_t,jit_int32_t,jit_float64_t);
+#  define absr_d(r0, r1)               FABS_D(r0, r1)
+#  define negr_d(r0, r1)               FNEG_D(r0, r1)
+#  define sqrtr_d(r0, r1)              FSQRT_D(r0, r1)
+#  define extr_d(r0, r1)               FCVT_D_L(r0, r1)
+#  define ldr_d(r0, r1)                        FLD(r0, r1, 0)
+#  define ldi_d(r0, im)                        _ldi_d(_jit, r0, im)
+static void _ldi_d(jit_state_t*, jit_int32_t, jit_word_t);
+#  define ldxr_d(r0, r1, r2)           _ldxr_d(_jit, r0, r1, r2)
+static void _ldxr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ldxi_d(r0, r1, i0)           _ldxi_d(_jit, r0, r1, i0)
+static void _ldxi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define str_d(r0, r1)                        FSD(r0, r1, 0)
+#  define sti_d(im, r0)                        _sti_d(_jit, im, r0)
+static void _sti_d(jit_state_t*, jit_word_t, jit_int32_t);
+#  define stxr_d(r0, r1, r2)           _stxr_d(_jit, r0, r1, r2)
+static void _stxr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define stxi_d(im, r0, r1)           _stxi_d(_jit, im, r0, r1)
+static void _stxi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define movr_d(r0, r1)               FMV_D(r0, r1)
+#  define movi_d(r0, im)               _movi_d(_jit, r0, im)
+static void _movi_d(jit_state_t*, jit_int32_t, jit_float64_t);
+#  define movr_d_w(r0, r1)             FMV_X_D(r0, r1)
+#  define movi_d_w(r0, im)             _movi_d_w(_jit, r0, im)
+static void _movi_d_w(jit_state_t*, jit_int32_t, jit_float64_t);
+#  define movr_w_d(r0, r1)             FMV_D_X(r0, r1)
+#  define extr_f_d(r0, r1)             FCVT_D_S(r0, r1)
+#  define ltr_d(r0, r1, r2)            FLT_D(r0, r1, r2)
+#  define lti_d(r0, r1, r2)            _lti_d(_jit, r0, r1, r2)
+static void _lti_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define ler_d(r0, r1, r2)            FLE_D(r0, r1, r2)
+#  define lei_d(r0, r1, r2)            _lei_d(_jit, r0, r1, r2)
+static void _lei_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define eqr_d(r0, r1, r2)            FEQ_D(r0, r1, r2)
+#  define eqi_d(r0, r1, r2)            _eqi_d(_jit, r0, r1, r2)
+static void _eqi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define ger_d(r0, r1, r2)            FLE_D(r0, r2, r1)
+#  define gei_d(r0, r1, r2)            _gei_d(_jit, r0, r1, r2)
+static void _gei_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define gtr_d(r0, r1, r2)            FLT_D(r0, r2, r1)
+#  define gti_d(r0, r1, r2)            _gti_d(_jit, r0, r1, r2)
+static void _gti_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define ner_d(r0, r1, r2)            _ner_d(_jit, r0, r1, r2)
+static void _ner_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define nei_d(r0, r1, r2)            _nei_d(_jit, r0, r1, r2)
+static void _nei_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define unltr_d(r0, r1, r2)          _unltr_d(_jit, r0, r1, r2)
+static void _unltr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define unlti_d(r0, r1, im)          _unlti_d(_jit, r0, r1, im)
+static void _unlti_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define unler_d(r0, r1, r2)          _unler_d(_jit, r0, r1, r2)
+static void _unler_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define unlei_d(r0, r1, im)          _unlei_d(_jit, r0, r1, im)
+static void _unlei_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define uneqr_d(r0, r1, r2)          _uneqr_d(_jit, r0, r1, r2)
+static void _uneqr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define uneqi_d(r0, r1, im)          _uneqi_d(_jit, r0, r1, im)
+static void _uneqi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define unger_d(r0, r1, r2)          _unger_d(_jit, r0, r1, r2)
+static void _unger_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ungei_d(r0, r1, im)          _ungei_d(_jit, r0, r1, im)
+static void _ungei_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define ungtr_d(r0, r1, r2)          _ungtr_d(_jit, r0, r1, r2)
+static void _ungtr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ungti_d(r0, r1, im)          _ungti_d(_jit, r0, r1, im)
+static void _ungti_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define ltgtr_d(r0, r1, r2)          _ltgtr_d(_jit, r0, r1, r2)
+static void _ltgtr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ltgti_d(r0, r1, im)          _ltgti_d(_jit, r0, r1, im)
+static void _ltgti_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define ordr_d(r0, r1, r2)           _ordr_d(_jit, r0, r1, r2)
+static void _ordr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ordi_d(r0, r1, im)           _ordi_d(_jit, r0, r1, im)
+static void _ordi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define unordr_d(r0, r1, r2)         _unordr_d(_jit, r0, r1, r2)
+static void _unordr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define unordi_d(r0, r1, im)         _unordi_d(_jit, r0, r1, im)
+static void _unordi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_float64_t);
+#  define bltr_d(br, r0, r1)           _bltr_d(_jit,br,r0,r1)
+static jit_word_t _bltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blti_d(br, r0, im)           _blti_d(_jit,br,r0,im)
+static jit_word_t _blti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bler_d(br, r0, r1)           _bler_d(_jit,br,r0,r1)
+static jit_word_t _bler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define blei_d(br, r0, im)           _blei_d(_jit,br,r0,im)
+static jit_word_t _blei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define beqr_d(br, r0, r1)           _beqr_d(_jit,br,r0,r1)
+static jit_word_t _beqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define beqi_d(br, r0, im)           _beqi_d(_jit,br,r0,im)
+static jit_word_t _beqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bger_d(br, r0, r1)           _bger_d(_jit,br,r0,r1)
+static jit_word_t _bger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgei_d(br, r0, im)           _bgei_d(_jit,br,r0,im)
+static jit_word_t _bgei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bgtr_d(br, r0, r1)           _bgtr_d(_jit,br,r0,r1)
+static jit_word_t _bgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bgti_d(br, r0, im)           _bgti_d(_jit,br,r0,im)
+static jit_word_t _bgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bner_d(br, r0, r1)           _bner_d(_jit,br,r0,r1)
+static jit_word_t _bner_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bnei_d(br, r0, im)           _bnei_d(_jit,br,r0,im)
+static jit_word_t _bnei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bunltr_d(br, r0, r1)         _bunltr_d(_jit,br,r0,r1)
+static jit_word_t _bunltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlti_d(br, r0, im)         _bunlti_d(_jit,br,r0,im)
+static jit_word_t _bunlti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bunler_d(br, r0, r1)         _bunler_d(_jit,br,r0,r1)
+static jit_word_t _bunler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunlei_d(br, r0, im)         _bunlei_d(_jit,br,r0,im)
+static jit_word_t _bunlei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define buneqr_d(br, r0, r1)         _buneqr_d(_jit,br,r0,r1)
+static jit_word_t _buneqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define buneqi_d(br, r0, im)         _buneqi_d(_jit,br,r0,im)
+static jit_word_t _buneqi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bunger_d(br, r0, r1)         _bunger_d(_jit,br,r0,r1)
+static jit_word_t _bunger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungei_d(br, r0, im)         _bungei_d(_jit,br,r0,im)
+static jit_word_t _bungei_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bungtr_d(br, r0, r1)         _bungtr_d(_jit,br,r0,r1)
+static jit_word_t _bungtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bungti_d(br, r0, im)         _bungti_d(_jit,br,r0,im)
+static jit_word_t _bungti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bltgtr_d(br, r0, r1)         _bltgtr_d(_jit,br,r0,r1)
+static jit_word_t _bltgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bltgti_d(br, r0, im)         _bltgti_d(_jit,br,r0,im)
+static jit_word_t _bltgti_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bordr_d(br, r0, r1)          _bordr_d(_jit,br,r0,r1)
+static jit_word_t _bordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bordi_d(br, r0, im)          _bordi_d(_jit,br,r0,im)
+static jit_word_t _bordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define bunordr_d(br, r0, r1)                _bunordr_d(_jit,br,r0,r1)
+static jit_word_t _bunordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bunordi_d(br, r0, im)                _bunordi_d(_jit,br,r0,im)
+static jit_word_t _bunordi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_float64_t);
+#  define vaarg_d(r0, r1)              _vaarg_d(_jit, r0, r1)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif /* PROTO */
+
+#if CODE
+#  define fpr_opi(name, type, size)                                    \
+static void                                                            \
+_##name##i_##type(jit_state_t *_jit,                                   \
+                 jit_int32_t r0, jit_int32_t r1,                       \
+                 jit_float##size##_t i0)                               \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    movi_##type(rn(reg), i0);                                          \
+    name##r_##type(r0, r1, rn(reg));                                   \
+    jit_unget_reg(reg);                                                        \
+}
+#  define fopi(name)                   fpr_opi(name, f, 32)
+#  define dopi(name)                   fpr_opi(name, d, 64)
+
+fopi(add)
+fopi(sub)
+fopi(rsb)
+fopi(mul)
+fopi(div)
+
+static void
+_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    if (simm12_p(i0))
+       FLW(r0, _ZERO_REGNO, i0);
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       ldr_f(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    addr(rn(t0), r1, r2);
+    ldr_f(r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    if (simm12_p(i0))
+       FLW(r0, r1, i0);
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       addi(rn(t0), r1, i0);
+       ldr_f(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                t0;
+    if (simm12_p(i0))
+       FSW(r0, _ZERO_REGNO, i0);
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       str_f(rn(t0), r0);
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    addr(rn(t0), r0, r1);
+    str_f(rn(t0), r2);
+    jit_unget_reg(t0);
+}
+
+static void
+_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    if (simm12_p(i0))
+       FSW(r0, r1, i0);
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       addi(rn(t0), r0, i0);
+       str_f(rn(t0), r1);
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t i0)
+{
+    union {
+       jit_int32_t      i;
+       jit_float32_t    f;
+    } data;
+    jit_int32_t                 reg;
+    data.f = i0;
+    if (data.i == 0)
+       movr_w_f(r0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.i);
+       movr_w_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_movi_f_w(jit_state_t *_jit, jit_int32_t r0, jit_float32_t i0)
+{
+    union {
+       jit_int32_t     i;
+       jit_float32_t   f;
+    } data;
+    data.f = i0;
+    movi(r0, data.i);
+}
+
+fopi(lt)
+fopi(le)
+fopi(eq)
+fopi(ge)
+fopi(gt)
+
+static void
+_ner_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    eqr_f(r0, r1, r2);
+    xori(r0, r0, 1);
+}
+fopi(ne)
+
+#  define fpr_bopi(name, type, size)                                   \
+static jit_word_t                                                      \
+_b##name##i_##type(jit_state_t *_jit,                                  \
+                 jit_word_t i0, jit_int32_t r0,                        \
+                 jit_float##size##_t i1)                               \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|                \
+                                         jit_class_nospill);           \
+    movi_##type(rn(reg), i1);                                          \
+    word = b##name##r_##type(i0, r0, rn(reg));                         \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+#  define fbopi(name)                  fpr_bopi(name, f, 32)
+#  define dbopi(name)                  fpr_bopi(name, d, 64)
+
+#  define unop(CLASS, OP)                                              \
+    jit_word_t         w;                                              \
+    jit_int32_t                t0, t1;                                         \
+    t0 = jit_get_reg(jit_class_gpr);                                   \
+    FCLASS_##CLASS(rn(t0), r1);                                                \
+    t1 = jit_get_reg(jit_class_gpr);                                   \
+    FCLASS_##CLASS(rn(t1), r2);                                                \
+    orr(rn(t0), rn(t0), rn(t1));                                       \
+    jit_unget_reg(t1);                                                 \
+    rshi(rn(t0), rn(t0), 8);                                           \
+    ltr(r0, _ZERO_REGNO, rn(t0));                                      \
+    jit_unget_reg(t0);                                                 \
+    w = _jit->pc.w;                                                    \
+    BLT(_ZERO_REGNO, r0, 0);                                           \
+    OP(r0, r1, r2);                                                    \
+    patch_at(w, _jit->pc.w)
+
+static void
+_unltr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(S, ltr_f);
+}
+fopi(unlt)
+
+static void
+_unler_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(S, ler_f);
+}
+fopi(unle)
+
+static void
+_uneqr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(S, eqr_f);
+}
+fopi(uneq)
+
+static void
+_unger_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(S, ger_f);
+}
+fopi(unge)
+
+static void
+_ungtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(S, gtr_f);
+}
+fopi(ungt)
+
+static void
+_ltgtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w0, w1;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr);
+    FCLASS_S(rn(t0), r1);
+    t1 = jit_get_reg(jit_class_gpr);
+    FCLASS_S(rn(t1), r2);
+    orr(rn(t0), rn(t0), rn(t1));
+    jit_unget_reg(t1);
+    rshi(rn(t0), rn(t0), 8);
+    ltr(r0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    w0 = _jit->pc.w;
+    BEQ(_ZERO_REGNO, r0, 0);
+    movr(r0, _ZERO_REGNO);
+    w1 = _jit->pc.w;
+    JAL(_ZERO_REGNO, 0);
+    patch_at(w0, _jit->pc.w);
+    ner_f(r0, r1, r2);
+    patch_at(w1, _jit->pc.w);
+}
+fopi(ltgt)
+
+static void
+_ordr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0, t1; 
+    t0 = jit_get_reg(jit_class_gpr);
+    FCLASS_S(rn(t0), r1);
+    t1 = jit_get_reg(jit_class_gpr);
+    FCLASS_S(rn(t1), r2);
+    orr(rn(t0), rn(t0), rn(t1));
+    jit_unget_reg(t1);
+    rshi(rn(t0), rn(t0), 8);
+    eqr(r0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+}
+fopi(ord)
+
+static void
+_unordr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0, t1; 
+    t0 = jit_get_reg(jit_class_gpr);
+    FCLASS_S(rn(t0), r1);
+    t1 = jit_get_reg(jit_class_gpr);
+    FCLASS_S(rn(t1), r2);
+    orr(rn(t0), rn(t0), rn(t1));
+    jit_unget_reg(t1);
+    rshi(rn(t0), rn(t0), 8);
+    ltr(r0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+}
+fopi(unord)
+
+static jit_word_t
+_bltr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ltr_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(lt)
+
+static jit_word_t
+_bler_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ler_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(le)
+
+static jit_word_t
+_beqr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    eqr_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(eq)
+
+static jit_word_t
+_bger_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ger_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(ge)
+
+static jit_word_t
+_bgtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    gtr_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(gt)
+
+static jit_word_t
+_bner_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    eqr_f(rn(t0), r1, r2);
+    w = beqr(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(ne)
+
+static jit_word_t
+_bunltr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    unltr_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(unlt)
+
+static jit_word_t
+_bunler_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    unler_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(unle)
+
+static jit_word_t
+_buneqr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    uneqr_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(uneq)
+
+static jit_word_t
+_bunger_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    unger_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(unge)
+
+static jit_word_t
+_bungtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ungtr_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(ungt)
+
+static jit_word_t
+_bltgtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ltgtr_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(ltgt)
+
+static jit_word_t
+_bordr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ordr_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(ord)
+
+static jit_word_t
+_bunordr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    unordr_f(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+fbopi(unord)
+
+dopi(add)
+dopi(sub)
+dopi(rsb)
+dopi(mul)
+dopi(div)
+
+static void
+_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    if (simm12_p(i0))
+       FLD(r0, _ZERO_REGNO, i0);
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       ldr_d(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    addr(rn(t0), r1, r2);
+    ldr_d(r0, rn(t0));
+    jit_unget_reg(t0);
+}
+
+static void
+_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                t0;
+    if (simm12_p(i0))
+       FLD(r0, r1, i0);
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       addi(rn(t0), r1, i0);
+       ldr_d(r0, rn(t0));
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                t0;
+    if (simm12_p(i0))
+       FSD(r0, _ZERO_REGNO, i0);
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       movi(rn(t0), i0);
+       str_d(rn(t0), r0);
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr);
+    addr(rn(t0), r0, r1);
+    str_d(rn(t0), r2);
+    jit_unget_reg(t0);
+}
+
+static void
+_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0;
+    if (simm12_p(i0))
+       FSD(r0, r1, i0);
+    else {
+       t0 = jit_get_reg(jit_class_gpr);
+       addi(rn(t0), r0, i0);
+       str_d(rn(t0), r1);
+       jit_unget_reg(t0);
+    }
+}
+
+static void
+_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t i0)
+{
+    union {
+       jit_word_t       w;
+       jit_float64_t    d;
+    } data;
+    jit_int32_t                 reg;
+    data.d = i0;
+    if (data.w == 0)
+       movr_w_d(r0, _ZERO_REGNO);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.w);
+       movr_w_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_movi_d_w(jit_state_t *_jit, jit_int32_t r0, jit_float64_t i0)
+{
+    union {
+       jit_int64_t     l;
+       jit_float64_t   d;
+    } data;
+    data.d = i0;
+    movi(r0, data.l);
+}
+
+dopi(lt)
+dopi(le)
+dopi(eq)
+dopi(ge)
+dopi(gt)
+
+static void
+_ner_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    eqr_d(r0, r1, r2);
+    xori(r0, r0, 1);
+}
+dopi(ne)
+
+static void
+_unltr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(D, ltr_d);
+}
+dopi(unlt)
+
+static void
+_unler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(D, ler_d);
+}
+dopi(unle)
+
+static void
+_uneqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(D, eqr_d);
+}
+dopi(uneq)
+
+static void
+_unger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(D, ger_d);
+}
+dopi(unge)
+
+static void
+_ungtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    unop(D, gtr_d);
+}
+dopi(ungt)
+
+static void
+_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w0, w1;
+    jit_int32_t                t0, t1;
+    t0 = jit_get_reg(jit_class_gpr);
+    FCLASS_D(rn(t0), r1);
+    t1 = jit_get_reg(jit_class_gpr);
+    FCLASS_D(rn(t1), r2);
+    orr(rn(t0), rn(t0), rn(t1));
+    jit_unget_reg(t1);
+    rshi(rn(t0), rn(t0), 8);
+    ltr(r0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    w0 = _jit->pc.w;
+    BEQ(_ZERO_REGNO, r0, 0);
+    movr(r0, _ZERO_REGNO);
+    w1 = _jit->pc.w;
+    JAL(_ZERO_REGNO, 0);
+    patch_at(w0, _jit->pc.w);
+    ner_d(r0, r1, r2);
+    patch_at(w1, _jit->pc.w);
+}
+dopi(ltgt)
+
+static void
+_ordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0, t1; 
+    t0 = jit_get_reg(jit_class_gpr);
+    FCLASS_D(rn(t0), r1);
+    t1 = jit_get_reg(jit_class_gpr);
+    FCLASS_D(rn(t1), r2);
+    orr(rn(t0), rn(t0), rn(t1));
+    jit_unget_reg(t1);
+    rshi(rn(t0), rn(t0), 8);
+    eqr(r0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+}
+dopi(ord)
+
+static void
+_unordr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                t0, t1; 
+    t0 = jit_get_reg(jit_class_gpr);
+    FCLASS_D(rn(t0), r1);
+    t1 = jit_get_reg(jit_class_gpr);
+    FCLASS_D(rn(t1), r2);
+    orr(rn(t0), rn(t0), rn(t1));
+    jit_unget_reg(t1);
+    rshi(rn(t0), rn(t0), 8);
+    ltr(r0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+}
+dopi(unord)
+
+static jit_word_t
+_bltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ltr_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(lt)
+
+static jit_word_t
+_bler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ler_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(le)
+
+static jit_word_t
+_beqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    eqr_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(eq)
+
+static jit_word_t
+_bger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ger_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(ge)
+
+static jit_word_t
+_bgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    gtr_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(gt)
+
+static jit_word_t
+_bner_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    eqr_d(rn(t0), r1, r2);
+    w = beqr(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(ne)
+
+static jit_word_t
+_bunltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    unltr_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(unlt)
+
+static jit_word_t
+_bunler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    unler_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(unle)
+
+static jit_word_t
+_buneqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    uneqr_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(uneq)
+
+static jit_word_t
+_bunger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    unger_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(unge)
+
+static jit_word_t
+_bungtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ungtr_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(ungt)
+
+static jit_word_t
+_bltgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ltgtr_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(ltgt)
+
+static jit_word_t
+_bordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    ordr_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(ord)
+
+static jit_word_t
+_bunordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                t0;
+    t0 = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    unordr_d(rn(t0), r1, r2);
+    w = bner(i0, _ZERO_REGNO, rn(t0));
+    jit_unget_reg(t0);
+    return (w);
+}
+dbopi(unord)
+
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+    /* Load argument. */
+    ldr_d(r0, r1);
+    /* Update va_list. */
+    addi(r1, r1, sizeof(jit_float64_t));
+}
+
+#endif /* CODE */
diff --git a/deps/lightning/lib/jit_riscv-sz.c b/deps/lightning/lib/jit_riscv-sz.c
new file mode 100644 (file)
index 0000000..2f1d725
--- /dev/null
@@ -0,0 +1,401 @@
+#if __WORDSIZE == 64
+#define JIT_INSTR_MAX 116
+    0, /* data */
+    0, /* live */
+    4, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    112,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    4, /* va_start */
+    8, /* va_arg */
+    8, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    20,        /* addi */
+    12,        /* addcr */
+    28,        /* addci */
+    28,        /* addxr */
+    28,        /* addxi */
+    4, /* subr */
+    20,        /* subi */
+    12,        /* subcr */
+    28,        /* subci */
+    28,        /* subxr */
+    28,        /* subxi */
+    28,        /* rsbi */
+    4, /* mulr */
+    20,        /* muli */
+    12,        /* qmulr */
+    24,        /* qmuli */
+    12,        /* qmulr_u */
+    24,        /* qmuli_u */
+    4, /* divr */
+    20,        /* divi */
+    4, /* divr_u */
+    20,        /* divi_u */
+    20,        /* qdivr */
+    16,        /* qdivi */
+    20,        /* qdivr_u */
+    16,        /* qdivi_u */
+    4, /* remr */
+    20,        /* remi */
+    4, /* remr_u */
+    20,        /* remi_u */
+    4, /* andr */
+    20,        /* andi */
+    4, /* orr */
+    20,        /* ori */
+    4, /* xorr */
+    20,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    4, /* ltr */
+    4, /* lti */
+    4, /* ltr_u */
+    4, /* lti_u */
+    8, /* ler */
+    12,        /* lei */
+    8, /* ler_u */
+    12,        /* lei_u */
+    12,        /* eqr */
+    12,        /* eqi */
+    8, /* ger */
+    12,        /* gei */
+    8, /* ger_u */
+    12,        /* gei_u */
+    4, /* gtr */
+    8, /* gti */
+    4, /* gtr_u */
+    8, /* gti_u */
+    8, /* ner */
+    8, /* nei */
+    4, /* movr */
+    24,        /* movi */
+    8, /* extr_c */
+    4, /* extr_uc */
+    8, /* extr_s */
+    8, /* extr_us */
+    4, /* extr_i */
+    8, /* extr_ui */
+    20,        /* htonr_us */
+    52,        /* htonr_ui */
+    116,       /* htonr_ul */
+    4, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    12,        /* ldi_uc */
+    4, /* ldr_s */
+    12,        /* ldi_s */
+    4, /* ldr_us */
+    12,        /* ldi_us */
+    4, /* ldr_i */
+    12,        /* ldi_i */
+    4, /* ldr_ui */
+    12,        /* ldi_ui */
+    4, /* ldr_l */
+    12,        /* ldi_l */
+    8, /* ldxr_c */
+    16,        /* ldxi_c */
+    8, /* ldxr_uc */
+    16,        /* ldxi_uc */
+    8, /* ldxr_s */
+    16,        /* ldxi_s */
+    8, /* ldxr_us */
+    16,        /* ldxi_us */
+    8, /* ldxr_i */
+    16,        /* ldxi_i */
+    8, /* ldxr_ui */
+    16,        /* ldxi_ui */
+    8, /* ldxr_l */
+    16,        /* ldxi_l */
+    4, /* str_c */
+    12,        /* sti_c */
+    4, /* str_s */
+    12,        /* sti_s */
+    4, /* str_i */
+    12,        /* sti_i */
+    4, /* str_l */
+    12,        /* sti_l */
+    8, /* stxr_c */
+    16,        /* stxi_c */
+    8, /* stxr_s */
+    16,        /* stxi_s */
+    8, /* stxr_i */
+    16,        /* stxi_i */
+    8, /* stxr_l */
+    16,        /* stxi_l */
+    4, /* bltr */
+    8, /* blti */
+    4, /* bltr_u */
+    8, /* blti_u */
+    4, /* bler */
+    8, /* blei */
+    4, /* bler_u */
+    8, /* blei_u */
+    4, /* beqr */
+    28,        /* beqi */
+    4, /* bger */
+    8, /* bgei */
+    4, /* bger_u */
+    8, /* bgei_u */
+    4, /* bgtr */
+    8, /* bgti */
+    4, /* bgtr_u */
+    8, /* bgti_u */
+    4, /* bner */
+    20,        /* bnei */
+    8, /* bmsr */
+    12,        /* bmsi */
+    8, /* bmcr */
+    12,        /* bmci */
+    32,        /* boaddr */
+    36,        /* boaddi */
+    16,        /* boaddr_u */
+    20,        /* boaddi_u */
+    32,        /* bxaddr */
+    36,        /* bxaddi */
+    16,        /* bxaddr_u */
+    20,        /* bxaddi_u */
+    32,        /* bosubr */
+    36,        /* bosubi */
+    16,        /* bosubr_u */
+    20,        /* bosubi_u */
+    32,        /* bxsubr */
+    36,        /* bxsubi */
+    16,        /* bxsubr_u */
+    20,        /* bxsubi_u */
+    4, /* jmpr */
+    28,        /* jmpi */
+    4, /* callr */
+    28,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    112,       /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    12,        /* addi_f */
+    4, /* subr_f */
+    12,        /* subi_f */
+    12,        /* rsbi_f */
+    4, /* mulr_f */
+    12,        /* muli_f */
+    4, /* divr_f */
+    12,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    4, /* ltr_f */
+    12,        /* lti_f */
+    4, /* ler_f */
+    12,        /* lei_f */
+    4, /* eqr_f */
+    12,        /* eqi_f */
+    4, /* ger_f */
+    12,        /* gei_f */
+    4, /* gtr_f */
+    12,        /* gti_f */
+    8, /* ner_f */
+    16,        /* nei_f */
+    28,        /* unltr_f */
+    36,        /* unlti_f */
+    28,        /* unler_f */
+    36,        /* unlei_f */
+    28,        /* uneqr_f */
+    36,        /* uneqi_f */
+    28,        /* unger_f */
+    36,        /* ungei_f */
+    28,        /* ungtr_f */
+    36,        /* ungti_f */
+    40,        /* ltgtr_f */
+    48,        /* ltgti_f */
+    28,        /* ordr_f */
+    36,        /* ordi_f */
+    20,        /* unordr_f */
+    28,        /* unordi_f */
+    4, /* truncr_f_i */
+    4, /* truncr_f_l */
+    4, /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    8, /* movi_f */
+    4, /* ldr_f */
+    12,        /* ldi_f */
+    8, /* ldxr_f */
+    16,        /* ldxi_f */
+    4, /* str_f */
+    12,        /* sti_f */
+    8, /* stxr_f */
+    16,        /* stxi_f */
+    8, /* bltr_f */
+    16,        /* blti_f */
+    8, /* bler_f */
+    16,        /* blei_f */
+    8, /* beqr_f */
+    16,        /* beqi_f */
+    8, /* bger_f */
+    16,        /* bgei_f */
+    8, /* bgtr_f */
+    16,        /* bgti_f */
+    8, /* bner_f */
+    16,        /* bnei_f */
+    32,        /* bunltr_f */
+    40,        /* bunlti_f */
+    32,        /* bunler_f */
+    40,        /* bunlei_f */
+    32,        /* buneqr_f */
+    40,        /* buneqi_f */
+    32,        /* bunger_f */
+    40,        /* bungei_f */
+    32,        /* bungtr_f */
+    40,        /* bungti_f */
+    44,        /* bltgtr_f */
+    52,        /* bltgti_f */
+    32,        /* bordr_f */
+    40,        /* bordi_f */
+    24,        /* bunordr_f */
+    32,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    24,        /* addi_d */
+    4, /* subr_d */
+    24,        /* subi_d */
+    24,        /* rsbi_d */
+    4, /* mulr_d */
+    24,        /* muli_d */
+    4, /* divr_d */
+    24,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    4, /* ltr_d */
+    24,        /* lti_d */
+    4, /* ler_d */
+    24,        /* lei_d */
+    4, /* eqr_d */
+    24,        /* eqi_d */
+    4, /* ger_d */
+    24,        /* gei_d */
+    4, /* gtr_d */
+    24,        /* gti_d */
+    8, /* ner_d */
+    28,        /* nei_d */
+    28,        /* unltr_d */
+    48,        /* unlti_d */
+    28,        /* unler_d */
+    48,        /* unlei_d */
+    28,        /* uneqr_d */
+    48,        /* uneqi_d */
+    28,        /* unger_d */
+    48,        /* ungei_d */
+    28,        /* ungtr_d */
+    48,        /* ungti_d */
+    40,        /* ltgtr_d */
+    60,        /* ltgti_d */
+    28,        /* ordr_d */
+    48,        /* ordi_d */
+    20,        /* unordr_d */
+    40,        /* unordi_d */
+    4, /* truncr_d_i */
+    4, /* truncr_d_l */
+    4, /* extr_d */
+    4, /* extr_f_d */
+    4, /* movr_d */
+    20,        /* movi_d */
+    4, /* ldr_d */
+    12,        /* ldi_d */
+    8, /* ldxr_d */
+    16,        /* ldxi_d */
+    4, /* str_d */
+    12,        /* sti_d */
+    8, /* stxr_d */
+    16,        /* stxi_d */
+    8, /* bltr_d */
+    28,        /* blti_d */
+    8, /* bler_d */
+    28,        /* blei_d */
+    8, /* beqr_d */
+    28,        /* beqi_d */
+    8, /* bger_d */
+    28,        /* bgei_d */
+    8, /* bgtr_d */
+    28,        /* bgti_d */
+    8, /* bner_d */
+    28,        /* bnei_d */
+    32,        /* bunltr_d */
+    52,        /* bunlti_d */
+    32,        /* bunler_d */
+    52,        /* bunlei_d */
+    32,        /* buneqr_d */
+    52,        /* buneqi_d */
+    32,        /* bunger_d */
+    52,        /* bungei_d */
+    32,        /* bungtr_d */
+    52,        /* bungti_d */
+    44,        /* bltgtr_d */
+    64,        /* bltgti_d */
+    32,        /* bordr_d */
+    52,        /* bordi_d */
+    24,        /* bunordr_d */
+    44,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    4, /* movr_w_f */
+    0, /* movr_ww_d */
+    4, /* movr_w_d */
+    0, /* movr_f_w */
+    4, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    4, /* movr_d_w */
+    16,        /* movi_d_w */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_riscv.c b/deps/lightning/lib/jit_riscv.c
new file mode 100644 (file)
index 0000000..55b2391
--- /dev/null
@@ -0,0 +1,1615 @@
+/*
+ * Copyright (C) 2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#define jit_arg_reg_p(i)               ((i) >= 0 && (i) < 8)
+#define jit_arg_f_reg_p(i)             ((i) >= 0 && (i) < 8)
+
+/*
+ * Types
+ */
+typedef jit_pointer_t jit_va_list_t;
+
+/*
+ * Prototypes
+ */
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+#define PROTO                          1
+#  include "jit_riscv-cpu.c"
+#  include "jit_riscv-fpu.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_register_t         _rvs[] = {
+    { 0x00,                            "zero" },
+    { 0x01,                            "ra" },
+    { 0x02,                            "sp" },
+    { 0x03,                            "gp" },
+#if 0          /* Pretend it does not exist, so _NOREG can be used in
+                * a 64 bit bitmask */
+    { 0x04,                            "tp" },
+#endif
+    { rc(gpr) | 0x05,                  "t0" },
+    { rc(gpr) | 0x06,                  "t1" },
+    { rc(gpr) | 0x07,                  "t2" },
+    { rc(gpr) | 0x1c,                  "t3" },
+    { rc(gpr) | 0x1d,                  "t4" },
+    { rc(gpr) | 0x1e,                  "t5" },
+    { rc(gpr) | 0x1f,                  "t6" },
+    { 0x08,                            "fp" },
+    { rc(sav) | rc(gpr) | 0x09,                "s1" },
+    { rc(sav) | rc(gpr) | 0x12,                "s2" },
+    { rc(sav) | rc(gpr) | 0x13,                "s3" },
+    { rc(sav) | rc(gpr) | 0x14,                "s4" },
+    { rc(sav) | rc(gpr) | 0x15,                "s5" },
+    { rc(sav) | rc(gpr) | 0x16,                "s6" },
+    { rc(sav) | rc(gpr) | 0x17,                "s7" },
+    { rc(sav) | rc(gpr) | 0x18,                "s8" },
+    { rc(sav) | rc(gpr) | 0x19,                "s9" },
+    { rc(sav) | rc(gpr) | 0x1a,                "s10" },
+    { rc(sav) | rc(gpr) | 0x1b,                "s11" },
+    { rc(arg) | rc(gpr) | 0x11,                "a7" },
+    { rc(arg) | rc(gpr) | 0x10,                "a6" },
+    { rc(arg) | rc(gpr) | 0x0f,                "a5" },
+    { rc(arg) | rc(gpr) | 0x0e,                "a4" },
+    { rc(arg) | rc(gpr) | 0x0d,                "a3" },
+    { rc(arg) | rc(gpr) | 0x0c,                "a2" },
+    { rc(arg) | rc(gpr) | 0x0b,                "a1" },
+    { rc(arg) | rc(gpr) | 0x0a,                "a0" },
+    { rc(fpr) | 0x00,                  "ft0" },
+    { rc(fpr) | 0x01,                  "ft1" },
+    { rc(fpr) | 0x02,                  "ft2" },
+    { rc(fpr) | 0x03,                  "ft3" },
+    { rc(fpr) | 0x04,                  "ft4" },
+    { rc(fpr) | 0x05,                  "ft5" },
+    { rc(fpr) | 0x06,                  "ft6" },
+    { rc(fpr) | 0x07,                  "ft7" },
+    { rc(fpr) | 0x1c,                  "ft8" },
+    { rc(fpr) | 0x1d,                  "ft9" },
+    { rc(fpr) | 0x1e,                  "ft10" },
+    { rc(fpr) | 0x1f,                  "ft11" },
+    { rc(sav) | rc(fpr) | 0x08,                "fs0" },
+    { rc(sav) | rc(fpr) | 0x09,                "fs1" },
+    { rc(sav) | rc(fpr) | 0x12,                "fs2" },
+    { rc(sav) | rc(fpr) | 0x13,                "fs3" },
+    { rc(sav) | rc(fpr) | 0x14,                "fs4" },
+    { rc(sav) | rc(fpr) | 0x15,                "fs5" },
+    { rc(sav) | rc(fpr) | 0x16,                "fs6" },
+    { rc(sav) | rc(fpr) | 0x17,                "fs7" },
+    { rc(sav) | rc(fpr) | 0x18,                "fs8" },
+    { rc(sav) | rc(fpr) | 0x19,                "fs9" },
+    { rc(sav) | rc(fpr) | 0x1a,                "fs10" },
+    { rc(sav) | rc(fpr) | 0x1b,                "fs11" },
+    { rc(arg) | rc(fpr) | 0x11,                "fa7" },
+    { rc(arg) | rc(fpr) | 0x10,                "fa6" },
+    { rc(arg) | rc(fpr) | 0x0f,                "fa5" },
+    { rc(arg) | rc(fpr) | 0x0e,                "fa4" },
+    { rc(arg) | rc(fpr) | 0x0d,                "fa3" },
+    { rc(arg) | rc(fpr) | 0x0c,                "fa2" },
+    { rc(arg) | rc(fpr) | 0x0b,                "fa1" },
+    { rc(arg) | rc(fpr) | 0x0a,                "fa0" },
+    { _NOREG,                          "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    _jitc->reglen = jit_size(_rvs) - 1;
+    jit_carry = _NOREG;
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                 offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = stack_framesize;
+    _jitc->function->self.argi = _jitc->function->self.argf =
+       _jitc->function->self.alen = 0;
+    _jitc->function->self.aoff = 0;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    return (_jitc->function->self.aoff);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 r0;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    r0 = jit_get_reg(jit_class_gpr);
+    jit_negr(r0, v);
+    jit_andi(r0, r0, -16);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, r0);
+    jit_addr(JIT_SP, JIT_SP, r0);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(r0);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    if (JIT_RET != u)
+       jit_movr(JIT_RET, u);
+    jit_live(JIT_RET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    if (u != JIT_FRET)
+       jit_movr_f(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    if (u != JIT_FRET)
+       jit_movr_d(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    if (u->code == jit_code_arg)
+       return (jit_arg_reg_p(u->u.w));
+    assert(u->code == jit_code_arg_f || u->code == jit_code_arg_d);
+    return (jit_arg_f_reg_p(u->u.w));
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare) {
+       jit_link_prepare();
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+    }
+    else {
+       jit_link_prolog();
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+       _jitc->function->vagp = _jitc->function->self.argi;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    assert(!(_jitc->function->self.call & jit_call_varargs));
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    assert(!(_jitc->function->self.call & jit_call_varargs));
+    if (jit_arg_f_reg_p(_jitc->function->self.argf))
+       offset = _jitc->function->self.argf++;
+    else if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi++;
+       offset += 8;
+    }
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg_f, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    assert(!(_jitc->function->self.call & jit_call_varargs));
+    if (jit_arg_f_reg_p(_jitc->function->self.argf))
+       offset = _jitc->function->self.argf++;
+    else if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi++;
+       offset += 8;
+    }
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg_d, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_c(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_uc(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_s(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_us(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_i(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_i(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_ui, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_ui(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_ui(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_l, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_l(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(JIT_RA0 - v->u.w, u);
+    else
+       jit_stxi(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi(JIT_RA0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_f(u, JIT_FA0 - v->u.w);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_w_f(u, JIT_RA0 - (v->u.w - 8));
+    else
+       jit_ldxi_f(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_f(JIT_FA0 - v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_f_w(JIT_RA0 - (v->u.w - 8), u);
+    else
+       jit_stxi_f(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movi_f(JIT_FA0 - v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8)) {
+       union {
+           jit_float32_t       f;
+           jit_int32_t         i;
+       } uu;
+       uu.f = u;
+       jit_movi(JIT_RA0 - (v->u.w - 8), uu.i);
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(u, JIT_FA0 - v->u.w);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_w_d(u, JIT_RA0 - (v->u.w - 8));
+    else
+       jit_ldxi_d(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_d(JIT_FA0 - v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8))
+       jit_movr_d_w(JIT_RA0 - (v->u.w - 8), u);
+    else
+       jit_stxi_d(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi_d(JIT_FA0 - v->u.w, u);
+    else if (jit_arg_reg_p(v->u.w - 8)) {
+       union {
+           jit_float64_t       d;
+           jit_int64_t         w;
+       } uu;
+       uu.d = u;
+       jit_movi(JIT_RA0 - (v->u.w - 8), uu.w);
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf) &&
+       !(_jitc->function->call.call & jit_call_varargs)) {
+       jit_movr_f(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr_f_w(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf) &&
+       !(_jitc->function->call.call & jit_call_varargs)) {
+       jit_movi_f(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi_f_w(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf) &&
+       !(_jitc->function->call.call & jit_call_varargs)) {
+       jit_movr_d(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr_d_w(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf) &&
+       !(_jitc->function->call.call & jit_call_varargs)) {
+       jit_movi_d(JIT_FA0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi_d_w(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(_jitc->function->call.size, JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_int32_t                spec;
+    spec = jit_class(_rvs[regno].spec);
+    if (spec & jit_class_arg) {
+       regno = JIT_RA0 - regno;
+       if (regno >= 0 && regno < node->v.w)
+           return (1);
+       if (spec & jit_class_fpr) {
+           regno = JIT_FA0 - regno;
+           if (regno >= 0 && regno < node->w.w)
+               return (1);
+       }
+    }
+
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_callr(r0);
+    node->v.w = _jitc->function->self.argi;
+    node->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_calli(i0);
+    node->v.w = _jitc->function->call.argi;
+    node->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_c, r0);
+    jit_extr_c(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_uc, r0);
+    jit_extr_uc(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_s, r0);
+    jit_extr_s(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_us, r0);
+    jit_extr_us(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+    jit_extr_i(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_ui, r0);
+    jit_extr_ui(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_l, r0);
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_f, r0);
+    if (r0 != JIT_FRET)
+       jit_movr_f(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_d, r0);
+    if (r0 != JIT_FRET)
+       jit_movr_d(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_word_t          value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_uint8_t     *data;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_int32_t      const_offset;
+       jit_int32_t      patch_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.const_offset = undo.patch_offset = 0;
+#  define assert_data(node)            /**/
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_rrf(name)                                                 \
+           case jit_code_##name##i_f:                                  \
+               assert_data(node);                                      \
+               name##i_f(rn(node->u.w), rn(node->v.w), node->w.f);     \
+               break
+#define case_rrd(name)                                                 \
+           case jit_code_##name##i_d:                                  \
+               assert_data(node);                                      \
+               name##i_d(rn(node->u.w), rn(node->v.w), node->w.d);     \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break;
+#define case_brf(name)                                                 \
+           case jit_code_##name##i_f:                                  \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i_f(temp->u.w, rn(node->v.w), node->w.f);     \
+               else {                                                  \
+                   word = name##i_f(_jit->pc.w, rn(node->v.w),         \
+                               node->w.f);                             \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brd(name)                                                 \
+           case jit_code_##name##i_d:                                  \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i_d(temp->u.w, rn(node->v.w), node->w.d);     \
+               else {                                                  \
+                   word = name##i_d(_jit->pc.w, rn(node->v.w),         \
+                               node->w.d);                             \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if (node->u.w == sizeof(jit_word_t) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rr(neg,);
+               case_rr(com,);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rr(trunc, _f_i);
+               case_rr(trunc, _d_i);
+               case_rr(trunc, _f_l);
+               case_rr(trunc, _d_l);
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+               case_rr(ld, _ui);
+               case_rw(ld, _ui);
+               case_rr(ld, _l);
+               case_rw(ld, _l);
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+               case_rrr(ldx, _ui);
+               case_rrw(ldx, _ui);
+               case_rrr(ldx, _l);
+               case_rrw(ldx, _l);
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+               case_rr(st, _l);
+               case_wr(st, _l);
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+               case_rrr(stx, _l);
+               case_wrr(stx, _l);
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+               case_rr(hton, _ul);
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+               case_rr(ext, _i);
+               case_rr(ext, _ui);
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), temp->u.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_rrr(add, _f);
+               case_rrf(add);
+               case_rrr(sub, _f);
+               case_rrf(sub);
+               case_rrf(rsb);
+               case_rrr(mul, _f);
+               case_rrf(mul);
+               case_rrr(div, _f);
+               case_rrf(div);
+               case_rr(abs, _f);
+               case_rr(neg, _f);
+               case_rr(sqrt, _f);
+               case_rr(ext, _f);
+               case_rr(ld, _f);
+               case_rw(ld, _f);
+               case_rrr(ldx, _f);
+               case_rrw(ldx, _f);
+               case_rr(st, _f);
+               case_wr(st, _f);
+               case_rrr(stx, _f);
+               case_wrr(stx, _f);
+               case_rr(mov, _f);
+           case jit_code_movi_f:
+               assert_data(node);
+               movi_f(rn(node->u.w), node->v.f);
+               break;
+               case_rr(ext, _d_f);
+               case_rrr(lt, _f);
+               case_rrf(lt);
+               case_rrr(le, _f);
+               case_rrf(le);
+               case_rrr(eq, _f);
+               case_rrf(eq);
+               case_rrr(ge, _f);
+               case_rrf(ge);
+               case_rrr(gt, _f);
+               case_rrf(gt);
+               case_rrr(ne, _f);
+               case_rrf(ne);
+               case_rrr(unlt, _f);
+               case_rrf(unlt);
+               case_rrr(unle, _f);
+               case_rrf(unle);
+               case_rrr(uneq, _f);
+               case_rrf(uneq);
+               case_rrr(unge, _f);
+               case_rrf(unge);
+               case_rrr(ungt, _f);
+               case_rrf(ungt);
+               case_rrr(ltgt, _f);
+               case_rrf(ltgt);
+               case_rrr(ord, _f);
+               case_rrf(ord);
+               case_rrr(unord, _f);
+               case_rrf(unord);
+               case_brr(blt, _f);
+               case_brf(blt);
+               case_brr(ble, _f);
+               case_brf(ble);
+               case_brr(beq, _f);
+               case_brf(beq);
+               case_brr(bge, _f);
+               case_brf(bge);
+               case_brr(bgt, _f);
+               case_brf(bgt);
+               case_brr(bne, _f);
+               case_brf(bne);
+               case_brr(bunlt, _f);
+               case_brf(bunlt);
+               case_brr(bunle, _f);
+               case_brf(bunle);
+               case_brr(buneq, _f);
+               case_brf(buneq);
+               case_brr(bunge, _f);
+               case_brf(bunge);
+               case_brr(bungt, _f);
+               case_brf(bungt);
+               case_brr(bltgt, _f);
+               case_brf(bltgt);
+               case_brr(bord, _f);
+               case_brf(bord);
+               case_brr(bunord, _f);
+               case_brf(bunord);
+               case_rrr(add, _d);
+               case_rrd(add);
+               case_rrr(sub, _d);
+               case_rrd(sub);
+               case_rrd(rsb);
+               case_rrr(mul, _d);
+               case_rrd(mul);
+               case_rrr(div, _d);
+               case_rrd(div);
+               case_rr(abs, _d);
+               case_rr(neg, _d);
+               case_rr(sqrt, _d);
+               case_rr(ext, _d);
+               case_rr(ld, _d);
+               case_rw(ld, _d);
+               case_rrr(ldx, _d);
+               case_rrw(ldx, _d);
+               case_rr(st, _d);
+               case_wr(st, _d);
+               case_rrr(stx, _d);
+               case_wrr(stx, _d);
+               case_rr(mov, _d);
+           case jit_code_movi_d:
+               assert_data(node);
+               movi_d(rn(node->u.w), node->v.d);
+               break;
+               case_rr(ext, _f_d);
+               case_rrr(lt, _d);
+               case_rrd(lt);
+               case_rrr(le, _d);
+               case_rrd(le);
+               case_rrr(eq, _d);
+               case_rrd(eq);
+               case_rrr(ge, _d);
+               case_rrd(ge);
+               case_rrr(gt, _d);
+               case_rrd(gt);
+               case_rrr(ne, _d);
+               case_rrd(ne);
+               case_rrr(unlt, _d);
+               case_rrd(unlt);
+               case_rrr(unle, _d);
+               case_rrd(unle);
+               case_rrr(uneq, _d);
+               case_rrd(uneq);
+               case_rrr(unge, _d);
+               case_rrd(unge);
+               case_rrr(ungt, _d);
+               case_rrd(ungt);
+               case_rrr(ltgt, _d);
+               case_rrd(ltgt);
+               case_rrr(ord, _d);
+               case_rrd(ord);
+               case_rrr(unord, _d);
+               case_rrd(unord);
+               case_brr(blt, _d);
+               case_brd(blt);
+               case_brr(ble, _d);
+               case_brd(ble);
+               case_brr(beq, _d);
+               case_brd(beq);
+               case_brr(bge, _d);
+               case_brd(bge);
+               case_brr(bgt, _d);
+               case_brd(bgt);
+               case_brr(bne, _d);
+               case_brd(bne);
+               case_brr(bunlt, _d);
+               case_brd(bunlt);
+               case_brr(bunle, _d);
+               case_brd(bunle);
+               case_brr(buneq, _d);
+               case_brd(buneq);
+               case_brr(bunge, _d);
+               case_brd(bunge);
+               case_brr(bungt, _d);
+               case_brd(bungt);
+               case_brr(bltgt, _d);
+               case_brd(bltgt);
+               case_brr(bord, _d);
+               case_brd(bord);
+               case_brr(bunord, _d);
+               case_brd(bunord);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       calli(temp->u.w);
+                   else {
+                       word = calli_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+           restart_function:
+               _jitc->again = 0;
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+                   goto restart_function;
+               }
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               break;
+           case jit_code_movr_w_f:
+               movr_w_f(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movr_f_w:
+               movr_f_w(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movi_f_w:
+               assert_data(node);
+               movi_f_w(rn(node->u.w), node->v.f);
+               break;
+           case jit_code_movr_w_d:
+               movr_w_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movr_d_w:
+               movr_d_w(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_movi_d_w:
+               assert_data(node);
+               movi_d_w(rn(node->u.w), node->v.d);
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:                 case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:             case jit_code_getarg_ui:
+           case jit_code_getarg_l:
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+           case jit_code_retval_ui:            case jit_code_retval_l:
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           default:
+               abort();
+       }
+       if (jit_carry != _NOREG) {
+           switch (node->code) {
+               case jit_code_note:
+               case jit_code_addcr:            case jit_code_addci:
+               case jit_code_addxr:            case jit_code_addxi:
+               case jit_code_subcr:            case jit_code_subci:
+               case jit_code_subxr:            case jit_code_subxi:
+                   break;
+               default:
+                   jit_unget_reg(jit_carry);
+                   jit_carry = _NOREG;
+                   break;
+           }
+       }
+       jit_regarg_clr(node, value);
+       assert(_jitc->regarg == 0 ||
+              (jit_carry != _NOREG && _jitc->regarg == (1 << jit_carry)));
+       assert(_jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+    }
+#undef case_brw
+#undef case_brr
+#undef case_wrr
+#undef case_rrw
+#undef case_rrr
+#undef case_wr
+#undef case_rw
+#undef case_rr
+
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = _jitc->patches.ptr[offset].inst;
+       value = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(word, value);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_riscv-cpu.c"
+#  include "jit_riscv-fpu.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+#if defined(__GNUC__)
+    jit_word_t         f, t, s;
+
+    s = sysconf(_SC_PAGE_SIZE);
+    f = (jit_word_t)fptr & -s;
+    t = (((jit_word_t)tptr) + s - 1) & -s;
+    __clear_cache((void *)f, (void *)t);
+#endif
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi(i0, rn(r0), rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi_d(i0, rn(r0), rn(r1));
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                 flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+    assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_s390-cpu.c b/deps/lightning/lib/jit_s390-cpu.c
new file mode 100644 (file)
index 0000000..02cac60
--- /dev/null
@@ -0,0 +1,3848 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  if __WORDSIZE == 32
+#    define ldr(r0,r1)                 ldr_i(r0,r1)
+#    define ldxr(r0,r1,r2)             ldxr_i(r0,r1,r2)
+#    define ldxi(r0,r1,i0)             ldxi_i(r0,r1,i0)
+#    define stxi(i0,r0,r1)             stxi_i(i0,r0,r1)
+#  else
+#    define ldr(r0,r1)                 ldr_l(r0,r1)
+#    define ldxr(r0,r1,r2)             ldxr_l(r0,r1,r2)
+#    define ldxi(r0,r1,i0)             ldxi_l(r0,r1,i0)
+#    define stxi(i0,r0,r1)             stxi_l(i0,r0,r1)
+#  endif
+#  define is(i)                                *_jit->pc.us++ = i
+#  if __WORDSIZE == 32
+#    define stack_framesize            96
+#  else
+#    define stack_framesize            160
+#  endif
+#  define _R0_REGNO                    0
+#  define _R1_REGNO                    1
+#  define _R7_REGNO                    7
+#  define _R13_REGNO                   13
+#  define _FP_REGNO                    _R13_REGNO
+#  define _R14_REGNO                   14
+#  define _R15_REGNO                   15
+#  define u12_p(i0)                    ((i0) >= 0 && (i0) <= 4095)
+#  define s16_p(i0)                    ((i0) >= -32768 && (i0) <= 32767)
+#  define x16(i0)                      ((i0) & 0xffff)
+#  define s20_p(i0)                    ((i0) >= -524288 && (i0) <= 524287)
+#  define x20(i0)                      ((i0) & 0xfffff)
+#  if __WORDSIZE == 32
+#    define s32_p(i0)                  1
+#  else
+#    define s32_p(i0)                                                  \
+    ((i0) >= -2147483648L && (i0) < 2147483647L)
+#  endif
+
+/*
+       Condition Code          Instruction     (Mask) Bit Mask Value
+       0                       8               8
+       1                       9               4
+       2                       10              2
+       3                       11              1
+
+AGR:
+       0       Zero
+       1       < zero
+       2       > zero
+       3       Overflow
+--
+1      ->      overflow                CC_O
+14     ->      no overflow             CC_NO
+
+ALGR:
+       0       Zero, no carry
+       1       Not zero, no carry
+       2       Zero, carry
+       3       Not zero, carry
+--
+2|1    ->      carry                   CC_NLE
+8|4    ->      no carry                CC_LE
+
+SGR:
+       0       Zero
+       1       < zero
+       2       > zero
+       3       Overflow
+--
+1      ->      overflow                CC_O
+14     ->      no overflow             CC_NO
+
+SLGR:
+       0       --
+       1       Not zero, borrow
+       2       Zero, no borrow
+       3       Not zero, no borrow
+--
+4      ->      borrow                  CC_L
+11     ->      no borrow               CC_NL
+  */
+
+#  define CC_NV                                0x0
+#  define CC_O                         0x1
+#  define CC_H                         0x2
+#  define CC_NLE                       0x3
+#  define CC_L                         0x4
+#  define CC_NHE                       0x5
+#  define CC_LH                                0x6
+#  define CC_NE                                0x7
+#  define CC_E                         0x8
+#  define CC_NLH                       0x9
+#  define CC_HE                                0xA
+#  define CC_NL                                0xB
+#  define CC_LE                                0xC
+#  define CC_NH                                0xD
+#  define CC_NO                                0xE
+#  define CC_AL                                0xF
+#  define _us                          jit_uint16_t
+#  define _ui                          jit_uint32_t
+#  define E_(Op)                       _E(_jit,Op)
+static void _E(jit_state_t*,_ui);
+#  define I_(Op,I)                     _I(_jit,Op,I)
+static void _I(jit_state_t*,_ui,_ui);
+#  define RR_(Op,R1,R2)                        _RR(_jit,Op,R1,R2)
+static void _RR(jit_state_t*,_ui,_ui,_ui);
+#  define RRE_(Op,R1,R2)               _RRE(_jit,Op,R1,R2)
+static void _RRE(jit_state_t*,_ui,_ui,_ui);
+#  define RRF_(Op,R3,M4,R1,R2)         _RRF(_jit,Op,R3,M4,R1,R2)
+static void _RRF(jit_state_t*,_ui,_ui,_ui,_ui,_ui);
+#  define RX_(Op,R1,X2,B2,D2)          _RX(_jit,Op,R1,X2,B2,D2)
+static void _RX(jit_state_t*,_ui,_ui,_ui,_ui,_ui);
+#  define RXE_(Op,R1,X2,B2,D2,Op2)     _RXE(_jit,Op,R1,X2,B2,D2,Op2)
+static void _RXE(jit_state_t*,_ui,_ui,_ui,_ui,_ui,_ui);
+#  define RXF_(Op,R3,X2,B2,D2,R1,Op2)  _RXF(_jit,Op,R3,X2,B2,D2,R1,Op2)
+static void _RXF(jit_state_t*,_ui,_ui,_ui,_ui,_ui,_ui,_ui);
+#  define RXY_(Op,R1,X2,B2,D2,Op2)     _RXY(_jit,Op,R1,X2,B2,D2,Op2)
+static void _RXY(jit_state_t*,_ui,_ui,_ui,_ui,_ui,_ui);
+#  define RS_(Op,R1,R3,B2,D2)          _RS(_jit,Op,R1,R3,B2,D2)
+static void _RS(jit_state_t*,_ui,_ui,_ui,_ui,_ui);
+#  define RSY_(Op,R1,R3,B2,D2,Op2)     RXY_(Op,R1,R3,B2,D2,Op2)
+#  define RSL_(Op,L1,B1,D1,Op2)                _RSL(_jit,Op,L1,B1,D1,Op2)
+static void _RSL(jit_state_t*,_ui,_ui,_ui,_ui,_ui);
+#  define RSI_(Op,R1,R3,I2)            _RSI(_jit,Op,R1,R3,I2)
+static void _RSI(jit_state_t*,_ui,_ui,_ui,_ui);
+#  define RI_(Op,R1,Op2,I2)            RSI_(Op,R1,Op2,I2)
+#  define RIE_(Op,R1,R3,I2,Op2)                _RIE(_jit,Op,R1,R3,I2,Op2)
+static void _RIE(jit_state_t*,_ui,_ui,_ui,_ui,_ui);
+#  define RIL_(Op,R1,Op2,I2)           _RIL(_jit,Op,R1,Op2,I2)
+static void _RIL(jit_state_t*,_ui,_ui,_ui,_ui);
+#  define SI_(Op,I2,B1,D1)             _SI(_jit,Op,I2,B1,D1)
+static void _SI(jit_state_t*,_ui,_ui,_ui,_ui);
+#  define SIY_(Op,I2,B1,D1,Op2)                _SIY(_jit,Op,I2,B1,D1,Op2)
+static void _SIY(jit_state_t*,_ui,_ui,_ui,_ui,_ui);
+#  define S_(Op,B2,D2)                 _S(_jit,Op,B2,D2)
+static void _S(jit_state_t*,_ui,_ui,_ui);
+#  define SSL_(Op,L,B1,D1,B2,D2)       SS_(Op,(L)>>4,(L)&0xF,B1,D1,B2,D2)
+#  define SS_(Op,LL,LH,B1,D1,B2,D2)    _SS(_jit,Op,LL,LH,B1,D1,B2,D2)
+static void _SS(jit_state_t*,_ui,_ui,_ui,_ui,_ui,_ui,_ui);
+#  define SSE_(Op,B1,D1,B2,D2)         _SSE(_jit,Op,B1,D1,B2,D2)
+static void _SSE(jit_state_t*,_ui,_ui,_ui,_ui,_ui);
+#  undef _us
+#  undef _ui
+#  define nop(c)                       _nop(_jit,c)
+static void _nop(jit_state_t*,jit_int32_t);
+#  if __WORDSIZE == 32
+#    define ADD_(r0,r1)                        AR(r0,r1)
+#    define ADDI_(r0,i0)               AHI(r0,i0)
+#    define ADDC_(r0,r1)               ALR(r0,r1)
+#    define ADDX_(r0,r1)               ALCR(r0,r1)
+#    define AND_(r0,r1)                        NR(r0,r1)
+#    define CMP_(r0,r1)                        CR(r0,r1)
+#    define CMPU_(r0,r1)               CLR(r0,r1)
+#    define DIVREM_(r0,r1)             DR(r0,r1)
+#    define DIVREMU_(r0,r1)            DLR(r0,r1)
+#    define OR_(r0,r1)                 OR(r0,r1)
+#    define MUL_(r0,r1)                        MSR(r0,r1)
+#    define MULI_(r0,i0)               MHI(r0,i0)
+#    define MULU_(r0,r1)               MLR(r0,r1)
+#    define SUB_(r0,r1)                        SR(r0,r1)
+#    define SUBC_(r0,r1)               SLR(r0,r1)
+#    define SUBX_(r0,r1)               SLBR(r0,r1)
+#    define TEST_(r0,r1)               LTR(r0,r1)
+#    define XOR_(r0,r1)                        XR(r0,r1)
+#  else
+#    define ADD_(r0,r1)                        AGR(r0,r1)
+#    define ADDI_(r0,i0)               AGHI(r0,i0)
+#    define ADDC_(r0,r1)               ALGR(r0,r1)
+#    define ADDX_(r0,r1)               ALCGR(r0,r1)
+#    define AND_(r0,r1)                        NGR(r0,r1)
+#    define CMP_(r0,r1)                        CGR(r0,r1)
+#    define CMPU_(r0,r1)               CLGR(r0,r1)
+#    define DIVREM_(r0,r1)             DSGR(r0,r1)
+#    define DIVREMU_(r0,r1)            DLGR(r0,r1)
+#    define MUL_(r0,r1)                        MSGR(r0,r1)
+#    define MULI_(r0,i0)               MGHI(r0,i0)
+#    define MULU_(r0,r1)               MLGR(r0,r1)
+#    define OR_(r0,r1)                 OGR(r0,r1)
+#    define SUB_(r0,r1)                        SGR(r0,r1)
+#    define SUBC_(r0,r1)               SLGR(r0,r1)
+#    define SUBX_(r0,r1)               SLBGR(r0,r1)
+#    define TEST_(r0,r1)               LTGR(r0,r1)
+#    define XOR_(r0,r1)                        XGR(r0,r1)
+#  endif
+/****************************************************************
+ * General Instructions                                                *
+ ****************************************************************/
+/* ADD */
+#  define AR(R1,R2)                    RR_(0x1A,R1,R2)
+#  define AGR(R1,R2)                   RRE_(0xB908,R1,R2)
+#  define AGFR(R1,R2)                  RRE_(0xB918,R1,R2)
+#  define A(R1,D2,X2,B2)               RX_(0x5A,R1,X2,B2,D2)
+#  define AY(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x5A)
+#  define AG(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x08)
+#  define AGF(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x18)
+/* ADD HALFWORD */
+#  define AH(R1,D2,X2,B2)              RX_(0x4A,R1,X2,B2,D2)
+#  define AHY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x7A)
+/* ADD HALFWORD IMMEDIATE */
+#  define AHI(R1,I2)                   RI_(0xA7,R1,0xA,I2)
+#  define AGHI(R1,I2)                  RI_(0xA7,R1,0xB,I2)
+/* ADD LOGICAL */
+#  define ALR(R1,R2)                   RR_(0x1E,R1,R2)
+#  define ALGR(R1,R2)                  RRE_(0xB90A,R1,R2)
+#  define ALGFR(R1,R2)                 RRE_(0xB91A,R1,R2)
+#  define AL(R1,D2,X2,B2)              RX_(0x5E,R1,X2,B2,D2)
+#  define ALY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x5E)
+#  define ALG(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x0A)
+#  define ALGF(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x1A)
+/* ADD LOGICAL WITH CARRY */
+#  define ALCR(R1,R2)                  RRE_(0xB998,R1,R2)
+#  define ALCGR(R1,R2)                 RRE_(0xB988,R1,R2)
+#  define ALC(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x98)
+#  define ALCG(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x88)
+/* AND */
+#  define NR(R1,R2)                    RR_(0x14,R1,R2)
+#  define NGR(R1,R2)                   RRE_(0xB980,R1,R2)
+#  define N(R1,D2,X2,B2)               RX_(0x54,R1,X2,B2,D2)
+#  define NY(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x54)
+#  define NG(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x80)
+#  define NI(D1,B1,I2)                 SI_(0x94,I2,B1,D1)
+#  define NIY(D1,B1,I2)                        SIY_(0xEB,I2,B1,D1,0x54)
+#  define NC(D1,L,B1,D2,B2)            SSL_(0xD4,L,B1,D1,B2,D2)
+/* AND IMMEDIATE */
+#  define NIHH(R1,I2)                  RI_(0xA5,R1,0x4,I2)
+#  define NIHL(R1,I2)                  RI_(0xA5,R1,0x5,I2)
+#  define NILH(R1,I2)                  RI_(0xA5,R1,0x6,I2)
+#  define NILL(R1,I2)                  RI_(0xA5,R1,0x7,I2)
+/* BRANCH AND LINK */
+#  define BALR(R1,R2)                  RR_(0x05,R1,R2)
+#  define BAL(R1,D2,X2,B2)             RX_(0x45,R1,X2,B2,D2)
+/* BRANCH AND SAVE */
+#  define BASR(R1,R2)                  RR_(0x0D,R1,R2)
+#  define BAS(R1,D2,X2,B2)             RX_(0x4D,R1,X2,B2,D2)
+/* BRANCH AND SAVE AND SET MODE */
+#  define BASSM(R1,R2)                 RR_(0x0C,R1,R2)
+/* BRANCH AND SET MODE */
+#  define BSM(R1,R2)                   RR_(0x0B,R1,R2)
+/* BRANCH ON CONDITION */
+#  define BCR(M1,R2)                   RR_(0x07,M1,R2)
+#  define BR(R2)                       BCR(CC_AL,R2)
+#  define NOPR(R2)                     BCR(CC_NV,R2)
+#  define BC(M1,D2,X2,B2)              RX_(0x47,M1,X2,B2,D2)
+/* BRANCH ON COUNT */
+#  define BCTR(R1,R2)                  RR_(0x06,R1,R2)
+#  define BCTGR(R1,R2)                 RRE_(0xB946,R1,R2)
+#  define BCT(R1,D2,X2,B2)             RX_(0x46,R1,X2,B2,D2)
+#  define BCTG(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x46)
+/* BRANCH ON INDEX HIGH */
+#  define BXH(R1,R3,D2,B2)             RS_(0x86,R1,R3,B2,D2)
+#  define BXHG(R1,R3,B2,D2)            RSY_(0xEB,R1,R3,B2,D2,0x44)
+/* BRANCH ON INDEX LOW OR EQUAL */
+#  define BXLE(R1,R3,D2,B2)            RS_(0x87,R1,R3,B2,D2)
+#  define BXLEG(R1,R3,B2,D2)           RSY_(0xEB,R1,R3,B2,D2,0x45)
+/* BRANCH RELATIVE AND SAVE */
+#  define BRAS(R1,I2)                  RI_(0xA7,R1,0x5,I2)
+/* BRANCH RELATIVE AND SAVE LONG */
+#  define BRASL(R1,I2)                 RIL_(0xC0,R1,0x5,I2)
+/* BRANCH RELATIVE ON CONDITION */
+#  define BRC(M1,I2)                   RI_(0xA7,M1,0x4,I2)
+#  define J(I2)                                BRC(CC_AL,I2)
+/* BRANCH RELATIVE ON CONDITION LONG */
+#  define BRCL(M1,I2)                  RIL_(0xC0,M1,0x4,I2)
+#  define BRL(I2)                      BRCL(CC_AL,I2)
+/* BRANCH RELATIVE ON COUNT */
+#  define BRCT(M1,I2)                  RI_(0xA7,M1,0x6,I2)
+#  define BRCTG(M1,I2)                 RI_(0xA7,M1,0x7,I2)
+/* BRANCH RELATIVE ON INDEX HIGH */
+#  define BRXH(R1,R3,I2)               RSI_(0x84,R1,R3,I2)
+#  define BRXHG(R1,R3,I2)              RIE_(0xEC,R1,R3,I2,0x44)
+/* BRANCH RELATIVE ON INDEX LOW OR EQUAL */
+#  define BRXLE(R1,R3,I2)              RSI_(0x85,R1,R3,I2)
+#  define BRXLEG(R1,R3,I2)             RIE_(0xEC,R1,R3,I2,0x45)
+/* CHECKSUM */
+#  define CKSUM(R1,R2)                 RRE_(0xB241,R1,R2)
+/* CIPHER MESAGE (KM) */
+#  define KM(R1,R2)                    RRE_(0xB92E,R1,R2)
+/* CIPHER MESAGE WITH CHAINING (KMC) */
+#  define KMC(R1,R2)                   RRE_(0xB92F,R1,R2)
+/* COMPARE */
+#  define CR(R1,R2)                    RR_(0x19,R1,R2)
+#  define CGR(R1,R2)                   RRE_(0xB920,R1,R2)
+#  define CGFR(R1,R2)                  RRE_(0xB930,R1,R2)
+#  define C(R1,D2,X2,B2)               RX_(0x59,R1,X2,B2,D2)
+#  define CY(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x59)
+#  define CG(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x20)
+#  define CGF(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x30)
+/* COMPARE AND FORM CODEWORD */
+#  define CFC(D2,B2)                   S_(0xB21A,B2,D2)
+/* COMPARE AND SWAP */
+#  define CS(R1,R3,D2,B2)              RS_(0xBA,R1,R3,B2,D2)
+#  define CSY(R1,R3,D2,B2)             RSY_(0xEB,R1,R3,B2,D2,0x14)
+#  define CSG(R1,R3,D2,B2)             RSY_(0xEB,R1,R3,B2,D2,0x30)
+/* COMPARE DOUBLE AND SWAP */
+#  define CDS(R1,R3,D2,B2)             RS_(0xBB,R1,R3,B2,D2)
+#  define CSDY(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x31)
+#  define CSDG(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x3E)
+/* COMPARE HALFWORD */
+#  define CH(R1,D2,X2,B2)              RX_(0x49,R1,X2,B2,D2)
+#  define CHY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x79)
+/* COMPARE HALFWORD IMMEDIATE */
+#  define CHI(R1,I2)                   RI_(0xA7,R1,0xE,I2)
+#  define CGHI(R1,I2)                  RI_(0xA7,R1,0xF,I2)
+/* COMPARE LOGICAL */
+#  define CLR(R1,R2)                   RR_(0x15,R1,R2)
+#  define CLGR(R1,R2)                  RRE_(0xB921,R1,R2)
+#  define CLGFR(R1,R2)                 RRE_(0xB931,R1,R2)
+#  define CL(R1,D2,X2,B2)              RX_(0x55,R1,X2,B2,D2)
+#  define CLY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x55)
+#  define CLG(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x21)
+#  define CLGF(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x31)
+#  define CLI(D1,B1,I2)                        SI_(0x95,I2,B1,D1)
+#  define CLIY(D1,B1,I2)               SIY_(0xEB,I2,B1,D1,0x55)
+#  define CLC(D1,L,B1,D2,B2)           SSL_(0xD5,L,B1,D1,B2,D2)
+/* COMPARE LOGICAL CHARACTERS UNDER MASK */
+#  define CLM(R1,M3,D2,B2)             RS_(0xBD,R1,M3,B2,D2)
+#  define CLMY(R1,M3,D2,B2)            RSY_(0xEB,R1,M3,B2,D2,0x21)
+#  define CLMH(R1,M3,D2,B2)            RSY_(0xEB,R1,M3,B2,D2,0x20)
+/* COMPARE LOGICAL LONG */
+#  define CLCL(R1,R2)                  RR_(0x0F,R1,R2)
+/* COMPARE LOGICAL LONG EXTENDED */
+#  define CLCLE(R1,R3,D2,B2)           RS_(0xA9,R1,R3,B2,D2)
+/* COMPARE LOGICAL LONG UNICODE */
+#  define CLCLU(R1,R3,D2,B2)           RSY_(0xEB,R1,R3,B2,D2,0x8F)
+/* COMPARE LOGICAL STRING */
+#  define CLST(R1,R2)                  RRE_(0xB25D,R1,R2)
+/* COMPARE UNTIL SUBSTRING EQUAL */
+#  define CUSE(R1,R2)                  RRE_(0xB257,R1,R2)
+/* COMPRESSION CALL */
+#  define CMPSC(R1,R2)                 RRE_(0xB263,R1,R2)
+/* COMPUTE INTERMEDIATE MESSAGE DIGEST (KIMD) */
+#  define KIMD(R1,R2)                  RRE_(0xB93E,R1,R2)
+/* COMPUTE LAST MESSAGE DIGEST (KIMD) */
+#  define KLMD(R1,R2)                  RRE_(0xB93F,R1,R2)
+/* COMPUTE MESSAGE AUTHENTICATION CODE (KMAC) */
+#  define KMAC(R1,R2)                  RRE_(0xB91E,R1,R2)
+/* CONVERT TO BINARY */
+#  define CVB(R1,D2,X2,B2)             RX_(0x4F,R1,X2,B2,D2)
+#  define CVBY(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x06)
+#  define CVBG(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x0e)
+/* CONVERT TO DECIMAL */
+#  define CVD(R1,D2,X2,B2)             RX_(0x4E,R1,X2,B2,D2)
+#  define CVDY(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x26)
+#  define CVDG(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x2E)
+/* CONVERT UNICODE TO UTF-8 */
+#  define CUUTF(R1,R2)                 RRE_(0xB2A6,R1,R2)
+/* CONVERT UTF-8 TO UNICODE */
+#  define CUTFU(R1,R2)                 RRE_(0xB2A7,R1,R2)
+/* COPY ACCESS */
+#  define CPYA(R1,R2)                  RRE_(0xB24D,R1,R2)
+/* DIVIDE */
+#  define DR(R1,R2)                    RR_(0x1D,R1,R2)
+#  define D(R1,D2,X2,B2)               RX_(0x5D,R1,X2,B2,D2)
+/* DIVIDE LOGICAL */
+#  define DLR(R1,R2)                   RRE_(0xB997,R1,R2)
+#  define DLGR(R1,R2)                  RRE_(0xB987,R1,R2)
+#  define DL(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x97)
+#  define DLG(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x87)
+/* DIVIDE SINGLE */
+#  define DSGR(R1,R2)                  RRE_(0xB90D,R1,R2)
+#  define DSGFR(R1,R2)                 RRE_(0xB91D,R1,R2)
+#  define DSG(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x0D)
+#  define DSGF(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x1D)
+/* EXCLUSIVE OR */
+#  define XR(R1,R2)                    RR_(0x17,R1,R2)
+#  define XGR(R1,R2)                   RRE_(0xB982,R1,R2)
+#  define X(R1,D2,X2,B2)               RX_(0x57,R1,X2,B2,D2)
+#  define XY(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x57)
+#  define XG(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x82)
+#  define XI(D1,B1,I2)                 SI_(0x97,I2,B1,D1)
+#  define XIY(D1,B1,I2)                        SIY_(0xEB,I2,B1,D1,0x57)
+#  define XC(D1,L,B1,D2,B2)            SSL_(0xD7,L,B1,D1,B2,D2)
+/* EXECUTE */
+#  define EX(R1,D2,X2,B2)              RX_(0x44,R1,X2,B2,D2)
+/* EXTRACT ACCESS */
+#  define EAR(R1,R2)                   RRE_(0xB24F,R1,R2)
+/* EXTRACT PSW */
+#  define EPSW(R1,R2)                  RRE_(0xB98D,R1,R2)
+/* INSERT CHARACTER */
+#  define IC(R1,D2,X2,B2)              RX_(0x43,R1,X2,B2,D2)
+#  define ICY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x73)
+/* INSERT CHARACTERS UNDER MASK */
+#  define ICM(R1,M3,D2,B2)             RS_(0xBF,R1,M3,B2,D2)
+#  define ICMY(R1,M3,D2,B2)            RSY_(0xEB,R1,M3,B2,D2,0x81)
+#  define ICMH(R1,M3,D2,B2)            RSY_(0xEB,R1,M3,B2,D2,0x80)
+/* INSERT IMMEDIATE */
+#  define IIHH(R1,I2)                  RI_(0xA5,R1,0x0,I2)
+#  define IIHL(R1,I2)                  RI_(0xA5,R1,0x1,I2)
+#  define IILH(R1,I2)                  RI_(0xA5,R1,0x2,I2)
+#  define IILL(R1,I2)                  RI_(0xA5,R1,0x3,I2)
+/* INSERT PROGRAM MASK */
+#  define IPM(R1)                      RRE_(0xB222,R1,0)
+/* LOAD */
+#  define LR(R1,R2)                    RR_(0x18,R1,R2)
+#  define LGR(R1,R2)                   RRE_(0xB904,R1,R2)
+#  define LGFR(R1,R2)                  RRE_(0xB914,R1,R2)
+#  define L(R1,D2,X2,B2)               RX_(0x58,R1,X2,B2,D2)
+#  define LY(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x58)
+#  define LG(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x04)
+#  define LGF(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x14)
+/* LOAD ACCESS MULTIPLE */
+#  define LAM(R1,R3,D2,B2)             RS_(0x9A,R1,R3,B2,D2)
+#  define LAMY(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x9A)
+/* LOAD ADDRESS */
+#  define LA(R1,D2,X2,B2)              RX_(0x41,R1,X2,B2,D2)
+#  define LAY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x71)
+/* LOAD ADDRESS EXTENDED */
+#  define LAE(R1,D2,X2,B2)             RX_(0x51,R1,X2,B2,D2)
+/* LOAD ADDRESS RELATIVE LONG */
+#  define LARL(R1,I2)                  RIL_(0xC0,R1,0x0,I2)
+/* LOAD AND TEST */
+#  define LTR(R1,R2)                   RR_(0x12,R1,R2)
+#  define LTGR(R1,R2)                  RRE_(0xB902,R1,R2)
+#  define LTGFR(R1,R2)                 RRE_(0xB912,R1,R2)
+/* LOAD BYTE */
+#  define LGBR(R1,R2)                  RRE_(0xB906,R1,R2)      /* disasm */
+#  define LB(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x76)
+#  define LGB(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x77)
+/* LOAD COMPLEMENT */
+#  define LCR(R1,R2)                   RR_(0x13,R1,R2)
+#  define LCGR(R1,R2)                  RRE_(0xB903,R1,R2)
+#  define LCGFR(R1,R2)                 RRE_(0xB913,R1,R2)
+/* LOAD HALFWORD */
+#  define LH(R1,D2,X2,B2)              RX_(0x48,R1,X2,B2,D2)
+#  define LHY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x78)
+#  define LGHR(R1,R2)                  RRE_(0xB907,R1,R2)      /* disasm */
+#  define LGH(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x15)
+/* LOAD HALFWORD IMMEDIATE */
+#  define LHI(R1,I2)                   RI_(0xA7,R1,0x8,I2)
+#  define LGHI(R1,I2)                  RI_(0xA7,R1,0x9,I2)
+/* LOAD LOGICAL */
+#  define LLGFR(R1,R2)                 RRE_(0xB916,R1,R2)
+#  define LLGF(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x16)
+/* LOAD LOGICAL CHARACTER */
+#  define LLGCR(R1,R2)                 RRE_(0xB984,R1,R2)      /* disasm */
+#  define LLGC(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x90)
+/* LOAD LOGICAL HALFWORD */
+#  define LLGHR(R1,R2)                 RRE_(0xB985,R1,R2)      /* disasm */
+#  define LLGH(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x91)
+/* LOAD LOGICAL IMMEDIATE */
+#  define LLIHH(R1,I2)                 RI_(0xA5,R1,0xC,I2)
+#  define LLIHL(R1,I2)                 RI_(0xA5,R1,0xD,I2)
+#  define LLILH(R1,I2)                 RI_(0xA5,R1,0xE,I2)
+#  define LLILL(R1,I2)                 RI_(0xA5,R1,0xF,I2)
+/* LOAD LOGICAL THIRTY ONE BITS */
+#  define LLGTR(R1,R2)                 RRE_(0xB917,R1,R2)
+#  define LLGT(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x17)
+/* LOAD MULTIPLE */
+#  define LM(R1,R3,D2,B2)              RS_(0x98,R1,R3,B2,D2)
+#  define LMY(R1,R3,D2,B2)             RSY_(0xEB,R1,R3,B2,D2,0x98)
+#  define LMG(R1,R3,D2,B2)             RSY_(0xEB,R1,R3,B2,D2,0x04)
+/* LOAD MULTIPLE DISJOINT */
+#  define LMD(R1,R3,D2,B2,D4,B4)       SS_(0xEF,R1,R3,B2,D2,B4,D4)
+/* LOAD MULTIPLE HIGH */
+#  define LMH(R1,R3,D2,B2)             RSY_(0xEB,R1,R3,B2,D2,0x96)
+/* LOAD NEGATIVE */
+#  define LNR(R1,R2)                   RR_(0x11,R1,R2)
+#  define LNGR(R1,R2)                  RRE_(0xB901,R1,R2)
+#  define LNGFR(R1,R2)                 RRE_(0xB911,R1,R2)
+/* LOAD PAIR FROM QUADWORD */
+#  define LPQ(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x8F)
+/* LOAD POSITIVE */
+#  define LPR(R1,R2)                   RR_(0x10,R1,R2)
+#  define LPGR(R1,R2)                  RRE_(0xB900,R1,R2)
+#  define LPGFR(R1,R2)                 RRE_(0xB910,R1,R2)
+/* LOAD REVERSED */
+#  define LRVR(R1,R2)                  RRE_(0xB91F,R1,R2)
+#  define LRVGR(R1,R2)                 RRE_(0xB90F,R1,R2)
+#  define LRVH(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x1F)
+#  define LRV(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x1E)
+#  define LRVG(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x0F)
+/* MONITOR CALL */
+#  define MC(D1,B1,I2)                 SI_(0xAF,I2,B1,D1)
+/* MOVE */
+#  define MVI(D1,B1,I2)                        SI_(0x92,I2,B1,D1)
+#  define MVIY(D1,B1,I2)               SIY_(0xEB,I2,B1,D1,0x52)
+#  define MVC(D1,L,B1,D2,B2)           SSL_(0xD2,L,B1,D1,B2,D2)
+/* MOVE INVERSE */
+#  define MVCIN(D1,L,B1,D2,B2)         SSL_(0xE8,L,B1,D1,B2,D2)
+/* MOVE LONG */
+#  define MVCL(R1,R2)                  RR_(0x0E,R1,R2)
+/* MOVE LONG EXTENDED */
+#  define MVCLE(R1,R3,D2,B2)           RS_(0xA8,R1,R3,B2,D2)
+/* MOVE LONG UNICODE */
+#  define MVCLU(R1,R3,D2,B2)           RSY_(0xEB,R1,R3,B2,D2,0x8E)
+/* MOVE NUMERICS */
+#  define MVN(D1,L,B1,D2,B2)           SSL_(0xD1,L,B1,D1,B2,D2)
+/* MOVE STRING */
+#  define MVST(R1,R2)                  RRE_(0xB255,R1,R2)
+/* MOVE WITH OFFSET */
+#  define MVO(D1,L1,B1,D2,L2,B2)       SS_(0xF1,L1,L2,B1,D1,B2,D2)
+/* MOVE ZONES */
+#  define MVZ(D1,L,B1,D2,B2)           SSL_(0xD3,L,B1,D1,B2,D2)
+/* MULTIPLY */
+#  define MR(R1,R2)                    RR_(0x1C,R1,R2)
+#  define M(R1,D2,X2,B2)               RX_(0x5C,R1,X2,B2,D2)
+/* MULTIPLY HALFWORD */
+#  define MH(R1,D2,X2,B2)              RX_(0x4C,R1,X2,B2,D2)
+/* MULTIPLY HALFWORD IMMEDIATE */
+#  define MHI(R1,I2)                   RI_(0xA7,R1,0xC,I2)
+#  define MGHI(R1,I2)                  RI_(0xA7,R1,0xD,I2)
+/* MULTIPLY LOGICAL */
+#  define MLR(R1,R2)                   RRE_(0xB996,R1,R2)
+#  define MLGR(R1,R2)                  RRE_(0xB986,R1,R2)
+#  define ML(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x96)
+#  define MLG(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x86)
+/* MULTIPLY SINGLE */
+#  define MSR(R1,R2)                   RRE_(0xB252,R1,R2)
+#  define MSGR(R1,R2)                  RRE_(0xB90C,R1,R2)
+#  define MSGFR(R1,R2)                 RRE_(0xB91C,R1,R2)
+#  define MS(R1,D2,X2,B2)              RX_(0x71,R1,X2,B2,D2)
+#  define MSY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x51)
+#  define MSG(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x0C)
+#  define MSGF(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x1C)
+/* OR */
+#  define OR(R1,R2)                    RR_(0x16,R1,R2)
+#  define OGR(R1,R2)                   RRE_(0xB981,R1,R2)
+#  define O(R1,D2,X2,B2)               RX_(0x56,R1,X2,B2,D2)
+#  define OY(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x56)
+#  define OG(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x81)
+#  define OI(D1,B1,I2)                 SI_(0x96,I2,B1,D1)
+#  define OIY(D1,B1,I2)                        SIY_(0xEB,I2,B1,D1,0x56)
+#  define OC(D1,L,B1,D2,B2)            SSL_(0xD6,L,B1,D1,B2,D2)
+/* OR IMMEDIATE */
+#  define OIHH(R1,I2)                  RI_(0xA5,R1,0x8,I2)
+#  define OIHL(R1,I2)                  RI_(0xA5,R1,0x9,I2)
+#  define OILH(R1,I2)                  RI_(0xA5,R1,0xA,I2)
+#  define OILL(R1,I2)                  RI_(0xA5,R1,0xB,I2)
+/* PACK */
+#  define PACK(D1,L1,B1,D2,L2,B2)      SS_(0xF2,L1,L2,B1,D1,B2,D2)
+/* PACK ASCII */
+#  define PKA(D1,B1,D2,L2,B2)          SSL_(0xE9,L2,B1,D1,B2,D2)
+/* PACK UNICODE */
+#  define PKU(D1,B1,D2,L2,B2)          SSL_(0xE1,L2,B1,D1,B2,D2)
+/* PERFORM LOCKED OPERATION */
+#  define PLO(R1,D2,B2,R3,D4,B4)       SS_(0xEE,R1,R3,B2,D2,B4,D4)
+/* ROTATE LEFT SINGLE LOGICAL */
+#  define RLL(R1,R3,D2,B2)             RSY_(0xEB,R1,R3,B2,D2,0x1D)
+#  define RLLG(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x1C)
+/* SEARCH STRING */
+#  define SRST(R1,R2)                  RRE_(0xB25E,R1,R2)
+/* SET ACCESS */
+#  define SAR(R1,R2)                   RRE_(0xB24E,R1,R2)
+/* SET ADDRESSING MODE */
+#  define SAM24()                      E_(0x10C)
+#  define SAM31()                      E_(0x10D)
+#  define SAM64()                      E_(0x10E)
+/* SET PROGRAM MASK */
+#  define SPM(R1)                      RR_(0x04,R1,0)
+/* SHIFT LEFT DOUBLE */
+#  define SLDA(R1,D2,B2)               RS_(0x8F,R1,0,B2,D2)
+/* SHIFT LEFT DOUBLE LOGICAL */
+#  define SLDL(R1,D2,B2)               RS_(0x8D,R1,0,B2,D2)
+/* SHIFT LEFT SINGLE */
+#  define SLA(R1,D2,B2)                        RS_(0x8B,R1,0,B2,D2)
+#  define SLAG(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x0B)
+/* SHIFT LEFT SINGLE LOGICAL */
+#  define SLL(R1,D2,B2)                        RS_(0x89,R1,0,B2,D2)
+#  define SLLG(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x0D)
+/* SHIFT RIGHT DOUBLE */
+#  define SRDA(R1,D2,B2)               RS_(0x8E,R1,0,B2,D2)
+/* SHIFT RIGHT DOUBLE LOGICAL */
+#  define SRDL(R1,D2,B2)               RS_(0x8C,R1,0,B2,D2)
+/* SHIFT RIGHT SINGLE */
+#  define SRA(R1,D2,B2)                        RS_(0x8A,R1,0,B2,D2)
+#  define SRAG(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x0A)
+/* SHIFT RIGHT SINGLE LOGICAL */
+#  define SRL(R1,D2,B2)                        RS_(0x88,R1,0,B2,D2)
+#  define SRLG(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x0C)
+/* STORE */
+#  define ST(R1,D2,X2,B2)              RX_(0x50,R1,X2,B2,D2)
+#  define STY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x50)
+#  define STG(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x24)
+/* STORE ACCESS MULTIPLE */
+#  define STAM(R1,R3,D2,B2)            RS_(0x9B,R1,R3,B2,D2)
+#  define STAMY(R1,R3,D2,B2)           RSY_(0xEB,R1,R3,B2,D2,0x9B)
+/* STORE CHARACTER */
+#  define STC(R1,D2,X2,B2)             RX_(0x42,R1,X2,B2,D2)
+#  define STCY(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x72)
+/* STORE CHARACTERS UNDER MASK */
+#  define STCM(R1,M3,D2,B2)            RS_(0xBE,R1,M3,B2,D2)
+#  define STCMY(R1,M3,D2,B2)           RSY_(0xEB,R1,M3,B2,D2,0x2D)
+#  define STCMH(R1,M3,D2,B2)           RSY_(0xEB,R1,M3,B2,D2,0x2C)
+/* STORE CLOCK */
+#  define STCK(D2,B2)                  S_(0xB205,B2,D2)
+/* STORE CLOCK EXTENDED */
+#  define STCKE(D2,B2)                 S_(0xB278,B2,D2)
+/* STORE HALFWORD */
+#  define STH(R1,D2,X2,B2)             RX_(0x40,R1,X2,B2,D2)
+#  define STHY(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x70)
+/* STORE MULTIPLE */
+#  define STM(R1,R3,D2,B2)             RS_(0x90,R1,R3,B2,D2)
+#  define STMY(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x90)
+#  define STMG(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x24)
+/* STORE MULTIPLE HIGH */
+#  define STMH(R1,R3,D2,B2)            RSY_(0xEB,R1,R3,B2,D2,0x26)
+/* STORE PAIR TO QUADWORD */
+#  define STPQ(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x8E)
+/* STORE REVERSED */
+#  define STRVH(R1,D2,X2,B2)           RXY_(0xE3,R1,X2,B2,D2,0x3F)
+#  define STRV(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x3E)
+#  define STRVG(R1,D2,X2,B2)           RXY_(0xE3,R1,X2,B2,D2,0x2F)
+/* SUBTRACT */
+#  define SR(R1,R2)                    RR_(0x1B,R1,R2)
+#  define SGR(R1,R2)                   RRE_(0xB909,R1,R2)
+#  define SGFR(R1,R2)                  RRE_(0xB919,R1,R2)
+#  define S(R1,D2,X2,B2)               RX_(0x5B,R1,X2,B2,D2)
+#  define SY(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x5B)
+#  define SG(R1,D2,X2,B2)              RXY_(0xE3,R1,X2,B2,D2,0x09)
+#  define SGF(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x19)
+/* SUBTRACT HALFWORD */
+#  define SH(R1,D2,X2,B2)              RX_(0x4B,R1,X2,B2,D2)
+#  define SHY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x7B)
+/* SUBTRACT LOGICAL */
+#  define SLR(R1,R2)                   RR_(0x1F,R1,R2)
+#  define SLGR(R1,R2)                  RRE_(0xB90B,R1,R2)
+#  define SLGFR(R1,R2)                 RRE_(0xB91B,R1,R2)
+#  define SL(R1,D2,X2,B2)              RX_(0x5F,R1,X2,B2,D2)
+#  define SLY(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x5F)
+#  define SLG(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x0B)
+#  define SLGF(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x1B)
+/* SUBTRACT LOGICAL WITH BORROW */
+#  define SLBR(R1,R2)                  RRE_(0xB999,R1,R2)
+#  define SLBGR(R1,R2)                 RRE_(0xB989,R1,R2)
+#  define SLB(R1,D2,X2,B2)             RXY_(0xE3,R1,X2,B2,D2,0x99)
+#  define SLBG(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x89)
+/* SUPERVISOR CALL */
+#  define SVC(I)                       I_(0xA,I)
+/* TEST ADDRESSING MODE */
+#  define TAM()                                E_(0x10B)
+/* TEST AND SET */
+#  define TS(D2,B2)                    RS_(0x93,0,0,B2,D2)
+/* TEST UNDER MASK (TEST UNDER MASK HIGH, TEST UNDER MASK LOW) */
+#  define TM(D1,B1,I2)                 SI_(0x91,I2,B1,D1)
+#  define TMY(D1,B1,I2)                        SIY_(0xEB,I2,B1,D1,0x51)
+#  define TMHH(R1,I2)                  RI_(0xA7,R1,0x2,I2)
+#  define TMHL(R1,I2)                  RI_(0xA7,R1,0x3,I2)
+#  define TMLH(R1,I2)                  RI_(0xA7,R1,0x0,I2)
+#  define TMH(R1,I2)                   TMLH(R1,I2)
+#  define TMLL(R1,I2)                  RI_(0xA7,R1,0x1,I2)
+#  define TML(R1,I2)                   TMLL(R1,I2)
+/* TRANSLATE */
+#  define TR(D1,L,B1,D2,B2)            SSL_(0xDC,L,B1,D1,B2,D2)
+/* TRANSLATE AND TEST */
+#  define TRT(D1,L,B1,D2,B2)           SSL_(0xDD,L,B1,D1,B2,D2)
+/* TRANSLATE EXTENDED */
+#  define TRE(R1,R2)                   RRE_(0xB2A5,R1,R2)
+/* TRANSLATE ONE TO ONE */
+#  define TROO(R1,R2)                  RRE_(0xB993,R1,R2)
+/* TRANSLATE ONE TO TWO */
+#  define TROT(R1,R2)                  RRE_(0xB992,R1,R2)
+/* TRANSLATE TWO TO ONE */
+#  define TRTO(R1,R2)                  RRE_(0xB991,R1,R2)
+/* TRANSLATE TWO TO TWO */
+#  define TRTT(R1,R2)                  RRE_(0xB990,R1,R2)
+/* UNPACK */
+#  define UNPK(D1,L1,B1,D2,L2,B2)      SS_(0xF3,L1,L2,B1,D1,B2,D2)
+/* UNPACK ASCII */
+#  define UNPKA(D1,L1,B1,D2,L2,B2)     SS_(0xEA,L1,L2,B1,D1,B2,D2)
+/* UNPACK UNICODE */
+#  define UNPKU(D1,L1,B1,D2,L2,B2)     SS_(0xE2,L1,L2,B1,D1,B2,D2)
+/* UPDATE TREE */
+#  define UPT()                                E_(0x0102)
+/****************************************************************
+ * Decimal Instructions                                                *
+ ****************************************************************/
+/* ADD DECIMAL */
+#  define AP(D1,L1,B1,D2,L2,B2)                SS_(0xFA,L1,L2,B1,D1,B2,D2)
+/* COMPARE DECIMAL */
+#  define CP(D1,L1,B1,D2,L2,B2)                SS_(0xF9,L1,L2,B1,D1,B2,D2)
+/* DIVIDE DECIMAL */
+#  define DP(D1,L1,B1,D2,L2,B2)                SS_(0xFD,L1,L2,B1,D1,B2,D2)
+/* EDIT */
+#  define ED(D1,L,B1,D2,B2)            SSL_(0xDE,L,B1,D1,B2,D2)
+/* EDIT AND MARK */
+#  define EDMK(D1,L,B1,D2,B2)          SSL_(0xDE,L,B1,D1,B2,D2)
+/* MULTIPLY DECIMAL */
+#  define MP(D1,L1,B1,D2,L2,B2)                SS_(0xFC,L1,L2,B1,D1,B2,D2)
+/* SHIFT AND ROUND DECIMAL */
+#  define SRP(D1,L1,B1,D2,L2,B2)       SS_(0xF0,L1,L2,B1,D1,B2,D2)
+/* SUBTRACE DECIMAL */
+#  define SP(D1,L1,B1,D2,L2,B2)                SS_(0xFB,L1,L2,B1,D1,B2,D2)
+/* TEST DECIMAL */
+#  define TP(D1,L1,B1)                 RSL_(0xEB,L1,B1,D1,0xC0)
+/* ZERO AND ADD */
+#  define ZAP(D1,L1,B1,D2,L2,B2)       SS_(0xF8,L1,L2,B1,D1,B2,D2)
+/****************************************************************
+ * Control Instructions                                                *
+ ****************************************************************/
+/* BRANCH AND SET AUTHORITY */
+#  define BSA(R1,R2)                   RRE_(0xB25A,R1,R2)
+/* BRANCH AND STACK */
+#  define BAKR(R1,R2)                  RRE_(0xB240,R1,R2)
+/* BRANCH IN SUBSPACE GROUP */
+#  define BSG(R1,R2)                   RRE_(0xB258,R1,R2)
+/* COMPARE AND SWAP AND PURGE */
+#  define CSP(R1,R2)                   RRE_(0xB250,R1,R2)
+#  define CSPG(R1,R2)                  RRE_(0xB98A,R1,R2)
+/* DIAGNOSE */
+#  define DIAG()                       SI_(0x83,0,0,0)
+/* EXTRACT AND SET EXTENDED AUTHORITY */
+#  define ESEA(R1)                     RRE_(0xB99D,R1,0)
+/* EXTRACT PRIMARY ASN */
+#  define EPAR(R1)                     RRE_(0xB226,R1,0)
+/* EXTRACT SECONDARY ASN */
+#  define ESAR(R1)                     RRE_(0xB227,R1,0)
+/* EXTRACT STACKED REGISTERS */
+#  define EREG(R1,R2)                  RRE_(0xB249,R1,R2)
+#  define EREGG(R1,R2)                 RRE_(0xB90E,R1,R2)
+/* EXTRACT STACKED STATE */
+#  define ESTA(R1,R2)                  RRE_(0xB24A,R1,R2)
+/* INSERT ADDRESS SPACE CONTROL */
+#  define IAC(R1)                      RRE_(0xB224,R1,0)
+/* INSERT PSW KEY */
+#  define IPK()                                S_(0xB20B,0,0)
+/* INSERT STORAGE KEY EXTENDED */
+#  define ISKE(R1,R2)                  RRE_(0xB229,R1,R2)
+/* INSERT VIRTUAL STORAGE KEY */
+#  define IVSK(R1,R2)                  RRE_(0xB223,R1,R2)
+/* INVALIDATE DAT TABLE ENTRY */
+#  define IDTE(R1,R2,R3)               RRF_(0xB98E,R3,0,R1,R2)
+/* INVALIDATE PAGE TABLE ENTRY */
+#  define IPTE(R1,R2)                  RRE_(0xB221,R1,R2)
+/* LOAD ADDRESS SPACE PARAMETER */
+#  define LASP(D1,B1,D2,B2)            SSE_(0xE500,B1,D1,B2,D2)
+/* LOAD CONTROL */
+#  define LCTL(R1,R3,D2,B2)            RS_(0xB7,R1,R3,B2,D2)
+#  define LCTLG(R1,R3,D2,B2)           RSY_(0xEB,R1,R3,B2,D2,0x2F)
+/* LOAD PSW */
+#  define LPSW(D2,B2)                  SI_(0x82,0,B2,D2)
+/* LOAD PSW EXTENDED */
+#  define LPSWE(D2,B2)                 S_(0xB2B2,B2,D2)
+/* LOAD REAL ADDRESS */
+#  define LRA(R1,D2,X2,B2)             RX_(0xB1,R1,X2,B2,D2)
+#  define LRAY(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x13)
+#  define LRAG(R1,D2,X2,B2)            RXY_(0xE3,R1,X2,B2,D2,0x03)
+/* LOAD USING REAL ADDRESS */
+#  define LURA(R1,R2)                  RRE_(0xB24B,R1,R2)
+#  define LURAG(R1,R2)                 RRE_(0xB905,R1,R2)
+/* MODIFY STACKED STATE */
+#  define MSTA(R1)                     RRE_(0xB247,R1,0)
+/* MOVE PAGE */
+#  define MVPG(R1,R2)                  RRE_(0xB254,R1,R2)
+/* MOVE TO PRIMARY */
+#  define MVCP(D1,R1,B1,D2,B2,R3)      SS_(0xDA,R1,R3,B1,D1,B2,D2)
+/* MOVE TO SECONDARY */
+#  define MVCS(D1,R1,B1,D2,B2,R3)      SS_(0xDB,R1,R3,B1,D1,B2,D2)
+/* MOVE WITH DESTINATION KEY */
+#  define MVCDK(D1,B1,D2,B2)           SSE_(0xE50F,B1,D1,B2,D2)
+/* MOVE WITH KEY */
+#  define MVCK(D1,R1,B1,D2,B2,R3)      SS_(0xD9,R1,R3,B1,D1,B2,D2)
+/* MOVE WITH SOURCE KEY */
+#  define MVCSK(D1,B1,D2,B2)           SSE_(0xE50E,B1,D1,B2,D2)
+/* PAGE IN */
+#  define PGIN(R1,R2)                  RRE_(0xB22E,R1,R2)
+/* PAGE OUT */
+#  define PGOUT(R1,R2)                 RRE_(0xB22F,R1,R2)
+/* PROGRAM CALL */
+#  define PC(D2,B2)                    S_(0xB218,B2,D2)
+/* PROGRAM RETURN */
+#  define PR()                         E_(0x0101)
+/* PROGRAM TRANSFER */
+#  define PT(R1,R2)                    RRE_(0xB228,R1,R2)
+/* PURGE ALB */
+#  define PALB()                       RRE_(0xB248,0,0)
+/* PURGE TLB */
+#  define PTLB()                       S_(0xB20D,0,0)
+/* RESET REFERENCE BIT EXTENDED */
+#  define RRBE(R1,R2)                  RRE_(0xB22A,R1,R2)
+/* RESUME PROGRAM */
+#  define RP(D2,B2)                    S_(0xB277,B2,D2)
+/* SET ADDRESS SPACE CONTROL */
+#  define SAC(D2,B2)                   S_(0xB219,B2,D2)
+/* SET ADDRESS SPACE CONTROL FAST */
+#  define SACF(D2,B2)                  S_(0xB279,B2,D2)
+/* SET CLOCK */
+#  define SCK(D2,B2)                   S_(0xB204,B2,D2)
+/* SET CLOCK COMPARATOR */
+#  define SCKC(D2,B2)                  S_(0xB206,B2,D2)
+/* SET CLOCK PROGRAMMABLE FIELD */
+#  define SCKPF()                      E_(0x0107)
+/* SET CPU TIMER */
+#  define SPT(D2,B2)                   S_(0xB208,B2,D2)
+/* SET PREFIX */
+#  define SPX(D2,B2)                   S_(0xB210,B2,D2)
+/* SET PSW FROM ADDRESS */
+#  define SPKA(D2,B2)                  S_(0xB20A,B2,D2)
+/* SET SECONDARY ASN */
+#  define SSAR(R1)                     RRE_(0xB225,R1,0)
+/* SET STORAGE KEY EXTENDED */
+#  define SSKE(R1,R2)                  RRE_(0xB22B,R1,R2)
+/* SET SYSTEM MASK */
+#  define SSM(D2,B2)                   SI_(0x80,0,B2,D2)
+/* SIGNAL PROCESSOR */
+#  define SIGP(R1,R3,D2,B2)            RS_(0xAE,R1,R3,B2,D2)
+/* STORE CLOCK COMPARATOR */
+#  define STCKC(D2,B2)                 S_(0xB207,B2,D2)
+/* STORE CONTROL */
+#  define STCTL(R1,R3,D2,B2)           RS_(0xB6,R1,R3,B2,D2)
+#  define STCTG(R1,R3,D2,B2)           RSY_(0xEB,R1,R3,B2,D2,0x25)
+/* STORE CPU ADDRESS */
+#  define STAP(D2,B2)                  S_(0xB212,B2,D2)
+/* STORE CPU ID */
+#  define STIDP(D2,B2)                 S_(0xB202,B2,D2)
+/* STORE CPU TIMER */
+#  define STPT(D2,B2)                  S_(0xB209,B2,D2)
+/* STORE FACILITY LIST */
+#  define STFL(D2,B2)                  S_(0xB2B1,B2,D2)
+/* STORE PREFIX */
+#  define STPX(D2,B2)                  S_(0xB211,B2,D2)
+/* STORE REAL ADDRES */
+#  define STRAG(D1,B1,D2,B2)           SSE_(0xE502,B1,D1,B2,D2)
+/* STORE SYSTEM INFORMATION */
+#  define STSI(D2,B2)                  S_(0xB27D,B2,D2)
+/* STORE THEN AND SYSTEM MASK */
+#  define STNSM(D1,B1,I2)              SI_(0xAC,I2,B1,D1)
+/* STORE THEN OR SYSTEM MASK */
+#  define STOSM(D1,B1,I2)              SI_(0xAD,I2,B1,D1)
+/* STORE USING REAL ADDRESS */
+#  define STURA(R1,R2)                 RRE_(0xB246,R1,R2)
+#  define STURG(R1,R2)                 RRE_(0xB925,R1,R2)
+/* TEST ACCESS */
+#  define TAR(R1,R2)                   RRE_(0xB24C,R1,R2)
+/* TEST BLOCK */
+#  define TB(R1,R2)                    RRE_(0xB22C,R1,R2)
+/* TEST PROTECTION */
+#  define TPROT(D1,B1,D2,B2)           SSE_(0xE501,B1,D1,B2,D2)
+/* TRACE */
+#  define TRACE(R1,R3,D2,B2)           RS_(0x99,R1,R3,B2,D2)
+#  define TRACG(R1,R3,D2,B2)           RSY_(0xEB,R1,R3,B2,D2,0x0F)
+/* TRAP */
+#  define TRAP2()                      E_(0x01FF)
+#  define TRAP4(D2,B2)                 S_(0xB2FF,B2,D2)
+/****************************************************************
+ * I/O Instructions                                            *
+ ****************************************************************/
+/* CANCEL SUBCHANNEL */
+#  define XSCH()                       S_(0xB276,0,0)
+/* CLEAR SUBCHANNEL */
+#  define CSCH()                       S_(0xB230,0,0)
+/* HALT SUBCHANNEL */
+#  define HSCH()                       S_(0xB231,0,0)
+/* MODIFY SUBCHANNEL */
+#  define MSCH(D2,B2)                  S_(0xB232,B2,D2)
+/* RESET CHANNEL PATH */
+#  define RCHP()                       S_(0xB23B,0,0)
+/* RESUME SUBCHANNEL */
+#  define RSCH()                       S_(0xB238,0,0)
+/* SET ADDRESS LIMIT */
+#  define SAL()                                S_(0xB237,0,0)
+/* SET CHANNEL MONITOR */
+#  define SCHM()                       S_(0xB23C,0,0)
+/* START SUBCHANNEL */
+#  define SSCH(D2,B2)                  S_(0xB233,B2,D2)
+/* STORE CHANNEL PATH STATUS */
+#  define STCPS(D2,B2)                 S_(0xB23A,B2,D2)
+/* STORE CHANNEL REPORT WORD */
+#  define STCRW(D2,B2)                 S_(0xB239,B2,D2)
+/* STORE SUBCHANNEL */
+#  define STSCH(D2,B2)                 S_(0xB234,B2,D2)
+/* TEST PENDING INTERRUPTION */
+#  define TPI(D2,B2)                   S_(0xB236,B2,D2)
+/* TEST SUBCHANNEL */
+#  define TSCH(D2,B2)                  S_(0xB235,B2,D2)
+#  define xdivr(r0,r1)                 _xdivr(_jit,r0,r1)
+static jit_int32_t _xdivr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define xdivr_u(r0,r1)               _xdivr_u(_jit,r0,r1)
+static jit_int32_t _xdivr_u(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define xdivi(r0,i0)                 _xdivi(_jit,r0,i0)
+static jit_int32_t _xdivi(jit_state_t*,jit_int32_t,jit_word_t);
+#  define xdivi_u(r0,i0)               _xdivi_u(_jit,r0,i0)
+static jit_int32_t _xdivi_u(jit_state_t*,jit_int32_t,jit_word_t);
+#  define crr(cc,r0,r1,r2)             _crr(_jit,cc,r0,r1,r2)
+static void _crr(jit_state_t*,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define cri(cc,r0,r1,i0)             _cri(_jit,cc,r0,r1,i0)
+static void _cri(jit_state_t*,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+#  define crr_u(cc,r0,r1,r2)           _crr_u(_jit,cc,r0,r1,r2)
+static void _crr_u(jit_state_t*,
+                  jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define cri_u(cc,r0,r1,i0)           _cri_u(_jit,cc,r0,r1,i0)
+static void _cri_u(jit_state_t*,
+                  jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+#  define brr(cc,i0,r0,r1)             _brr(_jit,cc,i0,r0,r1)
+static void _brr(jit_state_t*,jit_int32_t,
+                jit_word_t,jit_int32_t,jit_int32_t);
+#  define brr_p(cc,i0,r0,r1)           _brr_p(_jit,cc,i0,r0,r1)
+static jit_word_t _brr_p(jit_state_t*,jit_int32_t,
+                        jit_word_t,jit_int32_t,jit_int32_t);
+#  define bri(cc,i0,r0,i1)             _bri(_jit,cc,i0,r0,i1)
+static void _bri(jit_state_t*,jit_int32_t,
+                jit_word_t,jit_int32_t,jit_word_t);
+#  define bri_p(cc,i0,r0,i1)           _bri_p(_jit,cc,i0,r0,i1)
+static jit_word_t _bri_p(jit_state_t*,jit_int32_t,
+                        jit_word_t,jit_int32_t,jit_word_t);
+#  define brr_u(cc,i0,r0,r1)           _brr_u(_jit,cc,i0,r0,r1)
+static void _brr_u(jit_state_t*,jit_int32_t,
+                  jit_word_t,jit_int32_t,jit_int32_t);
+#  define brr_u_p(cc,i0,r0,r1)         _brr_u_p(_jit,cc,i0,r0,r1)
+static jit_word_t _brr_u_p(jit_state_t*,jit_int32_t,
+                          jit_word_t,jit_int32_t,jit_int32_t);
+#  define bri_u(cc,i0,r0,i1)           _bri_u(_jit,cc,i0,r0,i1)
+static void _bri_u(jit_state_t*,jit_int32_t,
+                  jit_word_t,jit_int32_t,jit_word_t);
+#  define bri_u_p(cc,i0,r0,i1)         _bri_u_p(_jit,cc,i0,r0,i1)
+static jit_word_t _bri_u_p(jit_state_t*,jit_int32_t,
+                          jit_word_t,jit_int32_t,jit_word_t);
+#  define baddr(c,s,i0,r0,r1)          _baddr(_jit,c,s,i0,r0,r1)
+static void _baddr(jit_state_t*,jit_int32_t,jit_bool_t,
+                  jit_word_t,jit_int32_t,jit_int32_t);
+#  define baddr_p(c,s,i0,r0,r1)                _baddr_p(_jit,c,s,i0,r0,r1)
+static jit_word_t _baddr_p(jit_state_t*,jit_int32_t,jit_bool_t,
+                          jit_word_t,jit_int32_t,jit_int32_t);
+#  define baddi(c,s,i0,r0,i1)          _baddi(_jit,c,s,i0,r0,i1)
+static void _baddi(jit_state_t*,jit_int32_t,jit_bool_t,
+                  jit_word_t,jit_int32_t,jit_word_t);
+#  define baddi_p(c,s,i0,r0,i1)                _baddi_p(_jit,c,s,i0,r0,i1)
+static jit_word_t _baddi_p(jit_state_t*,jit_int32_t,jit_bool_t,
+                          jit_word_t,jit_int32_t,jit_word_t);
+#  define bsubr(c,s,i0,r0,r1)          _bsubr(_jit,c,s,i0,r0,r1)
+static void _bsubr(jit_state_t*,jit_int32_t,jit_bool_t,
+                  jit_word_t,jit_int32_t,jit_int32_t);
+#  define bsubr_p(c,s,i0,r0,r1)                _bsubr_p(_jit,c,s,i0,r0,r1)
+static jit_word_t _bsubr_p(jit_state_t*,jit_int32_t,jit_bool_t,
+                          jit_word_t,jit_int32_t,jit_int32_t);
+#  define bsubi(c,s,i0,r0,i1)          _bsubi(_jit,c,s,i0,r0,i1)
+static void _bsubi(jit_state_t*,jit_int32_t,jit_bool_t,
+                  jit_word_t,jit_int32_t,jit_word_t);
+#  define bsubi_p(c,s,i0,r0,i1)                _bsubi_p(_jit,c,s,i0,r0,i1)
+static jit_word_t _bsubi_p(jit_state_t*,jit_int32_t,jit_bool_t,
+                          jit_word_t,jit_int32_t,jit_word_t);
+#  define bmxr(cc,i0,r0,r1)            _bmxr(_jit,cc,i0,r0,r1)
+static void _bmxr(jit_state_t*,jit_int32_t,
+                 jit_word_t,jit_int32_t,jit_int32_t);
+#  define bmxr_p(cc,i0,r0,r1)          _bmxr_p(_jit,cc,i0,r0,r1)
+static jit_word_t _bmxr_p(jit_state_t*,jit_int32_t,
+                         jit_word_t,jit_int32_t,jit_int32_t);
+#  define bmxi(cc,i0,r0,i1)            _bmxi(_jit,cc,i0,r0,i1)
+static void _bmxi(jit_state_t*,jit_int32_t,
+                 jit_word_t,jit_int32_t,jit_word_t);
+#  define bmxi_p(cc,i0,r0,i1)          _bmxi_p(_jit,cc,i0,r0,i1)
+static jit_word_t _bmxi_p(jit_state_t*,jit_int32_t,
+                         jit_word_t,jit_int32_t,jit_word_t);
+#  define movr(r0,r1)                  _movr(_jit,r0,r1)
+static void _movr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi(r0,i0)                  _movi(_jit,r0,i0)
+static void _movi(jit_state_t*,jit_int32_t,jit_word_t);
+#  define movi_p(r0,i0)                        _movi_p(_jit,r0,i0)
+static jit_word_t _movi_p(jit_state_t*,jit_int32_t,jit_word_t);
+#  define addr(r0,r1,r2)               _addr(_jit,r0,r1,r2)
+static void _addr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addi(r0,r1,i0)               _addi(_jit,r0,r1,i0)
+static void _addi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addcr(r0,r1,r2)              _addcr(_jit,r0,r1,r2)
+static void _addcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addci(r0,r1,i0)              _addci(_jit,r0,r1,i0)
+static void _addci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define addxr(r0,r1,r2)              _addxr(_jit,r0,r1,r2)
+static void _addxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addxi(r0,r1,i0)              _addxi(_jit,r0,r1,i0)
+static void _addxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subr(r0,r1,r2)               _subr(_jit,r0,r1,r2)
+static void _subr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subi(r0,r1,i0)               _subi(_jit,r0,r1,i0)
+static void _subi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subcr(r0,r1,r2)              _subcr(_jit,r0,r1,r2)
+static void _subcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subci(r0,r1,i0)              _subci(_jit,r0,r1,i0)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define subxr(r0,r1,r2)              _subxr(_jit,r0,r1,r2)
+static void _subxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subxi(r0,r1,i0)              _subxi(_jit,r0,r1,i0)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rsbi(r0, r1, i0)             _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define mulr(r0,r1,r2)               _mulr(_jit,r0,r1,r2)
+static void _mulr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define muli(r0,r1,i0)               _muli(_jit,r0,r1,i0)
+static void _muli(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr(r0,r1,r2,r3)           _qmulr(_jit,r0,r1,r2,r3)
+static void _qmulr(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qmuli(r0,r1,r2,i0)           _qmuli(_jit,r0,r1,r2,i0)
+static void _qmuli(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_word_t);
+#  define qmulr_u(r0,r1,r2,r3)         _qmulr_u(_jit,r0,r1,r2,r3)
+static void _qmulr_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qmuli_u(r0,r1,r2,i0)         _qmuli_u(_jit,r0,r1,r2,i0)
+static void _qmuli_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_word_t);
+#  define divr(r0,r1,r2)               _divr(_jit,r0,r1,r2)
+static void _divr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi(r0,r1,i0)               _divi(_jit,r0,r1,i0)
+static void _divi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define divr_u(r0,r1,r2)             _divr_u(_jit,r0,r1,r2)
+static void _divr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi_u(r0,r1,i0)             _divi_u(_jit,r0,r1,i0)
+static void _divi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define remr(r0,r1,r2)               _remr(_jit,r0,r1,r2)
+static void _remr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi(r0,r1,i0)               _remi(_jit,r0,r1,i0)
+static void _remi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define remr_u(r0,r1,r2)             _remr_u(_jit,r0,r1,r2)
+static void _remr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define remi_u(r0,r1,i0)             _remi_u(_jit,r0,r1,i0)
+static void _remi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define qdivr(r0,r1,r2,r3)           _qdivr(_jit,r0,r1,r2,r3)
+static void _qdivr(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qdivi(r0,r1,r2,i0)           _qdivi(_jit,r0,r1,r2,i0)
+static void _qdivi(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_word_t);
+#  define qdivr_u(r0,r1,r2,r3)         _qdivr_u(_jit,r0,r1,r2,r3)
+static void _qdivr_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_int32_t);
+#  define qdivi_u(r0,r1,r2,i0)         _qdivi_u(_jit,r0,r1,r2,i0)
+static void _qdivi_u(jit_state_t*,jit_int32_t,
+                    jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define lshr(r0,r1,r2)             _lshr(_jit,r0,r1,r2)
+static void _lshr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  else
+#    define lshr(r0,r1,r2)             SLLG(r0,r1,0,r2)
+#  endif
+#  define lshi(r0,r1,i0)               _lshi(_jit,r0,r1,i0)
+static void _lshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define rshr(r0,r1,r2)             _rshr(_jit,r0,r1,r2)
+static void _rshr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  else
+#    define rshr(r0,r1,r2)             SRAG(r0,r1,0,r2)
+#  endif
+#  define rshi(r0,r1,i0)               _rshi(_jit,r0,r1,i0)
+static void _rshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define rshr_u(r0,r1,r2)           _rshr_u(_jit,r0,r1,r2)
+static void _rshr_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  else
+#    define rshr_u(r0,r1,r2)           SRLG(r0,r1,0,r2)
+#  endif
+#  define rshi_u(r0,r1,i0)             _rshi_u(_jit,r0,r1,i0)
+static void _rshi_u(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define negr(r0,r1)                        LCR(r0,r1)
+#  else
+#    define negr(r0,r1)                        LCGR(r0,r1)
+#  endif
+#  define comr(r0,r1)                  _comr(_jit,r0,r1)
+static void _comr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define andr(r0,r1,r2)               _andr(_jit,r0,r1,r2)
+static void _andr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define andi(r0,r1,i0)               _andi(_jit,r0,r1,i0)
+static void _andi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define orr(r0,r1,r2)                        _orr(_jit,r0,r1,r2)
+static void _orr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ori(r0,r1,i0)                        _ori(_jit,r0,r1,i0)
+static void _ori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define xorr(r0,r1,r2)               _xorr(_jit,r0,r1,r2)
+static void _xorr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define xori(r0,r1,i0)               _xori(_jit,r0,r1,i0)
+static void _xori(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define htonr_us(r0,r1)              extr_us(r0,r1)
+#  if __WORDSIZE == 32
+#    define htonr_ui(r0,r1)            movr(r0,r1)
+#  else
+#    define htonr_ui(r0,r1)            extr_ui(r0,r1)
+#    define htonr_ul(r0,r1)            movr(r0,r1)
+#  endif
+#  define extr_c(r0,r1)                        LGBR(r0,r1)
+#  define extr_uc(r0,r1)               LLGCR(r0,r1)
+#  define extr_s(r0,r1)                        LGHR(r0,r1)
+#  define extr_us(r0,r1)               LLGHR(r0,r1)
+#  if __WORDSIZE == 64
+#    define extr_i(r0,r1)              LGFR(r0,r1)
+#    define extr_ui(r0,r1)             LLGFR(r0,r1)
+#  endif
+#  define ldr_c(r0,r1)                 LGB(r0,0,0,r1)
+#  define ldi_c(r0,i0)                 _ldi_c(_jit,r0,i0)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_c(r0,r1,r2)             _ldxr_c(_jit,r0,r1,r2)
+static void _ldxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_c(r0,r1,i0)             _ldxi_c(_jit,r0,r1,i0)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_uc(r0,r1)                        LLGC(r0,0,0,r1)
+#  define ldi_uc(r0,i0)                        _ldi_uc(_jit,r0,i0)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_uc(r0,r1,r2)            _ldxr_uc(_jit,r0,r1,r2)
+static void _ldxr_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_uc(r0,r1,i0)            _ldxi_uc(_jit,r0,r1,i0)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define ldr_s(r0,r1)               LH(r0,0,0,r1)
+#  else
+#    define ldr_s(r0,r1)               LGH(r0,0,0,r1)
+#  endif
+#  define ldi_s(r0,i0)                 _ldi_s(_jit,r0,i0)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_s(r0,r1,r2)             _ldxr_s(_jit,r0,r1,r2)
+static void _ldxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_s(r0,r1,i0)             _ldxi_s(_jit,r0,r1,i0)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldr_us(r0,r1)                        LLGH(r0,0,0,r1)
+#  define ldi_us(r0,i0)                        _ldi_us(_jit,r0,i0)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_us(r0,r1,r2)            _ldxr_us(_jit,r0,r1,r2)
+static void _ldxr_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_us(r0,r1,i0)            _ldxi_us(_jit,r0,r1,i0)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define ldr_i(r0,r1)               LLGF(r0,0,0,r1)
+#  else
+#    define ldr_i(r0,r1)               LGF(r0,0,0,r1)
+#  endif
+#  define ldi_i(r0,i0)                 _ldi_i(_jit,r0,i0)
+static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_i(r0,r1,r2)             _ldxr_i(_jit,r0,r1,r2)
+static void _ldxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_i(r0,r1,i0)             _ldxi_i(_jit,r0,r1,i0)
+static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 64
+#    define ldr_ui(r0,r1)              LLGF(r0,0,0,r1)
+#    define ldi_ui(r0,i0)              _ldi_ui(_jit,r0,i0)
+static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
+#    define ldxr_ui(r0,r1,r2)          _ldxr_ui(_jit,r0,r1,r2)
+static void _ldxr_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define ldxi_ui(r0,r1,i0)          _ldxi_ui(_jit,r0,r1,i0)
+static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#    define ldr_l(r0,r1)               LG(r0,0,0,r1)
+#    define ldi_l(r0,i0)               _ldi_l(_jit,r0,i0)
+static void _ldi_l(jit_state_t*,jit_int32_t,jit_word_t);
+#    define ldxr_l(r0,r1,r2)           _ldxr_l(_jit,r0,r1,r2)
+static void _ldxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#    define ldxi_l(r0,r1,i0)           _ldxi_l(_jit,r0,r1,i0)
+static void _ldxi_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  endif
+#  define str_c(r0,r1)                 STC(r1,0,0,r0)
+#  define sti_c(i0,r0)                 _sti_c(_jit,i0,r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_c(r0,r1,r2)             _stxr_c(_jit,r0,r1,r2)
+static void _stxr_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_c(i0,r0,r1)             _stxi_c(_jit,i0,r0,r1)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define str_s(r0,r1)                 STH(r1,0,0,r0)
+#  define sti_s(i0,r0)                 _sti_s(_jit,i0,r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_s(r0,r1,r2)             _stxr_s(_jit,r0,r1,r2)
+static void _stxr_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_s(i0,r0,r1)             _stxi_s(_jit,i0,r0,r1)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define str_i(r0,r1)                 ST(r1,0,0,r0)
+#  define sti_i(i0,r0)                 _sti_i(_jit,i0,r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_i(r0,r1,r2)             _stxr_i(_jit,r0,r1,r2)
+static void _stxr_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_i(i0,r0,r1)             _stxi_i(_jit,i0,r0,r1)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#    define str_l(r0,r1)               STG(r1,0,0,r0)
+#    define sti_l(i0,r0)               _sti_l(_jit,i0,r0)
+static void _sti_l(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_l(r0,r1,r2)             _stxr_l(_jit,r0,r1,r2)
+static void _stxr_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_l(i0,r0,r1)             _stxi_l(_jit,i0,r0,r1)
+static void _stxi_l(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  endif
+#  define ltr(r0,r1,r2)                        crr(CC_L,r0,r1,r2)
+#  define lti(r0,r1,i0)                        cri(CC_L,r0,r1,i0)
+#  define ltr_u(r0,r1,r2)              crr_u(CC_L,r0,r1,r2)
+#  define lti_u(r0,r1,i0)              cri_u(CC_L,r0,r1,i0)
+#  define ler(r0,r1,r2)                        crr(CC_LE,r0,r1,r2)
+#  define lei(r0,r1,i0)                        cri(CC_LE,r0,r1,i0)
+#  define ler_u(r0,r1,r2)              crr_u(CC_LE,r0,r1,r2)
+#  define lei_u(r0,r1,i0)              cri_u(CC_LE,r0,r1,i0)
+#  define eqr(r0,r1,r2)                        crr(CC_E,r0,r1,r2)
+#  define eqi(r0,r1,i0)                        cri(CC_E,r0,r1,i0)
+#  define ger(r0,r1,r2)                        crr(CC_HE,r0,r1,r2)
+#  define gei(r0,r1,i0)                        cri(CC_HE,r0,r1,i0)
+#  define ger_u(r0,r1,r2)              crr_u(CC_HE,r0,r1,r2)
+#  define gei_u(r0,r1,i0)              cri_u(CC_HE,r0,r1,i0)
+#  define gtr(r0,r1,r2)                        crr(CC_H,r0,r1,r2)
+#  define gti(r0,r1,i0)                        cri(CC_H,r0,r1,i0)
+#  define gtr_u(r0,r1,r2)              crr_u(CC_H,r0,r1,r2)
+#  define gti_u(r0,r1,i0)              cri_u(CC_H,r0,r1,i0)
+#  define ner(r0,r1,r2)                        crr(CC_NE,r0,r1,r2)
+#  define nei(r0,r1,i0)                        cri(CC_NE,r0,r1,i0)
+#  define bltr(i0,r0,r1)               brr(CC_L,i0,r0,r1)
+#  define bltr_p(i0,r0,r1)             brr_p(CC_L,i0,r0,r1)
+#  define blti(i0,r0,i1)               bri(CC_L,i0,r0,i1)
+#  define blti_p(i0,r0,i1)             bri_p(CC_L,i0,r0,i1)
+#  define bltr_u(i0,r0,r1)             brr_u(CC_L,i0,r0,r1)
+#  define bltr_u_p(i0,r0,r1)           brr_u_p(CC_L,i0,r0,r1)
+#  define blti_u(i0,r0,i1)             bri_u(CC_L,i0,r0,i1)
+#  define blti_u_p(i0,r0,i1)           bri_u_p(CC_L,i0,r0,i1)
+#  define bler(i0,r0,r1)               brr(CC_LE,i0,r0,r1)
+#  define bler_p(i0,r0,r1)             brr_p(CC_LE,i0,r0,r1)
+#  define blei(i0,r0,i1)               bri(CC_LE,i0,r0,i1)
+#  define blei_p(i0,r0,i1)             bri_p(CC_LE,i0,r0,i1)
+#  define bler_u(i0,r0,r1)             brr_u(CC_LE,i0,r0,r1)
+#  define bler_u_p(i0,r0,r1)           brr_u_p(CC_LE,i0,r0,r1)
+#  define blei_u(i0,r0,i1)             bri_u(CC_LE,i0,r0,i1)
+#  define blei_u_p(i0,r0,i1)           bri_u_p(CC_LE,i0,r0,i1)
+#  define beqr(i0,r0,r1)               brr(CC_E,i0,r0,r1)
+#  define beqr_p(i0,r0,r1)             brr_p(CC_E,i0,r0,r1)
+#  define beqi(i0,r0,i1)               bri(CC_E,i0,r0,i1)
+#  define beqi_p(i0,r0,i1)             bri_p(CC_E,i0,r0,i1)
+#  define bger(i0,r0,r1)               brr(CC_HE,i0,r0,r1)
+#  define bger_p(i0,r0,r1)             brr_p(CC_HE,i0,r0,r1)
+#  define bgei(i0,r0,i1)               bri(CC_HE,i0,r0,i1)
+#  define bgei_p(i0,r0,i1)             bri_p(CC_HE,i0,r0,i1)
+#  define bger_u(i0,r0,r1)             brr_u(CC_HE,i0,r0,r1)
+#  define bger_u_p(i0,r0,r1)           brr_u_p(CC_HE,i0,r0,r1)
+#  define bgei_u(i0,r0,i1)             bri_u(CC_HE,i0,r0,i1)
+#  define bgei_u_p(i0,r0,i1)           bri_u_p(CC_HE,i0,r0,i1)
+#  define bgtr(i0,r0,r1)               brr(CC_H,i0,r0,r1)
+#  define bgtr_p(i0,r0,r1)             brr_p(CC_H,i0,r0,r1)
+#  define bgti(i0,r0,i1)               bri(CC_H,i0,r0,i1)
+#  define bgti_p(i0,r0,i1)             bri_p(CC_H,i0,r0,i1)
+#  define bgtr_u(i0,r0,r1)             brr_u(CC_H,i0,r0,r1)
+#  define bgtr_u_p(i0,r0,r1)           brr_u_p(CC_H,i0,r0,r1)
+#  define bgti_u(i0,r0,i1)             bri_u(CC_H,i0,r0,i1)
+#  define bgti_u_p(i0,r0,i1)           bri_u_p(CC_H,i0,r0,i1)
+#  define bner(i0,r0,r1)               brr(CC_NE,i0,r0,r1)
+#  define bner_p(i0,r0,r1)             brr_p(CC_NE,i0,r0,r1)
+#  define bnei(i0,r0,i1)               bri(CC_NE,i0,r0,i1)
+#  define bnei_p(i0,r0,i1)             bri_p(CC_NE,i0,r0,i1)
+#  define boaddr(i0,r0,r1)             baddr(CC_O,1,i0,r0,r1)
+#  define boaddr_p(i0,r0,r1)           baddr_p(CC_O,1,i0,r0,r1)
+#  define boaddi(i0,r0,i1)             baddi(CC_O,1,i0,r0,i1)
+#  define boaddi_p(i0,r0,i1)           baddi_p(CC_O,1,i0,r0,i1)
+#  define boaddr_u(i0,r0,r1)           baddr(CC_NLE,0,i0,r0,r1)
+#  define boaddr_u_p(i0,r0,r1)         baddr_p(CC_NLE,0,i0,r0,r1)
+#  define boaddi_u(i0,r0,i1)           baddi(CC_NLE,0,i0,r0,i1)
+#  define boaddi_u_p(i0,r0,i1)         baddi_p(CC_NLE,0,i0,r0,i1)
+#  define bxaddr(i0,r0,r1)             baddr(CC_NO,1,i0,r0,r1)
+#  define bxaddr_p(i0,r0,r1)           baddr_p(CC_NO,1,i0,r0,r1)
+#  define bxaddi(i0,r0,i1)             baddi(CC_NO,1,i0,r0,i1)
+#  define bxaddi_p(i0,r0,i1)           baddi_p(CC_NO,1,i0,r0,i1)
+#  define bxaddr_u(i0,r0,r1)           baddr(CC_LE,0,i0,r0,r1)
+#  define bxaddr_u_p(i0,r0,r1)         baddr_p(CC_LE,0,i0,r0,r1)
+#  define bxaddi_u(i0,r0,i1)           baddi(CC_LE,0,i0,r0,i1)
+#  define bxaddi_u_p(i0,r0,i1)         baddi_p(CC_LE,0,i0,r0,i1)
+#  define bosubr(i0,r0,r1)             bsubr(CC_O,1,i0,r0,r1)
+#  define bosubr_p(i0,r0,r1)           bsubr_p(CC_O,1,i0,r0,r1)
+#  define bosubi(i0,r0,i1)             bsubi(CC_O,1,i0,r0,i1)
+#  define bosubi_p(i0,r0,i1)           bsubi_p(CC_O,1,i0,r0,i1)
+#  define bosubr_u(i0,r0,r1)           bsubr(CC_L,0,i0,r0,r1)
+#  define bosubr_u_p(i0,r0,r1)         bsubr_p(CC_L,0,i0,r0,r1)
+#  define bosubi_u(i0,r0,i1)           bsubi(CC_L,0,i0,r0,i1)
+#  define bosubi_u_p(i0,r0,i1)         bsubi_p(CC_L,0,i0,r0,i1)
+#  define bxsubr(i0,r0,r1)             bsubr(CC_NO,1,i0,r0,r1)
+#  define bxsubr_p(i0,r0,r1)           bsubr_p(CC_NO,1,i0,r0,r1)
+#  define bxsubi(i0,r0,i1)             bsubi(CC_NO,1,i0,r0,i1)
+#  define bxsubi_p(i0,r0,i1)           bsubi_p(CC_NO,1,i0,r0,i1)
+#  define bxsubr_u(i0,r0,r1)           bsubr(CC_NL,0,i0,r0,r1)
+#  define bxsubr_u_p(i0,r0,r1)         bsubr_p(CC_NL,0,i0,r0,r1)
+#  define bxsubi_u(i0,r0,i1)           bsubi(CC_NL,0,i0,r0,i1)
+#  define bxsubi_u_p(i0,r0,i1)         bsubi_p(CC_NL,0,i0,r0,i1)
+#  define bmsr(i0,r0,r1)               bmxr(CC_NE,i0,r0,r1)
+#  define bmsr_p(i0,r0,r1)             bmxr_p(CC_NE,i0,r0,r1)
+#  define bmsi(i0,r0,i1)               bmxi(CC_NE,i0,r0,i1)
+#  define bmsi_p(i0,r0,i1)             bmxi_p(CC_NE,i0,r0,i1)
+#  define bmcr(i0,r0,r1)               bmxr(CC_E,i0,r0,r1)
+#  define bmcr_p(i0,r0,r1)             bmxr_p(CC_E,i0,r0,r1)
+#  define bmci(i0,r0,i1)               bmxi(CC_E,i0,r0,i1)
+#  define bmci_p(i0,r0,i1)             bmxi_p(CC_E,i0,r0,i1)
+#  define jmpr(r0)                     BR(r0)
+#  define jmpi(i0)                     _jmpi(_jit,i0)
+static void _jmpi(jit_state_t*,jit_word_t);
+#  define jmpi_p(i0)                   _jmpi_p(_jit,i0)
+static jit_word_t _jmpi_p(jit_state_t*,jit_word_t);
+#  define callr(r0)                    BALR(_R14_REGNO,r0)
+#  define calli(i0)                    _calli(_jit,i0)
+static void _calli(jit_state_t*,jit_word_t);
+#  define calli_p(i0)                  _calli_p(_jit,i0)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t);
+#  define prolog(i0)                   _prolog(_jit,i0)
+static void _prolog(jit_state_t*,jit_node_t*);
+#  define epilog(i0)                   _epilog(_jit,i0)
+static void _epilog(jit_state_t*,jit_node_t*);
+#  define vastart(r0)                  _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#  define vaarg(r0, r1)                        _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define patch_at(instr,label)                _patch_at(_jit,instr,label)
+static void _patch_at(jit_state_t*,jit_word_t,jit_word_t);
+#endif
+
+#if CODE
+#  define _us                          jit_uint16_t
+#  define _ui                          jit_uint32_t
+static void
+_E(jit_state_t *_jit, _ui Op)
+{
+    union {
+       struct {
+           _us op;
+       } b;
+       _us     s;
+    } i0;
+    i0.b.op = Op;
+    assert(i0.b.op == Op);
+    is(i0.s);
+}
+
+static void
+_I(jit_state_t *_jit, _ui Op, _ui I)
+{
+    union {
+       struct {
+           _us op : 8;
+           _us i  : 8;
+       } b;
+       _us     s;
+    } i0;
+    i0.b.op = Op;
+    i0.b.i  = I;
+    assert(i0.b.op == Op);
+    assert(i0.b.i  == I);
+    is(i0.s);
+}
+
+static void
+_RR(jit_state_t *_jit, _ui Op, _ui R1, _ui R2)
+{
+    union {
+       struct {
+           _us op : 8;
+           _us r1 : 4;
+           _us r2 : 4;
+       } b;
+       _us     s;
+    } i0;
+    i0.b.op = Op;
+    i0.b.r1 = R1;
+    i0.b.r2 = R2;
+    assert(i0.b.op == Op);
+    assert(i0.b.r1 == R1);
+    assert(i0.b.r2 == R2);
+    is(i0.s);
+}
+
+static void
+_RRE(jit_state_t *_jit, _ui Op, _ui R1, _ui R2)
+{
+    union {
+       struct {
+           _us op;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us _  : 8;
+           _us r1 : 4;
+           _us r2 : 4;
+       } b;
+       _us     s;
+    } i1;
+    i0.b.op = Op;
+    i1.b._ = 0;
+    i1.b.r1 = R1;
+    i1.b.r2 = R2;
+    assert(i0.b.op == Op);
+    assert(i1.b.r1 == R1);
+    assert(i1.b.r2 == R2);
+    is(i0.s);
+    is(i1.s);
+}
+
+static void
+_RRF(jit_state_t *_jit, _ui Op, _ui R3, _ui M4, _ui R1, _ui R2)
+{
+    union {
+       struct {
+           _us op;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us r3 : 4;
+           _us m4 : 4;
+           _us r1 : 4;
+           _us r2 : 4;
+       } b;
+       _us     s;
+    } i1;
+    i0.b.op = Op;
+    i1.b.r3 = R3;
+    i1.b.m4 = M4;
+    i1.b.r1 = R1;
+    i1.b.r2 = R2;
+    assert(i0.b.op == Op);
+    assert(i1.b.r3 == R3);
+    assert(i1.b.m4 == M4);
+    assert(i1.b.r1 == R1);
+    assert(i1.b.r2 == R2);
+    is(i0.s);
+    is(i1.s);
+}
+
+static void
+_RX(jit_state_t *_jit, _ui Op, _ui R1, _ui X2, _ui B2, _ui D2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us r1 :  4;
+           _us x2 :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b2 :  4;
+           _us d2 : 12;
+       } b;
+       _us     s;
+    } i1;
+    i0.b.op = Op;
+    i0.b.r1 = R1;
+    i0.b.x2 = X2;
+    i1.b.b2 = B2;
+    i1.b.d2 = D2;
+    assert(i0.b.op == Op);
+    assert(i0.b.r1 == R1);
+    assert(i0.b.x2 == X2);
+    assert(i1.b.b2 == B2);
+    assert(i1.b.d2 == D2);
+    is(i0.s);
+    is(i1.s);
+}
+
+static void
+_RXE(jit_state_t *_jit, _ui Op, _ui R1, _ui X2, _ui B2, _ui D2, _ui Op2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us r1 :  4;
+           _us x2 :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b2 :  4;
+           _us d2 : 12;
+       } b;
+       _ui     s;
+    } i1;
+    union {
+       struct {
+           _us _  :  8;
+           _us op :  8;
+       } b;
+       _us     s;
+    } i2;
+    i2.b._ = 0;
+    i0.b.op = Op;
+    i0.b.r1 = R1;
+    i0.b.x2 = X2;
+    i1.b.b2 = B2;
+    i1.b.d2 = D2;
+    i2.b.op = Op2;
+    assert(i0.b.op == Op);
+    assert(i0.b.r1 == R1);
+    assert(i0.b.x2 == X2);
+    assert(i1.b.b2 == B2);
+    assert(i1.b.d2 == D2);
+    assert(i2.b.op == Op2);
+    is(i0.s);
+    is(i1.s);
+    is(i2.s);
+}
+
+static void
+_RXF(jit_state_t *_jit, _ui Op, _ui R3, _ui X2, _ui B2, _ui D2, _ui R1, _ui Op2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us r3 :  4;
+           _us x2 :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b2 :  4;
+           _us d2 : 12;
+       } b;
+       _us     s;
+    } i1;
+    union {
+       struct {
+           _us r1 :  4;
+           _us _  :  4;
+           _us op :  8;
+       } b;
+       _us     s;
+    } i2;
+    i2.b._ = 0;
+    i0.b.op = Op;
+    i0.b.r3 = R3;
+    i0.b.x2 = X2;
+    i1.b.b2 = B2;
+    i1.b.d2 = D2;
+    i2.b.r1 = R1;
+    i2.b.op = Op2;
+    assert(i0.b.op == Op);
+    assert(i0.b.r3 == R3);
+    assert(i0.b.x2 == X2);
+    assert(i1.b.b2 == B2);
+    assert(i1.b.d2 == D2);
+    assert(i2.b.r1 == R1);
+    assert(i2.b.op == Op2);
+    is(i0.s);
+    is(i1.s);
+    is(i2.s);
+}
+
+static void
+_RXY(jit_state_t *_jit, _ui Op, _ui R1, _ui X2, _ui B2, _ui D2, _ui Op2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us r1 :  4;
+           _us x2 :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b2 :  4;
+           _us dl : 12;
+       } b;
+       _us     s;
+    } i1;
+    union {
+       struct {
+           _us dh :  8;
+           _us op :  8;
+       } b;
+       _us     s;
+    } i2;
+    i0.s = i1.s = i2.s = 0;
+    i0.b.op = Op;
+    i0.b.r1 = R1;
+    i0.b.x2 = X2;
+    i1.b.b2 = B2;
+    i1.b.dl = D2 & 0xfff;
+    i2.b.dh = D2 >> 12;
+    i2.b.op = Op2;
+    assert(i0.b.op == Op);
+    assert(i0.b.r1 == R1);
+    assert(i0.b.x2 == X2);
+    assert(i1.b.b2 == B2);
+    assert(i2.b.dh == D2 >> 12);
+    assert(i2.b.op == Op2);
+    is(i0.s);
+    is(i1.s);
+    is(i2.s);
+}
+
+static void
+_RS(jit_state_t *_jit, _ui Op, _ui R1, _ui R3, _ui B2, _ui D2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us r1 :  4;
+           _us r3 :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b2 :  4;
+           _us d2 : 12;
+       } b;
+       _us     s;
+    } i1;
+    i0.s = i1.s = 0;
+    i0.b.op = Op;
+    i0.b.r1 = R1;
+    i0.b.r3 = R3;
+    i1.b.b2 = B2;
+    i1.b.d2 = D2;
+    assert(i0.b.op == Op);
+    assert(i0.b.r1 == R1);
+    assert(i0.b.r3 == R3);
+    assert(i1.b.b2 == B2);
+    assert(i1.b.d2 == D2);
+    is(i0.s);
+    is(i1.s);
+}
+
+static void
+_RSL(jit_state_t *_jit, _ui Op, _ui L1, _ui B1, _ui D1, _ui Op2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us l1 :  4;
+           _us _  :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b1 :  4;
+           _us d1 : 12;
+       } b;
+       _us     s;
+    } i1;
+    union {
+       struct {
+           _us _  :  8;
+           _us op :  8;
+       } b;
+       _us     s;
+    } i2;
+    i0.b._ = 0;
+    i2.b._ = 0;
+    i0.b.op = Op;
+    i0.b.l1 = L1;
+    i1.b.b1 = B1;
+    i1.b.d1 = D1;
+    i2.b.op = Op2;
+    assert(i0.b.op == Op);
+    assert(i0.b.l1 == L1);
+    assert(i1.b.b1 == B1);
+    assert(i1.b.d1 == D1);
+    assert(i2.b.op == Op2);
+    is(i0.s);
+    is(i1.s);
+    is(i2.s);
+}
+
+static void
+_RSI(jit_state_t *_jit, _ui Op, _ui R1, _ui R3, _ui I2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us r1 :  4;
+           _us r3 :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us i2;
+       } b;
+       _us     s;
+    } i1;
+    i0.b.op = Op;
+    i0.b.r1 = R1;
+    i0.b.r3 = R3;
+    i1.b.i2 = I2;
+    assert(i0.b.op == Op);
+    assert(i0.b.r1 == R1);
+    assert(i0.b.r3 == R3);
+    assert(i1.b.i2 == I2);
+    is(i0.s);
+    is(i1.s);
+}
+
+static void
+_RIE(jit_state_t *_jit, _ui Op, _ui R1, _ui R3, _ui I2, _ui Op2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us r1 :  4;
+           _us r3 :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us i2;
+       } b;
+       _us     s;
+    } i1;
+    union {
+       struct {
+           _us _  :  8;
+           _us op :  8;
+       } b;
+       _us     s;
+    } i2;
+    i2.b._ = 0;
+    i0.b.op = Op;
+    i0.b.r1 = R1;
+    i0.b.r3 = R3;
+    i1.b.i2 = I2;
+    i2.b.op = Op2;
+    assert(i0.b.op == Op);
+    assert(i0.b.r1 == R1);
+    assert(i0.b.r3 == R3);
+    assert(i1.b.i2 == I2);
+    assert(i2.b.op == Op2);
+    is(i0.s);
+    is(i1.s);
+    is(i2.s);
+}
+
+static void
+_RIL(jit_state_t *_jit, _ui Op, _ui R1, _ui Op2, _ui I2)
+{
+    union {
+       struct {
+           _us o1 :  8;
+           _us r1 :  4;
+           _us o2 :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _ui ih : 16;
+           _ui il : 16;
+       } b;
+       _ui     i;
+    } i12;
+    i0.b.o1 = Op;
+    i0.b.r1 = R1;
+    i0.b.o2 = Op2;
+    i12.i   = I2;
+    assert(i0.b.o1 == Op);
+    assert(i0.b.r1 == R1);
+    assert(i0.b.o2 == Op2);
+    is(i0.s);
+    is(i12.b.ih);
+    is(i12.b.il);
+}
+
+static void
+_SI(jit_state_t *_jit, _ui Op, _ui I2, _ui B1, _ui D1)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us i2 :  8;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b1 :  4;
+           _us d1 : 12;
+       } b;
+       _us     s;
+    } i1;
+    i0.b.op = Op;
+    i0.b.i2 = I2;
+    i1.b.b1 = B1;
+    i1.b.d1 = D1;
+    assert(i0.b.op == Op);
+    assert(i0.b.i2 == I2);
+    assert(i1.b.b1 == B1);
+    assert(i1.b.d1 == D1);
+    is(i0.s);
+    is(i1.s);
+}
+
+static void
+_SIY(jit_state_t *_jit, _ui Op, _ui I2, _ui B1, _ui D1, _ui Op2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us i2 :  8;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b1 :  4;
+           _us dl : 12;
+       } b;
+       _us     s;
+    } i1;
+    union {
+       struct {
+           _us dh :  8;
+           _us op :  8;
+       } b;
+       _us     s;
+    } i2;
+    i0.b.op = Op;
+    i0.b.i2 = I2;
+    i1.b.b1 = B1;
+    i1.b.dl = D1 & 0xfff;
+    i2.b.dh = D1 >> 8;
+    i2.b.op = Op2;
+    assert(i0.b.op == Op);
+    assert(i0.b.i2 == I2);
+    assert(i1.b.b1 == B1);
+    assert(i2.b.dh == D1 >> 8);
+    assert(i2.b.op == Op2);
+    is(i0.s);
+    is(i1.s);
+    is(i2.s);
+}
+
+static void
+_S(jit_state_t *_jit, _ui Op, _ui B2, _ui D2)
+{
+    union {
+       struct {
+           _us op;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b2 :  4;
+           _us d2 : 12;
+       } b;
+       _us     s;
+    } i1;
+    i0.b.op = Op;
+    i1.b.b2 = B2;
+    i1.b.d2 = D2;
+    assert(i0.b.op == Op);
+    assert(i1.b.b2 == B2);
+    assert(i1.b.d2 == D2);
+    is(i0.s);
+    is(i1.s);
+}
+
+static void
+_SS(jit_state_t *_jit, _ui Op, _ui LL, _ui LH, _ui B1, _ui D1, _ui B2, _ui D2)
+{
+    union {
+       struct {
+           _us op :  8;
+           _us ll :  4;
+           _us lh :  4;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b1 :  4;
+           _us d1 : 12;
+       } b;
+       _us     s;
+    } i1;
+    union {
+       struct {
+           _us b2 :  4;
+           _us d2 : 12;
+       } b;
+       _us     s;
+    } i2;
+    i0.b.op = Op;
+    i0.b.ll = LL;
+    i0.b.lh = LH;
+    i1.b.b1 = B1;
+    i1.b.d1 = D1;
+    i2.b.b2 = B2;
+    i2.b.d2 = D2;
+    assert(i0.b.op == Op);
+    assert(i0.b.ll == LL);
+    assert(i0.b.lh == LH);
+    assert(i1.b.b1 == B1);
+    assert(i1.b.d1 == D1);
+    assert(i2.b.b2 == B2);
+    assert(i2.b.d2 == D2);
+    is(i0.s);
+    is(i1.s);
+    is(i2.s);
+}
+
+static void
+_SSE(jit_state_t *_jit, _ui Op, _ui B1, _ui D1, _ui B2, _ui D2)
+{
+    union {
+       struct {
+           _us op;
+       } b;
+       _us     s;
+    } i0;
+    union {
+       struct {
+           _us b1 :  4;
+           _us d1 : 12;
+       } b;
+       _us     s;
+    } i1;
+    union {
+       struct {
+           _us b2 :  4;
+           _us d2 : 12;
+       } b;
+       _us     s;
+    } i2;
+    i0.b.op = Op;
+    i1.b.b1 = B1;
+    i1.b.d1 = D1;
+    i2.b.b2 = B2;
+    i2.b.d2 = D2;
+    assert(i0.b.op == Op);
+    assert(i1.b.b1 == B1);
+    assert(i1.b.d1 == D1);
+    assert(i2.b.b2 == B2);
+    assert(i2.b.d2 == D2);
+    is(i0.s);
+    is(i1.s);
+    is(i2.s);
+}
+#  undef _us
+#  undef _ui
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t c)
+{
+    assert(c >= 0 && !(c & 1));
+    while (c) {
+       NOPR(_R7_REGNO);
+       c -= 2;
+    }
+}
+
+static jit_int32_t
+_xdivr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                regno;
+    regno = jit_get_reg_pair();
+#if __WORDSIZE == 32
+    movr(rn(regno), r0);
+    SRDA(rn(regno), 32, 0);
+#else
+    movr(rn(regno) + 1, r0);
+#endif
+    DIVREM_(rn(regno), r1);
+    jit_unget_reg_pair(regno);
+    return (regno);
+}
+
+static jit_int32_t
+_xdivr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                regno;
+    regno = jit_get_reg_pair();
+#if __WORDSIZE == 32
+    movr(rn(regno), r0);
+    SRDL(rn(regno), 32, 0);
+#else
+    movr(rn(regno) + 1, r0);
+#endif
+    movi(rn(regno), 0);
+    DIVREMU_(rn(regno), r1);
+    jit_unget_reg_pair(regno);
+    return (regno);
+}
+
+static jit_int32_t
+_xdivi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                imm, regno;
+    regno = jit_get_reg_pair();
+    imm = jit_get_reg(jit_class_gpr);
+#if __WORDSIZE == 32
+    movr(rn(regno), r0);
+    SRDA(rn(regno), 32, 0);
+#else
+    movr(rn(regno) + 1, r0);
+#endif
+    movi(rn(imm), i0);
+    DIVREM_(rn(regno), rn(imm));
+    jit_unget_reg(imm);
+    jit_unget_reg_pair(regno);
+    return (regno);
+}
+
+static jit_int32_t
+_xdivi_u(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    /* cannot overlap because operand is 128-bit */
+    jit_int32_t                imm, regno;
+    regno = jit_get_reg_pair();
+    imm = jit_get_reg(jit_class_gpr);
+#if __WORDSIZE == 32
+    movr(rn(regno), r0);
+    SRDL(rn(regno), 32, 0);
+#else
+    movr(rn(regno) + 1, r0);
+#endif
+    movi(rn(regno), 0);
+    movi(rn(imm), i0);
+    DIVREMU_(rn(regno), rn(imm));
+    jit_unget_reg(imm);
+    jit_unget_reg_pair(regno);
+    return (regno);
+}
+
+static void
+_crr(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                reg, rg;
+    if (r0 == r1 || r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       rg = rn(reg);
+    }
+    else
+       rg = r0;
+    movi(rg, 1);
+    CMP_(r1, r2);
+    w = _jit->pc.w;
+    BRC(cc, 0);
+    movi(rg, 0);
+    patch_at(w, _jit->pc.w);
+    if (r0 == r1 || r0 == r2) {
+       movr(r0, rg);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_cri(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    crr(cc, r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_crr_u(jit_state_t *_jit, jit_int32_t cc,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    jit_int32_t                reg, rg;
+    if (r0 == r1 || r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       rg = rn(reg);
+    }
+    else
+       rg = r0;
+    movi(rg, 1);
+    CMPU_(r1, r2);
+    w = _jit->pc.w;
+    BRC(cc, 0);
+    movi(rg, 0);
+    patch_at(w, _jit->pc.w);
+    if (r0 == r1 || r0 == r2) {
+       movr(r0, rg);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_cri_u(jit_state_t *_jit, jit_int32_t cc,
+       jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    crr_u(cc, r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_brr(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d;
+    CMP_(r0, r1);
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(d))
+       BRC(cc, x16(d));
+    else {
+       assert(s32_p(d));
+       BRCL(cc, d);
+    }
+}
+
+static jit_word_t
+_brr_p(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP_(r0, r1);
+    w = _jit->pc.w;
+    BRCL(cc, 0);
+    return (w);
+}
+
+static void
+_bri(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    brr(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static jit_word_t
+_bri_p(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = brr_p(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_brr_u(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d;
+    CMPU_(r0, r1);
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(d))
+       BRC(cc, x16(d));
+    else {
+       assert(s32_p(d));
+       BRCL(cc, d);
+    }
+}
+
+static jit_word_t
+_brr_u_p(jit_state_t *_jit, jit_int32_t cc,
+        jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMPU_(r0, r1);
+    w = _jit->pc.w;
+    BRCL(cc, 0);
+    return (w);
+}
+
+static void
+_bri_u(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    brr_u(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static jit_word_t
+_bri_u_p(jit_state_t *_jit, jit_int32_t cc,
+        jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = brr_u_p(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_baddr(jit_state_t *_jit, jit_int32_t c, jit_bool_t s,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d;
+    if (s)             addr(r0, r0, r1);
+    else               addcr(r0, r0, r1);
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(d))
+       BRC(c, x16(d));
+    else {
+       assert(s32_p(d));
+       BRCL(c, d);
+    }
+}
+
+static void
+_baddi(jit_state_t *_jit, jit_int32_t c, jit_bool_t s,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    baddr(c, s, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static jit_word_t
+_baddr_p(jit_state_t *_jit, jit_int32_t c, jit_bool_t s,
+        jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    if (s)             addr(r0, r0, r1);
+    else               addcr(r0, r0, r1);
+    d = (i0 - _jit->pc.w) >> 1;
+    w = _jit->pc.w;
+    BRCL(c, d);
+    return (w);
+}
+
+static jit_word_t
+_baddi_p(jit_state_t *_jit, jit_int32_t c, jit_bool_t s,
+        jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = baddr_p(c, s, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_bsubr(jit_state_t *_jit, jit_int32_t c, jit_bool_t s,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d;
+    if (s)             subr(r0, r0, r1);
+    else               subcr(r0, r0, r1);
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(d))
+       BRC(c, x16(d));
+    else {
+       assert(s32_p(d));
+       BRCL(c, d);
+    }
+}
+
+static void
+_bsubi(jit_state_t *_jit, jit_int32_t c, jit_bool_t s,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    bsubr(c, s, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static jit_word_t
+_bsubr_p(jit_state_t *_jit, jit_int32_t c, jit_bool_t s,
+        jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d, w;
+    if (s)             subr(r0, r0, r1);
+    else               subcr(r0, r0, r1);
+    d = (i0 - _jit->pc.w) >> 1;
+    w = _jit->pc.w;
+    BRCL(c, d);
+    return (w);
+}
+
+static jit_word_t
+_bsubi_p(jit_state_t *_jit, jit_int32_t c, jit_bool_t s,
+        jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    w = bsubr_p(c, s, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_bmxr(jit_state_t *_jit, jit_int32_t cc,
+      jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), r0);
+    andr(rn(reg), rn(reg), r1);
+    TEST_(rn(reg), rn(reg));
+    jit_unget_reg(reg);
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(d))
+       BRC(cc, x16(d));
+    else {
+       assert(s32_p(d));
+       BRCL(cc, d);
+    }
+}
+
+static jit_word_t
+_bmxr_p(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), r0);
+    andr(rn(reg), rn(reg), r1);
+    TEST_(rn(reg), rn(reg));
+    jit_unget_reg(reg);
+    w = _jit->pc.w;
+    BRCL(cc, 0);
+    return (w);
+}
+
+static void
+_bmxi(jit_state_t *_jit, jit_int32_t cc,
+      jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         d;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i1);
+    andr(rn(reg), rn(reg), r0);
+    TEST_(rn(reg), rn(reg));
+    jit_unget_reg(reg);
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(d))
+       BRC(cc, x16(d));
+    else {
+       assert(s32_p(d));
+       BRCL(cc, d);
+    }
+}
+
+static jit_word_t
+_bmxi_p(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i1);
+    andr(rn(reg), rn(reg), r0);
+    TEST_(rn(reg), rn(reg));
+    jit_unget_reg(reg);
+    w = _jit->pc.w;
+    BRCL(cc, 0);
+    return (w);
+}
+
+static void
+_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#if __WORDSIZE == 32
+    if (r0 != r1)
+       LR(r0, r1);
+#else
+    if (r0 != r1)
+       LGR(r0, r1);
+#endif
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         d;
+#if __WORDSIZE == 64
+    jit_int32_t                bits;
+#endif
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(i0)) {
+#if __WORDSIZE == 32
+       LHI(r0, x16(i0));
+#else
+       LGHI(r0, x16(i0));
+#endif
+    }
+    /* easy way of loading a large amount of 32 bit values and
+     * usually address of constants */
+    else if (!(i0 & 1) &&
+#if __WORDSIZE == 32
+            i0 > 0
+#else
+            s32_p(d)
+#endif
+            )
+       LARL(r0, d);
+    else {
+#if __WORDSIZE == 32
+       LHI(r0, x16(i0));
+       IILH(r0, x16((jit_uword_t)i0 >> 16));
+#else
+       bits = 0;
+       if (i0 &             0xffffL)   bits |= 1;
+       if (i0 &         0xffff0000L)   bits |= 2;
+       if (i0 &     0xffff00000000L)   bits |= 4;
+       if (i0 & 0xffff000000000000L)   bits |= 8;
+       if (bits != 15)                 LGHI(r0, 0);
+       if (bits & 1)                   IILL(r0, x16(i0));
+       if (bits & 2)                   IILH(r0, x16((jit_uword_t)i0 >> 16));
+       if (bits & 4)                   IIHL(r0, x16((jit_uword_t)i0 >> 32));
+       if (bits & 8)                   IIHH(r0, x16((jit_uword_t)i0 >> 48));
+#endif
+    }
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+    w = _jit->pc.w;
+#if __WORDSIZE == 32
+    LHI(r0, x16(i0));
+#else
+    IILL(r0, x16(i0));
+#endif
+    IILH(r0, x16((jit_uword_t)i0 >> 16));
+#if __WORDSIZE == 64
+    IIHL(r0, x16((jit_uword_t)i0 >> 32));
+    IIHH(r0, x16((jit_uword_t)i0 >> 48));
+#endif
+    return (w);
+}
+
+static void
+_addr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       ADD_(r0, r1);
+    else {
+       movr(r0, r1);
+       ADD_(r0, r2);
+    }
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (r0 == r1 && s16_p(i0))
+       ADDI_(r0, x16(i0));
+#if __WORDSIZE == 64
+    else if (s20_p(i0))
+       LAY(r0, x20(i0), 0, r1);
+#endif
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       ADDC_(r0, r1);
+    else {
+       movr(r0, r1);
+       ADDC_(r0, r2);
+    }
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    addcr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_addxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       ADDX_(r0, r1);
+    else {
+       movr(r0, r1);
+       ADDX_(r0, r2);
+    }
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    addxr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r2);
+       movr(r0, r1);
+       SUB_(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movr(r0, r1);
+       SUB_(r0, r2);
+    }
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (r0 == r1 && s16_p(-i0))
+       ADDI_(r0, x16(-i0));
+#if __WORDSIZE == 64
+    else if (s20_p(-i0))
+       LAY(r0, x20(-i0), 0, r1);
+#endif
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_subcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r2);
+       movr(r0, r1);
+       SUBC_(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movr(r0, r1);
+       SUBC_(r0, r2);
+    }
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    subcr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_subxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r2);
+       movr(r0, r1);
+       SUBX_(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movr(r0, r1);
+       SUBX_(r0, r2);
+    }
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    subxr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    subi(r0, r1, i0);
+    negr(r0, r0);
+}
+
+static void
+_mulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       MUL_(r0, r1);
+    else {
+       movr(r0, r1);
+       MUL_(r0, r2);
+    }
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s16_p(i0)) {
+       movr(r0, r1);
+       MULI_(r0, x16(i0));
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       mulr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_qmulr(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                reg;
+    /* The only invalid condition is r0 == r1 */
+    jit_int32_t                t2, t3, s2, s3;
+    if (r2 == r0 || r2 == r1) {
+       s2 = jit_get_reg(jit_class_gpr);
+       t2 = rn(s2);
+       movr(t2, r2);
+    }
+    else
+       t2 = r2;
+    if (r3 == r0 || r3 == r1) {
+       s3 = jit_get_reg(jit_class_gpr);
+       t3 = rn(s3);
+       movr(t3, r3);
+    }
+    else
+       t3 = r3;
+    qmulr_u(r0, r1, r2, r3);
+    reg = jit_get_reg(jit_class_gpr);
+    /**/
+    rshi(rn(reg), t2, 63);
+    mulr(rn(reg), rn(reg), t3);
+    addr(r1, r1, rn(reg));
+    /**/
+    rshi(rn(reg), t3, 63);
+    mulr(rn(reg), rn(reg), t2);
+    addr(r1, r1, rn(reg));
+    jit_unget_reg(reg);
+    if (t2 != r2)
+       jit_unget_reg(s2);
+    if (t3 != r3)
+       jit_unget_reg(s3);
+}
+
+static void
+_qmuli(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    qmulr(r0, r1, r2, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_qmulr_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                regno;
+    regno = jit_get_reg_pair();
+    movr(rn(regno) + 1, r2);
+    MULU_(rn(regno), r3);
+    movr(r0, rn(regno) + 1);
+    movr(r1, rn(regno));
+    jit_unget_reg_pair(regno);
+}
+
+static void
+_qmuli_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                regno;
+    regno = jit_get_reg_pair();
+    movr(rn(regno) + 1, r2);
+    movi(rn(regno), i0);
+    MULU_(rn(regno), rn(regno));
+    movr(r0, rn(regno) + 1);
+    movr(r1, rn(regno));
+    jit_unget_reg_pair(regno);
+}
+
+static void
+_divr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                regno;
+    regno = xdivr(r1, r2);
+    movr(r0, rn(regno) + 1);
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                regno;
+    regno = xdivi(r1, i0);
+    movr(r0, rn(regno) + 1);
+}
+
+static void
+_divr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                regno;
+    regno = xdivr_u(r1, r2);
+    movr(r0, rn(regno) + 1);
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                regno;
+    regno = xdivi_u(r1, i0);
+    movr(r0, rn(regno) + 1);
+}
+
+static void
+_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                regno;
+    regno = xdivr(r1, r2);
+    movr(r0, rn(regno));
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                regno;
+    regno = xdivi(r1, i0);
+    movr(r0, rn(regno));
+}
+
+static void
+_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                regno;
+    regno = xdivr_u(r1, r2);
+    movr(r0, rn(regno));
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                regno;
+    regno = xdivi_u(r1, i0);
+    movr(r0, rn(regno));
+}
+
+static void
+_qdivr(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                regno;
+    regno = xdivr(r2, r3);
+    movr(r0, rn(regno) + 1);
+    movr(r1, rn(regno));
+}
+
+static void
+_qdivi(jit_state_t *_jit,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                regno;
+    regno = xdivi(r2, i0);
+    movr(r0, rn(regno) + 1);
+    movr(r1, rn(regno));
+}
+
+static void
+_qdivr_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_int32_t r3)
+{
+    jit_int32_t                regno;
+    regno = xdivr_u(r2, r3);
+    movr(r0, rn(regno) + 1);
+    movr(r1, rn(regno));
+}
+
+static void
+_qdivi_u(jit_state_t *_jit,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2, jit_word_t i0)
+{
+    jit_int32_t                regno;
+    regno = xdivi_u(r2, i0);
+    movr(r0, rn(regno) + 1);
+    movr(r1, rn(regno));
+}
+
+#  if __WORDSIZE == 32
+static void
+_lshr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg_but_zero(0);
+       movr(rn(reg), r2);
+       movr(r0, r1);
+       SLL(r0, 0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+    else {
+       movr(r0, r1);
+       SLL(r0, 0, r2);
+    }
+}
+#endif
+
+static void
+_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    lshr(r0, r1, rn(reg));
+    jit_unget_reg_but_zero(reg);
+}
+
+#  if __WORDSIZE == 32
+static void
+_rshr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg_but_zero(0);
+       movr(rn(reg), r2);
+       movr(r0, r1);
+       SRA(r0, 0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+    else {
+       movr(r0, r1);
+       SRA(r0, 0, r2);
+    }
+}
+#endif
+
+static void
+_rshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    rshr(r0, r1, rn(reg));
+    jit_unget_reg_but_zero(reg);
+}
+
+#  if __WORDSIZE == 32
+static void
+_rshr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg_but_zero(0);
+       movr(rn(reg), r2);
+       movr(r0, r1);
+       SRL(r0, 0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+    else {
+       movr(r0, r1);
+       SRL(r0, 0, r2);
+    }
+}
+#endif
+
+static void
+_rshi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    rshr_u(r0, r1, rn(reg));
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_comr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), -1);
+    movr(r0, r1);
+    XOR_(r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_andr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       AND_(r0, r1);
+    else {
+       movr(r0, r1);
+       AND_(r0, r2);
+    }
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(r0, r1);
+    NILL(r0, x16(i0));
+    NILH(r0, x16((jit_uword_t)i0 >> 16));
+#if __WORDSIZE == 64
+    NIHL(r0, x16((jit_uword_t)i0 >> 32));
+    NIHH(r0, x16((jit_uword_t)i0 >> 48));
+#endif
+}
+
+static void
+_orr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       OR_(r0, r1);
+    else {
+       movr(r0, r1);
+       OR_(r0, r2);
+    }
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(r0, r1);
+    OILL(r0, x16(i0));
+    OILH(r0, x16((jit_uword_t)i0 >> 16));
+#if __WORDSIZE == 64
+    OIHL(r0, x16((jit_uword_t)i0 >> 32));
+    OIHH(r0, x16((jit_uword_t)i0 >> 48));
+#endif
+}
+
+static void
+_xorr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       XOR_(r0, r1);
+    else {
+       movr(r0, r1);
+       XOR_(r0, r2);
+    }
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    xorr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    movi(r0, i0);
+    ldr_c(r0, r0);
+}
+
+static void
+_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2) {
+       addr(r0, r0, r1);
+       ldr_c(r0, r0);
+    }
+    else {
+       movr(r0, r1);
+       addr(r0, r0, r2);
+       ldr_c(r0, r0);
+    }
+}
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s20_p(i0)) {
+#if __WORDSIZE == 32
+       LB(r0, x20(i0), 0, r1);
+#else
+       LGB(r0, x20(i0), 0, r1);
+#endif
+    }
+    else if (r0 != r1) {
+       movi(r0, i0);
+       addr(r0, r0, r1);
+       ldr_c(r0, r0);
+    }
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r1);
+       ldr_c(r0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    movi(r0, i0);
+    ldr_uc(r0, r0);
+}
+
+static void
+_ldxr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2) {
+       addr(r0, r0, r1);
+       ldr_uc(r0, r0);
+    }
+    else {
+       movr(r0, r1);
+       addr(r0, r0, r2);
+       ldr_uc(r0, r0);
+    }
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s20_p(i0))
+       LLGC(r0, x20(i0), 0, r1);
+    else if (r0 != r1) {
+       movi(r0, i0);
+       addr(r0, r0, r1);
+       ldr_uc(r0, r0);
+    }
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r1);
+       ldr_uc(r0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    movi(r0, i0);
+    ldr_s(r0, r0);
+}
+
+static void
+_ldxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2) {
+       addr(r0, r0, r1);
+       ldr_s(r0, r0);
+    }
+    else {
+       movr(r0, r1);
+       addr(r0, r0, r2);
+       ldr_s(r0, r0);
+    }
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+#if __WORDSIZE == 32
+    if (u12_p(i0))
+       LH(r0, i0, 0, r1);
+    else
+#endif
+    if (s20_p(i0)) {
+#if __WORDSIZE == 32
+       LHY(r0, x20(i0), 0, r1);
+#else
+       LGH(r0, x20(i0), 0, r1);
+#endif
+    }
+    else if (r0 != r1) {
+       movi(r0, i0);
+       addr(r0, r0, r1);
+       ldr_s(r0, r0);
+    }
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r1);
+       ldr_s(r0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    movi(r0, i0);
+    ldr_us(r0, r0);
+}
+
+static void
+_ldxr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2) {
+       addr(r0, r0, r1);
+       ldr_us(r0, r0);
+    }
+    else {
+       movr(r0, r1);
+       addr(r0, r0, r2);
+       ldr_us(r0, r0);
+    }
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s20_p(i0))
+       LLGH(r0, x20(i0), 0, r1);
+    else if (r0 != r1) {
+       movi(r0, i0);
+       addr(r0, r0, r1);
+       ldr_us(r0, r0);
+    }
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r1);
+       ldr_us(r0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    movi(r0, i0);
+    ldr_i(r0, r0);
+}
+
+static void
+_ldxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2) {
+       addr(r0, r0, r1);
+       ldr_i(r0, r0);
+    }
+    else {
+       movr(r0, r1);
+       addr(r0, r0, r2);
+       ldr_i(r0, r0);
+    }
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s20_p(i0))
+       LGF(r0, x20(i0), 0, r1);
+    else if (r0 != r1) {
+       movi(r0, i0);
+       addr(r0, r0, r1);
+       ldr_i(r0, r0);
+    }
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r1);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+#if __WORDSIZE == 64
+static void
+_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    movi(r0, i0);
+    ldr_ui(r0, r0);
+}
+
+static void
+_ldxr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2) {
+       addr(r0, r0, r1);
+       ldr_ui(r0, r0);
+    }
+    else {
+       movr(r0, r1);
+       addr(r0, r0, r2);
+       ldr_ui(r0, r0);
+    }
+}
+
+static void
+_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s20_p(i0))
+       LLGF(r0, x20(i0), 0, r1);
+    else if (r0 != r1) {
+       movi(r0, i0);
+       addr(r0, r0, r1);
+       ldr_ui(r0, r0);
+    }
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r1);
+       ldr_ui(r0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_ldi_l(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    movi(r0, i0);
+    ldr_l(r0, r0);
+}
+
+static void
+_ldxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2) {
+       addr(r0, r0, r1);
+       ldr_l(r0, r0);
+    }
+    else {
+       movr(r0, r1);
+       addr(r0, r0, r2);
+       ldr_l(r0, r0);
+    }
+}
+
+static void
+_ldxi_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s20_p(i0))
+       LG(r0, x20(i0), 0, r1);
+    else if (r0 != r1) {
+       movi(r0, i0);
+       addr(r0, r0, r1);
+       ldr_l(r0, r0);
+    }
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r1);
+       ldr_l(r0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+#endif
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    str_c(rn(reg), r0);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movr(rn(reg), r0);
+    addr(rn(reg), rn(reg), r1);
+    str_c(rn(reg), r2);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (u12_p(i0))
+       STC(r1, i0, 0, r0);
+    else if (s20_p(i0))
+       STCY(r1, x20(i0), 0, r0);
+    else {
+       reg = jit_get_reg_but_zero(0);
+       addi(rn(reg), r0, i0);
+       str_c(rn(reg), r1);
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    str_s(rn(reg), r0);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movr(rn(reg), r0);
+    addr(rn(reg), rn(reg), r1);
+    str_s(rn(reg), r2);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (u12_p(i0))
+       STH(r1, i0, 0, r0);
+    else if (s20_p(i0))
+       STHY(r1, x20(i0), 0, r0);
+    else {
+       reg = jit_get_reg_but_zero(0);
+       addi(rn(reg), r0, i0);
+       str_s(rn(reg), r1);
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    str_i(rn(reg), r0);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movr(rn(reg), r0);
+    addr(rn(reg), rn(reg), r1);
+    str_i(rn(reg), r2);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (u12_p(i0))
+       ST(r1, i0, 0, r0);
+    else if (s20_p(i0))
+       STY(r1, x20(i0), 0, r0);
+    else {
+       reg = jit_get_reg_but_zero(0);
+       addi(rn(reg), r0, i0);
+       str_i(rn(reg), r1);
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+#if __WORDSIZE == 64
+static void
+_sti_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    str_l(rn(reg), r0);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movr(rn(reg), r0);
+    addr(rn(reg), rn(reg), r1);
+    str_l(rn(reg), r2);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxi_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (s20_p(i0))
+       STG(r1, x20(i0), 0, r0);
+    else {
+       reg = jit_get_reg_but_zero(0);
+       addi(rn(reg), r0, i0);
+       str_l(rn(reg), r1);
+       jit_unget_reg_but_zero(reg);
+    }
+}
+#endif
+
+static void
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         d;
+    jit_int32_t                reg;
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(d))
+       J(x16(d));
+    else if (s32_p(d))
+       BRL(d);
+    else {
+       reg = jit_get_reg_but_zero(jit_class_nospill);
+       movi(rn(reg), i0);
+       jmpr(rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static jit_word_t
+_jmpi_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(jit_class_nospill);
+    w = movi_p(rn(reg), i0);
+    jmpr(rn(reg));
+    jit_unget_reg_but_zero(reg);
+    return (w);
+}
+
+static void
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         d;
+    jit_int32_t                reg;
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s32_p(d))
+       BRASL(_R14_REGNO, d);
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       callr(rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    w = movi_p(rn(reg), i0);
+    callr(rn(reg));
+    jit_unget_reg_but_zero(reg);
+    return (w);
+}
+
+static jit_int32_t     gprs[] = {
+    _R2, _R3, _R4, _R5,
+    _R6, _R7, _R8, _R9, _R10, _R11, _R12, _R13
+};
+
+static void
+_prolog(jit_state_t *_jit, jit_node_t *i0)
+{
+    jit_int32_t                regno, offset;
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar)
+       _jitc->function->self.aoff &= -8;
+    _jitc->function->stack = ((_jitc->function->self.alen -
+                             /* align stack at 8 bytes */
+                             _jitc->function->self.aoff) + 7) & -8;
+    /* *IFF* a non variadic function,
+     * Lightning does not reserve stack space for spilling arguments
+     * in registers.
+     * S390x, as per gcc, has 8 stack slots for spilling arguments,
+     * (%r6 is callee save) and uses an alloca like approach to save
+     * callee save fpr registers.
+     * Since argument registers are not saved in any lightning port,
+     * use the 8 slots to spill any modified fpr register, and still
+     * use the same stack frame logic as gcc.
+     * Save at least %r13 to %r15, as %r13 is used as frame pointer.
+     * *IFF* a variadic function, a "standard" stack frame, with
+     * fpr registers saved in an alloca'ed area, is used.
+     */
+    if ((_jitc->function->self.call & jit_call_varargs) &&
+       jit_arg_reg_p(_jitc->function->vagp))
+       regno = _jitc->function->vagp;
+    else {
+       for (regno = 4; regno < jit_size(gprs) - 1; regno++) {
+           if (jit_regset_tstbit(&_jitc->function->regset, gprs[regno]))
+               break;
+       }
+    }
+#if __WORDSIZE == 32
+#  define FP_OFFSET            64
+    if (_jitc->function->self.call & jit_call_varargs)
+       offset = regno * 4 + 8;
+    else
+       offset = (regno - 4) * 4 + 32;
+    STM(rn(gprs[regno]), _R15_REGNO, x20(offset), _R15_REGNO);
+#else
+#  define FP_OFFSET            128
+    if (_jitc->function->self.call & jit_call_varargs)
+       offset = regno * 8 + 16;
+    else
+       offset = (regno - 4) * 8 + 48;
+    STMG(rn(gprs[regno]), _R15_REGNO, x20(offset), _R15_REGNO);
+#endif
+
+#define SPILL(R, O)                                                    \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->function->regset, R))             \
+           stxi_d(O, _R15_REGNO, rn(R));                               \
+    } while (0)
+    if (_jitc->function->self.call & jit_call_varargs) {
+       for (regno = _jitc->function->vafp; jit_arg_f_reg_p(regno); ++regno)
+           stxi_d(FP_OFFSET + regno * 8, _R15_REGNO, rn(_F0 - regno));
+       SPILL(_F8, _jitc->function->vaoff + offsetof(jit_va_list_t, f8));
+       SPILL(_F9, _jitc->function->vaoff + offsetof(jit_va_list_t, f9));
+       SPILL(_F10, _jitc->function->vaoff + offsetof(jit_va_list_t, f10));
+       SPILL(_F11, _jitc->function->vaoff + offsetof(jit_va_list_t, f11));
+       SPILL(_F12, _jitc->function->vaoff + offsetof(jit_va_list_t, f12));
+       SPILL(_F13, _jitc->function->vaoff + offsetof(jit_va_list_t, f13));
+       SPILL(_F14, _jitc->function->vaoff + offsetof(jit_va_list_t, f14));
+    }
+    else {
+       /* First 4 in low address */
+#if __WORDSIZE == 32
+       SPILL(_F10, 0);
+       SPILL(_F11, 8);
+       SPILL(_F12, 16);
+       SPILL(_F13, 24);
+       /* gpr registers here */
+       SPILL(_F14, 72);
+       SPILL(_F8, 80);
+       SPILL(_F9, 88);
+#else
+       SPILL(_F10, 16);
+       SPILL(_F11, 24);
+       SPILL(_F12, 32);
+       SPILL(_F13, 48);
+       /* Last 3 in high address */
+       SPILL(_F14, 136);
+       SPILL(_F8, 144);
+       SPILL(_F9, 152);
+#endif
+    }
+#undef SPILL
+    movr(_R13_REGNO, _R15_REGNO);
+    subi(_R15_REGNO, _R15_REGNO, stack_framesize + _jitc->function->stack);
+    if (_jitc->function->allocar) {
+       regno = jit_get_reg(jit_class_gpr);
+       movi(rn(regno), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, _R13_REGNO, rn(regno));
+       jit_unget_reg(regno);
+    }
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *i0)
+{
+    jit_int32_t                regno, offset;
+    if (_jitc->function->assume_frame)
+       return;
+    if ((_jitc->function->self.call & jit_call_varargs) &&
+       jit_arg_reg_p(_jitc->function->vagp))
+       regno = _jitc->function->vagp;
+    else {
+       for (regno = 4; regno < jit_size(gprs) - 1; regno++) {
+           if (jit_regset_tstbit(&_jitc->function->regset, gprs[regno]))
+               break;
+       }
+    }
+#if __WORDSIZE == 32
+    if (_jitc->function->self.call & jit_call_varargs)
+       offset = regno * 4 + 8;
+    else
+       offset = (regno - 4) * 4 + 32;
+#else
+    if (_jitc->function->self.call & jit_call_varargs)
+       offset = regno * 8 + 16;
+    else
+       offset = (regno - 4) * 8 + 48;
+#endif
+    movr(_R15_REGNO, _R13_REGNO);
+
+#define LOAD(R, O)                                                     \
+    do {                                                               \
+       if (jit_regset_tstbit(&_jitc->function->regset, R))             \
+           ldxi_d(rn(R), _R15_REGNO, O);                               \
+    } while (0)
+    if (_jitc->function->self.call & jit_call_varargs) {
+       LOAD(_F8, _jitc->function->vaoff + offsetof(jit_va_list_t, f8));
+       LOAD(_F9, _jitc->function->vaoff + offsetof(jit_va_list_t, f9));
+       LOAD(_F10, _jitc->function->vaoff + offsetof(jit_va_list_t, f10));
+       LOAD(_F11, _jitc->function->vaoff + offsetof(jit_va_list_t, f11));
+       LOAD(_F12, _jitc->function->vaoff + offsetof(jit_va_list_t, f12));
+       LOAD(_F13, _jitc->function->vaoff + offsetof(jit_va_list_t, f13));
+       LOAD(_F14, _jitc->function->vaoff + offsetof(jit_va_list_t, f14));
+    }
+    else {
+#if __WORDSIZE == 32
+       LOAD(_F10, 0);
+       LOAD(_F11, 8);
+       LOAD(_F12, 16);
+       LOAD(_F13, 24);
+       LOAD(_F14, 72);
+       LOAD(_F8, 80);
+       LOAD(_F9, 88);
+#else
+       LOAD(_F10, 16);
+       LOAD(_F11, 24);
+       LOAD(_F12, 32);
+       LOAD(_F13, 48);
+       LOAD(_F14, 136);
+       LOAD(_F8, 144);
+       LOAD(_F9, 152);
+#endif
+    }
+#undef LOAD
+#if __WORDSIZE == 32
+    LM(rn(gprs[regno]), _R15_REGNO, x20(offset), _R15_REGNO);
+#else
+    LMG(rn(gprs[regno]), _R15_REGNO, x20(offset), _R15_REGNO);
+#endif
+    BR(_R14_REGNO);
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Return jit_va_list_t in the register argument */
+    addi(r0, _R13_REGNO, _jitc->function->vaoff);
+    reg = jit_get_reg(jit_class_gpr);
+
+    /* Initialize gp offset in the save area. */
+    movi(rn(reg), _jitc->function->vagp);
+    stxi(offsetof(jit_va_list_t, gpoff), r0, rn(reg));
+
+    /* Initialize fp offset in the save area. */
+    movi(rn(reg), _jitc->function->vafp);
+    stxi(offsetof(jit_va_list_t, fpoff), r0, rn(reg));
+
+    /* Initialize overflow pointer to the first stack argument. */
+    addi(rn(reg), _R13_REGNO, _jitc->function->self.size);
+    stxi(offsetof(jit_va_list_t, over), r0, rn(reg));
+
+    /* Initialize register save area pointer. */
+    stxi(offsetof(jit_va_list_t, save), r0, _R13_REGNO);
+
+    jit_unget_reg(reg);
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                rg0;
+    jit_int32_t                rg1;
+    jit_int32_t                rg2;
+    jit_word_t         ge_code;
+    jit_word_t         lt_code;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg_but_zero(0);
+    rg1 = jit_get_reg_but_zero(0);
+
+    /* Load the gp offset in save area in the first temporary. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, gpoff));
+
+    /* Jump over if there are no remaining arguments in the save area. */
+    ge_code = bgei_p(_jit->pc.w, rn(rg0), 5);
+
+    /* Load the save area pointer in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, save));
+
+    /* Scale offset */
+    rg2 = jit_get_reg_but_zero(0);
+    lshi(rn(rg2), rn(rg0),
+#if __WORDSIZE == 32
+        2
+#else
+        3
+#endif
+        );
+    /* Add offset to saved area. */
+    addi(rn(rg2), rn(rg2), 2 * sizeof(jit_word_t));
+
+    /* Load the vararg argument in the first argument. */
+    ldxr(r0, rn(rg1), rn(rg2));
+    jit_unget_reg_but_zero(rg2);
+
+    /* Update the gp offset. */
+    addi(rn(rg0), rn(rg0), 1);
+    stxi(offsetof(jit_va_list_t, gpoff), r1, rn(rg0));
+
+    /* Will only need one temporary register below. */
+    jit_unget_reg_but_zero(rg1);
+
+    /* Jump over overflow code. */
+    lt_code = jmpi_p(_jit->pc.w);
+
+    /* Where to land if argument is in overflow area. */
+    patch_at(ge_code, _jit->pc.w);
+
+    /* Load overflow pointer. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, over));
+
+    /* Load argument. */
+    ldr(r0, rn(rg0));
+
+    /* Update overflow pointer. */
+    addi(rn(rg0), rn(rg0), sizeof(jit_word_t));
+    stxi(offsetof(jit_va_list_t, over), r1, rn(rg0));
+
+    /* Where to land if argument is in save area. */
+    patch_at(lt_code, _jit->pc.w);
+
+    jit_unget_reg_but_zero(rg0);
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
+{
+    jit_word_t                  d;
+    union {
+       jit_uint16_t            *s;
+       jit_word_t               w;
+    } u;
+    u.w = instr;
+    union {
+       struct {
+           jit_uint16_t        op :  8;
+           jit_uint16_t        r1 :  4;
+           jit_uint16_t        r3 :  4;
+       } b;
+       jit_uint16_t            s;
+    } i0;
+    union {
+       struct {
+           jit_uint16_t        i2;
+       } b;
+       jit_uint16_t            s;
+    } i1;
+    union {
+       struct {
+           jit_uint32_t        ih : 16;
+           jit_uint32_t        il : 16;
+       } b;
+       jit_uint32_t            i;
+    } i12;
+    i0.s = u.s[0];
+    /* movi_p */
+    if (i0.b.op ==
+#if __WORDSIZE == 32
+       0xA7 && i0.b.r3 == 8
+#else
+       0xA5
+#endif
+       ) {
+#if __WORDSIZE == 64
+       assert(i0.b.r3 == 3);
+#endif
+       i1.b.i2 = (jit_uword_t)label;
+       u.s[1] = i1.s;
+       i0.s = u.s[2];
+       assert(i0.b.op == 0xA5 && i0.b.r3 == 2);
+       i1.b.i2 = (jit_uword_t)label >> 16;
+       u.s[3] = i1.s;
+#if __WORDSIZE == 64
+       i0.s = u.s[4];
+       assert(i0.b.op == 0xA5 && i0.b.r3 == 1);
+       i1.b.i2 = (jit_uword_t)label >> 32;
+       u.s[5] = i1.s;
+       i0.s = u.s[6];
+       assert(i0.b.op == 0xA5 && i0.b.r3 == 0);
+       i1.b.i2 = (jit_uword_t)label >> 48;
+       u.s[7] = i1.s;
+#endif
+    }
+    /* BRC */
+    else if (i0.b.op == 0xA7) {
+       assert(i0.b.r3 == 0x4);
+       d = (label - instr) >> 1;
+       assert(s16_p(d));
+       i1.b.i2 = d;
+       u.s[1] = i1.s;
+    }
+    /* BRCL */
+    else if (i0.b.op == 0xC0) {
+       assert(i0.b.r3 == 0x4);
+       d = (label - instr) >> 1;
+       assert(s32_p(d));
+       i12.i = d;
+       u.s[1] = i12.b.ih;
+       u.s[2] = i12.b.il;
+    }
+    else
+       abort();
+}
+#endif
diff --git a/deps/lightning/lib/jit_s390-fpu.c b/deps/lightning/lib/jit_s390-fpu.c
new file mode 100644 (file)
index 0000000..6d60513
--- /dev/null
@@ -0,0 +1,1316 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  define RND_CUR                      0
+#  define RND_BIAS_NEAR                        1
+#  define RND_NEAR                     4
+#  define RND_ZERO                     5
+#  define RND_POS_INF                  6
+#  define RND_NEG_INF                  7
+/****************************************************************
+ * Floating Point Instructions                                 *
+ ****************************************************************/
+/* CONVERT BFP TO HFP */
+#  define THDER(R1,R2)                 RRE_(0xB358,R1,R2)
+#  define THDR(R1,R2)                  RRE_(0xB359,R1,R2)
+/* CONVERT HFP TO BFP */
+#  define TBEDR(R1,R2)                 RRE_(0xB350,R1,R2)
+#  define TBDR(R1,R2)                  RRE_(0xB351,R1,R2)
+/* LOAD */
+#  define LER(R1,R2)                   RR_(0x38,R1,R2)
+#  define LDR(R1,R2)                   RR_(0x28,R1,R2)
+#  define LXR(R1,R2)                   RRE_(0xB365,R1,R2)
+#  define LE(R1,D2,X2,B2)              RX_(0x78,R1,X2,B2,D2)
+#  define LD(R1,D2,X2,B2)              RX_(0x68,R1,X2,B2,D2)
+#  define LEY(R1,D2,X2,B2)             RXY_(0xED,R1,X2,B2,D2,0x64)
+#  define LDY(R1,D2,X2,B2)             RXY_(0xED,R1,X2,B2,D2,0x65)
+/* LOAD ZERO */
+#  define LZER(R1)                     RRE_(0xB374,R1,0)
+#  define LZDR(R1)                     RRE_(0xB375,R1,0)
+#  define LZXR(R1)                     RRE_(0xB376,R1,0)
+/* STORE */
+#  define STE(R1,D2,X2,B2)             RX_(0x70,R1,X2,B2,D2)
+#  define STD(R1,D2,X2,B2)             RX_(0x60,R1,X2,B2,D2)
+#  define STEY(R1,D2,X2,B2)            RXY_(0xED,R1,X2,B2,D2,0x66)
+#  define STDY(R1,D2,X2,B2)            RXY_(0xED,R1,X2,B2,D2,0x67)
+/****************************************************************
+ * Hexadecimal Floating Point Instructions                     *
+ ****************************************************************/
+/* ADD NORMALIZED */
+#  define AER(R1,R2)                   RR_(0x3A,R1,R2)
+#  define ADR(R1,R2)                   RR_(0x2A,R1,R2)
+#  define AXR(R1,R2)                   RR_(0x36,R1,R2)
+#  define AE(R1,D2,X2,B2)              RX_(0x7A,R1,X2,B2,D2)
+#  define AD(R1,D2,X2,B2)              RX_(0x6A,R1,X2,B2,D2)
+/* ADD UNNORMALIZED */
+#  define AUR(R1,R2)                   RR_(0x3E,R1,R2)
+#  define AWR(R1,R2)                   RR_(0x2E,R1,R2)
+#  define AU(R1,D2,X2,B2)              RX_(0x7E,R1,X2,B2,D2)
+#  define AW(R1,D2,X2,B2)              RX_(0x6E,R1,X2,B2,D2)
+/* COMPARE */
+#  define CER(R1,R2)                   RR_(0x39,R1,R2)
+#  define CDR(R1,R2)                   RR_(0x29,R1,R2)
+#  define CXR(R1,R2)                   RRE_(0xB369,R1,R2)
+#  define CE(R1,D2,X2,B2)              RX_(0x79,R1,X2,B2,D2)
+#  define CD(R1,D2,X2,B2)              RX_(0x69,R1,X2,B2,D2)
+/* CONVERT FROM FIXED */
+#  define CEFR(R1,R2)                  RRE_(0xB3B4,R1,R2)
+#  define CDFR(R1,R2)                  RRE_(0xB3B5,R1,R2)
+#  define CXFR(R1,R2)                  RRE_(0xB3B6,R1,R2)
+#  define CEGR(R1,R2)                  RRE_(0xB3C4,R1,R2)
+#  define CDGR(R1,R2)                  RRE_(0xB3C5,R1,R2)
+#  define CXGR(R1,R2)                  RRE_(0xB3C6,R1,R2)
+/* CONVERT TO FIXED */
+#  define CFER(R1,R2)                  RRE_(0xB3B8,R1,R2)
+#  define CFDR(R1,R2)                  RRE_(0xB3B9,R1,R2)
+#  define CFXR(R1,R2)                  RRE_(0xB3BA,R1,R2)
+#  define CGER(R1,R2)                  RRE_(0xB3C8,R1,R2)
+#  define CGDR(R1,R2)                  RRE_(0xB3C9,R1,R2)
+#  define CGXR(R1,R2)                  RRE_(0xB3CA,R1,R2)
+/* DIVIDE */
+#  define DER(R1,R2)                   RR_(0x3D,R1,R2)
+#  define DDR(R1,R2)                   RR_(0x2D,R1,R2)
+#  define DXR(R1,R2)                   RRE_(0xB22D,R1,R2)
+#  define DE(R1,D2,X2,B2)              RX_(0x7D,R1,X2,B2,D2)
+#  define DD(R1,D2,X2,B2)              RX_(0x6D,R1,X2,B2,D2)
+/* HALVE */
+#  define HER(R1,R2)                   RR_(0x34,R1,R2)
+#  define HDR(R1,R2)                   RR_(0x24,R1,R2)
+/* LOAD AND TEST */
+#  define LTER(R1,R2)                  RR_(0x32,R1,R2)
+#  define LTDR(R1,R2)                  RR_(0x22,R1,R2)
+#  define LTXR(R1,R2)                  RRE_(0xB362,R1,R2)
+/* LOAD COMPLEMENT */
+#  define LCER(R1,R2)                  RR_(0x33,R1,R2)
+#  define LCDR(R1,R2)                  RR_(0x23,R1,R2)
+#  define LCXR(R1,R2)                  RRE_(0xB363,R1,R2)
+/* LOAD FP INTEGER */
+#  define FIER(R1,R2)                  RRE_(0xB377,R1,R2)
+#  define FIDR(R1,R2)                  RRE_(0xB37F,R1,R2)
+#  define FIXR(R1,R2)                  RRE_(0xB367,R1,R2)
+/* LOAD LENGHTENED */
+#  define LDER(R1,R2)                  RRE_(0xB324,R1,R2)
+#  define LXDR(R1,R2)                  RRE_(0xB325,R1,R2)
+#  define LXER(R1,R2)                  RRE_(0xB326,R1,R2)
+#  define LDE(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x24)
+#  define LXD(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x25)
+#  define LXE(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x26)
+/* LOAD NEGATIVE */
+#  define LNER(R1,R2)                  RR_(0x31,R1,R2)
+#  define LNDR(R1,R2)                  RR_(0x21,R1,R2)
+#  define LNXR(R1,R2)                  RRE_(0xB361,R1,R2)
+/* LOAD POSITIVE */
+#  define LPER(R1,R2)                  RR_(0x30,R1,R2)
+#  define LPDR(R1,R2)                  RR_(0x20,R1,R2)
+#  define LPXR(R1,R2)                  RRE_(0xB360,R1,R2)
+/* LOAD ROUNDED */
+#  define LEDR(R1,R2)                  RR_(0x35,R1,R2)
+#  define LDXR(R1,R2)                  RR_(0x25,R1,R2)
+#  define LRER(R1,R2)                  LEDR(R1,R2)
+#  define LRDR(R1,R2)                  LDXR(R1,R2)
+#  define LRXR(R1,R2)                  RRE_(0xB366,R1,R2)
+/* MULTIPLY */
+#  define MEER(R1,R2)                  RRE_(0xB337,R1,R2)
+#  define MDR(R1,R2)                   RR_(0x2C,R1,R2)
+#  define MXR(R1,R2)                   RR_(0x26,R1,R2)
+#  define MDER(R1,R2)                  RR_(0x3C,R1,R2)
+#  define MXDR(R1,R2)                  RR_(0x27,R1,R2)
+#  define MER(R1,R2)                   MDER(R1,R2)
+#  define MEE(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x37)
+#  define MD(R1,D2,X2,B2)              RX_(0x6C,R1,X2,B2,D2)
+#  define MDE(R1,D2,X2,B2)             RX_(0x7C,R1,X2,B2,D2)
+#  define MXD(R1,D2,X2,B2)             RX_(0x67,R1,X2,B2,D2)
+#  define ME(R1,D2,X2,B2)              MDE(R1,D2,X2,B2)
+/* MULTIPLY AND ADD */
+#  define MAER(R1,R3,R2)               RRF_(0xB32E,R1,0,R3,R2)
+#  define MADR(R1,R3,R2)               RRF_(0xB33E,R1,0,R3,R2)
+#  define MAE(R1,R3,D2,X2,B2)          RXF_(0xED,R3,X2,B2,D2,R1,0x2E)
+#  define MAD(R1,R3,D2,X2,B2)          RXF_(0xED,R3,X2,B2,D2,R1,0x3E)
+/* MULTIPLY AND SUBTRACT */
+#  define MSER(R1,R3,R2)               RRF_(0xB32F,R1,0,R3,R2)
+#  define MSDR(R1,R3,R2)               RRF_(0xB33F,R1,0,R3,R2)
+#  define MSE(R1,R3,D2,X2,B2)          RXF_(0xED,R3,X2,B2,D2,R1,0x2F)
+#  define MSD(R1,R3,D2,X2,B2)          RXF_(0xED,R3,X2,B2,D2,R1,0x3F)
+/* SQUARE ROOT */
+#  define SQER(R1,R2)                  RRE_(0xB245,R1,R2)
+#  define SQDR(R1,R2)                  RRE_(0xB244,R1,R2)
+#  define SQXR(R1,R2)                  RRE_(0xB336,R1,R2)
+#  define SQE(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x34)
+#  define SQD(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x35)
+/* SUBTRACT NORMALIZED */
+#  define SER(R1,R2)                   RR_(0x3B,R1,R2)
+#  define SDR(R1,R2)                   RR_(0x2B,R1,R2)
+#  define SXR(R1,R2)                   RR_(0x37,R1,R2)
+#  define SE(R1,D2,X2,B2)              RX_(0x7B,R1,X2,B2,D2)
+#  define SD(R1,D2,X2,B2)              RX_(0x6B,R1,X2,B2,D2)
+/* SUBTRACT UNNORMALIZED */
+#  define SUR(R1,R2)                   RR_(0x3F,R1,R2)
+#  define SWR(R1,R2)                   RR_(0x2F,R1,R2)
+#  define SU(R1,D2,X2,B2)              RX_(0x7F,R1,X2,B2,D2)
+#  define SW(R1,D2,X2,B2)              RX_(0x6F,R1,X2,B2,D2)
+/****************************************************************
+ * Binary Floating Point Instructions                          *
+ ****************************************************************/
+/* ADD */
+#  define AEBR(R1,R2)                  RRE_(0xB30A,R1,R2)
+#  define ADBR(R1,R2)                  RRE_(0xB31A,R1,R2)
+#  define AXBR(R1,R2)                  RRE_(0xB34A,R1,R2)
+#  define AEB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x0A)
+#  define ADB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x1A)
+/* COMPARE */
+#  define CEBR(R1,R2)                  RRE_(0xB309,R1,R2)
+#  define CDBR(R1,R2)                  RRE_(0xB319,R1,R2)
+#  define CXBR(R1,R2)                  RRE_(0xB349,R1,R2)
+#  define CEB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x09)
+#  define CDB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x19)
+/* COMPARE AND SIGNAL */
+#  define KEBR(R1,R2)                  RRE_(0xB308,R1,R2)
+#  define KDBR(R1,R2)                  RRE_(0xB318,R1,R2)
+#  define KXBR(R1,R2)                  RRE_(0xB348,R1,R2)
+#  define KEB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x08)
+#  define KDB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x18)
+/* CONVERT FROM FIXED */
+#  define CEFBR(R1,R2)                 RRE_(0xB394,R1,R2)
+#  define CDFBR(R1,R2)                 RRE_(0xB395,R1,R2)
+#  define CXFBR(R1,R2)                 RRE_(0xB396,R1,R2)
+#  define CEGBR(R1,R2)                 RRE_(0xB3A4,R1,R2)
+#  define CDGBR(R1,R2)                 RRE_(0xB3A5,R1,R2)
+#  define CXGBR(R1,R2)                 RRE_(0xB3A6,R1,R2)
+/* CONVERT TO FIXED */
+#  define CFEBR(R1,M3,R2)              RRF_(0xB398,M3,0,R1,R2)
+#  define CFDBR(R1,M3,R2)              RRF_(0xB399,M3,0,R1,R2)
+#  define CFXBR(R1,M3,R2)              RRF_(0xB39A,M3,0,R1,R2)
+#  define CGEBR(R1,M3,R2)              RRF_(0xB3A8,M3,0,R1,R2)
+#  define CGDBR(R1,M3,R2)              RRF_(0xB3A9,M3,0,R1,R2)
+#  define CGXBR(R1,M3,R2)              RRF_(0xB3AA,M3,0,R1,R2)
+/* DIVIDE */
+#  define DEBR(R1,R2)                  RRE_(0xB30D,R1,R2)
+#  define DDBR(R1,R2)                  RRE_(0xB31D,R1,R2)
+#  define DXBR(R1,R2)                  RRE_(0xB34D,R1,R2)
+#  define DEB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x0D)
+#  define DDB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x1D)
+/* DIVIDE TO INTEGER */
+#  define DIEBR(R1,R3,R2,M4)           RRF_(0xB353,R3,M4,R1,R2)
+#  define DIDBR(R1,R3,R2,M4)           RRF_(0xB35B,R3,M4,R1,R2)
+/* EXTRACT FPC */
+#  define EFPC(R1)                     RRE_(0xB38C,R1,0)
+/* LOAD AND TEST */
+#  define LTEBR(R1,R2)                 RRE_(0xB302,R1,R2)
+#  define LTDBR(R1,R2)                 RRE_(0xB312,R1,R2)
+#  define LTXBR(R1,R2)                 RRE_(0xB342,R1,R2)
+/* LOAD COMPLEMENT */
+#  define LCEBR(R1,R2)                 RRE_(0xB303,R1,R2)
+#  define LCDBR(R1,R2)                 RRE_(0xB313,R1,R2)
+#  define LCXBR(R1,R2)                 RRE_(0xB343,R1,R2)
+/* LOAD FP INTEGER */
+#  define FIEBR(R1,M3,R2)              RRF_(0xB357,M3,0,R1,R2)
+#  define FIDBR(R1,M3,R2)              RRF_(0xB35F,M3,0,R1,R2)
+#  define FIXBR(R1,M3,R2)              RRF_(0xB347,M3,0,R1,R2)
+/* LOAD FPC */
+#  define LFPC(D2,B2)                  S_(0xB29D,B2,D2)
+/* LOAD LENGTHENED */
+#  define LDEBR(R1,R2)                 RRE_(0xB304,R1,R2)
+#  define LXDBR(R1,R2)                 RRE_(0xB305,R1,R2)
+#  define LXEBR(R1,R2)                 RRE_(0xB306,R1,R2)
+#  define LDEB(R1,D2,X2,B2)            RXE_(0xED,R1,X2,B2,D2,0x04)
+#  define LXDB(R1,D2,X2,B2)            RXE_(0xED,R1,X2,B2,D2,0x05)
+#  define LXEB(R1,D2,X2,B2)            RXE_(0xED,R1,X2,B2,D2,0x06)
+/* LOAD NEGATIVE */
+#  define LNEBR(R1,R2)                 RRE_(0xB301,R1,R2)
+#  define LNDBR(R1,R2)                 RRE_(0xB311,R1,R2)
+#  define LNXBR(R1,R2)                 RRE_(0xB341,R1,R2)
+/* LOAD POSITIVE */
+#  define LPEBR(R1,R2)                 RRE_(0xB300,R1,R2)
+#  define LPDBR(R1,R2)                 RRE_(0xB310,R1,R2)
+#  define LPXBR(R1,R2)                 RRE_(0xB340,R1,R2)
+/* LOAD ROUNDED */
+#  define LEDBR(R1,R2)                 RRE_(0xB344,R1,R2)
+#  define LDXBR(R1,R2)                 RRE_(0xB345,R1,R2)
+#  define LEXBR(R1,R2)                 RRE_(0xB346,R1,R2)
+/* MULTIPLY */
+#  define MEEBR(R1,R2)                 RRE_(0xB317,R1,R2)
+#  define MDBR(R1,R2)                  RRE_(0xB31C,R1,R2)
+#  define MXBR(R1,R2)                  RRE_(0xB34C,R1,R2)
+#  define MDEBR(R1,R2)                 RRE_(0xB30C,R1,R2)
+#  define MXDBR(R1,R2)                 RRE_(0xB307,R1,R2)
+#  define MEEB(R1,D2,X2,B2)            RXE_(0xED,R1,X2,B2,D2,0x17)
+#  define MDB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x1C)
+#  define MDEB(R1,D2,X2,B2)            RXE_(0xED,R1,X2,B2,D2,0x0C)
+#  define MXDB(R1,D2,X2,B2)            RXE_(0xED,R1,X2,B2,D2,0x07)
+/* MULTIPLY AND ADD */
+#  define MAEBR(R1,R3,R2)              RRF_(0xB30E,R1,0,R3,R2)
+#  define MADBR(R1,R3,R2)              RRF_(0xB31E,R1,0,R3,R2)
+#  define MAEB(R1,R3,D2,X2,B2)         RXF_(0xED,R3,X2,B2,D2,R1,0x0E)
+#  define MADB(R1,R3,D2,X2,B2)         RXF_(0xED,R3,X2,B2,D2,R1,0x1E)
+/* MULTIPLY AND SUBTRACT */
+#  define MSEBR(R1,R3,R2)              RRF_(0xB30F,R1,0,R3,R2)
+#  define MSDBR(R1,R3,R2)              RRF_(0xB31F,R1,0,R3,R2)
+#  define MSEB(R1,R3,D2,X2,B2)         RXF_(0xED,R3,X2,B2,D2,R1,0x0F)
+#  define MSDB(R1,R3,D2,X2,B2)         RXF_(0xED,R3,X2,B2,D2,R1,0x1F)
+/* SET FPC */
+#  define SFPC(R1)                     RRE_(0xB384,R1,0)
+/* SET ROUNDING MODE */
+#  define SRNM(D2,B2)                  S_(0xB299,B2,D2)
+/* SQUARE ROOT */
+#  define SQEBR(R1,R2)                 RRE_(0xB314,R1,R2)
+#  define SQDBR(R1,R2)                 RRE_(0xB315,R1,R2)
+#  define SQXBR(R1,R2)                 RRE_(0xB316,R1,R2)
+/* STORE FPC */
+#  define STFPC(D2,B2)                 S_(0xB29C,B2,D2)
+/* SUBTRACT */
+#  define SEBR(R1,R2)                  RRE_(0xB30B,R1,R2)
+#  define SDBR(R1,R2)                  RRE_(0xB31B,R1,R2)
+#  define SXBR(R1,R2)                  RRE_(0xB34B,R1,R2)
+#  define SEB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x0B)
+#  define SDB(R1,D2,X2,B2)             RXE_(0xED,R1,X2,B2,D2,0x1B)
+/* TEST DATA CLASS */
+#  define TCEB(R1,D2,X2,B2)            RXE_(0xED,R1,X2,B2,D2,0x10)
+#  define TCDB(R1,D2,X2,B2)            RXE_(0xED,R1,X2,B2,D2,0x11)
+#  define TCXB(R1,D2,X2,B2)            RXE_(0xED,R1,X2,B2,D2,0x12)
+#  define fp(code,r0,r1,i0)            _fp(_jit,jit_code_##code##i_f,r0,r1,i0)
+static void _fp(jit_state_t*,jit_code_t,
+               jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define dp(code,r0,r1,i0)            _dp(_jit,jit_code_##code##i_d,r0,r1,i0)
+static void _dp(jit_state_t*,jit_code_t,
+               jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define fr(cc,r0,r1,r2)              _fr(_jit,cc,r0,r1,r2)
+static void _fr(jit_state_t*,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t);
+#  define dr(cc,r0,r1,r2)              _dr(_jit,cc,r0,r1,r2)
+static void _dr(jit_state_t*,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_int32_t);
+#  define fi(cc,r0,r1,i0)              _fi(_jit,cc,r0,r1,i0)
+static void _fi(jit_state_t*,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define di(cc,r0,r1,i0)              _di(_jit,cc,r0,r1,i0)
+static void _di(jit_state_t*,jit_int32_t,
+               jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define bfr(cc,i0,r0,r1)             _bfr(_jit,cc,i0,r0,r1)
+static void _bfr(jit_state_t*,jit_int32_t,
+                jit_word_t,jit_int32_t,jit_int32_t);
+#  define bdr(cc,i0,r0,r1)             _bdr(_jit,cc,i0,r0,r1)
+static void _bdr(jit_state_t*,jit_int32_t,
+                jit_word_t,jit_int32_t,jit_int32_t);
+#  define bfr_p(cc,i0,r0,r1)           _bfr_p(_jit,cc,i0,r0,r1)
+static jit_word_t _bfr_p(jit_state_t*,jit_int32_t,
+                        jit_word_t,jit_int32_t,jit_int32_t);
+#  define bdr_p(cc,i0,r0,r1)           _bdr_p(_jit,cc,i0,r0,r1)
+static jit_word_t _bdr_p(jit_state_t*,jit_int32_t,
+                        jit_word_t,jit_int32_t,jit_int32_t);
+#  define bfi(cc,i0,r0,i1)             _bfi(_jit,cc,i0,r0,i1)
+static void _bfi(jit_state_t*,jit_int32_t,
+                jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bdi(cc,i0,r0,i1)             _bdi(_jit,cc,i0,r0,i1)
+static void _bdi(jit_state_t*,jit_int32_t,
+                jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bfi_p(cc,i0,r0,i1)           _bfi_p(_jit,cc,i0,r0,i1)
+static jit_word_t _bfi_p(jit_state_t*,jit_int32_t,
+                        jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bdi_p(cc,i0,r0,i1)           _bdi_p(_jit,cc,i0,r0,i1)
+static jit_word_t _bdi_p(jit_state_t*,jit_int32_t,
+                        jit_word_t,jit_int32_t,jit_float64_t*);
+#  define buneqr(db,i0,r0,r1)          _buneqr(_jit,db,i0,r0,r1)
+static jit_word_t _buneqr(jit_state_t*,jit_int32_t,
+                         jit_word_t,jit_int32_t,jit_int32_t);
+#  define buneqi(db,i0,r0,i1)          _buneqi(_jit,db,i0,r0,(jit_word_t)i1)
+static jit_word_t _buneqi(jit_state_t*,jit_int32_t,
+                         jit_word_t,jit_int32_t,jit_word_t);
+#  define bltgtr(db,i0,r0,r1)          _bltgtr(_jit,db,i0,r0,r1)
+static jit_word_t _bltgtr(jit_state_t*,jit_int32_t,
+                         jit_word_t,jit_int32_t,jit_int32_t);
+#  define bltgti(db,i0,r0,i1)          _bltgti(_jit,db,i0,r0,(jit_word_t)i1)
+static jit_word_t _bltgti(jit_state_t*,jit_int32_t,
+                         jit_word_t,jit_int32_t,jit_word_t);
+#  define movr_f(r0,r1)                        _movr_f(_jit,r0,r1)
+static void _movr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi_f(r0,i0)                        _movi_f(_jit,r0,i0)
+static void _movi_f(jit_state_t*,jit_int32_t,jit_float32_t*);
+#  define movr_d(r0,r1)                        _movr_d(_jit,r0,r1)
+static void _movr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movi_d(r0,i0)                        _movi_d(_jit,r0,i0)
+static void _movi_d(jit_state_t*,jit_int32_t,jit_float64_t*);
+#  define absr_f(r0,r1)                        LPEBR(r0,r1)
+#  define absr_d(r0,r1)                        LPDBR(r0,r1)
+#  define negr_f(r0,r1)                        LCEBR(r0,r1)
+#  define negr_d(r0,r1)                        LCDBR(r0,r1)
+#  define sqrtr_f(r0,r1)               SQEBR(r0,r1)
+#  define sqrtr_d(r0,r1)               SQDBR(r0,r1)
+#  define truncr_f_i(r0,r1)            CFEBR(r0,RND_ZERO,r1)
+#  define truncr_d_i(r0,r1)            CFDBR(r0,RND_ZERO,r1)
+#  if __WORDSIZE == 64
+#    define truncr_f_l(r0,r1)          CGEBR(r0,RND_ZERO,r1)
+#    define truncr_d_l(r0,r1)          CGDBR(r0,RND_ZERO,r1)
+#  endif
+#  if __WORDSIZE == 32
+#    define extr_f(r0,r1)              CEFBR(r0,r1)
+#    define extr_d(r0,r1)              CDFBR(r0,r1)
+#  else
+#    define extr_f(r0,r1)              CEGBR(r0,r1)
+#    define extr_d(r0,r1)              CDGBR(r0,r1)
+#  endif
+#  define extr_d_f(r0,r1)              LEDBR(r0,r1)
+#  define extr_f_d(r0,r1)              LDEBR(r0,r1)
+#  define addr_f(r0,r1,r2)             _addr_f(_jit,r0,r1,r2)
+static void _addr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addi_f(r0,r1,i0)             fp(add,r0,r1,i0)
+#  define addr_d(r0,r1,r2)             _addr_d(_jit,r0,r1,r2)
+static void _addr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addi_d(r0,r1,i0)             dp(add,r0,r1,i0)
+#  define subr_f(r0,r1,r2)             _subr_f(_jit,r0,r1,r2)
+static void _subr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subi_f(r0,r1,i0)             fp(sub,r0,r1,i0)
+#  define subr_d(r0,r1,r2)             _subr_d(_jit,r0,r1,r2)
+static void _subr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subi_d(r0,r1,i0)             dp(sub,r0,r1,i0)
+#  define rsbr_f(r0,r1,r2)             subr_f(r0,r2,r1)
+#  define rsbi_f(r0,r1,i0)             fp(rsb,r0,r1,i0)
+#  define rsbr_d(r0,r1,r2)             subr_d(r0,r2,r1)
+#  define rsbi_d(r0,r1,i0)             dp(rsb,r0,r1,i0)
+#  define mulr_f(r0,r1,r2)             _mulr_f(_jit,r0,r1,r2)
+static void _mulr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define muli_f(r0,r1,i0)             fp(mul,r0,r1,i0)
+#  define mulr_d(r0,r1,r2)             _mulr_d(_jit,r0,r1,r2)
+static void _mulr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define muli_d(r0,r1,i0)             dp(mul,r0,r1,i0)
+#  define divr_f(r0,r1,r2)             _divr_f(_jit,r0,r1,r2)
+static void _divr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi_f(r0,r1,i0)             fp(div,r0,r1,i0)
+#  define divr_d(r0,r1,r2)             _divr_d(_jit,r0,r1,r2)
+static void _divr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define divi_d(r0,r1,i0)             dp(div,r0,r1,i0)
+#  define ldr_f(r0,r1)                 LE(r0,0,0,r1)
+#  define ldr_d(r0,r1)                 LD(r0,0,0,r1)
+#  define ldi_f(r0,i0)                 _ldi_f(_jit,r0,i0)
+static void _ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldi_d(r0,i0)                 _ldi_d(_jit,r0,i0)
+static void _ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_f(r0,r1,r2)             _ldxr_f(_jit,r0,r1,r2)
+static void _ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxr_d(r0,r1,r2)             _ldxr_d(_jit,r0,r1,r2)
+static void _ldxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ldxi_f(r0,r1,i0)             _ldxi_f(_jit,r0,r1,i0)
+static void _ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxi_d(r0,r1,i0)             _ldxi_d(_jit,r0,r1,i0)
+static void _ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define str_f(r0,r1)                 STE(r1,0,0,r0)
+#  define str_d(r0,r1)                 STD(r1,0,0,r0)
+#  define sti_f(i0,r0)                 _sti_f(_jit,i0,r0)
+static void _sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#  define sti_d(i0,r0)                 _sti_d(_jit,i0,r0)
+static void _sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_f(r0,r1,r2)             _stxr_f(_jit,r0,r1,r2)
+static void _stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxr_d(r0,r1,r2)             _stxr_d(_jit,r0,r1,r2)
+static void _stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define stxi_f(i0,r0,r1)             _stxi_f(_jit,i0,r0,r1)
+static void _stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxi_d(i0,r0,r1)             _stxi_d(_jit,i0,r0,r1)
+static void _stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define ltr_f(r0,r1,r2)              fr(CC_L,r0,r1,r2)
+#  define ltr_d(r0,r1,r2)              dr(CC_L,r0,r1,r2)
+#  define lti_f(r0,r1,i0)              fi(CC_L,r0,r1,i0)
+#  define lti_d(r0,r1,i0)              di(CC_L,r0,r1,i0)
+#  define ler_f(r0,r1,r2)              fr(CC_LE,r0,r1,r2)
+#  define ler_d(r0,r1,r2)              dr(CC_LE,r0,r1,r2)
+#  define lei_f(r0,r1,i0)              fi(CC_LE,r0,r1,i0)
+#  define lei_d(r0,r1,i0)              di(CC_LE,r0,r1,i0)
+#  define eqr_f(r0,r1,r2)              fr(CC_E,r0,r1,r2)
+#  define eqr_d(r0,r1,r2)              dr(CC_E,r0,r1,r2)
+#  define eqi_f(r0,r1,i0)              fi(CC_E,r0,r1,i0)
+#  define eqi_d(r0,r1,i0)              di(CC_E,r0,r1,i0)
+#  define ger_f(r0,r1,r2)              fr(CC_HE,r0,r1,r2)
+#  define ger_d(r0,r1,r2)              dr(CC_HE,r0,r1,r2)
+#  define gei_f(r0,r1,i0)              fi(CC_HE,r0,r1,i0)
+#  define gei_d(r0,r1,i0)              di(CC_HE,r0,r1,i0)
+#  define gtr_f(r0,r1,r2)              fr(CC_H,r0,r1,r2)
+#  define gtr_d(r0,r1,r2)              dr(CC_H,r0,r1,r2)
+#  define gti_f(r0,r1,i0)              fi(CC_H,r0,r1,i0)
+#  define gti_d(r0,r1,i0)              di(CC_H,r0,r1,i0)
+#  define ner_f(r0,r1,r2)              fr(CC_NE,r0,r1,r2)
+#  define ner_d(r0,r1,r2)              dr(CC_NE,r0,r1,r2)
+#  define nei_f(r0,r1,i0)              fi(CC_NE,r0,r1,i0)
+#  define nei_d(r0,r1,i0)              di(CC_NE,r0,r1,i0)
+#  define unltr_f(r0,r1,r2)            fr(CC_NHE,r0,r1,r2)
+#  define unltr_d(r0,r1,r2)            dr(CC_NHE,r0,r1,r2)
+#  define unlti_f(r0,r1,i0)            fi(CC_NHE,r0,r1,i0)
+#  define unlti_d(r0,r1,i0)            di(CC_NHE,r0,r1,i0)
+#  define unler_f(r0,r1,r2)            fr(CC_NH,r0,r1,r2)
+#  define unler_d(r0,r1,r2)            dr(CC_NH,r0,r1,r2)
+#  define unlei_f(r0,r1,i0)            fi(CC_NH,r0,r1,i0)
+#  define unlei_d(r0,r1,i0)            di(CC_NH,r0,r1,i0)
+#  define uneqr_f(r0,r1,r2)            _uneqr_f(_jit,r0,r1,r2)
+static void _uneqr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define uneqr_d(r0,r1,r2)            _uneqr_d(_jit,r0,r1,r2)
+static void _uneqr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define uneqi_f(r0,r1,i0)            fp(uneq,r0,r1,i0)
+#  define uneqi_d(r0,r1,i0)            dp(uneq,r0,r1,i0)
+#  define unger_f(r0,r1,r2)            fr(CC_NL,r0,r1,r2)
+#  define unger_d(r0,r1,r2)            dr(CC_NL,r0,r1,r2)
+#  define ungei_f(r0,r1,i0)            fi(CC_NL,r0,r1,i0)
+#  define ungei_d(r0,r1,i0)            di(CC_NL,r0,r1,i0)
+#  define ungtr_f(r0,r1,r2)            fr(CC_NLE,r0,r1,r2)
+#  define ungtr_d(r0,r1,r2)            dr(CC_NLE,r0,r1,r2)
+#  define ungti_f(r0,r1,i0)            fi(CC_NLE,r0,r1,i0)
+#  define ungti_d(r0,r1,i0)            di(CC_NLE,r0,r1,i0)
+#  define ltgtr_f(r0,r1,r2)            _ltgtr_f(_jit,r0,r1,r2)
+static void _ltgtr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ltgtr_d(r0,r1,r2)            _ltgtr_d(_jit,r0,r1,r2)
+static void _ltgtr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ltgti_f(r0,r1,i0)            fp(ltgt,r0,r1,i0)
+#  define ltgti_d(r0,r1,i0)            dp(ltgt,r0,r1,i0)
+#  define ordr_f(r0,r1,r2)             fr(CC_NO,r0,r1,r2)
+#  define ordr_d(r0,r1,r2)             dr(CC_NO,r0,r1,r2)
+#  define ordi_f(r0,r1,i0)             fi(CC_NO,r0,r1,i0)
+#  define ordi_d(r0,r1,i0)             di(CC_NO,r0,r1,i0)
+#  define unordr_f(r0,r1,r2)           fr(CC_O,r0,r1,r2)
+#  define unordr_d(r0,r1,r2)           dr(CC_O,r0,r1,r2)
+#  define unordi_f(r0,r1,i0)           fi(CC_O,r0,r1,i0)
+#  define unordi_d(r0,r1,i0)           di(CC_O,r0,r1,i0)
+#  define bltr_f(i0,r0,r1)             bfr(CC_L,i0,r0,r1)
+#  define bltr_d(i0,r0,r1)             bdr(CC_L,i0,r0,r1)
+#  define blti_f(i0,r0,i1)             bfi(CC_L,i0,r0,i1)
+#  define blti_d(i0,r0,i1)             bdi(CC_L,i0,r0,i1)
+#  define bltr_f_p(i0,r0,r1)           bfr_p(CC_L,i0,r0,r1)
+#  define bltr_d_p(i0,r0,r1)           bdr_p(CC_L,i0,r0,r1)
+#  define blti_f_p(i0,r0,i1)           bfi_p(CC_L,i0,r0,i1)
+#  define blti_d_p(i0,r0,i1)           bdi_p(CC_L,i0,r0,i1)
+#  define bler_f(i0,r0,r1)             bfr(CC_LE,i0,r0,r1)
+#  define bler_d(i0,r0,r1)             bdr(CC_LE,i0,r0,r1)
+#  define blei_f(i0,r0,i1)             bfi(CC_LE,i0,r0,i1)
+#  define blei_d(i0,r0,i1)             bdi(CC_LE,i0,r0,i1)
+#  define bler_f_p(i0,r0,r1)           bfr_p(CC_LE,i0,r0,r1)
+#  define bler_d_p(i0,r0,r1)           bdr_p(CC_LE,i0,r0,r1)
+#  define blei_f_p(i0,r0,i1)           bfi_p(CC_LE,i0,r0,i1)
+#  define blei_d_p(i0,r0,i1)           bdi_p(CC_LE,i0,r0,i1)
+#  define beqr_f(i0,r0,r1)             bfr(CC_E,i0,r0,r1)
+#  define beqr_d(i0,r0,r1)             bdr(CC_E,i0,r0,r1)
+#  define beqi_f(i0,r0,i1)             bfi(CC_E,i0,r0,i1)
+#  define beqi_d(i0,r0,i1)             bdi(CC_E,i0,r0,i1)
+#  define beqr_f_p(i0,r0,r1)           bfr_p(CC_E,i0,r0,r1)
+#  define beqr_d_p(i0,r0,r1)           bdr_p(CC_E,i0,r0,r1)
+#  define beqi_f_p(i0,r0,i1)           bfi_p(CC_E,i0,r0,i1)
+#  define beqi_d_p(i0,r0,i1)           bdi_p(CC_E,i0,r0,i1)
+#  define bger_f(i0,r0,r1)             bfr(CC_HE,i0,r0,r1)
+#  define bger_d(i0,r0,r1)             bdr(CC_HE,i0,r0,r1)
+#  define bgei_f(i0,r0,i1)             bfi(CC_HE,i0,r0,i1)
+#  define bgei_d(i0,r0,i1)             bdi(CC_HE,i0,r0,i1)
+#  define bger_f_p(i0,r0,r1)           bfr_p(CC_HE,i0,r0,r1)
+#  define bger_d_p(i0,r0,r1)           bdr_p(CC_HE,i0,r0,r1)
+#  define bgei_f_p(i0,r0,i1)           bfi_p(CC_HE,i0,r0,i1)
+#  define bgei_d_p(i0,r0,i1)           bdi_p(CC_HE,i0,r0,i1)
+#  define bgtr_f(i0,r0,r1)             bfr(CC_H,i0,r0,r1)
+#  define bgtr_d(i0,r0,r1)             bdr(CC_H,i0,r0,r1)
+#  define bgti_f(i0,r0,i1)             bfi(CC_H,i0,r0,i1)
+#  define bgti_d(i0,r0,i1)             bdi(CC_H,i0,r0,i1)
+#  define bgtr_f_p(i0,r0,r1)           bfr_p(CC_H,i0,r0,r1)
+#  define bgtr_d_p(i0,r0,r1)           bdr_p(CC_H,i0,r0,r1)
+#  define bgti_f_p(i0,r0,i1)           bfi_p(CC_H,i0,r0,i1)
+#  define bgti_d_p(i0,r0,i1)           bdi_p(CC_H,i0,r0,i1)
+#  define bner_f(i0,r0,r1)             bfr(CC_NE,i0,r0,r1)
+#  define bner_d(i0,r0,r1)             bdr(CC_NE,i0,r0,r1)
+#  define bnei_f(i0,r0,i1)             bfi(CC_NE,i0,r0,i1)
+#  define bnei_d(i0,r0,i1)             bdi(CC_NE,i0,r0,i1)
+#  define bner_f_p(i0,r0,r1)           bfr_p(CC_NE,i0,r0,r1)
+#  define bner_d_p(i0,r0,r1)           bdr_p(CC_NE,i0,r0,r1)
+#  define bnei_f_p(i0,r0,i1)           bfi_p(CC_NE,i0,r0,i1)
+#  define bnei_d_p(i0,r0,i1)           bdi_p(CC_NE,i0,r0,i1)
+#  define bunltr_f(i0,r0,r1)           bfr(CC_NHE,i0,r0,r1)
+#  define bunltr_d(i0,r0,r1)           bdr(CC_NHE,i0,r0,r1)
+#  define bunlti_f(i0,r0,i1)           bfi(CC_NHE,i0,r0,i1)
+#  define bunlti_d(i0,r0,i1)           bdi(CC_NHE,i0,r0,i1)
+#  define bunltr_f_p(i0,r0,r1)         bfr_p(CC_NHE,i0,r0,r1)
+#  define bunltr_d_p(i0,r0,r1)         bdr_p(CC_NHE,i0,r0,r1)
+#  define bunlti_f_p(i0,r0,i1)         bfi_p(CC_NHE,i0,r0,i1)
+#  define bunlti_d_p(i0,r0,i1)         bdi_p(CC_NHE,i0,r0,i1)
+#  define bunler_f(i0,r0,r1)           bfr(CC_NH,i0,r0,r1)
+#  define bunler_d(i0,r0,r1)           bdr(CC_NH,i0,r0,r1)
+#  define bunlei_f(i0,r0,i1)           bfi(CC_NH,i0,r0,i1)
+#  define bunlei_d(i0,r0,i1)           bdi(CC_NH,i0,r0,i1)
+#  define bunler_f_p(i0,r0,r1)         bfr_p(CC_NH,i0,r0,r1)
+#  define bunler_d_p(i0,r0,r1)         bdr_p(CC_NH,i0,r0,r1)
+#  define bunlei_f_p(i0,r0,i1)         bfi_p(CC_NH,i0,r0,i1)
+#  define bunlei_d_p(i0,r0,i1)         bdi_p(CC_NH,i0,r0,i1)
+#  define buneqr_f(i0,r0,r1)           buneqr(0,i0,r0,r1)
+#  define buneqr_d(i0,r0,r1)           buneqr(1,i0,r0,r1)
+#  define buneqi_f(i0,r0,i1)           buneqi(0,i0,r0,i1)
+#  define buneqi_d(i0,r0,i1)           buneqi(1,i0,r0,i1)
+#  define buneqr_f_p(i0,r0,r1)         buneqr(0,i0,r0,r1)
+#  define buneqr_d_p(i0,r0,r1)         buneqr(1,i0,r0,r1)
+#  define buneqi_f_p(i0,r0,i1)         buneqi(0,i0,r0,i1)
+#  define buneqi_d_p(i0,r0,i1)         buneqi(1,i0,r0,i1)
+#  define bunger_f(i0,r0,r1)           bfr(CC_NL,i0,r0,r1)
+#  define bunger_d(i0,r0,r1)           bdr(CC_NL,i0,r0,r1)
+#  define bungei_f(i0,r0,i1)           bfi(CC_NL,i0,r0,i1)
+#  define bungei_d(i0,r0,i1)           bdi(CC_NL,i0,r0,i1)
+#  define bunger_f_p(i0,r0,r1)         bfr_p(CC_NL,i0,r0,r1)
+#  define bunger_d_p(i0,r0,r1)         bdr_p(CC_NL,i0,r0,r1)
+#  define bungei_f_p(i0,r0,i1)         bfi_p(CC_NL,i0,r0,i1)
+#  define bungei_d_p(i0,r0,i1)         bdi_p(CC_NL,i0,r0,i1)
+#  define bungtr_f(i0,r0,r1)           bfr(CC_NLE,i0,r0,r1)
+#  define bungtr_d(i0,r0,r1)           bdr(CC_NLE,i0,r0,r1)
+#  define bungti_f(i0,r0,i1)           bfi(CC_NLE,i0,r0,i1)
+#  define bungti_d(i0,r0,i1)           bdi(CC_NLE,i0,r0,i1)
+#  define bungtr_f_p(i0,r0,r1)         bfr_p(CC_NLE,i0,r0,r1)
+#  define bungtr_d_p(i0,r0,r1)         bdr_p(CC_NLE,i0,r0,r1)
+#  define bungti_f_p(i0,r0,i1)         bfi_p(CC_NLE,i0,r0,i1)
+#  define bungti_d_p(i0,r0,i1)         bdi_p(CC_NLE,i0,r0,i1)
+#  define bltgtr_f(i0,r0,r1)           bltgtr(0,i0,r0,r1)
+#  define bltgtr_d(i0,r0,r1)           bltgtr(1,i0,r0,r1)
+#  define bltgti_f(i0,r0,i1)           bltgti(0,i0,r0,i1)
+#  define bltgti_d(i0,r0,i1)           bltgti(1,i0,r0,i1)
+#  define bltgtr_f_p(i0,r0,r1)         bltgtr(0,i0,r0,r1)
+#  define bltgtr_d_p(i0,r0,r1)         bltgtr(1,i0,r0,r1)
+#  define bltgti_f_p(i0,r0,i1)         bltgti(0,i0,r0,i1)
+#  define bltgti_d_p(i0,r0,i1)         bltgti(1,i0,r0,i1)
+#  define bordr_f(i0,r0,r1)            bfr(CC_NO,i0,r0,r1)
+#  define bordr_d(i0,r0,r1)            bdr(CC_NO,i0,r0,r1)
+#  define bordi_f(i0,r0,i1)            bfi(CC_NO,i0,r0,i1)
+#  define bordi_d(i0,r0,i1)            bdi(CC_NO,i0,r0,i1)
+#  define bordr_f_p(i0,r0,r1)          bfr_p(CC_NO,i0,r0,r1)
+#  define bordr_d_p(i0,r0,r1)          bdr_p(CC_NO,i0,r0,r1)
+#  define bordi_f_p(i0,r0,i1)          bfi_p(CC_NO,i0,r0,i1)
+#  define bordi_d_p(i0,r0,i1)          bdi_p(CC_NO,i0,r0,i1)
+#  define bunordr_f(i0,r0,r1)          bfr(CC_O,i0,r0,r1)
+#  define bunordr_d(i0,r0,r1)          bdr(CC_O,i0,r0,r1)
+#  define bunordi_f(i0,r0,i1)          bfi(CC_O,i0,r0,i1)
+#  define bunordi_d(i0,r0,i1)          bdi(CC_O,i0,r0,i1)
+#  define bunordr_f_p(i0,r0,r1)                bfr_p(CC_O,i0,r0,r1)
+#  define bunordr_d_p(i0,r0,r1)                bdr_p(CC_O,i0,r0,r1)
+#  define bunordi_f_p(i0,r0,i1)                bfi_p(CC_O,i0,r0,i1)
+#  define bunordi_d_p(i0,r0,i1)                bdi_p(CC_O,i0,r0,i1)
+#  define vaarg_d(r0, r1)              _vaarg_d(_jit, r0, r1)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif
+
+#if CODE
+static void
+_fp(jit_state_t *_jit, jit_code_t code,
+    jit_int32_t r0, jit_int32_t r1, jit_float32_t *i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    movi_f(rn(reg), i0);
+    switch (code) {
+       case jit_code_addi_f:   addr_f(r0, r1, rn(reg));        break;
+       case jit_code_subi_f:   subr_f(r0, r1, rn(reg));        break;
+       case jit_code_rsbi_f:   rsbr_f(r0, r1, rn(reg));        break;
+       case jit_code_muli_f:   mulr_f(r0, r1, rn(reg));        break;
+       case jit_code_divi_f:   divr_f(r0, r1, rn(reg));        break;
+       case jit_code_uneqi_f:  uneqr_f(r0, r1, rn(reg));       break;
+       case jit_code_ltgti_f:  ltgtr_f(r0, r1, rn(reg));       break;
+       default:                abort();
+    }
+    jit_unget_reg(reg);
+}
+
+static void
+_dp(jit_state_t *_jit, jit_code_t code,
+    jit_int32_t r0, jit_int32_t r1, jit_float64_t *i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr);
+    movi_d(rn(reg), i0);
+    switch (code) {
+       case jit_code_addi_d:   addr_d(r0, r1, rn(reg));        break;
+       case jit_code_subi_d:   subr_d(r0, r1, rn(reg));        break;
+       case jit_code_rsbi_d:   rsbr_d(r0, r1, rn(reg));        break;
+       case jit_code_muli_d:   mulr_d(r0, r1, rn(reg));        break;
+       case jit_code_divi_d:   divr_d(r0, r1, rn(reg));        break;
+       case jit_code_uneqi_d:  uneqr_d(r0, r1, rn(reg));       break;
+       case jit_code_ltgti_d:  ltgtr_d(r0, r1, rn(reg));       break;
+       default:                abort();
+    }
+    jit_unget_reg(reg);
+}
+
+static void
+_fr(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    LGHI(r0, 1);
+    CEBR(r1, r2);
+    w = _jit->pc.w;
+    BRC(cc, 0);
+    LGHI(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+
+static void
+_dr(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         w;
+    LGHI(r0, 1);
+    CDBR(r1, r2);
+    w = _jit->pc.w;
+    BRC(cc, 0);
+    LGHI(r0, 0);
+    patch_at(w, _jit->pc.w);
+}
+
+static void
+_fi(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_float32_t *i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi_f(rn(reg), i0);
+    fr(cc, r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_di(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_float64_t *i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    movi_d(rn(reg), i0);
+    dr(cc, r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+
+static void
+_bfr(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d;
+    CEBR(r0, r1);
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(d))
+       BRC(cc, x16(d));
+    else {
+       assert(s32_p(d));
+       BRCL(cc, d);
+    }
+}
+
+static void
+_bdr(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         d;
+    CDBR(r0, r1);
+    d = (i0 - _jit->pc.w) >> 1;
+    if (s16_p(d))
+       BRC(cc, x16(d));
+    else {
+       assert(s32_p(d));
+       BRCL(cc, d);
+    }
+}
+
+static jit_word_t
+_bfr_p(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CEBR(r0, r1);
+    w = _jit->pc.w;
+    BRCL(cc, 0);
+    return (w);
+}
+
+static jit_word_t
+_bdr_p(jit_state_t *_jit, jit_int32_t cc,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CDBR(r0, r1);
+    w = _jit->pc.w;
+    BRCL(cc, 0);
+    return (w);
+}
+
+static void
+_bfi(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_float32_t *i1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi_f(rn(reg), i1);
+    bfr(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_bdi(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_float64_t *i1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi_d(rn(reg), i1);
+    bdr(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static jit_word_t
+_bfi_p(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_float32_t *i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi_f(rn(reg), i1);
+    w = bfr_p(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bdi_p(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_float64_t *i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi_d(rn(reg), i1);
+    w = bdr_p(cc, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_buneqr(jit_state_t *_jit, jit_int32_t db,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         unord, ne, w;
+    if (db)    CDBR(r0, r1);
+    else       CEBR(r0, r1);
+    unord = _jit->pc.w;
+    BRC(CC_O, 0);                      /* unord satisfies condition */
+    ne = _jit->pc.w;
+    BRC(CC_NE, 0);                     /* ne does not satisfy condition */
+    patch_at(unord, _jit->pc.w);
+    w = _jit->pc.w;
+    BRCL(CC_AL, (i0 - _jit->pc.w) >> 1);
+    patch_at(ne, _jit->pc.w);
+    return (w);
+}
+
+static jit_word_t
+_buneqi(jit_state_t *_jit, jit_int32_t db,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    if (db)
+       movi_d(rn(reg), (jit_float64_t *)i1);
+    else
+       movi_f(rn(reg), (jit_float32_t *)i1);
+    w = buneqr(db, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static jit_word_t
+_bltgtr(jit_state_t *_jit, jit_int32_t db,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         unord, eq, w;
+    if (db)    CDBR(r0, r1);
+    else       CEBR(r0, r1);
+    unord = _jit->pc.w;
+    BRC(CC_O, 0);                      /* unord does not satisfy condition */
+    eq = _jit->pc.w;
+    BRC(CC_E, 0);                      /* eq does not satisfy condition */
+    w = _jit->pc.w;
+    BRCL(CC_AL, (i0 - _jit->pc.w) >> 1);
+    patch_at(unord, _jit->pc.w);
+    patch_at(eq, _jit->pc.w);
+    return (w);
+}
+
+static jit_word_t
+_bltgti(jit_state_t *_jit, jit_int32_t db,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_fpr|jit_class_nospill);
+    if (db)
+       movi_d(rn(reg), (jit_float64_t *)i1);
+    else
+       movi_f(rn(reg), (jit_float32_t *)i1);
+    w = bltgtr(db, i0, r0, rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_movr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       LER(r0, r1);
+}
+
+static void
+_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t      i;
+       jit_float32_t    f;
+    } data;
+    jit_int32_t                 reg;
+
+    if (*(jit_int32_t *)i0 == 0)
+       LZER(r0);
+    else if (_jitc->no_data) {
+       data.f = *i0;
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), data.i & 0xffffffff);
+       stxi_i(-4, _FP_REGNO, rn(reg));
+       jit_unget_reg_but_zero(reg);
+       ldxi_f(r0, _FP_REGNO, -4);
+    }
+    else
+       ldi_f(r0, (jit_word_t)i0);
+}
+
+static void
+_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       LDR(r0, r1);
+}
+
+static void
+_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+#if __WORDSIZE == 32
+       jit_int32_t      i[2];
+#else
+       jit_int64_t      l;
+#endif
+       jit_float64_t    d;
+    } data;
+    jit_int32_t                 reg;
+
+    if (*(jit_int64_t *)i0 == 0)
+       LZDR(r0);
+    else if (_jitc->no_data) {
+       data.d = *i0;
+       reg = jit_get_reg_but_zero(0);
+#if __WORDSIZE == 32
+       movi(rn(reg), data.i[0]);
+       stxi_i(-8, _FP_REGNO, rn(reg));
+       movi(rn(reg), data.i[1]);
+       stxi_i(-4, _FP_REGNO, rn(reg));
+#else
+       movi(rn(reg), data.l);
+       stxi_l(-8, _FP_REGNO, rn(reg));
+#endif
+       jit_unget_reg_but_zero(reg);
+       ldxi_d(r0, _FP_REGNO, -8);
+    }
+    else
+       ldi_d(r0, (jit_word_t)i0);
+}
+
+static void
+_addr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       AEBR(r0, r1);
+    else {
+       movr_f(r0, r1);
+       AEBR(r0, r2);
+    }
+}
+
+static void
+_addr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       ADBR(r0, r1);
+    else {
+       movr_d(r0, r1);
+       ADBR(r0, r2);
+    }
+}
+
+static void
+_subr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg(jit_class_fpr);
+       movr_f(rn(reg), r2);
+       movr_f(r0, r1);
+       SEBR(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movr_f(r0, r1);
+       SEBR(r0, r2);
+    }
+}
+
+static void
+_subr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg(jit_class_fpr);
+       movr_d(rn(reg), r2);
+       movr_d(r0, r1);
+       SDBR(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movr_d(r0, r1);
+       SDBR(r0, r2);
+    }
+}
+
+static void
+_mulr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       MEEBR(r0, r1);
+    else {
+       movr_f(r0, r1);
+       MEEBR(r0, r2);
+    }
+}
+
+static void
+_mulr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       MDBR(r0, r1);
+    else {
+       movr_d(r0, r1);
+       MDBR(r0, r2);
+    }
+}
+
+static void
+_divr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg(jit_class_fpr);
+       movr_f(rn(reg), r2);
+       movr_f(r0, r1);
+       DEBR(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movr_f(r0, r1);
+       DEBR(r0, r2);
+    }
+}
+
+static void
+_divr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2) {
+       reg = jit_get_reg(jit_class_fpr);
+       movr_d(rn(reg), r2);
+       movr_d(r0, r1);
+       DDBR(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movr_d(r0, r1);
+       DDBR(r0, r2);
+    }
+}
+
+static void
+_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    ldr_f(r0, rn(reg));
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    ldr_d(r0, rn(reg));
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movr(rn(reg), r1);
+    addr(rn(reg), rn(reg), r2);
+    ldr_f(r0, rn(reg));
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movr(rn(reg), r1);
+    addr(rn(reg), rn(reg), r2);
+    ldr_d(r0, rn(reg));
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (u12_p(i0))
+       LE(r0, i0, 0, r1);
+    else if (s20_p(i0))
+       LEY(r0, x20(i0), 0, r1);
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r1);
+       ldr_f(r0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (u12_p(i0))
+       LD(r0, i0, 0, r1);
+    else if (s20_p(i0))
+       LDY(r0, x20(i0), 0, r1);
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r1);
+       ldr_d(r0, rn(reg));
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    str_f(rn(reg), r0);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movi(rn(reg), i0);
+    str_d(rn(reg), r0);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movr(rn(reg), r0);
+    addr(rn(reg), rn(reg), r1);
+    str_f(rn(reg), r2);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg_but_zero(0);
+    movr(rn(reg), r0);
+    addr(rn(reg), rn(reg), r1);
+    str_d(rn(reg), r2);
+    jit_unget_reg_but_zero(reg);
+}
+
+static void
+_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (u12_p(i0))
+       STE(r1, i0, 0, r0);
+    else if (s20_p(i0))
+       STEY(r1, x20(i0), 0, r0);
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r0);
+       str_f(rn(reg), r1);
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (u12_p(i0))
+       STD(r1, i0, 0, r0);
+    else if (s20_p(i0))
+       STDY(r1, x20(i0), 0, r0);
+    else {
+       reg = jit_get_reg_but_zero(0);
+       movi(rn(reg), i0);
+       addr(rn(reg), rn(reg), r0);
+       str_d(rn(reg), r1);
+       jit_unget_reg_but_zero(reg);
+    }
+}
+
+static void
+_uneqr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         unord, eq;
+    movi(r0, 1);                       /* set to one */
+    CEBR(r1, r2);
+    unord = _jit->pc.w;                        /* keep set to one if unord */
+    BRC(CC_O, 0);
+    eq = _jit->pc.w;
+    BRC(CC_E, 0);                      /* keep set to one if eq */
+    movi(r0, 0);                       /* set to zero */
+    patch_at(unord, _jit->pc.w);
+    patch_at(eq, _jit->pc.w);
+}
+
+static void
+_uneqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         unord, eq;
+    movi(r0, 1);                       /* set to one */
+    CDBR(r1, r2);
+    unord = _jit->pc.w;                        /* keep set to one if unord */
+    BRC(CC_O, 0);
+    eq = _jit->pc.w;
+    BRC(CC_E, 0);                      /* keep set to one if eq */
+    movi(r0, 0);                       /* set to zero */
+    patch_at(unord, _jit->pc.w);
+    patch_at(eq, _jit->pc.w);
+}
+
+static void
+_ltgtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         unord, eq;
+    movi(r0, 0);                       /* set to zero */
+    CEBR(r1, r2);
+    unord = _jit->pc.w;                        /* keep set to zero if unord */
+    BRC(CC_O, 0);
+    eq = _jit->pc.w;
+    BRC(CC_E, 0);                      /* keep set to zero if eq */
+    movi(r0, 1);                       /* set to one */
+    patch_at(unord, _jit->pc.w);
+    patch_at(eq, _jit->pc.w);
+}
+
+static void
+_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_word_t         unord, eq;
+    movi(r0, 0);                       /* set to zero */
+    CDBR(r1, r2);
+    unord = _jit->pc.w;                        /* keep set to zero if unord */
+    BRC(CC_O, 0);
+    eq = _jit->pc.w;
+    BRC(CC_E, 0);                      /* keep set to zero if eq */
+    movi(r0, 1);                       /* set to one */
+    patch_at(unord, _jit->pc.w);
+    patch_at(eq, _jit->pc.w);
+}
+
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                rg0;
+    jit_int32_t                rg1;
+    jit_int32_t                rg2;
+    jit_word_t         ge_code;
+    jit_word_t         lt_code;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg_but_zero(jit_class_gpr);
+    rg1 = jit_get_reg_but_zero(jit_class_gpr);
+
+    /* Load the fp offset in save area in the first temporary. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, fpoff));
+
+    /* Jump over if there are no remaining arguments in the save area. */
+    ge_code = bgei_p(_jit->pc.w, rn(rg0), NUM_FLOAT_REG_ARGS);
+
+    /* Load the save area pointer in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, save));
+
+    /* Scale offset. */
+    rg2 = jit_get_reg_but_zero(0);
+    lshi(rn(rg2), rn(rg0), 3);
+    /* Add offset to saved area */
+    addi(rn(rg2), rn(rg2), 16 * sizeof(jit_word_t));
+
+    /* Load the vararg argument in the first argument. */
+    ldxr_d(r0, rn(rg1), rn(rg2));
+    jit_unget_reg_but_zero(rg2);
+
+    /* Update the fp offset. */
+    addi(rn(rg0), rn(rg0), 1);
+    stxi(offsetof(jit_va_list_t, fpoff), r1, rn(rg0));
+
+    /* Will only need one temporary register below. */
+    jit_unget_reg_but_zero(rg1);
+
+    /* Jump over overflow code. */
+    lt_code = jmpi_p(_jit->pc.w);
+
+    /* Where to land if argument is in overflow area. */
+    patch_at(ge_code, _jit->pc.w);
+
+    /* Load overflow pointer. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, over));
+
+    /* Load argument. */
+    ldr_d(r0, rn(rg0));
+
+    /* Update overflow pointer. */
+    addi(rn(rg0), rn(rg0), sizeof(jit_float64_t));
+    stxi(offsetof(jit_va_list_t, over), r1, rn(rg0));
+
+    /* Where to land if argument is in save area. */
+    patch_at(lt_code, _jit->pc.w);
+
+    jit_unget_reg_but_zero(rg0);
+}
+#endif
diff --git a/deps/lightning/lib/jit_s390-sz.c b/deps/lightning/lib/jit_s390-sz.c
new file mode 100644 (file)
index 0000000..bb8b2dc
--- /dev/null
@@ -0,0 +1,804 @@
+
+#if __WORDSIZE == 32
+#define JIT_INSTR_MAX 104
+    0, /* data */
+    0, /* live */
+    6, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    2, /* label */
+    42,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    44,        /* va_start */
+    104,       /* va_arg */
+    100,       /* va_arg_d */
+    0, /* va_end */
+    8, /* addr */
+    24,        /* addi */
+    8, /* addcr */
+    20,        /* addci */
+    8, /* addxr */
+    12,        /* addxi */
+    12,        /* subr */
+    24,        /* subi */
+    12,        /* subcr */
+    20,        /* subci */
+    12,        /* subxr */
+    12,        /* subxi */
+    28,        /* rsbi */
+    8, /* mulr */
+    24,        /* muli */
+    60,        /* qmulr */
+    68,        /* qmuli */
+    16,        /* qmulr_u */
+    32,        /* qmuli_u */
+    12,        /* divr */
+    28,        /* divi */
+    16,        /* divr_u */
+    32,        /* divi_u */
+    16,        /* qdivr */
+    20,        /* qdivi */
+    20,        /* qdivr_u */
+    24,        /* qdivi_u */
+    12,        /* remr */
+    28,        /* remi */
+    16,        /* remr_u */
+    32,        /* remi_u */
+    8, /* andr */
+    20,        /* andi */
+    8, /* orr */
+    20,        /* ori */
+    8, /* xorr */
+    24,        /* xori */
+    6, /* lshr */
+    10,        /* lshi */
+    6, /* rshr */
+    10,        /* rshi */
+    6, /* rshr_u */
+    10,        /* rshi_u */
+    4, /* negr */
+    12,        /* comr */
+    20,        /* ltr */
+    24,        /* lti */
+    20,        /* ltr_u */
+    24,        /* lti_u */
+    20,        /* ler */
+    24,        /* lei */
+    20,        /* ler_u */
+    24,        /* lei_u */
+    20,        /* eqr */
+    24,        /* eqi */
+    20,        /* ger */
+    24,        /* gei */
+    20,        /* ger_u */
+    24,        /* gei_u */
+    20,        /* gtr */
+    24,        /* gti */
+    20,        /* gtr_u */
+    24,        /* gti_u */
+    20,        /* ner */
+    24,        /* nei */
+    4, /* movr */
+    16,        /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    4, /* extr_i */
+    4, /* extr_ui */
+    4, /* htonr_us */
+    4, /* htonr_ui */
+    4, /* htonr_ul */
+    6, /* ldr_c */
+    18,        /* ldi_c */
+    6, /* ldr_uc */
+    18,        /* ldi_uc */
+    6, /* ldr_s */
+    18,        /* ldi_s */
+    6, /* ldr_us */
+    18,        /* ldi_us */
+    6, /* ldr_i */
+    18,        /* ldi_i */
+    6, /* ldr_ui */
+    18,        /* ldi_ui */
+    6, /* ldr_l */
+    18,        /* ldi_l */
+    14,        /* ldxr_c */
+    26,        /* ldxi_c */
+    14,        /* ldxr_uc */
+    26,        /* ldxi_uc */
+    14,        /* ldxr_s */
+    26,        /* ldxi_s */
+    14,        /* ldxr_us */
+    26,        /* ldxi_us */
+    14,        /* ldxr_i */
+    26,        /* ldxi_i */
+    14,        /* ldxr_ui */
+    26,        /* ldxi_ui */
+    14,        /* ldxr_l */
+    26,        /* ldxi_l */
+    4, /* str_c */
+    16,        /* sti_c */
+    4, /* str_s */
+    16,        /* sti_s */
+    4, /* str_i */
+    16,        /* sti_i */
+    6, /* str_l */
+    18,        /* sti_l */
+    12,        /* stxr_c */
+    28,        /* stxi_c */
+    12,        /* stxr_s */
+    28,        /* stxi_s */
+    12,        /* stxr_i */
+    28,        /* stxi_i */
+    14,        /* stxr_l */
+    30,        /* stxi_l */
+    10,        /* bltr */
+    14,        /* blti */
+    10,        /* bltr_u */
+    14,        /* blti_u */
+    10,        /* bler */
+    14,        /* blei */
+    10,        /* bler_u */
+    14,        /* blei_u */
+    10,        /* beqr */
+    26,        /* beqi */
+    10,        /* bger */
+    14,        /* bgei */
+    10,        /* bger_u */
+    14,        /* bgei_u */
+    10,        /* bgtr */
+    14,        /* bgti */
+    10,        /* bgtr_u */
+    14,        /* bgti_u */
+    10,        /* bner */
+    26,        /* bnei */
+    18,        /* bmsr */
+    18,        /* bmsi */
+    18,        /* bmcr */
+    18,        /* bmci */
+    10,        /* boaddr */
+    14,        /* boaddi */
+    10,        /* boaddr_u */
+    14,        /* boaddi_u */
+    10,        /* bxaddr */
+    14,        /* bxaddi */
+    10,        /* bxaddr_u */
+    14,        /* bxaddi_u */
+    10,        /* bosubr */
+    14,        /* bosubi */
+    10,        /* bosubr_u */
+    14,        /* bosubi_u */
+    10,        /* bxsubr */
+    14,        /* bxsubi */
+    10,        /* bxsubr_u */
+    14,        /* bxsubi_u */
+    2, /* jmpr */
+    18,        /* jmpi */
+    2, /* callr */
+    18,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    40,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    6, /* addr_f */
+    26,        /* addi_f */
+    8, /* subr_f */
+    26,        /* subi_f */
+    28,        /* rsbi_f */
+    6, /* mulr_f */
+    26,        /* muli_f */
+    8, /* divr_f */
+    26,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    16,        /* ltr_f */
+    36,        /* lti_f */
+    16,        /* ler_f */
+    36,        /* lei_f */
+    16,        /* eqr_f */
+    36,        /* eqi_f */
+    16,        /* ger_f */
+    36,        /* gei_f */
+    16,        /* gtr_f */
+    36,        /* gti_f */
+    16,        /* ner_f */
+    36,        /* nei_f */
+    16,        /* unltr_f */
+    36,        /* unlti_f */
+    16,        /* unler_f */
+    36,        /* unlei_f */
+    20,        /* uneqr_f */
+    40,        /* uneqi_f */
+    16,        /* unger_f */
+    36,        /* ungei_f */
+    16,        /* ungtr_f */
+    36,        /* ungti_f */
+    20,        /* ltgtr_f */
+    40,        /* ltgti_f */
+    16,        /* ordr_f */
+    36,        /* ordi_f */
+    16,        /* unordr_f */
+    36,        /* unordi_f */
+    4, /* truncr_f_i */
+    4, /* truncr_f_l */
+    4, /* extr_f */
+    4, /* extr_d_f */
+    2, /* movr_f */
+    20,        /* movi_f */
+    4, /* ldr_f */
+    16,        /* ldi_f */
+    12,        /* ldxr_f */
+    24,        /* ldxi_f */
+    4, /* str_f */
+    16,        /* sti_f */
+    12,        /* stxr_f */
+    24,        /* stxi_f */
+    10,        /* bltr_f */
+    30,        /* blti_f */
+    10,        /* bler_f */
+    30,        /* blei_f */
+    10,        /* beqr_f */
+    30,        /* beqi_f */
+    10,        /* bger_f */
+    30,        /* bgei_f */
+    10,        /* bgtr_f */
+    30,        /* bgti_f */
+    10,        /* bner_f */
+    30,        /* bnei_f */
+    10,        /* bunltr_f */
+    30,        /* bunlti_f */
+    10,        /* bunler_f */
+    30,        /* bunlei_f */
+    18,        /* buneqr_f */
+    38,        /* buneqi_f */
+    10,        /* bunger_f */
+    30,        /* bungei_f */
+    10,        /* bungtr_f */
+    30,        /* bungti_f */
+    18,        /* bltgtr_f */
+    38,        /* bltgti_f */
+    10,        /* bordr_f */
+    30,        /* bordi_f */
+    10,        /* bunordr_f */
+    30,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    6, /* addr_d */
+    26,        /* addi_d */
+    8, /* subr_d */
+    26,        /* subi_d */
+    28,        /* rsbi_d */
+    6, /* mulr_d */
+    26,        /* muli_d */
+    8, /* divr_d */
+    26,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    16,        /* ltr_d */
+    36,        /* lti_d */
+    16,        /* ler_d */
+    36,        /* lei_d */
+    16,        /* eqr_d */
+    36,        /* eqi_d */
+    16,        /* ger_d */
+    36,        /* gei_d */
+    16,        /* gtr_d */
+    36,        /* gti_d */
+    16,        /* ner_d */
+    36,        /* nei_d */
+    16,        /* unltr_d */
+    36,        /* unlti_d */
+    16,        /* unler_d */
+    36,        /* unlei_d */
+    20,        /* uneqr_d */
+    40,        /* uneqi_d */
+    16,        /* unger_d */
+    36,        /* ungei_d */
+    16,        /* ungtr_d */
+    36,        /* ungti_d */
+    20,        /* ltgtr_d */
+    40,        /* ltgti_d */
+    16,        /* ordr_d */
+    36,        /* ordi_d */
+    16,        /* unordr_d */
+    36,        /* unordi_d */
+    4, /* truncr_d_i */
+    4, /* truncr_d_l */
+    4, /* extr_d */
+    4, /* extr_f_d */
+    2, /* movr_d */
+    24,        /* movi_d */
+    4, /* ldr_d */
+    16,        /* ldi_d */
+    12,        /* ldxr_d */
+    24,        /* ldxi_d */
+    4, /* str_d */
+    16,        /* sti_d */
+    12,        /* stxr_d */
+    24,        /* stxi_d */
+    10,        /* bltr_d */
+    30,        /* blti_d */
+    10,        /* bler_d */
+    30,        /* blei_d */
+    10,        /* beqr_d */
+    34,        /* beqi_d */
+    10,        /* bger_d */
+    30,        /* bgei_d */
+    10,        /* bgtr_d */
+    30,        /* bgti_d */
+    10,        /* bner_d */
+    30,        /* bnei_d */
+    10,        /* bunltr_d */
+    30,        /* bunlti_d */
+    10,        /* bunler_d */
+    30,        /* bunlei_d */
+    18,        /* buneqr_d */
+    38,        /* buneqi_d */
+    10,        /* bunger_d */
+    30,        /* bungei_d */
+    10,        /* bungtr_d */
+    30,        /* bungti_d */
+    18,        /* bltgtr_d */
+    38,        /* bltgti_d */
+    10,        /* bordr_d */
+    30,        /* bordi_d */
+    10,        /* bunordr_d */
+    30,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __WORDSIZE */
+
+#if __WORDSIZE == 64
+#define JIT_INSTR_MAX 104
+    0, /* data */
+    0, /* live */
+    6, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    2, /* label */
+    42,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    44,        /* va_start */
+    104,       /* va_arg */
+    100,       /* va_arg_d */
+    0, /* va_end */
+    8, /* addr */
+    24,        /* addi */
+    8, /* addcr */
+    20,        /* addci */
+    8, /* addxr */
+    12,        /* addxi */
+    12,        /* subr */
+    24,        /* subi */
+    12,        /* subcr */
+    20,        /* subci */
+    12,        /* subxr */
+    12,        /* subxi */
+    28,        /* rsbi */
+    8, /* mulr */
+    24,        /* muli */
+    60,        /* qmulr */
+    68,        /* qmuli */
+    16,        /* qmulr_u */
+    32,        /* qmuli_u */
+    12,        /* divr */
+    28,        /* divi */
+    16,        /* divr_u */
+    32,        /* divi_u */
+    16,        /* qdivr */
+    20,        /* qdivi */
+    20,        /* qdivr_u */
+    24,        /* qdivi_u */
+    12,        /* remr */
+    28,        /* remi */
+    16,        /* remr_u */
+    32,        /* remi_u */
+    8, /* andr */
+    20,        /* andi */
+    8, /* orr */
+    20,        /* ori */
+    8, /* xorr */
+    24,        /* xori */
+    6, /* lshr */
+    10,        /* lshi */
+    6, /* rshr */
+    10,        /* rshi */
+    6, /* rshr_u */
+    10,        /* rshi_u */
+    4, /* negr */
+    12,        /* comr */
+    20,        /* ltr */
+    24,        /* lti */
+    20,        /* ltr_u */
+    24,        /* lti_u */
+    20,        /* ler */
+    24,        /* lei */
+    20,        /* ler_u */
+    24,        /* lei_u */
+    20,        /* eqr */
+    24,        /* eqi */
+    20,        /* ger */
+    24,        /* gei */
+    20,        /* ger_u */
+    24,        /* gei_u */
+    20,        /* gtr */
+    24,        /* gti */
+    20,        /* gtr_u */
+    24,        /* gti_u */
+    20,        /* ner */
+    24,        /* nei */
+    4, /* movr */
+    16,        /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    4, /* extr_i */
+    4, /* extr_ui */
+    4, /* htonr_us */
+    4, /* htonr_ui */
+    4, /* htonr_ul */
+    6, /* ldr_c */
+    18,        /* ldi_c */
+    6, /* ldr_uc */
+    18,        /* ldi_uc */
+    6, /* ldr_s */
+    18,        /* ldi_s */
+    6, /* ldr_us */
+    18,        /* ldi_us */
+    6, /* ldr_i */
+    18,        /* ldi_i */
+    6, /* ldr_ui */
+    18,        /* ldi_ui */
+    6, /* ldr_l */
+    18,        /* ldi_l */
+    14,        /* ldxr_c */
+    26,        /* ldxi_c */
+    14,        /* ldxr_uc */
+    26,        /* ldxi_uc */
+    14,        /* ldxr_s */
+    26,        /* ldxi_s */
+    14,        /* ldxr_us */
+    26,        /* ldxi_us */
+    14,        /* ldxr_i */
+    26,        /* ldxi_i */
+    14,        /* ldxr_ui */
+    26,        /* ldxi_ui */
+    14,        /* ldxr_l */
+    26,        /* ldxi_l */
+    4, /* str_c */
+    16,        /* sti_c */
+    4, /* str_s */
+    16,        /* sti_s */
+    4, /* str_i */
+    16,        /* sti_i */
+    6, /* str_l */
+    18,        /* sti_l */
+    12,        /* stxr_c */
+    28,        /* stxi_c */
+    12,        /* stxr_s */
+    28,        /* stxi_s */
+    12,        /* stxr_i */
+    28,        /* stxi_i */
+    14,        /* stxr_l */
+    30,        /* stxi_l */
+    10,        /* bltr */
+    14,        /* blti */
+    10,        /* bltr_u */
+    14,        /* blti_u */
+    10,        /* bler */
+    14,        /* blei */
+    10,        /* bler_u */
+    14,        /* blei_u */
+    10,        /* beqr */
+    26,        /* beqi */
+    10,        /* bger */
+    14,        /* bgei */
+    10,        /* bger_u */
+    14,        /* bgei_u */
+    10,        /* bgtr */
+    14,        /* bgti */
+    10,        /* bgtr_u */
+    14,        /* bgti_u */
+    10,        /* bner */
+    26,        /* bnei */
+    18,        /* bmsr */
+    18,        /* bmsi */
+    18,        /* bmcr */
+    18,        /* bmci */
+    10,        /* boaddr */
+    14,        /* boaddi */
+    10,        /* boaddr_u */
+    14,        /* boaddi_u */
+    10,        /* bxaddr */
+    14,        /* bxaddi */
+    10,        /* bxaddr_u */
+    14,        /* bxaddi_u */
+    10,        /* bosubr */
+    14,        /* bosubi */
+    10,        /* bosubr_u */
+    14,        /* bosubi_u */
+    10,        /* bxsubr */
+    14,        /* bxsubi */
+    10,        /* bxsubr_u */
+    14,        /* bxsubi_u */
+    2, /* jmpr */
+    18,        /* jmpi */
+    2, /* callr */
+    18,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    40,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    6, /* addr_f */
+    26,        /* addi_f */
+    8, /* subr_f */
+    26,        /* subi_f */
+    28,        /* rsbi_f */
+    6, /* mulr_f */
+    26,        /* muli_f */
+    8, /* divr_f */
+    26,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    16,        /* ltr_f */
+    36,        /* lti_f */
+    16,        /* ler_f */
+    36,        /* lei_f */
+    16,        /* eqr_f */
+    36,        /* eqi_f */
+    16,        /* ger_f */
+    36,        /* gei_f */
+    16,        /* gtr_f */
+    36,        /* gti_f */
+    16,        /* ner_f */
+    36,        /* nei_f */
+    16,        /* unltr_f */
+    36,        /* unlti_f */
+    16,        /* unler_f */
+    36,        /* unlei_f */
+    20,        /* uneqr_f */
+    40,        /* uneqi_f */
+    16,        /* unger_f */
+    36,        /* ungei_f */
+    16,        /* ungtr_f */
+    36,        /* ungti_f */
+    20,        /* ltgtr_f */
+    40,        /* ltgti_f */
+    16,        /* ordr_f */
+    36,        /* ordi_f */
+    16,        /* unordr_f */
+    36,        /* unordi_f */
+    4, /* truncr_f_i */
+    4, /* truncr_f_l */
+    4, /* extr_f */
+    4, /* extr_d_f */
+    2, /* movr_f */
+    20,        /* movi_f */
+    4, /* ldr_f */
+    16,        /* ldi_f */
+    12,        /* ldxr_f */
+    24,        /* ldxi_f */
+    4, /* str_f */
+    16,        /* sti_f */
+    12,        /* stxr_f */
+    24,        /* stxi_f */
+    10,        /* bltr_f */
+    30,        /* blti_f */
+    10,        /* bler_f */
+    30,        /* blei_f */
+    10,        /* beqr_f */
+    30,        /* beqi_f */
+    10,        /* bger_f */
+    30,        /* bgei_f */
+    10,        /* bgtr_f */
+    30,        /* bgti_f */
+    10,        /* bner_f */
+    30,        /* bnei_f */
+    10,        /* bunltr_f */
+    30,        /* bunlti_f */
+    10,        /* bunler_f */
+    30,        /* bunlei_f */
+    18,        /* buneqr_f */
+    38,        /* buneqi_f */
+    10,        /* bunger_f */
+    30,        /* bungei_f */
+    10,        /* bungtr_f */
+    30,        /* bungti_f */
+    18,        /* bltgtr_f */
+    38,        /* bltgti_f */
+    10,        /* bordr_f */
+    30,        /* bordi_f */
+    10,        /* bunordr_f */
+    30,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    6, /* addr_d */
+    26,        /* addi_d */
+    8, /* subr_d */
+    26,        /* subi_d */
+    28,        /* rsbi_d */
+    6, /* mulr_d */
+    26,        /* muli_d */
+    8, /* divr_d */
+    26,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    16,        /* ltr_d */
+    36,        /* lti_d */
+    16,        /* ler_d */
+    36,        /* lei_d */
+    16,        /* eqr_d */
+    36,        /* eqi_d */
+    16,        /* ger_d */
+    36,        /* gei_d */
+    16,        /* gtr_d */
+    36,        /* gti_d */
+    16,        /* ner_d */
+    36,        /* nei_d */
+    16,        /* unltr_d */
+    36,        /* unlti_d */
+    16,        /* unler_d */
+    36,        /* unlei_d */
+    20,        /* uneqr_d */
+    40,        /* uneqi_d */
+    16,        /* unger_d */
+    36,        /* ungei_d */
+    16,        /* ungtr_d */
+    36,        /* ungti_d */
+    20,        /* ltgtr_d */
+    40,        /* ltgti_d */
+    16,        /* ordr_d */
+    36,        /* ordi_d */
+    16,        /* unordr_d */
+    36,        /* unordi_d */
+    4, /* truncr_d_i */
+    4, /* truncr_d_l */
+    4, /* extr_d */
+    4, /* extr_f_d */
+    2, /* movr_d */
+    24,        /* movi_d */
+    4, /* ldr_d */
+    16,        /* ldi_d */
+    12,        /* ldxr_d */
+    24,        /* ldxi_d */
+    4, /* str_d */
+    16,        /* sti_d */
+    12,        /* stxr_d */
+    24,        /* stxi_d */
+    10,        /* bltr_d */
+    30,        /* blti_d */
+    10,        /* bler_d */
+    30,        /* blei_d */
+    10,        /* beqr_d */
+    34,        /* beqi_d */
+    10,        /* bger_d */
+    30,        /* bgei_d */
+    10,        /* bgtr_d */
+    30,        /* bgti_d */
+    10,        /* bner_d */
+    30,        /* bnei_d */
+    10,        /* bunltr_d */
+    30,        /* bunlti_d */
+    10,        /* bunler_d */
+    30,        /* bunlei_d */
+    18,        /* buneqr_d */
+    38,        /* buneqi_d */
+    10,        /* bunger_d */
+    30,        /* bungei_d */
+    10,        /* bungtr_d */
+    30,        /* bungti_d */
+    18,        /* bltgtr_d */
+    38,        /* bltgti_d */
+    10,        /* bordr_d */
+    30,        /* bordi_d */
+    10,        /* bunordr_d */
+    30,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_s390.c b/deps/lightning/lib/jit_s390.c
new file mode 100644 (file)
index 0000000..7cd1d7f
--- /dev/null
@@ -0,0 +1,1690 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+
+#if __WORDSIZE == 32
+#  define NUM_FLOAT_REG_ARGS           2
+#else
+#  define NUM_FLOAT_REG_ARGS           4
+#endif
+#define jit_arg_reg_p(i)               ((i) >= 0 && (i) < 5)
+#define jit_arg_f_reg_p(i)             ((i) >= 0 && (i) < NUM_FLOAT_REG_ARGS)
+
+/*
+ * Types
+ */
+typedef struct jit_va_list {
+    /* The offsets are "1" based, as addresses are fixed in the
+     * standard stack frame format. */
+    jit_word_t         gpoff;
+    jit_word_t         fpoff;
+
+    /* Easier when there is an explicitly defined type...
+(gdb) ptype ap
+type = struct __va_list_tag {
+    long __gpr;
+    long __fpr;
+    void *__overflow_arg_area;
+    void *__reg_save_area;
+
+    Note that gopff (__gpr) and fpoff (__fpr) are jit_word_t equivalent
+    and, again, "1" (unit) based, so must be adjusted at va_arg time.
+ */
+    jit_pointer_t      over;
+    jit_pointer_t      save;
+
+    /* For variadic functions, always allocate space to save callee
+     * save fpr registers.
+     * Note that s390 has a standard stack frame format that lightning
+     * does not fully comply with, but for variadic functions it must,
+     * for those (variadic) do not use the "empty" spaces for any
+     * callee save fpr register, but save them after the va_list
+     * space; and use the standard stack frame format, as required
+     * by variadic functions (and have a compatible va_list pointer). */
+    jit_float64_t      f8;
+    jit_float64_t      f9;
+    jit_float64_t      f10;
+    jit_float64_t      f11;
+    jit_float64_t      f12;
+    jit_float64_t      f13;
+    jit_float64_t      f14;
+    jit_float64_t      f15;
+} jit_va_list_t;
+
+/*
+ * Prototypes
+ */
+#define jit_get_reg_pair()             _jit_get_reg_pair(_jit)
+static jit_int32_t _jit_get_reg_pair(jit_state_t*);
+#define jit_unget_reg_pair(regno)      _jit_unget_reg_pair(_jit,regno)
+static void _jit_unget_reg_pair(jit_state_t*,jit_int32_t);
+#define jit_get_reg_but_zero(flags)    _jit_get_reg_but_zero(_jit,flags)
+static jit_int32_t _jit_get_reg_but_zero(jit_state_t*,jit_int32_t);
+#define jit_unget_reg_but_zero(reg)    jit_unget_reg(reg)
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+/* libgcc */
+extern void __clear_cache(void *, void *);
+
+#define PROTO                          1
+#  include "jit_s390-cpu.c"
+#  include "jit_s390-fpu.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_register_t         _rvs[] = {
+    { rc(gpr) | 0x0,                   "%r0" },
+    { rc(gpr) | 0x1,                   "%r1" },
+    { rc(gpr) | rc(sav) | 0xc,         "%r12" },
+    { rc(gpr) | rc(sav) | 0xb,         "%r11" },
+    { rc(gpr) | rc(sav) | 0xa,         "%r10" },
+    { rc(gpr) | rc(sav) | 0x9,         "%r9" },
+    { rc(gpr) | rc(sav) | 0x8,         "%r8" },
+    { rc(gpr) | rc(sav) | 0x7,         "%r7" },
+    { rc(gpr) | rc(arg) | rc(sav) | 0x6,"%r6" },
+    { rc(gpr) | rc(arg) | 0x5,         "%r5" },
+    { rc(gpr) | rc(arg) | 0x4,         "%r4" },
+    { rc(gpr) | rc(arg) | 0x3,         "%r3" },
+    { rc(gpr) | rc(arg) | 0x2,         "%r2" },
+    { rc(sav) | 0xd,                   "%r13" },       /* used as JIT_FP */
+    { 0xe,                             "%r14" },
+    { rc(sav) | 0xf,                   "%r15" },
+    { rc(fpr) | 0x1,                   "%f1" },
+    { rc(fpr) | 0x3,                   "%f3" },
+    { rc(fpr) | 0x5,                   "%f5" },
+    { rc(fpr) | 0x7,                   "%f7" },
+    { rc(fpr) | rc(sav) | 0xe,         "%f14" },
+    /* Do not use as temporary to simplify stack layout */
+    { 0xf,                             "%f15" },
+    { rc(fpr) | rc(sav) | 0x8,         "%f8" },
+    { rc(fpr) | rc(sav) | 0x9,         "%f9" },
+    { rc(fpr) | rc(sav) | 0xa,         "%f10" },
+    { rc(fpr) | rc(sav) | 0xb,         "%f11" },
+    { rc(fpr) | rc(sav) | 0xc,         "%f12" },
+    { rc(fpr) | rc(sav) | 0xd,         "%f13" },
+    { rc(fpr) | rc(arg) | 0x6,         "%f6" },
+    { rc(fpr) | rc(arg) | 0x4,         "%f4" },
+    { rc(fpr) | rc(arg) | 0x2,         "%f2" },
+    { rc(fpr) | rc(arg) | 0x0,         "%f0" },
+    { _NOREG,                          "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    _jitc->reglen = jit_size(_rvs) - 1;
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = stack_framesize;
+    _jitc->function->self.argi = _jitc->function->self.argf =
+       _jitc->function->self.aoff = _jitc->function->self.alen = 0;
+    /* preallocate 8 bytes if not using a constant data buffer */
+    if (_jitc->no_data)
+       _jitc->function->self.aoff = -8;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    return (_jitc->function->self.aoff);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 reg;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    jit_negr(reg, v);
+    jit_andi(reg, reg, -8);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, reg);
+    jit_addr(JIT_SP, JIT_SP, reg);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(reg);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    jit_movr(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    jit_movr_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    jit_movr_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    if (u->code == jit_code_arg)
+       return (jit_arg_reg_p(u->u.w));
+    assert(u->code == jit_code_arg_f || u->code == jit_code_arg_d);
+    return (jit_arg_f_reg_p(u->u.w));
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare) {
+       jit_link_prepare();
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+    }
+    else {
+       jit_link_prolog();
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+
+       /* Allocate va_list like object in the stack. */
+       _jitc->function->vaoff = jit_allocai(sizeof(jit_va_list_t));
+
+       /* Initialize gp offset in save area. */
+       if (jit_arg_reg_p(_jitc->function->self.argi))
+           _jitc->function->vagp = _jitc->function->self.argi;
+       else
+           _jitc->function->vagp = 5;
+
+       /* Initialize fp offset in save area. */
+       if (jit_arg_f_reg_p(_jitc->function->self.argf))
+           _jitc->function->vafp = _jitc->function->self.argf;
+       else
+           _jitc->function->vafp = NUM_FLOAT_REG_ARGS;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    if (jit_arg_f_reg_p(_jitc->function->self.argf))
+       offset = _jitc->function->self.argf++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg_f, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    if (jit_arg_f_reg_p(_jitc->function->self.argf))
+       offset = _jitc->function->self.argf++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_float64_t);
+    }
+    node = jit_new_node_ww(jit_code_arg_d, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, _R2 - v->u.w);
+    else
+       jit_ldxi_c(u, JIT_FP,
+                  v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int8_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, _R2 - v->u.w);
+    else
+       jit_ldxi_uc(u, JIT_FP,
+                   v->u.w + (__WORDSIZE >> 3) - sizeof(jit_uint8_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, _R2 - v->u.w);
+    else
+       jit_ldxi_s(u, JIT_FP,
+                  v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int16_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, _R2 - v->u.w);
+    else
+       jit_ldxi_us(u, JIT_FP,
+                   v->u.w + (__WORDSIZE >> 3) - sizeof(jit_uint16_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w)) {
+#if __WORDSIZE == 32
+       jit_movr(u, _R2 - v->u.w);
+#else
+       jit_extr_i(u, _R2 - v->u.w);
+#endif
+    }
+    else
+       jit_ldxi_i(u, JIT_FP,
+                  v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int32_t));
+    jit_dec_synth();
+}
+
+#if __WORDSIZE == 64
+void
+_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_ui, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_ui(u, _R2 - v->u.w);
+    else
+       jit_ldxi_ui(u, JIT_FP,
+                   v->u.w + (__WORDSIZE >> 3) - sizeof(jit_uint32_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_l, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, _R2 - v->u.w);
+    else
+       jit_ldxi_l(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+#endif
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(_R2 - v->u.w, u);
+    else
+       jit_stxi(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi(_R2 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_f(u, _F0 - v->u.w);
+    else
+       jit_ldxi_f(u, JIT_FP,
+                  v->u.w
+#if __WORDSIZE == 64
+                  + (__WORDSIZE >> 3) - sizeof(jit_float32_t)
+#endif
+                  );
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_f(_F0 - v->u.w, u);
+    else
+       jit_stxi_f(v->u.w
+#if __WORDSIZE == 64
+                  + (__WORDSIZE >> 3) - sizeof(jit_float32_t)
+#endif
+                  , JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movi_f(_F0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(v->u.w
+#if __WORDSIZE == 64
+                  + (__WORDSIZE >> 3) - sizeof(jit_float32_t)
+#endif
+                  , JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(u, _F0 - v->u.w);
+    else
+       jit_ldxi_d(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(_F0 - v->u.w, u);
+    else
+       jit_stxi_d(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movi_d(_F0 - v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(_R2 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi(_jitc->function->call.size + stack_framesize, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(_R2 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size + stack_framesize, JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movr_f(_F0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size + stack_framesize
+#if __WORDSIZE == 64
+                  + (__WORDSIZE >> 3) - sizeof(jit_float32_t)
+#endif
+                  , JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movi_f(_F0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(_jitc->function->call.size + stack_framesize
+#if __WORDSIZE == 64
+                  + (__WORDSIZE >> 3) - sizeof(jit_float32_t)
+#endif
+                  , JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movr_d(_F0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else {
+       jit_stxi_d(_jitc->function->call.size + stack_framesize, JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movi_d(_F0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(_jitc->function->call.size + stack_framesize, JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_int32_t                spec;
+    spec = jit_class(_rvs[regno].spec);
+    if (spec & jit_class_arg) {
+       regno = _R2 - regno;
+       if (regno >= 0 && regno < node->v.w)
+           return (1);
+       if (spec & jit_class_fpr) {
+           regno = _F0 - regno;
+           if (regno >= 0 && regno < node->w.w)
+               return (1);
+       }
+    }
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *call;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    call = jit_callr(r0);
+    call->v.w = _jitc->function->call.argi;
+    call->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_calli(i0);
+    node->v.w = _jitc->function->call.argi;
+    node->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_c, r0);
+    jit_extr_c(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_uc, r0);
+    jit_extr_uc(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_s, r0);
+    jit_extr_s(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_us, r0);
+    jit_extr_us(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+#if __WORDSIZE == 64
+    jit_extr_i(r0, JIT_RET);
+#else
+    jit_movr(r0, JIT_RET);
+#endif
+    jit_dec_synth();
+}
+
+#if __WORDSIZE == 64
+void
+_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_ui, r0);
+    jit_extr_ui(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_l, r0);
+    jit_movr(r0, JIT_RET);
+    jit_dec_synth();
+}
+#endif
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_f, r0);
+    jit_movr_f(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_d, r0);
+    jit_movr_d(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_int32_t                 value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_int32_t      patch_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.patch_offset = 0;
+
+#define assert_data(node)              /**/
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_rrf(name)                                                 \
+           case jit_code_##name##i_f:                                  \
+               assert_data(node);                                      \
+               name##i_f(rn(node->u.w), rn(node->v.w),                 \
+                         (jit_float32_t *)node->w.n->u.w);             \
+               break
+#define case_rrd(name)                                                 \
+           case jit_code_##name##i_d:                                  \
+               assert_data(node);                                      \
+               name##i_d(rn(node->u.w), rn(node->v.w),                 \
+                         (jit_float64_t *)node->w.n->u.w);             \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type##_p(_jit->pc.w,                \
+                                            rn(node->v.w),             \
+                                            rn(node->w.w));            \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type##_p(_jit->pc.w,                \
+                                            rn(node->v.w), node->w.w); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break;
+#define case_brf(name)                                                 \
+           case jit_code_##name##i_f:                                  \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i_f(temp->u.w, rn(node->v.w),                 \
+                             (jit_float32_t *)node->w.n->u.w);         \
+               else {                                                  \
+                   word = name##i_f_p(_jit->pc.w, rn(node->v.w),       \
+                                      (jit_float32_t *)node->w.n->u.w);\
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brd(name)                                                 \
+           case jit_code_##name##i_d:                                  \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i_d(temp->u.w, rn(node->v.w),                 \
+                             (jit_float64_t *)node->w.n->u.w);         \
+               else {                                                  \
+                   word = name##i_d_p(_jit->pc.w, rn(node->v.w),       \
+                                      (jit_float64_t *)node->w.n->u.w);\
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if (node->u.w == sizeof(jit_word_t) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               if ((node->link || (node->flag & jit_flag_use)) &&
+                   (word = _jit->pc.w & 3))
+                   nop(4 - word);
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rr(neg,);
+               case_rr(com,);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rr(trunc, _f_i);
+               case_rr(trunc, _d_i);
+#if __WORDSIZE == 64
+               case_rr(trunc, _f_l);
+               case_rr(trunc, _d_l);
+#endif
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+#if __WORDSIZE == 64
+               case_rr(ld, _ui);
+               case_rw(ld, _ui);
+               case_rr(ld, _l);
+               case_rw(ld, _l);
+#endif
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+#if __WORDSIZE == 64
+               case_rrr(ldx, _ui);
+               case_rrw(ldx, _ui);
+               case_rrr(ldx, _l);
+               case_rrw(ldx, _l);
+#endif
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+#if __WORDSIZE == 64
+               case_rr(st, _l);
+               case_wr(st, _l);
+#endif
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+#if __WORDSIZE == 64
+               case_rrr(stx, _l);
+               case_wrr(stx, _l);
+#endif
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+#if __WORDSIZE == 64
+               case_rr(hton, _ul);
+#endif
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+#if __WORDSIZE == 64
+               case_rr(ext, _i);
+               case_rr(ext, _ui);
+#endif
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), temp->u.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_rrr(add, _f);
+               case_rrf(add);
+               case_rrr(sub, _f);
+               case_rrf(sub);
+               case_rrf(rsb);
+               case_rrr(mul, _f);
+               case_rrf(mul);
+               case_rrr(div, _f);
+               case_rrf(div);
+               case_rr(abs, _f);
+               case_rr(neg, _f);
+               case_rr(sqrt, _f);
+               case_rr(ext, _f);
+               case_rr(ld, _f);
+               case_rw(ld, _f);
+               case_rrr(ldx, _f);
+               case_rrw(ldx, _f);
+               case_rr(st, _f);
+               case_wr(st, _f);
+               case_rrr(stx, _f);
+               case_wrr(stx, _f);
+               case_rr(mov, _f);
+           case jit_code_movi_f:
+               assert_data(node);
+               movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _d_f);
+               case_rrr(lt, _f);
+               case_rrf(lt);
+               case_rrr(le, _f);
+               case_rrf(le);
+               case_rrr(eq, _f);
+               case_rrf(eq);
+               case_rrr(ge, _f);
+               case_rrf(ge);
+               case_rrr(gt, _f);
+               case_rrf(gt);
+               case_rrr(ne, _f);
+               case_rrf(ne);
+               case_rrr(unlt, _f);
+               case_rrf(unlt);
+               case_rrr(unle, _f);
+               case_rrf(unle);
+               case_rrr(uneq, _f);
+               case_rrf(uneq);
+               case_rrr(unge, _f);
+               case_rrf(unge);
+               case_rrr(ungt, _f);
+               case_rrf(ungt);
+               case_rrr(ltgt, _f);
+               case_rrf(ltgt);
+               case_rrr(ord, _f);
+               case_rrf(ord);
+               case_rrr(unord, _f);
+               case_rrf(unord);
+               case_brr(blt, _f);
+               case_brf(blt);
+               case_brr(ble, _f);
+               case_brf(ble);
+               case_brr(beq, _f);
+               case_brf(beq);
+               case_brr(bge, _f);
+               case_brf(bge);
+               case_brr(bgt, _f);
+               case_brf(bgt);
+               case_brr(bne, _f);
+               case_brf(bne);
+               case_brr(bunlt, _f);
+               case_brf(bunlt);
+               case_brr(bunle, _f);
+               case_brf(bunle);
+               case_brr(buneq, _f);
+               case_brf(buneq);
+               case_brr(bunge, _f);
+               case_brf(bunge);
+               case_brr(bungt, _f);
+               case_brf(bungt);
+               case_brr(bltgt, _f);
+               case_brf(bltgt);
+               case_brr(bord, _f);
+               case_brf(bord);
+               case_brr(bunord, _f);
+               case_brf(bunord);
+               case_rrr(add, _d);
+               case_rrd(add);
+               case_rrr(sub, _d);
+               case_rrd(sub);
+               case_rrd(rsb);
+               case_rrr(mul, _d);
+               case_rrd(mul);
+               case_rrr(div, _d);
+               case_rrd(div);
+               case_rr(abs, _d);
+               case_rr(neg, _d);
+               case_rr(sqrt, _d);
+               case_rr(ext, _d);
+               case_rr(ld, _d);
+               case_rw(ld, _d);
+               case_rrr(ldx, _d);
+               case_rrw(ldx, _d);
+               case_rr(st, _d);
+               case_wr(st, _d);
+               case_rrr(stx, _d);
+               case_wrr(stx, _d);
+               case_rr(mov, _d);
+           case jit_code_movi_d:
+               assert_data(node);
+               movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               break;
+               case_rr(ext, _f_d);
+               case_rrr(lt, _d);
+               case_rrd(lt);
+               case_rrr(le, _d);
+               case_rrd(le);
+               case_rrr(eq, _d);
+               case_rrd(eq);
+               case_rrr(ge, _d);
+               case_rrd(ge);
+               case_rrr(gt, _d);
+               case_rrd(gt);
+               case_rrr(ne, _d);
+               case_rrd(ne);
+               case_rrr(unlt, _d);
+               case_rrd(unlt);
+               case_rrr(unle, _d);
+               case_rrd(unle);
+               case_rrr(uneq, _d);
+               case_rrd(uneq);
+               case_rrr(unge, _d);
+               case_rrd(unge);
+               case_rrr(ungt, _d);
+               case_rrd(ungt);
+               case_rrr(ltgt, _d);
+               case_rrd(ltgt);
+               case_rrr(ord, _d);
+               case_rrd(ord);
+               case_rrr(unord, _d);
+               case_rrd(unord);
+               case_brr(blt, _d);
+               case_brd(blt);
+               case_brr(ble, _d);
+               case_brd(ble);
+               case_brr(beq, _d);
+               case_brd(beq);
+               case_brr(bge, _d);
+               case_brd(bge);
+               case_brr(bgt, _d);
+               case_brd(bgt);
+               case_brr(bne, _d);
+               case_brd(bne);
+               case_brr(bunlt, _d);
+               case_brd(bunlt);
+               case_brr(bunle, _d);
+               case_brd(bunle);
+               case_brr(buneq, _d);
+               case_brd(buneq);
+               case_brr(bunge, _d);
+               case_brd(bunge);
+               case_brr(bungt, _d);
+               case_brd(bungt);
+               case_brr(bltgt, _d);
+               case_brd(bltgt);
+               case_brr(bord, _d);
+               case_brd(bord);
+               case_brr(bunord, _d);
+               case_brd(bunord);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       calli(temp->u.w);
+                   else {
+                       word = calli_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+           restart_function:
+               _jitc->again = 0;
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+                   goto restart_function;
+               }
+               if (node->link && (word = _jit->pc.w & 3))
+                   nop(4 - word);
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:                 case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:
+#if __WORDSIZE == 64
+           case jit_code_getarg_ui:            case jit_code_getarg_l:
+#endif
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+#if __WORDSIZE == 64
+           case jit_code_retval_ui:            case jit_code_retval_l:
+#endif
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           default:
+               abort();
+       }
+       jit_regarg_clr(node, value);
+       assert(_jitc->regarg == 0 && _jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+    }
+#undef case_brw
+#undef case_brr
+#undef case_wrr
+#undef case_rrw
+#undef case_rrr
+#undef case_wr
+#undef case_rw
+#undef case_rr
+
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(_jitc->patches.ptr[offset].inst, word);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_s390-cpu.c"
+#  include "jit_s390-fpu.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+#if defined(__GNUC__)
+    jit_word_t         f, t, s;
+
+    s = sysconf(_SC_PAGE_SIZE);
+    f = (jit_word_t)fptr & -s;
+    t = (((jit_word_t)tptr) + s - 1) & -s;
+    __clear_cache((void *)f, (void *)t);
+#endif
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_gpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    ldxi(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_gpr_t r1)
+{
+    stxi(i0, rn(r0), rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_fpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_fpr_t r1)
+{
+    stxi_d(i0, rn(r0), rn(r1));
+}
+
+static jit_int32_t
+_jit_get_reg_pair(jit_state_t *_jit)
+{
+    jit_int32_t                r1, r2;
+    /* Try to find a register pair for use with operations that
+     * require a odd based register pair. Search for the best
+     * match to avoid spills or at least a valid operation.
+     */
+
+    /* Try non callee save first */
+    if (jit_reg_free_p(_R0) && jit_reg_free_p(_R1))
+       r1 = _R0, r2 = _R1;
+    else if (jit_reg_free_p(_R2) && jit_reg_free_p(_R3))
+       r1 = _R2, r2 = _R3;
+    else if (jit_reg_free_p(_R4) && jit_reg_free_p(_R5))
+       r1 = _R4, r2 = _R5;
+    /* Try callee save registers */
+    else if (jit_reg_free_p(_R10) && jit_reg_free_p(_R11))
+       r1 = _R10, r2 = _R11;
+    else if (jit_reg_free_p(_R8) && jit_reg_free_p(_R9))
+       r1 = _R8, r2 = _R9;
+    else if (jit_reg_free_p(_R6) && jit_reg_free_p(_R7))
+       r1 = _R6, r2 = _R7;
+
+    /* We *must* find a register pair */
+    else if (jit_reg_free_if_spill_p(_R0) && jit_reg_free_if_spill_p(_R1))
+       r1 = _R0, r2 = _R1;
+    else if (jit_reg_free_if_spill_p(_R2) && jit_reg_free_if_spill_p(_R3))
+       r1 = _R2, r2 = _R3;
+    else if (jit_reg_free_if_spill_p(_R4) && jit_reg_free_if_spill_p(_R5))
+       r1 = _R4, r2 = _R5;
+    else if (jit_reg_free_if_spill_p(_R10) && jit_reg_free_if_spill_p(_R11))
+       r1 = _R10, r2 = _R11;
+    else if (jit_reg_free_if_spill_p(_R8) && jit_reg_free_if_spill_p(_R9))
+       r1 = _R8, r2 = _R9;
+    else if (jit_reg_free_if_spill_p(_R6) && jit_reg_free_if_spill_p(_R7))
+       r1 = _R6, r2 = _R7;
+    else
+       /* Do not jit_get_reg() all registers to avoid it */
+       abort();
+
+    (void)jit_get_reg(jit_class_gpr|jit_class_named|r1);
+    (void)jit_get_reg(jit_class_gpr|jit_class_named|r2);
+
+    return (r1);
+}
+
+static void
+_jit_unget_reg_pair(jit_state_t *_jit, jit_int32_t reg)
+{
+    jit_int32_t                r1, r2;
+    r1 = reg;
+    switch (r1) {
+       case _R0:       r2 = _R1;       break;
+       case _R2:       r2 = _R3;       break;
+       case _R4:       r2 = _R5;       break;
+       case _R6:       r2 = _R7;       break;
+       case _R8:       r2 = _R9;       break;
+       case _R10:      r2 = _R11;      break;
+       default:        abort();
+    }
+    jit_unget_reg(r1);
+    jit_unget_reg(r2);
+}
+
+static jit_int32_t
+_jit_get_reg_but_zero(jit_state_t *_jit, jit_int32_t flags)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    if (reg == _R0) {
+       reg = jit_get_reg(jit_class_gpr|flags);
+       jit_unget_reg(_R0);
+    }
+    return (reg);
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+    assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_size.c b/deps/lightning/lib/jit_size.c
new file mode 100644 (file)
index 0000000..61f1aa4
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+#if GET_JIT_SIZE
+#  include <stdio.h>
+#endif
+
+/*
+ * Initialization
+ */
+static jit_int16_t     _szs[jit_code_last_code] = {
+#if GET_JIT_SIZE
+#  define JIT_INSTR_MAX                256
+#else
+#  if defined(__i386__) || defined(__x86_64__)
+#    include "jit_x86-sz.c"
+#  elif defined(__mips__)
+#    include "jit_mips-sz.c"
+#  elif defined(__arm__)
+#    include "jit_arm-sz.c"
+#  elif defined(__powerpc__)
+#    include "jit_ppc-sz.c"
+#  elif defined(__sparc__)
+#    include "jit_sparc-sz.c"
+#  elif defined(__ia64__)
+#    include "jit_ia64-sz.c"
+#  elif defined(__hppa__)
+#    include "jit_hppa-sz.c"
+#  elif defined(__aarch64__)
+#    include "jit_aarch64-sz.c"
+#  elif defined(__s390__) || defined(__s390x__)
+#    include "jit_s390-sz.c"
+#  elif defined(__alpha__)
+#    include "jit_alpha-sz.c"
+#  elif defined(__riscv)
+#    include "jit_riscv-sz.c"
+#  endif
+#endif
+};
+
+/*
+ * Implementation
+ */
+void
+jit_init_size(void)
+{
+#if DEBUG
+#  if !GET_JIT_SIZE
+    jit_word_t         offset;
+
+    for (offset = 0; offset < jit_size(_szs); offset++)
+       if (_szs[offset] != 0)
+           return;
+    /* Ensure data was collected */
+    abort();
+#  endif
+#endif
+}
+
+#if GET_JIT_SIZE
+void
+_jit_size_prepare(jit_state_t *_jit)
+{
+    _jitc->cptr = _jit->code.ptr;
+    _jitc->size = _jit->pc.w;
+}
+
+void
+_jit_size_collect(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_word_t         length;
+
+    if (_jitc->cptr == _jit->code.ptr) {
+       length = _jit->pc.w - _jitc->size;
+       if (_szs[node->code] < length)
+           _szs[node->code] = length;
+    }
+}
+
+#else
+jit_word_t
+_jit_get_size(jit_state_t *_jit)
+{
+    jit_word_t          size;
+    jit_node_t         *node;
+
+    for (size = JIT_INSTR_MAX, node = _jitc->head; node; node = node->next)
+       size += _szs[node->code];
+
+    return ((size + 4095) & -4096);
+}
+#endif
+
+jit_word_t
+jit_get_max_instr(void)
+{
+    return (JIT_INSTR_MAX >= 144 ? JIT_INSTR_MAX : 144);
+}
+
+void
+jit_finish_size(void)
+{
+#if GET_JIT_SIZE
+    FILE               *fp;
+    jit_word_t          offset;
+
+    /* Define a single path */
+    fp = fopen(JIT_SIZE_PATH, "a");
+    assert(fp);
+    for (offset = 0; offset < jit_size(_szs); offset++)
+       fprintf(fp, "%d %d\n", offset, _szs[offset]);
+    fclose(fp);
+#endif
+}
diff --git a/deps/lightning/lib/jit_sparc-cpu.c b/deps/lightning/lib/jit_sparc-cpu.c
new file mode 100644 (file)
index 0000000..051647a
--- /dev/null
@@ -0,0 +1,2568 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  define _G2_REGNO                            0x02
+#  define _G3_REGNO                            0x03
+#  define _G4_REGNO                            0x04
+#  define _O0_REGNO                            0x08
+#  define _O1_REGNO                            0x09
+#  define _SP_REGNO                            0x0e
+#  define _FP_REGNO                            0x1e
+#  define _O7_REGNO                            0x0f
+#  define _L0_REGNO                            0x10
+#  define _L1_REGNO                            0x11
+#  define _L2_REGNO                            0x12
+#  define _L3_REGNO                            0x13
+#  define _L4_REGNO                            0x14
+#  define _L5_REGNO                            0x15
+#  define _L6_REGNO                            0x16
+#  define _L7_REGNO                            0x17
+#  define _I7_REGNO                            0x1f
+/*
+ *                                     - previous stack frame
+ * fp  ----
+ * fp- local variables (in lightning, 8 bytes space for float conversion)
+ * fp- alloca
+ * sp+ stack arguments
+ * sp+ 6 words to save register arguments
+ * sp+ 1 word for hidden address of aggregate return value (32 bits only)
+ * sp+ 16 words for in and local registers
+ * sp  ----
+ *     decreasing memory address       - next stack frame (not yet allocated)
+ */
+#  define stack_framesize                      ((16 + (__WORDSIZE == 32) + 6) * sizeof(jit_word_t))
+typedef union {
+    struct {                           jit_uint32_t b: 2;      } op;
+    struct {   jit_uint32_t _: 2;      jit_uint32_t b: 1;      } a;
+    struct {   jit_uint32_t _: 2;      jit_uint32_t b: 5;      } rd;
+    struct {   jit_uint32_t _: 2;      jit_uint32_t b: 30;     } disp30;
+    struct {   jit_uint32_t _: 3;      jit_uint32_t b: 4;      } cond;
+    struct {   jit_uint32_t _: 7;      jit_uint32_t b: 3;      } op2;
+    struct {   jit_uint32_t _: 7;      jit_uint32_t b: 6;      } op3;
+    struct {   jit_uint32_t _: 10;     jit_uint32_t b: 1;      } cc1;
+    struct {   jit_uint32_t _: 10;     jit_uint32_t b: 22;     } imm22;
+    struct {   jit_uint32_t _: 10;     jit_uint32_t b: 22;     } disp22;
+    struct {   jit_uint32_t _: 11;     jit_uint32_t b: 1;      } cc0;
+    struct {   jit_uint32_t _: 12;     jit_uint32_t b: 1;      } p;
+    struct {   jit_uint32_t _: 13;     jit_uint32_t b: 19;     } disp19;
+    struct {   jit_uint32_t _: 13;     jit_uint32_t b: 5;      } rs1;
+    struct {   jit_uint32_t _: 18;     jit_uint32_t b: 1;      } i;
+    struct {   jit_uint32_t _: 18;     jit_uint32_t b: 9;      } opf;
+    struct {   jit_uint32_t _: 19;     jit_uint32_t b: 1;      } x;
+    struct {   jit_uint32_t _: 19;     jit_uint32_t b: 8;      } asi;
+    struct {   jit_uint32_t _: 19;     jit_uint32_t b: 6;      } res;
+    struct {   jit_uint32_t _: 19;     jit_uint32_t b: 13;     } simm13;
+    struct {   jit_uint32_t _: 20;     jit_uint32_t b: 7;      } asix;
+    struct {   jit_uint32_t _: 20;     jit_uint32_t b: 6;      } asis;
+    struct {   jit_uint32_t _: 26;     jit_uint32_t b: 6;      } shim;
+    struct {   jit_uint32_t _: 25;     jit_uint32_t b: 7;      } imm7;
+    struct {   jit_uint32_t _: 27;     jit_uint32_t b: 5;      } rs2;
+    jit_int32_t                                                          v;
+} jit_instr_t;
+#  define ii(i)                                *_jit->pc.ui++ = i
+#  define s7_p(imm)                    ((imm) <= 63 && (imm) >= -64)
+#  define s13_p(imm)                   ((imm) <= 4095 && (imm) >= -4096)
+#  define s19_p(imm)                   ((imm) <= 262143 && (imm) >= -262144)
+#  define s22_p(imm)                   ((imm) <= 2097151 && (imm) >= -20971512)
+#  define s30_p(imm)                   ((imm) <= 536870911 && (imm) >= -536870912)
+#  define f1(op, disp30)               _f1(_jit, op, disp30)
+static void _f1(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define f2r(op, rd, op2, imm22)      _f2r(_jit, op, rd, op2, imm22)
+static void _f2r(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define f2b(op, a, cond, op2, disp22)        _f2b(_jit, op, a, cond, op2, disp22)
+static void
+_f2b(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#    define f2bp(op,a,cond,op2,cc1,cc0,p,disp19)                               \
+       _f2bp(_jit,op,a,cond,op2,cc1,cc0,p,disp19)
+static void
+_f2bp(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,
+      jit_int32_t,jit_int32_t,jit_int32_t);
+#  endif
+#  define f3r(op, rd, op3, rs1, rs2)   _f3r(_jit, op, rd, op3, rs1, rs2)
+static void _f3r(jit_state_t*,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#  define f3rx(op, rd, op3, rs1, rs2)  _f3rx(_jit, op, rd, op3, rs1, rs2)
+static void _f3rx(jit_state_t*,
+                 jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  endif
+#  define f3i(op, rd, op3, rs1, simm13)        _f3i(_jit, op, rd, op3, rs1, simm13)
+static void _f3i(jit_state_t*,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define f3s(op, rd, op3, rs1, simm13)        _f3s(_jit, op, rd, op3, rs1, simm13)
+static void _f3s(jit_state_t*,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define f3t(cond, rs1, i, ri)                _f3t(_jit, cond, rs1, i, ri)
+static void _f3t(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t)
+    maybe_unused;
+#  define f3a(op, rd, op3, rs1, rs2)   _f3a(_jit, op, rd, op3, rs1, asi, rs2)
+static void _f3a(jit_state_t*,jit_int32_t,
+                jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t)
+    maybe_unused;
+#  define LDSB(rs1, rs2, rd)           f3r(3, rd, 9, rs1, rs2)
+#  define LDSBI(rs1, imm, rd)          f3i(3, rd, 9, rs1, imm)
+#  define LDSH(rs1, rs2, rd)           f3r(3, rd, 10, rs1, rs2)
+#  define LDSHI(rs1, imm, rd)          f3i(3, rd, 10, rs1, imm)
+#  define LDUB(rs1, rs2, rd)           f3r(3, rd, 1, rs1, rs2)
+#  define LDUBI(rs1, imm, rd)          f3i(3, rd, 1, rs1, imm)
+#  define LDUH(rs1, rs2, rd)           f3r(3, rd, 2, rs1, rs2)
+#  define LDUHI(rs1, imm, rd)          f3i(3, rd, 2, rs1, imm)
+#  if __WORDSIZE == 32
+#    define LD(rs1, rs2, rd)           f3r(3, rd, 0, rs1, rs2)
+#    define LDI(rs1, imm, rd)          f3i(3, rd, 0, rs1, imm)
+#    define LDD(rs1, rs2, rd)          f3r(3, rd, 3, rs1, rs2)
+#    define LDDI(rs1, imm, rd)         f3i(3, rd, 3, rs1, imm)
+#  else
+#    define LDSW(rs1, rs2, rd)         f3r(3, rd, 8, rs1, rs2)
+#    define LDSWI(rs1, imm, rd)                f3i(3, rd, 8, rs1, imm)
+#    define LDUW(rs1, rs2, rd)         f3r(3, rd, 0, rs1, rs2)
+#    define LDUWI(rs1, imm, rd)                f3i(3, rd, 0, rs1, imm)
+#    define LDX(rs1, rs2, rd)          f3r(3, rd, 11, rs1, rs2)
+#    define LDXI(rs1, imm, rd)         f3i(3, rd, 11, rs1, imm)
+#  endif
+#  define LDSBA(rs1, rs2, asi, rd)     f3a(3, rd, 25, rs1, asi, rs2)
+#  define LDSHA(rs1, rs2, asi, rd)     f3a(3, rd, 26, rs1, asi, rs2)
+#  define LDUBA(rs1, rs2, asi, rd)     f3a(3, rd, 17, rs1, asi, rs2)
+#  define LDUHA(rs1, rs2, asi, rd)     f3a(3, rd, 18, rs1, asi, rs2)
+#  if __WORDSIZE == 32
+#    define LDA(rs1, rs2, asi, rd)     f3a(3, rd, 16, rs1, asi, rs2)
+#    define LDDA(rs1, rs2, asi, rd)    f3a(3, rd, 19, rs1, asi, rs2)
+#  else
+#    define LDSWA(rs1, rs2, asi, rd)   f3a(3, rd, 24, rs1, asi, rs2)
+#    define LDUWA(rs1, rs2, asi, rd)   f3a(3, rd, 16, rs1, asi, rs2)
+#    define LDXA(rs1, rs2, asi, rd)    f3a(3, rd, 27, rs1, asi, rs2)
+#  endif
+#  define LDC(rs1, rs2, rd)            f3r(3, rd, 48, rs1, rs2)
+#  define LDCI(rs1, imm, rd)           f3i(3, rd, 48, rs1, imm)
+#  define LDDC(rs1, rs2, rd)           f3r(3, rd, 51, rs1, rs2)
+#  define LDDCI(rs1, imm, rd)          f3i(3, rd, 51, rs1, imm)
+#  define LDCSR(rs1, rs2, rd)          f3r(3, rd, 49, rs1, rs2)
+#  define LDCSRI(rs1, imm, rd)         f3i(3, rd, 49, rs1, imm)
+#  define STB(rd, rs1, rs2)            f3r(3, rd, 5, rs1, rs2)
+#  define STBI(rd, rs1, imm)           f3i(3, rd, 5, rs1, imm)
+#  define STH(rd, rs1, rs2)            f3r(3, rd, 6, rs1, rs2)
+#  define STHI(rd, rs1, imm)           f3i(3, rd, 6, rs1, imm)
+#  if __WORDSIZE == 32
+#    define ST(rd, rs1, rs2)           f3r(3, rd, 4, rs1, rs2)
+#    define STI(rd, rs1, imm)          f3i(3, rd, 4, rs1, imm)
+#    define STD(rrd, s1, rs2)          f3r(3, rd, 7, rs1, rs2)
+#    define STDI(rd, rs1, imm)         f3i(3, rd, 7, rs1, imm)
+#  else
+#    define STW(rd, rs1, rs2)          f3r(3, rd, 4, rs1, rs2)
+#    define STWI(rd, rs1, imm)         f3i(3, rd, 4, rs1, imm)
+#    define STX(rd, rs1, rs2)          f3r(3, rd, 14, rs1, rs2)
+#    define STXI(rd, rs1, imm)         f3i(3, rd, 14, rs1, imm)
+#  endif
+#  define STBA(rd, rs1, rs2)           f3a(3, rd, 21, rs1, asi, rs2)
+#  define STHA(rd, rs1, rs2)           f3a(3, rd, 22, rs1, asi, rs2)
+#  if __WORDSIZE == 32
+#    define STA(rd, rs1, rs2)          f3a(3, rd, 20, rs1, asi, rs2)
+#    define STDA(rd, rs1, rs2)         f3a(3, rd, 23, rs1, asi, rs2)
+#  else
+#    define STWA(rd, rs1, rs2)         f3a(3, rd, 20, rs1, asi, rs2)
+#    define STXA(rd, rs1, rs2)         f3a(3, rd, 30, rs1, asi, rs2)
+#  endif
+#  define STC(rd, rs1, rs2)            f3r(3, rd, 52, rs1, rs2)
+#  define STCI(rd, rs1, imm)           f3i(3, rd, 52, rs1, imm)
+#  define STDC(rd, rs1, rs2)           f3r(3, rd, 55, rs1, rs2)
+#  define STDCI(rd, rs1, imm)          f3i(3, rd, 55, rs1, imm)
+#  define STCSR(rd, rs1, rs2)          f3r(3, rd, 53, rs1, rs2)
+#  define STCSRI(rd, rs1, imm)         f3i(3, rd, 53, rs1, imm)
+#  define STDCQ(rd, rs1, rs2)          f3r(3, rd, 54, rs1, rs2)
+#  define STDCQI(rd, rs1, imm)         f3i(3, rd, 54, rs1, imm)
+#  define LDSTUB(rs1, rs2, rd)         f3r(3, rd, 13, rs1, rs2)
+#  define LDSTUBI(rs1, imm, rd)                f3r(3, rd, 13, rs1, imm)
+#  define LDSTUBA(rs1, rs2, asi, rd)   f3a(3, rd, 21, rs1, asi, rs2)
+#  define SWAP(rs1, rs2, rd)           f3r(3, rd, 15, rs1, rs2)
+#  define SWAPI(rs1, imm, rd)          f3r(3, rd, 15, rs1, imm)
+#  define SWAPA(rs1, rs2, asi, rd)     f3a(3, rd, 23, rs1, asi, rs2)
+#  define NOP()                                SETHI(0, 0)
+#  define HI(im)                       ((im) >> 10)
+#  define LO(im)                       ((im) & 0x3ff)
+#  define SETHI(im, rd)                        f2r(0, rd, 4, im)
+#  define AND(rs1, rs2, rd)            f3r(2, rd, 1, rs1, rs2)
+#  define ANDI(rs1, imm, rd)           f3i(2, rd, 1, rs1, imm)
+#  define ANDcc(rs1, rs2, rd)          f3r(2, rd, 17, rs1, rs2)
+#  define ANDIcc(rs1, imm, rd)         f3i(2, rd, 17, rs1, imm)
+#  define BTST(rs1, rs2)               ANDcc(rs1, rs2, 0)
+#  define BTSTI(rs1, imm)              ANDIcc(rs1, imm, 0)
+#  define ANDN(rs1, rs2, rd)           f3r(2, rd, 5, rs1, rs2)
+#  define ANDNI(rs1, imm, rd)          f3i(2, rd, 5, rs1, imm)
+#  define ANDNcc(rs1, rs2, rd)         f3r(2, rd, 21, rs1, rs2)
+#  define ANDNIcc(rs1, imm, rd)                f3i(2, rd, 21, rs1, imm)
+#  define OR(rs1, rs2, rd)             f3r(2, rd, 2, rs1, rs2)
+#  define ORI(rs1, imm, rd)            f3i(2, rd, 2, rs1, imm)
+#  define ORcc(rs1, rs2, rd)           f3r(2, rd, 18, rs1, rs2)
+#  define ORIcc(rs1, imm, rd)          f3i(2, rd, 18, rs1, imm)
+#  define ORN(rs1, rs2, rd)            f3r(2, rd, 6, rs1, rs2)
+#  define ORNI(rs1, imm, rd)           f3i(2, rd, 6, rs1, imm)
+#  define ORNcc(rs1, rs2, rd)          f3r(2, rd, 22, rs1, rs2)
+#  define ORNIcc(rs1, imm, rd)         f3i(2, rd, 22, rs1, imm)
+#  define XOR(rs1, rs2, rd)            f3r(2, rd, 3, rs1, rs2)
+#  define XORI(rs1, imm, rd)           f3i(2, rd, 3, rs1, imm)
+#  define XORcc(rs1, rs2, rd)          f3r(2, rd, 19, rs1, rs2)
+#  define XORIcc(rs1, imm, rd)         f3i(2, rd, 19, rs1, imm)
+#  define XNOR(rs1, rs2, rd)           f3r(2, rd, 7, rs1, rs2)
+#  define XNORI(rs1, imm, rd)          f3i(2, rd, 7, rs1, imm)
+#  define XNORcc(rs1, rs2, rd)         f3r(2, rd, 23, rs1, rs2)
+#  define XNORIcc(rs1, imm, rd)                f3i(2, rd, 23, rs1, imm)
+#  define SLL(rs1, rs2, rd)            f3r(2, rd, 37, rs1, rs2)
+#  define SLLI(rs1, imm, rd)           f3i(2, rd, 37, rs1, imm)
+#  define SRL(rs1, rs2, rd)            f3r(2, rd, 38, rs1, rs2)
+#  define SRLI(rs1, imm, rd)           f3i(2, rd, 38, rs1, imm)
+#  define SRA(rs1, rs2, rd)            f3r(2, rd, 39, rs1, rs2)
+#  define SRAI(rs1, imm, rd)           f3i(2, rd, 39, rs1, imm)
+#  if __WORDSIZE == 64
+#    define SLLX(rs1, rs2, rd)         f3rx(2, rd, 37, rs1, rs2)
+#    define SLLXI(rs1, imm, rd)                f3s(2, rd, 37, rs1, imm)
+#    define SRLX(rs1, rs2, rd)         f3rx(2, rd, 38, rs1, rs2)
+#    define SRLXI(rs1, imm, rd)                f3s(2, rd, 38, rs1, imm)
+#    define SRAX(rs1, rs2, rd)         f3rx(2, rd, 39, rs1, rs2)
+#    define SRAXI(rs1, imm, rd)                f3s(2, rd, 39, rs1, imm)
+#  endif
+#  define ADD(rs1, rs2, rd)            f3r(2, rd, 0, rs1, rs2)
+#  define ADDI(rs1, imm, rd)           f3i(2, rd, 0, rs1, imm)
+#  define ADDcc(rs1, rs2, rd)          f3r(2, rd, 16, rs1, rs2)
+#  define ADDIcc(rs1, imm, rd)         f3i(2, rd, 16, rs1, imm)
+#  define ADDX(rs1, rs2, rd)           f3r(2, rd, 8, rs1, rs2)
+#  define ADDXI(rs1, imm, rd)          f3i(2, rd, 8, rs1, imm)
+#  define ADDXcc(rs1, rs2, rd)         f3r(2, rd, 24, rs1, rs2)
+#  define ADDXIcc(rs1, imm, rd)                f3i(2, rd, 24, rs1, imm)
+#  define TADDcc(rs1, rs2, rd)         f3r(2, rd, 32, rs1, rs2)
+#  define TADDIcc(rs1, imm, rd)                f3i(2, rd, 32, rs1, imm)
+#  define TADDccTV(rs1, rs2, rd)       f3r(2, rd, 34, rs1, rs2)
+#  define TADDIccTV(rs1, imm, rd)      f3i(2, rd, 34, rs1, imm)
+#  define SUB(rs1, rs2, rd)            f3r(2, rd, 4, rs1, rs2)
+#  define NEG(rs1, rd)                 SUB(0, rs1, rd)
+#  define SUBI(rs1, imm, rd)           f3i(2, rd, 4, rs1, imm)
+#  define SUBcc(rs1, rs2, rd)          f3r(2, rd, 20, rs1, rs2)
+#  define SUBIcc(rs1, imm, rd)         f3i(2, rd, 20, rs1, imm)
+#  define CMP(rs1, rs2)                        SUBcc(rs1, rs2, 0)
+#  define CMPI(rs1, imm)               SUBIcc(rs1, imm, 0)
+#  define SUBX(rs1, rs2, rd)           f3r(2, rd, 12, rs1, rs2)
+#  define SUBXI(rs1, imm, rd)          f3i(2, rd, 12, rs1, imm)
+#  define SUBXcc(rs1, rs2, rd)         f3r(2, rd, 28, rs1, rs2)
+#  define SUBXIcc(rs1, imm, rd)                f3i(2, rd, 28, rs1, imm)
+#  define TSUBcc(rs1, rs2, rd)         f3r(2, rd, 33, rs1, rs2)
+#  define TDADDIcc(rs1, imm, rd)       f3i(2, rd, 33, rs1, imm)
+#  define TSUBccTV(rs1, rs2, rd)       f3r(2, rd, 35, rs1, rs2)
+#  define TSUBIccTV(rs1, imm, rd)      f3i(2, rd, 35, rs1, imm)
+#  define MULScc(rs1, rs2, rd)         f3r(2, rd, 36, rs1, rs2)
+#  define MULSIcc(rs1, imm, rd)                f3i(2, rd, 36, rs1, imm)
+#  define UMUL(rs1, rs2, rd)           f3r(2, rd, 10, rs1, rs2)
+#  define UMULI(rs1, imm, rd)          f3i(2, rd, 10, rs1, imm)
+#  define SMUL(rs1, rs2, rd)           f3r(2, rd, 11, rs1, rs2)
+#  define SMULI(rs1, imm, rd)          f3i(2, rd, 11, rs1, imm)
+#  define UMULcc(rs1, rs2, rd)         f3r(2, rd, 26, rs1, rs2)
+#  define UMULIcc(rs1, imm, rd)                f3i(2, rd, 26, rs1, imm)
+#  define SMULcc(rs1, rs2, rd)         f3r(2, rd, 27, rs1, rs2)
+#  define SMULIcc(rs1, imm, rd)                f3i(2, rd, 27, rs1, imm)
+#  define UDIV(rs1, rs2, rd)           f3r(2, rd, 14, rs1, rs2)
+#  define UDIVI(rs1, imm, rd)          f3i(2, rd, 14, rs1, imm)
+#  define SDIV(rs1, rs2, rd)           f3r(2, rd, 15, rs1, rs2)
+#  define SDIVI(rs1, imm, rd)          f3i(2, rd, 15, rs1, imm)
+#  define UDIVcc(rs1, rs2, rd)         f3r(2, rd, 30, rs1, rs2)
+#  define UDIVIcc(rs1, imm, rd)                f3i(2, rd, 30, rs1, imm)
+#  define SDIVcc(rs1, rs2, rd)         f3r(2, rd, 31, rs1, rs2)
+#  define SDIVIcc(rs1, imm, rd)                f3i(2, rd, 31, rs1, imm)
+#  if __WORDSIZE == 64
+#    define MULX(rs1, rs2, rd)         f3r(2, rd, 9, rs1, rs2)
+#    define MULXI(rs1, imm, rd)                f3i(2, rd, 9, rs1, imm)
+#    define SDIVX(rs1, rs2, rd)                f3r(2, rd, 45, rs1, rs2)
+#    define SDIVXI(rs1, imm, rd)       f3i(2, rd, 45, rs1, imm)
+#    define UDIVX(rs1, rs2, rd)                f3r(2, rd, 13, rs1, rs2)
+#    define UDIVXI(rs1, imm, rd)       f3i(2, rd, 13, rs1, imm)
+#  endif
+#  define SAVE(rs1, rs2, rd)           f3r(2, rd, 60, rs1, rs2)
+#  define SAVEI(rs1, imm, rd)          f3i(2, rd, 60, rs1, imm)
+#  define RESTORE(rs1, rs2, rd)                f3r(2, rd, 61, rs1, rs2)
+#  define RESTOREI(rs1, imm, rd)       f3i(2, rd, 61, rs1, imm)
+#  define SPARC_BA                     8       /* always */
+#  define SPARC_BN                     0       /* never */
+#  define SPARC_BNE                    9       /* not equal - not Z */
+#  define SPARC_BNZ                    SPARC_BNE
+#  define SPARC_BE                     1       /* equal - Z */
+#  define SPARC_BZ                     SPARC_BE
+#  define SPARC_BG                     10      /* greater - not (Z or (N xor V)) */
+#  define SPARC_BLE                    2       /* less or equal - Z or (N xor V) */
+#  define SPARC_BGE                    11      /* greater or equal - not (N xor V) */
+#  define SPARC_BL                     3       /* less - N xor V */
+#  define SPARC_BGU                    12      /* greater unsigned - not (C or Z) */
+#  define SPARC_BLEU                   4       /* less or equal unsigned - C or Z */
+#  define SPARC_BCC                    13      /* carry clear - not C */
+#  define SPARC_BGEU                   SPARC_BCC
+#  define SPARC_BCS                    5       /* carry set - C */
+#  define SPARC_BLU                    SPARC_BCS
+#  define SPARC_BPOS                   14      /* positive - not N */
+#  define SPARC_BNEG                   6       /* negative - N */
+#  define SPARC_BVC                    15      /* overflow clear - not V */
+#  define SPARC_BVS                    7       /* overflow set - V */
+/* Preferred BPcc integer branch opcodes */
+#  if __WORDSIZE == 64
+#    define SPARC_BPA                  8       /* always - 1 */
+#    define SPARC_BPN                  0       /* never - 0 */
+#    define SPARC_BPNE                 9       /* not equal - not Z */
+#    define SPARC_BPE                  1       /* equal - Z */
+#    define SPARC_BPG                  10      /* greater - not (Z or (N xor V)) */
+#    define SPARC_BPLE                 2       /* less or equal - Z or (N xor V) */
+#    define SPARC_BPGE                 11      /* greater or equal - not (N xor V) */
+#    define SPARC_BPL                  3       /* less - N xor V */
+#    define SPARC_BPGU                 12      /* greater unsigned - not (C or V) */
+#    define SPARC_BPLEU                        4       /* less or equal unsigned  - C or Z */
+#    define SPARC_BPCC                 13      /* carry clear (greater than or equal, unsigned) - not C */
+#    define SPARC_BPCS                 5       /* carry set (less than, unsigned) - C */
+#    define SPARC_BPPOS                        14      /* positive - not N */
+#    define SPARC_BPNEG                        6       /* negative - N */
+#    define SPARC_BPVC                 15      /* overflow clear - not V */
+#    define SPARC_BPVS                 7       /* overflow set - V */
+#  endif
+#  define B(cc, imm)                   f2b(0, 0, cc, 2, imm)
+#  define Ba(cc, imm)                  f2b(0, 1, cc, 2, imm)
+#  define BA(imm)                      B(SPARC_BA, imm)
+#  define BAa(imm)                     Ba(SPARC_BA, imm)
+#  define BN(imm)                      B(SPARC_BN, imm)
+#  define BNa(imm)                     Ba(SPARC_BN, imm)
+#  define BNE(imm)                     B(SPARC_BNE, imm)
+#  define BNEa(imm)                    Ba(SPARC_BNE, imm)
+#  define BNZ(imm)                     BNE(imm)
+#  define BNZa(imm)                    BNEa(imm)
+#  define BE(imm)                      B(SPARC_BE, imm)
+#  define BEa(imm)                     Ba(SPARC_BE, imm)
+#  define BZ(imm)                      BE(imm)
+#  define BZa(imm)                     BEa(imm)
+#  define BG(imm)                      B(SPARC_BG, imm)
+#  define BGa(imm)                     Ba(SPARC_BG, imm)
+#  define BLE(imm)                     B(SPARC_BLE, imm)
+#  define BLEa(imm)                    Ba(SPARC_BLE, imm)
+#  define BGE(imm)                     B(SPARC_BGE, imm)
+#  define BGEa(imm)                    Ba(SPARC_BGE, imm)
+#  define BL(imm)                      B(SPARC_BL, imm)
+#  define BLa(imm)                     Ba(SPARC_BL, imm)
+#  define BGU(imm)                     B(SPARC_BGU, imm)
+#  define BGUa(imm)                    Ba(SPARC_BGU, imm)
+#  define BLEU(imm)                    B(SPARC_BLEU, imm)
+#  define BLEUa(imm)                   Ba(SPARC_BLEU, imm)
+#  define BCC(imm)                     B(SPARC_BCC, imm)
+#  define BCCa(imm)                    Ba(SPARC_BCC, imm)
+#  define BGEU(imm)                    BCC(imm)
+#  define BGEUa(imm)                   BCCa(imm)
+#  define BCS(imm)                     B(SPARC_BCS, imm)
+#  define BCSa(imm)                    Ba(SPARC_BCS, imm)
+#  define BLU(imm)                     BCS(imm)
+#  define BLUa(imm)                    BCSa(imm)
+#  define BPOS(imm)                    B(SPARC_BPOS, imm)
+#  define BPOSa(imm)                   Ba(SPARC_BPOS, imm)
+#  define BNEG(imm)                    B(SPARC_BNEG, imm)
+#  define BNEGa(imm)                   Ba(SPARC_BNEG, imm)
+#  define BVC(imm)                     B(SPARC_BVC, imm)
+#  define BVCa(imm)                    Ba(SPARC_BVC, imm)
+#  define BVS(imm)                     B(SPARC_BVS, imm)
+#  define BVSa(imm)                    Ba(SPARC_BVS, imm)
+#  if __WORDSIZE == 64
+#    define BPccap(cc,a,cc1, cc2,p,imm)        f2bp(0, a, cc, 1, cc1, cc0, p, imm)
+#    define BPap(cc, imm)              f2bp(0, 1, cc, 1, 1, 0, p, imm)
+#    define BPa(cc, imm)               f2bp(0, 1, cc, 1, 1, 0, 1, imm)
+#    define BP(cc, imm)                        f2bp(0, 0, cc, 1, 1, 0, 1, imm)
+#    define BPA(imm)                   BP(SPARC_BPA, imm)
+#    define BPN(imm)                   BP(SPARC_BPN, imm)
+#    define BNPE(imm)                  BP(SPARC_BPNE, imm)
+#    define BPE(imm)                   BP(SPARC_BPE, imm)
+#    define BPG(imm)                   BP(SPARC_BPG, imm)
+#    define BPLE(imm)                  BP(SPARC_BPLE, imm)
+#    define BPGE(imm)                  BP(SPARC_BPGE, imm)
+#    define BPL(imm)                   BP(SPARC_BPL, imm)
+#    define BPGU(imm)                  BP(SPARC_BPGU, imm)
+#    define BPLEU(imm)                 BP(SPARC_BPLEU, imm)
+#    define BPCC(imm)                  BP(SPARC_BPCC, imm)
+#    define BPCS(imm)                  BP(SPARC_BPCS, imm)
+#    define BPPOS(imm)                 BP(SPARC_BPPOS, imm)
+#    define BPNEG(imm)                 BP(SPARC_BPNEG, imm)
+#    define BPVC(imm)                  BP(SPARC_BPVC, imm)
+#    define BPVS(imm)                  BP(SPARC_BPVS, imm)
+#  endif
+#  define SPARC_CBA                    8       /* always */
+#  define SPARC_CBN                    0       /* never */
+#  define SPARC_CB3                    7       /* 3 */
+#  define SPARC_CB2                    6       /* 2 */
+#  define SPARC_CB23                   5       /* 2 or 3 */
+#  define SPARC_CB1                    4       /* 1 */
+#  define SPARC_CB13                   3       /* 1 or 3 */
+#  define SPARC_CB12                   2       /* 1 or 2 */
+#  define SPARC_CB123                  1       /* 1 or 2 or 3 */
+#  define SPARC_CB0                    9       /* 0 */
+#  define SPARC_CB03                   10      /* 0 or 3 */
+#  define SPARC_CB02                   11      /* 0 or 2 */
+#  define SPARC_CB023                  12      /* 0 or 2 or 3 */
+#  define SPARC_CB01                   13      /* 0 or 1 */
+#  define SPARC_CB013                  14      /* 0 or 1 or 3 */
+#  define SPARC_CB012                  15      /* 0 or 1 or 2 */
+#  define CB(cc, imm)                  f2b(0, 0, cc, 7, imm)
+#  define CBa(cc, imm)                 f2b(0, 1, cc, 7, imm)
+#  define CBA(imm)                     CB(SPARC_CBA, imm)
+#  define CBAa(imm)                    CBa(SPARC_CBA, imm)
+#  define CBN(imm)                     CB(SPARC_CBN, imm)
+#  define CBNa(imm)                    CBa(SPARC_CBN, imm)
+#  define CB3(imm)                     CB(SPARC_CB3, imm)
+#  define CB3a(imm)                    CBa(SPARC_CB3, imm)
+#  define CB2(imm)                     CB(SPARC_CB2, imm)
+#  define CB2a(imm)                    CBa(SPARC_CB2, imm)
+#  define CB23(imm)                    CB(SPARC_CB23, imm)
+#  define CB23a(imm)                   CBa(SPARC_CB23, imm)
+#  define CB1(imm)                     CB(SPARC_CB1, imm)
+#  define CB1a(imm)                    CBa(SPARC_CB1, imm)
+#  define CB13(imm)                    CB(SPARC_CB13, imm)
+#  define CB13a(imm)                   CBa(SPARC_CB13, imm)
+#  define CB12(imm)                    CB(SPARC_CB12, imm)
+#  define CB12a(imm)                   CBa(SPARC_CB12, imm)
+#  define CB123(imm)                   CB(SPARC_CB123, imm)
+#  define CB123a(imm)                  CBa(SPARC_CB123, imm)
+#  define CB0(imm)                     CB(SPARC_CB0, imm)
+#  define CB0a(imm)                    CBa(SPARC_CB0, imm)
+#  define CB03(imm)                    CB(SPARC_CB03, imm)
+#  define CB03a(imm)                   CBa(SPARC_CB03, imm)
+#  define CB02(imm)                    CB(SPARC_CB02, imm)
+#  define CB02a(imm)                   CBa(SPARC_CB02, imm)
+#  define CB023(imm)                   CB(SPARC_CB103, imm)
+#  define CB023a(imm)                  CBa(SPARC_CB023, imm)
+#  define CB01(imm)                    CB(SPARC_CB01, imm)
+#  define CB01a(imm)                   CBa(SPARC_CB01, imm)
+#  define CB013(imm)                   CB(SPARC_CB013, imm)
+#  define CB013a(imm)                  CBa(SPARC_CB013, imm)
+#  define CB012(imm)                   CB(SPARC_CB012, imm)
+#  define CB012a(imm)                  CBa(SPARC_CB012, imm)
+#  define CALLI(imm)                   f1(1, imm)
+#  define CALL(r0)                     JMPL(_O7_REGNO, r0, 0)
+#  define RETL()                       JMPLI(0, _O7_REGNO, 8)
+#  define RET()                                JMPLI(0, _I7_REGNO, 8)
+#  define JMPL(rd, rs1, rs2)           f3r(2, rd, 56, rs1, rs2)
+#  define JMPLI(rd, rs1, imm)          f3i(2, rd, 56, rs1, imm)
+#  define RETT(rs1, rs2)               f3r(2, 0, 57, rs1, rs2)
+#  define RETTI(rs1, imm)              f3i(2, 0, 57, rs1, imm)
+#  define SPARC_TA                     8       /* always */
+#  define SPARC_TN                     0       /* never */
+#  define SPARC_TNE                    9       /* not equal - not Z */
+#  define SPARC_TNZ                    SPARC_BNE
+#  define SPARC_TE                     1       /* equal - Z */
+#  define SPARC_TZ                     SPARC_BE
+#  define SPARC_TG                     10      /* greater - not (Z or (N xor V)) */
+#  define SPARC_TLE                    2       /* less or equal - Z or (N xor V) */
+#  define SPARC_TGE                    11      /* greater or equal - not (N xor V) */
+#  define SPARC_TL                     3       /* less - N xor V */
+#  define SPARC_TGU                    12      /* greater unsigned - not (C or Z) */
+#  define SPARC_TLEU                   4       /* less or equal unsigned - C or Z */
+#  define SPARC_TCC                    13      /* carry clear - not C */
+#  define SPARC_TGEU                   SPARC_BCC
+#  define SPARC_TCS                    5       /* carry set - C */
+#  define SPARC_TLU                    SPARC_BCS
+#  define SPARC_TPOS                   14      /* positive - not N */
+#  define SPARC_TNEG                   6       /* negative - N */
+#  define SPARC_TVC                    15      /* overflow clear - not V */
+#  define SPARC_TVS                    7       /* overflow set - V */
+#  define T(cc, rs1, rs2)              f3t(cc, rs1, 0, rs2)
+#  define TI(cc, rs1, imm)             f3t(cc, rs1, 1, imm)
+#  define TA(rs1, rs2)                 T(SPARC_TA, rs1, rs2)
+#  define TAI(rs1, imm)                        TI(SPARC_TA, rs1, imm)
+#  define TN(rs1, rs2)                 T(SPARC_TN, rs1, rs2)
+#  define TNI(rs1, imm)                        TI(SPARC_TN, rs1, imm)
+#  define TNE(rs1, rs2)                        T(SPARC_TNE, rs1, rs2)
+#  define TNEI(rs1, imm)               TI(SPARC_TNE, rs1, imm)
+#  define TNZ(rs1, rs2)                        TNE(rs1, rs2)
+#  define TNZI(rs1, imm)               TNEI(rs1, imm)
+#  define TE(rs1, rs2)                 T(SPARC_TE, rs1, rs2)
+#  define TEI(rs1, imm)                        TI(SPARC_TE, rs1, imm)
+#  define TZ(rs1, rs2)                 TE(rs1, rs2)
+#  define TZI(rs1, imm)                        TEI(rs1, imm)
+#  define TG(rs1, rs2)                 T(SPARC_TG, rs1, rs2)
+#  define TGI(rs1, imm)                        TI(SPARC_TG, rs1, imm)
+#  define TLE(rs1, rs2)                        T(SPARC_TLE, rs1, rs2)
+#  define TLEI(rs1, imm)               TI(SPARC_TLE, rs1, imm)
+#  define TGE(rs1, rs2)                        T(SPARC_TGE, rs1, rs2)
+#  define TGEI(rs1, imm)               TI(SPARC_TGE, rs1, imm)
+#  define TL(rs1, rs2)                 T(SPARC_TL, rs1, rs2)
+#  define TLI(rs1, imm)                        TI(SPARC_TL, rs1, imm)
+#  define TGU(rs1, rs2)                        T(SPARC_TGU, rs1, rs2)
+#  define TGUI(rs1, imm)               TI(SPARC_TGU, rs1, imm)
+#  define TLEU(rs1, rs2)               T(SPARC_TLEU, rs1, rs2)
+#  define TLEUI(rs1, imm)              TI(SPARC_TLEU, rs1, imm)
+#  define TCC(rs1, rs2)                        T(SPARC_TCC, rs1, rs2)
+#  define TCCI(rs1, imm)               TI(SPARC_TCC, rs1, imm)
+#  define TGEU(rs1, rs2)               TCC(rs1, rs2)
+#  define TGEUI(rs1, imm)              TCCI(rs1, imm)
+#  define TCS(rs1, rs2)                        T(SPARC_TCC, rs1, rs2)
+#  define TCSI(rs1, imm)               TI(SPARC_TCC, rs1, imm)
+#  define TLU(rs1, rs2)                        TCS(rs1, rs2)
+#  define TLUI(rs1, imm)               TCSI(rs1, imm)
+#  define TPOS(rs1, rs2)               T(SPARC_TPOS, rs1, rs2)
+#  define TPOSI(rs1, imm)              TI(SPARC_TPOS, rs1, imm)
+#  define TNEG(rs1, rs2)               T(SPARC_TNEG, rs1, rs2)
+#  define TNEGI(rs1, imm)              TI(SPARC_TNEG, rs1, imm)
+#  define TVC(rs1, rs2)                        T(SPARC_TVC, rs1, rs2)
+#  define TVCI(rs1, imm)               TI(SPARC_TVC, rs1, imm)
+#  define TVS(rs1, rs2)                        T(SPARC_TVS, rs1, rs2)
+#  define TVSI(rs1, imm)               TI(SPARC_TVS, rs1, imm)
+#  define RDY(rd)                      f3r(2, rd, 40, 0, 0)
+#  define RDASR(rs1, rd)               f3r(2, rd, 40, rs1, 0)
+#  define RDPSR(rd)                    f3r(2, rd, 41, 0, 0)
+#  define RDWIM(rd)                    f3r(2, rd, 42, 0, 0)
+#  define RDTBR(rd)                    f3r(2, rd, 43, 0, 0)
+#  define WRY(rs1, rs2)                        f3r(2, 0, 48, rs1, rs2)
+#  define WRYI(rs1, imm)               f3i(2, 0, 48, rs1, imm)
+#  define WRASR(rs1, rs2, rd)          f3r(2, rd, 48, rs1, rs2)
+#  define WRASRI(rs1, imm, rd)         f3i(2, rd, 48, rs1, imm)
+#  define WRPSR(rs1, rs2, rd)          f3r(2, rd, 49, rs1, rs2)
+#  define WRPSRI(rs1, imm, rd)         f3i(2, rd, 49, rs1, imm)
+#  define WRWIM(rs1, rs2, rd)          f3r(2, rd, 50, rs1, rs2)
+#  define WRWIMI(rs1, imm, rd)         f3i(2, rd, 50, rs1, imm)
+#  define WRTBR(rs1, rs2, rd)          f3r(2, rd, 51, rs1, rs2)
+#  define WRTBRI(rs1, imm, rd)         f3i(2, rd, 51, rs1, imm)
+#  define STBAR()                      f3i(2, 0, 40, 15, 0)
+#  define UNIMP(imm)                   f2r(0, 0, 0, imm)
+#  define FLUSH(rs1, rs2)              f3r(2, 0, 59, rs1, rs2)
+#  define FLUSHI(rs1, im)              f3i(2, 0, 59, rs1, imm)
+#  define nop(i0)                      _nop(_jit, i0)
+static void _nop(jit_state_t*, jit_int32_t);
+#  define movr(r0, r1)                 _movr(_jit, r0, r1)
+static void _movr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define movi(r0, i0)                 _movi(_jit, r0, i0)
+static void _movi(jit_state_t*, jit_int32_t, jit_word_t);
+#  define movi_p(r0, i0)               _movi_p(_jit, r0, i0)
+static jit_word_t _movi_p(jit_state_t*, jit_int32_t, jit_word_t);
+#  define comr(r0, r1)                 XNOR(r1, 0, r0)
+#  define negr(r0, r1)                 NEG(r1, r0)
+#  define addr(r0, r1, r2)             ADD(r1, r2, r0)
+#  define addi(r0, r1, i0)             _addi(_jit, r0, r1, i0)
+static void _addi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  if __WORDSIZE == 32
+#    define addcr(r0, r1, r2)          ADDcc(r1, r2, r0)
+#  else
+#    define addcr(r0, r1, r2)          _addcr(_jit, r0, r1, r2)
+static void _addcr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  endif
+#  define addci(r0, r1, i0)            _addci(_jit, r0, r1, i0)
+static void _addci(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  if __WORDSIZE == 32
+#    define addxr(r0, r1, r2)          ADDXcc(r1, r2, r0)
+#  else
+#    define addxr(r0, r1, r2)          _addxr(_jit, r0, r1, r2)
+static void _addxr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  endif
+#  define addxi(r0, r1, i0)            _addxi(_jit, r0, r1, i0)
+static void _addxi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define subr(r0, r1, r2)             SUB(r1, r2, r0)
+#  define subi(r0, r1, i0)             _subi(_jit, r0, r1, i0)
+static void _subi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  if __WORDSIZE == 32
+#    define subcr(r0, r1, r2)          SUBcc(r1, r2, r0)
+#  else
+#    define subcr(r0, r1, r2)          _subcr(_jit, r0, r1, r2)
+static void _subcr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  endif
+#  define subci(r0, r1, i0)            _subci(_jit, r0, r1, i0)
+static void _subci(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  if __WORDSIZE == 32
+#    define subxr(r0, r1, r2)          SUBXcc(r1, r2, r0)
+#  else
+#    define subxr(r0, r1, r2)          _subxr(_jit, r0, r1, r2)
+static void _subxr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  endif
+#  define subxi(r0, r1, i0)            _subxi(_jit, r0, r1, i0)
+static void _subxi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define rsbi(r0, r1, i0)             _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define mulr(r0, r1, r2)           UMUL(r1, r2, r0)
+#  else
+#    define mulr(r0, r1, r2)           MULX(r1, r2, r0)
+#  endif
+#  define muli(r0, r1, i0)             _muli(_jit, r0, r1, i0)
+static void _muli(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  if __WORDSIZE == 32
+#    define qmulr(r0,r1,r2,r3)         iqmulr(r0,r1,r2,r3,1)
+#    define qmulr_u(r0,r1,r2,r3)       iqmulr(r0,r1,r2,r3,0)
+#    define iqmulr(r0,r1,r2,r3,cc)     _iqmulr(_jit,r0,r1,r2,r3,cc)
+static void _iqmulr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#  define qmuli(r0,r1,r2,i0)           iqmuli(r0,r1,r2,i0,1)
+#  define qmuli_u(r0,r1,r2,i0)         iqmuli(r0,r1,r2,i0,0)
+#  define iqmuli(r0,r1,r2,i0,cc)       _iqmuli(_jit,r0,r1,r2,i0,cc)
+static void _iqmuli(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#  else
+#    define qmulr(r0,r1,r2,r3)         _qmulr(_jit,r0,r1,r2,r3)
+static void _qmulr(jit_state_t*,jit_int32_t,jit_int32_t,
+                  jit_int32_t,jit_int32_t);
+#  define qmuli(r0,r1,r2,i0)           _qmuli(_jit,r0,r1,r2,i0)
+static void _qmuli(jit_state_t*,jit_int32_t,jit_int32_t,
+                  jit_int32_t,jit_word_t);
+#    define qmulr_u(r0,r1,r2,r3)       _qmulr_u(_jit,r0,r1,r2,r3)
+static void _qmulr_u(jit_state_t*,jit_int32_t,jit_int32_t,
+                    jit_int32_t,jit_int32_t);
+#  define qmuli_u(r0,r1,r2,i0)         _qmuli_u(_jit,r0,r1,r2,i0)
+static void _qmuli_u(jit_state_t*,jit_int32_t,jit_int32_t,
+                    jit_int32_t,jit_word_t);
+#  endif
+#  define divr(r0, r1, r2)             _divr(_jit, r0, r1, r2)
+static void _divr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define divi(r0, r1, i0)             _divi(_jit, r0, r1, i0)
+static void _divi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define divr_u(r0, r1, r2)           _divr_u(_jit, r0, r1, r2)
+static void _divr_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define divi_u(r0, r1, i0)           _divi_u(_jit, r0, r1, i0)
+static void _divi_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define qdivr(r0,r1,r2,r3)           iqdivr(r0,r1,r2,r3,1)
+#  define qdivr_u(r0,r1,r2,r3)         iqdivr(r0,r1,r2,r3,0)
+#  define iqdivr(r0,r1,r2,r3,cc)       _iqdivr(_jit,r0,r1,r2,r3,cc)
+static void _iqdivr(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_bool_t);
+#  define qdivi(r0,r1,r2,i0)           iqdivi(r0,r1,r2,i0,1)
+#  define qdivi_u(r0,r1,r2,i0)         iqdivi(r0,r1,r2,i0,0)
+#  define iqdivi(r0,r1,r2,i0,cc)       _iqdivi(_jit,r0,r1,r2,i0,cc)
+static void _iqdivi(jit_state_t*,jit_int32_t,jit_int32_t,
+                   jit_int32_t,jit_word_t,jit_bool_t);
+#  define remr(r0, r1, r2)             _remr(_jit, r0, r1, r2)
+static void _remr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define remi(r0, r1, i0)             _remi(_jit, r0, r1, i0)
+static void _remi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define remr_u(r0, r1, r2)           _remr_u(_jit, r0, r1, r2)
+static void _remr_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define remi_u(r0, r1, i0)           _remi_u(_jit, r0, r1, i0)
+static void _remi_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define andr(r0, r1, r2)             AND(r1, r2, r0)
+#  define andi(r0, r1, i0)             _andi(_jit, r0, r1, i0)
+static void _andi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define orr(r0, r1, r2)              OR(r1, r2, r0)
+#  define ori(r0, r1, i0)              _ori(_jit, r0, r1, i0)
+static void _ori(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define xorr(r0, r1, r2)             XOR(r1, r2, r0)
+#  define xori(r0, r1, i0)             _xori(_jit, r0, r1, i0)
+static void _xori(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  if __WORDSIZE == 32
+#    define lshr(r0, r1, r2)           SLL(r1, r2, r0)
+#    define lshi(r0, r1, i0)           SLLI(r1, i0, r0)
+#    define rshr(r0, r1, r2)           SRA(r1, r2, r0)
+#    define rshi(r0, r1, i0)           SRAI(r1, i0, r0)
+#    define rshr_u(r0, r1, r2)         SRL(r1, r2, r0)
+#    define rshi_u(r0, r1, i0)         SRLI(r1, i0, r0)
+#  else
+#    define lshr(r0, r1, r2)           SLLX(r1, r2, r0)
+#    define lshi(r0, r1, i0)           SLLXI(r1, i0, r0)
+#    define rshr(r0, r1, r2)           SRAX(r1, r2, r0)
+#    define rshi(r0, r1, i0)           SRAXI(r1, i0, r0)
+#    define rshr_u(r0, r1, r2)         SRLX(r1, r2, r0)
+#    define rshi_u(r0, r1, i0)         SRLXI(r1, i0, r0)
+#  endif
+#  define htonr_us(r0,r1)              extr_us(r0,r1)
+#  define extr_c(r0,r1)                        _extr_c(_jit,r0,r1)
+static void _extr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_uc(r0,r1)               andi(r0, r1, 0xff)
+#  define extr_s(r0,r1)                        _extr_s(_jit,r0,r1)
+static void _extr_s(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_us(r0,r1)               _extr_us(_jit,r0,r1)
+static void _extr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 32
+#    define htonr_ui(r0,r1)            movr(r0,r1)
+#  else
+#    define htonr_ui(r0,r1)            extr_ui(r0,r1)
+#    define htonr_ul(r0,r1)            movr(r0,r1)
+#    define extr_i(r0,r1)              _extr_i(_jit,r0,r1)
+static void _extr_i(jit_state_t*,jit_int32_t,jit_int32_t);
+#    define extr_ui(r0,r1)             _extr_ui(_jit,r0,r1)
+static void _extr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  endif
+#  define cr(cc, r0, r1, r2)           _cr(_jit, cc, r0, r1, r2)
+static void _cr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define cw(cc, r0, r1, i0)           _cw(_jit, cc, r0, r1, i0)
+static void _cw(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define ltr(r0, r1, r2)            cr(SPARC_BL, r0, r1, r2)
+#    define lti(r0, r1, i0)            cw(SPARC_BL, r0, r1, i0)
+#    define ltr_u(r0, r1, r2)          cr(SPARC_BLU, r0, r1, r2)
+#    define lti_u(r0, r1, i0)          cw(SPARC_BLU, r0, r1, i0)
+#    define ler(r0, r1, r2)            cr(SPARC_BLE, r0, r1, r2)
+#    define lei(r0, r1, i0)            cw(SPARC_BLE, r0, r1, i0)
+#    define ler_u(r0, r1, r2)          cr(SPARC_BLEU, r0, r1, r2)
+#    define lei_u(r0, r1, i0)          cw(SPARC_BLEU, r0, r1, i0)
+#    define eqr(r0, r1, r2)            cr(SPARC_BE, r0, r1, r2)
+#    define eqi(r0, r1, i0)            cw(SPARC_BE, r0, r1, i0)
+#    define ger(r0, r1, r2)            cr(SPARC_BGE, r0, r1, r2)
+#    define gei(r0, r1, i0)            cw(SPARC_BGE, r0, r1, i0)
+#    define ger_u(r0, r1, r2)          cr(SPARC_BGEU, r0, r1, r2)
+#    define gei_u(r0, r1, i0)          cw(SPARC_BGEU, r0, r1, i0)
+#    define gtr(r0, r1, r2)            cr(SPARC_BG, r0, r1, r2)
+#    define gti(r0, r1, i0)            cw(SPARC_BG, r0, r1, i0)
+#    define gtr_u(r0, r1, r2)          cr(SPARC_BGU, r0, r1, r2)
+#    define gti_u(r0, r1, i0)          cw(SPARC_BGU, r0, r1, i0)
+#    define ner(r0, r1, r2)            cr(SPARC_BNE, r0, r1, r2)
+#    define nei(r0, r1, i0)            cw(SPARC_BNE, r0, r1, i0)
+#  else
+#  define ltr(r0, r1, r2)              cr(SPARC_BPL, r0, r1, r2)
+#  define lti(r0, r1, i0)              cw(SPARC_BPL, r0, r1, i0)
+#  define ltr_u(r0, r1, r2)            cr(SPARC_BPCS, r0, r1, r2)
+#  define lti_u(r0, r1, i0)            cw(SPARC_BPCS, r0, r1, i0)
+#  define ler(r0, r1, r2)              cr(SPARC_BPLE, r0, r1, r2)
+#  define lei(r0, r1, i0)              cw(SPARC_BPLE, r0, r1, i0)
+#  define ler_u(r0, r1, r2)            cr(SPARC_BPLEU, r0, r1, r2)
+#  define lei_u(r0, r1, i0)            cw(SPARC_BPLEU, r0, r1, i0)
+#  define eqr(r0, r1, r2)              cr(SPARC_BPE, r0, r1, r2)
+#  define eqi(r0, r1, i0)              cw(SPARC_BPE, r0, r1, i0)
+#  define ger(r0, r1, r2)              cr(SPARC_BPGE, r0, r1, r2)
+#  define gei(r0, r1, i0)              cw(SPARC_BPGE, r0, r1, i0)
+#  define ger_u(r0, r1, r2)            cr(SPARC_BPCC, r0, r1, r2)
+#  define gei_u(r0, r1, i0)            cw(SPARC_BPCC, r0, r1, i0)
+#  define gtr(r0, r1, r2)              cr(SPARC_BPG, r0, r1, r2)
+#  define gti(r0, r1, i0)              cw(SPARC_BPG, r0, r1, i0)
+#  define gtr_u(r0, r1, r2)            cr(SPARC_BPGU, r0, r1, r2)
+#  define gti_u(r0, r1, i0)            cw(SPARC_BPGU, r0, r1, i0)
+#  define ner(r0, r1, r2)              cr(SPARC_BPNE, r0, r1, r2)
+#  define nei(r0, r1, i0)              cw(SPARC_BPNE, r0, r1, i0)
+#  endif
+#  define ldr_c(r0, r1)                        LDSB(r1, 0, r0)
+#  define ldi_c(r0, i0)                        _ldi_c(_jit, r0, i0)
+static void _ldi_c(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_uc(r0, r1)               LDUB(r1, 0, r0)
+#  define ldi_uc(r0, i0)               _ldi_uc(_jit, r0, i0)
+static void _ldi_uc(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_s(r0, r1)                        LDSH(r1, 0, r0)
+#  define ldi_s(r0, i0)                        _ldi_s(_jit, r0, i0)
+static void _ldi_s(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldr_us(r0, r1)               LDUH(r1, 0, r0)
+#  define ldi_us(r0, i0)               _ldi_us(_jit, r0, i0)
+static void _ldi_us(jit_state_t*,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define ldr_i(r0, r1)              LD(r1, 0, r0)
+#    define ldr(u, v)                  ldr_i(u, v)
+#    define ldi(u, v)                  ldi_i(u, v)
+#  else
+#    define ldr_i(r0, r1)              LDSW(r1, 0, r0)
+#    define ldr_ui(r0, r1)             LDUW(r1, 0, r0)
+#    define ldr_l(r0, r1)              LDX(r1, 0, r0)
+#    define ldr(u, v)                  ldr_l(u, v)
+#    define ldi(u, v)                  ldi_l(u, v)
+#  endif
+#  define ldi_i(r0, i0)                        _ldi_i(_jit, r0, i0)
+static void _ldi_i(jit_state_t*,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 64
+#    define ldi_ui(r0, i0)             _ldi_ui(_jit, r0, i0)
+static void _ldi_ui(jit_state_t*,jit_int32_t,jit_word_t);
+#    define ldi_l(r0, i0)              _ldi_l(_jit, r0, i0)
+static void _ldi_l(jit_state_t*,jit_int32_t,jit_word_t);
+#  endif
+#  define ldxr_c(r0, r1, r2)           LDSB(r1, r2, r0)
+#  define ldxi_c(r0, r1, i0)           _ldxi_c(_jit, r0, r1, i0)
+static void _ldxi_c(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_uc(r0, r1, r2)          LDUB(r1, r2, r0)
+#  define ldxi_uc(r0, r1, i0)          _ldxi_uc(_jit, r0, r1, i0)
+static void _ldxi_uc(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_s(r0, r1, r2)           LDSH(r1, r2, r0)
+#  define ldxi_s(r0, r1, i0)           _ldxi_s(_jit, r0, r1, i0)
+static void _ldxi_s(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define ldxr_us(r0, r1, r2)          LDUH(r1, r2, r0)
+#  define ldxi_us(r0, r1, i0)          _ldxi_us(_jit, r0, r1, i0)
+static void _ldxi_us(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define ldxr(u, v, w)              ldxr_i(u, v, w)
+#    define ldxr_i(r0, r1, r2)         LD(r1, r2, r0)
+#    define ldxi(u, v, w)              ldxi_i(u, v, w)
+#  else
+#    define ldxr(u, v, w)              ldxr_l(u, v, w)
+#    define ldxr_i(r0, r1, r2)         LDSW(r1, r2, r0)
+#    define ldxr_ui(r0, r1, r2)                LDUW(r1, r2, r0)
+#    define ldxr_l(r0, r1, r2)         LDX(r1, r2, r0)
+#    define ldxi(u, v, w)              ldxi_l(u, v, w)
+#  endif
+#  define ldxi_i(r0, r1, i0)           _ldxi_i(_jit, r0, r1, i0)
+static void _ldxi_i(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 64
+#    define ldxi_ui(r0, r1, i0)                _ldxi_ui(_jit, r0, r1, i0)
+static void _ldxi_ui(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#    define ldxi_l(r0, r1, i0)         _ldxi_l(_jit, r0, r1, i0)
+static void _ldxi_l(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  endif
+#  define str_c(r0, r1)                        STB(r1, r0, 0)
+#  define sti_c(i0, r0)                        _sti_c(_jit, i0, r0)
+static void _sti_c(jit_state_t*,jit_word_t,jit_int32_t);
+#  define str_s(r0, r1)                        STH(r1, r0, 0)
+#  define sti_s(i0, r0)                        _sti_s(_jit, i0, r0)
+static void _sti_s(jit_state_t*,jit_word_t,jit_int32_t);
+#  if __WORDSIZE == 32
+#    define str(u, v)                  str_i(u, v)
+#    define str_i(r0, r1)              STI(r1, r0, 0)
+#    define sti(u, v)                  sti_i(u, v)
+#  else
+#    define str(u, v)                  str_l(u, v)
+#    define str_i(r0, r1)              STW(r1, r0, 0)
+#    define str_l(r0, r1)              STX(r1, r0, 0)
+#    define sti(u, v)                  sti_l(u, v)
+#  endif
+#  define sti_i(i0, r0)                        _sti_i(_jit, i0, r0)
+static void _sti_i(jit_state_t*,jit_word_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#    define sti_l(i0, r0)              _sti_l(_jit, i0, r0)
+static void _sti_l(jit_state_t*,jit_word_t,jit_int32_t);
+#  endif
+#  define stxr_c(r0, r1, r2)           STB(r2, r1, r0)
+#  define stxi_c(i0, r0, r1)           _stxi_c(_jit, i0, r0, r1)
+static void _stxi_c(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define stxr_s(r0, r1, r2)           STH(r2, r1, r0)
+#  define stxi_s(i0, r0, r1)           _stxi_s(_jit, i0, r0, r1)
+static void _stxi_s(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 32
+#    define stxr(u, v, w)              stxr_i(u, v, w)
+#    define stxr_i(r0, r1, r2)         ST(r2, r1, r0)
+#    define stxi(u, v, w)              stxi_i(u, v, w)
+#  else
+#    define stxr(u, v, w)              stxr_l(u, v, w)
+#    define stxr_i(r0, r1, r2)         STW(r2, r1, r0)
+#    define stxi(u, v, w)              stxi_l(u, v, w)
+#    define stxr_l(r0, r1, r2)         STX(r2, r1, r0)
+#  endif
+#  define stxi_i(i0, r0, r1)           _stxi_i(_jit, i0, r0, r1)
+static void _stxi_i(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  if __WORDSIZE == 64
+#    define stxi_l(i0, r0, r1)         _stxi_l(_jit, i0, r0, r1)
+static void _stxi_l(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  endif
+#  define br(cc, i0, r0, r1)           _br(_jit, cc, i0, r0, r1)
+static jit_word_t
+_br(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bw(cc, i0, r0, i1)           _bw(_jit, cc, i0, r0, i1)
+static jit_word_t
+_bw(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define bltr(i0, r0, r1)           br(SPARC_BL, i0, r0, r1)
+#    define blti(i0, r0, i1)           bw(SPARC_BL, i0, r0, i1)
+#    define bltr_u(i0, r0, r1)         br(SPARC_BLU, i0, r0, r1)
+#    define blti_u(i0, r0, i1)         bw(SPARC_BLU, i0, r0, i1)
+#    define bler(i0, r0, r1)           br(SPARC_BLE, i0, r0, r1)
+#    define blei(i0, r0, i1)           bw(SPARC_BLE, i0, r0, i1)
+#    define bler_u(i0, r0, r1)         br(SPARC_BLEU, i0, r0, r1)
+#    define blei_u(i0, r0, i1)         bw(SPARC_BLEU, i0, r0, i1)
+#    define beqr(i0, r0, r1)           br(SPARC_BE, i0, r0, r1)
+#    define beqi(i0, r0, i1)           bw(SPARC_BE, i0, r0, i1)
+#    define bger(i0, r0, r1)           br(SPARC_BGE, i0, r0, r1)
+#    define bgei(i0, r0, i1)           bw(SPARC_BGE, i0, r0, i1)
+#    define bger_u(i0, r0, r1)         br(SPARC_BGEU, i0, r0, r1)
+#    define bgei_u(i0, r0, i1)         bw(SPARC_BGEU, i0, r0, i1)
+#    define bgtr(i0, r0, r1)           br(SPARC_BG, i0, r0, r1)
+#    define bgti(i0, r0, i1)           bw(SPARC_BG, i0, r0, i1)
+#    define bgtr_u(i0, r0, r1)         br(SPARC_BGU, i0, r0, r1)
+#    define bgti_u(i0, r0, i1)         bw(SPARC_BGU, i0, r0, i1)
+#    define bner(i0, r0, r1)           br(SPARC_BNE, i0, r0, r1)
+#    define bnei(i0, r0, i1)           bw(SPARC_BNE, i0, r0, i1)
+#  else
+#    define bltr(i0, r0, r1)           br(SPARC_BPL, i0, r0, r1)
+#    define blti(i0, r0, i1)           bw(SPARC_BPL, i0, r0, i1)
+#    define bltr_u(i0, r0, r1)         br(SPARC_BPCS, i0, r0, r1)
+#    define blti_u(i0, r0, i1)         bw(SPARC_BPCS, i0, r0, i1)
+#    define bler(i0, r0, r1)           br(SPARC_BPLE, i0, r0, r1)
+#    define blei(i0, r0, i1)           bw(SPARC_BPLE, i0, r0, i1)
+#    define bler_u(i0, r0, r1)         br(SPARC_BPLEU, i0, r0, r1)
+#    define blei_u(i0, r0, i1)         bw(SPARC_BPLEU, i0, r0, i1)
+#    define beqr(i0, r0, r1)           br(SPARC_BPE, i0, r0, r1)
+#    define beqi(i0, r0, i1)           bw(SPARC_BPE, i0, r0, i1)
+#    define bger(i0, r0, r1)           br(SPARC_BPGE, i0, r0, r1)
+#    define bgei(i0, r0, i1)           bw(SPARC_BPGE, i0, r0, i1)
+#    define bger_u(i0, r0, r1)         br(SPARC_BPCC, i0, r0, r1)
+#    define bgei_u(i0, r0, i1)         bw(SPARC_BPCC, i0, r0, i1)
+#    define bgtr(i0, r0, r1)           br(SPARC_BPG, i0, r0, r1)
+#    define bgti(i0, r0, i1)           bw(SPARC_BPG, i0, r0, i1)
+#    define bgtr_u(i0, r0, r1)         br(SPARC_BPGU, i0, r0, r1)
+#    define bgti_u(i0, r0, i1)         bw(SPARC_BPGU, i0, r0, i1)
+#    define bner(i0, r0, r1)           br(SPARC_BPNE, i0, r0, r1)
+#    define bnei(i0, r0, i1)           bw(SPARC_BPNE, i0, r0, i1)
+#  endif
+#  define b_asr(jif,add,sgn,i0,r0,r1)  _b_asr(_jit,jif,add,sgn,i0,r0,r1)
+static jit_word_t
+_b_asr(jit_state_t*,jit_bool_t,jit_bool_t,jit_bool_t,
+       jit_word_t,jit_int32_t,jit_int32_t);
+#  define b_asw(jif,add,sgn,i0,r0,i1)  _b_asw(_jit,jif,add,sgn,i0,r0,i1)
+static jit_word_t
+_b_asw(jit_state_t*,jit_bool_t,jit_bool_t,jit_bool_t,
+       jit_word_t,jit_int32_t,jit_word_t);
+#  define boaddr(i0, r0, r1)           b_asr(1, 1, 1, i0, r0, r1)
+#  define boaddi(i0, r0, i1)           b_asw(1, 1, 1, i0, r0, i1)
+#  define boaddr_u(i0, r0, r1)         b_asr(1, 1, 0, i0, r0, r1)
+#  define boaddi_u(i0, r0, i1)         b_asw(1, 1, 0, i0, r0, i1)
+#  define bxaddr(i0, r0, r1)           b_asr(0, 1, 1, i0, r0, r1)
+#  define bxaddi(i0, r0, i1)           b_asw(0, 1, 1, i0, r0, i1)
+#  define bxaddr_u(i0, r0, r1)         b_asr(0, 1, 0, i0, r0, r1)
+#  define bxaddi_u(i0, r0, i1)         b_asw(0, 1, 0, i0, r0, i1)
+#  define bosubr(i0, r0, r1)           b_asr(1, 0, 1, i0, r0, r1)
+#  define bosubi(i0, r0, i1)           b_asw(1, 0, 1, i0, r0, i1)
+#  define bosubr_u(i0, r0, r1)         b_asr(1, 0, 0, i0, r0, r1)
+#  define bosubi_u(i0, r0, i1)         b_asw(1, 0, 0, i0, r0, i1)
+#  define bxsubr(i0, r0, r1)           b_asr(0, 0, 1, i0, r0, r1)
+#  define bxsubi(i0, r0, i1)           b_asw(0, 0, 1, i0, r0, i1)
+#  define bxsubr_u(i0, r0, r1)         b_asr(0, 0, 0, i0, r0, r1)
+#  define bxsubi_u(i0, r0, i1)         b_asw(0, 0, 0, i0, r0, i1)
+#  define bm_r(set, i0, r0, r1)                _bm_r(_jit,set,i0,r0,r1)
+static jit_word_t
+_bm_r(jit_state_t*,jit_bool_t,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bm_w(set,i0,r0,i1)           _bm_w(_jit,set,i0,r0,i1)
+static jit_word_t
+_bm_w(jit_state_t*,jit_bool_t,jit_word_t,jit_int32_t,jit_word_t);
+#  define bmsr(i0, r0, r1)             bm_r(1, i0, r0, r1)
+#  define bmsi(i0, r0, i1)             bm_w(1, i0, r0, i1)
+#  define bmcr(i0, r0, r1)             bm_r(0, i0, r0, r1)
+#  define bmci(i0, r0, i1)             bm_w(0, i0, r0, i1)
+#  define jmpr(r0)                     _jmpr(_jit, r0)
+static void _jmpr(jit_state_t*,jit_int32_t);
+#  define jmpi(i0)                     _jmpi(_jit, i0)
+static void _jmpi(jit_state_t*,jit_word_t);
+#  define jmpi_p(i0)                   _jmpi_p(_jit, i0)
+static jit_word_t _jmpi_p(jit_state_t*,jit_word_t);
+#  define callr(r0)                    _callr(_jit, r0)
+static void _callr(jit_state_t*,jit_int32_t);
+#  define calli(i0)                    _calli(_jit, i0)
+static void _calli(jit_state_t*,jit_word_t);
+#  define calli_p(i0)                  _calli_p(_jit, i0)
+static jit_word_t _calli_p(jit_state_t*,jit_word_t);
+#  define prolog(node)                 _prolog(_jit, node)
+static void _prolog(jit_state_t*,jit_node_t*);
+#  define epilog(node)                 _epilog(_jit, node)
+static void _epilog(jit_state_t*,jit_node_t*);
+#define vastart(r0)                    _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#define vaarg(r0, r1)                  _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#define patch_at(jump, label)          _patch_at(_jit, jump, label)
+static void _patch_at(jit_state_t*,jit_word_t,jit_word_t);
+#endif
+
+#if CODE
+static void
+_f2r(jit_state_t *_jit,
+     jit_int32_t op, jit_int32_t rd, jit_int32_t op2, jit_int32_t imm22)
+{
+    jit_instr_t                v;
+    assert(!(op  & 0xfffffffc));
+    assert(!(rd  & 0xffffffe0));
+    assert(!(op2 & 0xfffffff8));
+    assert(s22_p(imm22));
+    v.op.b    = op;
+    v.rd.b    = rd;
+    v.op2.b   = op2;
+    v.imm22.b = imm22;
+    ii(v.v);
+}
+
+static void
+_f2b(jit_state_t *_jit,
+     jit_int32_t op, jit_int32_t a, jit_int32_t cond, jit_int32_t op2,
+     jit_int32_t disp22)
+{
+    jit_instr_t                v;
+    assert(!(op   & 0xfffffffc));
+    assert(!(a    & 0xfffffffe));
+    assert(!(cond & 0xfffffff0));
+    assert(!(op2  & 0xfffffff8));
+    assert(s22_p(disp22));
+    v.op.b     = op;
+    v.a.b      = a;
+    v.cond.b   = cond;
+    v.op2.b    = op2;
+    v.disp22.b = disp22;
+    ii(v.v);
+}
+
+#  if __WORDSIZE == 64
+static void
+_f2bp(jit_state_t *_jit,
+      jit_int32_t op, jit_int32_t a, jit_int32_t cond, jit_int32_t op2,
+      jit_int32_t cc1, jit_int32_t cc0, jit_int32_t p, jit_int32_t disp19)
+{
+    jit_instr_t                v;
+    assert(!(op   & 0xfffffffc));
+    assert(!(a    & 0xfffffffe));
+    assert(!(cond & 0xfffffff0));
+    assert(!(op2  & 0xfffffff8));
+    assert(s19_p(disp19));
+    v.op.b     = op;
+    v.a.b      = a;
+    v.cond.b   = cond;
+    v.op2.b    = op2;
+    v.cc1.b    = cc1;
+    v.cc0.b    = cc0;
+    v.p.b      = p;
+    v.disp19.b = disp19;
+    ii(v.v);
+}
+#  endif
+
+static void
+_f3r(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd,
+     jit_int32_t op3, jit_int32_t rs1, jit_int32_t rs2)
+{
+    jit_instr_t                v;
+    assert(!(op  & 0xfffffffc));
+    assert(!(rd  & 0xffffffe0));
+    assert(!(op3 & 0xffffffc0));
+    assert(!(rs1 & 0xffffffe0));
+    assert(!(rs2 & 0xffffffe0));
+    v.op.b  = op;
+    v.rd.b  = rd;
+    v.op3.b = op3;
+    v.rs1.b = rs1;
+    v.i.b   = 0;
+    v.asi.b = 0;
+    v.rs2.b = rs2;
+    ii(v.v);
+}
+
+#  if __WORDSIZE == 64
+static void
+_f3rx(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd,
+      jit_int32_t op3, jit_int32_t rs1, jit_int32_t rs2)
+{
+    jit_instr_t                v;
+    assert(!(op  & 0xfffffffc));
+    assert(!(rd  & 0xffffffe0));
+    assert(!(op3 & 0xffffffc0));
+    assert(!(rs1 & 0xffffffe0));
+    assert(!(rs2 & 0xffffffe0));
+    v.op.b   = op;
+    v.rd.b   = rd;
+    v.op3.b  = op3;
+    v.rs1.b  = rs1;
+    v.i.b    = 0;
+    v.x.b    = 1;
+    v.asix.b = 0;
+    v.rs2.b  = rs2;
+    ii(v.v);
+}
+
+static void
+_f3s(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd,
+      jit_int32_t op3, jit_int32_t rs1, jit_int32_t shim)
+{
+    jit_instr_t                v;
+    assert(!(op   & 0xfffffffc));
+    assert(!(rd   & 0xffffffe0));
+    assert(!(op3  & 0xffffffc0));
+    assert(!(rs1  & 0xffffffe0));
+    assert(!(shim & 0xffffffc0));
+    v.op.b   = op;
+    v.rd.b   = rd;
+    v.op3.b  = op3;
+    v.rs1.b  = rs1;
+    v.i.b    = 1;
+    v.x.b    = 1;
+    v.asis.b = 0;
+    v.shim.b = shim;
+    ii(v.v);
+}
+#  endif
+
+static void
+_f3i(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd,
+     jit_int32_t op3, jit_int32_t rs1, jit_int32_t simm13)
+{
+    jit_instr_t                v;
+    assert(!(op  & 0xfffffffc));
+    assert(!(rd  & 0xffffffe0));
+    assert(!(op3 & 0xffffffc0));
+    assert(!(rs1 & 0xffffffe0));
+    assert(s13_p(simm13));
+    v.op.b     = op;
+    v.rd.b     = rd;
+    v.op3.b    = op3;
+    v.rs1.b    = rs1;
+    v.i.b      = 1;
+    v.simm13.b = simm13;
+    ii(v.v);
+}
+
+static void
+_f3t(jit_state_t *_jit, jit_int32_t cond,
+     jit_int32_t rs1, jit_int32_t i, jit_int32_t rs2_imm7)
+{
+    jit_instr_t                v;
+    assert(!(cond & 0xfffffff0));
+    assert(!(i    & 0xfffffffe));
+    assert(!(rs1 & 0xffffffe0));
+    v.op.b     = 2;
+    v.rd.b     = cond;
+    v.op3.b    = 58;
+    v.i.b      = i;
+    if (i) {
+       assert(s7_p(rs2_imm7));
+       v.res.b  = 0;
+       v.imm7.b = rs2_imm7;
+    }
+    else {
+       assert(!(rs2_imm7 & 0xffffffe0));
+       v.asi.b = 0;
+       v.rs2.b = rs2_imm7;
+    }
+    ii(v.v);
+}
+
+static void
+_f3a(jit_state_t *_jit, jit_int32_t op, jit_int32_t rd,
+     jit_int32_t op3, jit_int32_t rs1, jit_int32_t asi, jit_int32_t rs2)
+{
+    jit_instr_t                v;
+    assert(!(op  & 0xfffffffc));
+    assert(!(rd  & 0xffffffe0));
+    assert(!(op3 & 0xffffffc0));
+    assert(!(rs1 & 0xffffffe0));
+    assert(!(asi & 0xffffff00));
+    assert(!(rs2 & 0xffffffe0));
+    v.op.b    = op;
+    v.rd.b    = rd;
+    v.op3.b   = op3;
+    v.rs1.b   = rs1;
+    v.i.b     = 0;
+    v.asi.b   = asi;
+    v.rs2.b   = rs2;
+    ii(v.v);
+}
+
+static void
+_f1(jit_state_t *_jit, jit_int32_t op, jit_int32_t disp30)
+{
+    jit_instr_t                v;
+    assert(!(op  & 0xfffffffc));
+    assert(s30_p(disp30));
+    v.op.b     = op;
+    v.disp30.b = disp30;
+    ii(v.v);
+}
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t i0)
+{
+    for (; i0 > 0; i0 -= 4)
+       NOP();
+    assert(i0 == 0);
+}
+
+static void
+_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       ORI(r1, 0, r0);
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    if (s13_p(i0))
+       ORI(0, i0, r0);
+    else {
+#  if __WORDSIZE == 64
+       if (i0 & 0xffffffff00000000) {
+           jit_int32_t reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), (i0 >> 32) & 0xffffffff);
+           movi(r0, i0 & 0xffffffff);
+           lshi(rn(reg), rn(reg), 32);
+           OR(rn(reg), r0, r0);
+           jit_unget_reg(reg);
+       }
+       else {
+#  endif
+           SETHI(HI((int)i0), r0);
+           if (LO(i0))
+               ORI(r0, LO(i0), r0);
+#  if __WORDSIZE == 64
+       }
+#  endif
+    }
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_word_t         w;
+#  if __WORDSIZE == 64
+    jit_int32_t                reg;
+#  endif
+    w = _jit->pc.w;
+#  if __WORDSIZE == 64
+    reg = jit_get_reg(jit_class_gpr);
+    SETHI(HI((int)i0), r0);
+    ORI(r0, LO(i0), r0);
+    i0 = (int)(i0 >> 32);
+    SETHI(HI(i0), rn(reg));
+    ORI(rn(reg), LO(i0), rn(reg));
+    SLLXI(rn(reg), 32, rn(reg));
+    OR(rn(reg), r0, r0);
+    jit_unget_reg(reg);
+#  else
+    SETHI(HI(i0), r0);
+    ORI(r0, LO(i0), r0);
+#  endif
+    return (w);
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       ADDI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_addcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       addr(rn(reg), r1, r2);
+       ltr_u(rn(jit_carry), rn(reg), r1);
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       addr(r0, r1, r2);
+       ltr_u(rn(jit_carry), r0, r1);
+    }
+}
+#  endif
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+#  if __WORDSIZE == 32
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       ADDIcc(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addcr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+#  else
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, i0);
+       ltr_u(rn(jit_carry), rn(reg), r1);
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       addi(r0, r1, i0);
+       ltr_u(rn(jit_carry), r0, r1);
+    }
+#  endif
+}
+
+#  if __WORDSIZE == 64
+static void
+_addxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    addcr(r0, r1, r2);
+    addcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+#  endif
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+#  if __WORDSIZE == 32
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       ADDXIcc(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       addxr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+#  else
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    addci(r0, r1, i0);
+    addcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+#  endif
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       SUBI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_subcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       subr(rn(reg), r1, r2);
+       ltr_u(rn(jit_carry), r1, rn(reg));
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       subr(r0, r1, r2);
+       ltr_u(rn(jit_carry), r1, r0);
+    }
+}
+#  endif
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+#  if __WORDSIZE == 32
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       SUBIcc(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subcr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+#  else
+    jit_int32_t                reg;
+    if (jit_carry == _NOREG)
+       jit_carry = jit_get_reg(jit_class_gpr);
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       addi(rn(reg), r1, -i0);
+       ltr_u(rn(jit_carry), r1, rn(reg));
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       addi(r0, r1, -i0);
+       ltr_u(rn(jit_carry), r1, r0);
+    }
+#  endif
+}
+
+#  if __WORDSIZE == 64
+static void
+_subxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    subcr(r0, r1, r2);
+    subcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+}
+#endif
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+#  if __WORDSIZE == 32
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       SUBXIcc(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       subxr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+#  else
+    jit_int32_t                reg;
+    assert(jit_carry != _NOREG);
+    reg = jit_get_reg(jit_class_gpr);
+    movr(rn(reg), rn(jit_carry));
+    subci(r0, r1, i0);
+    subcr(r0, r0, rn(reg));
+    jit_unget_reg(reg);
+#  endif
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    subi(r0, r1, i0);
+    negr(r0, r0);
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 32
+       UMULI(r1, i0, r0);
+#  else
+       MULXI(r1, i0, r0);
+#  endif
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       mulr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 32
+static void
+_iqmulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    if (sign)
+       SMUL(r2, r3, r0);
+    else
+       UMUL(r2, r3, r0);
+    RDY(r1);
+}
+
+static void
+_iqmuli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+       if (sign)
+           SMULI(r2, i0, r0);
+       else
+           UMULI(r2, i0, r0);
+       RDY(r1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       iqmulr(r0, r1, r2, rn(reg), sign);
+       jit_unget_reg(reg);
+    }
+}
+
+#  else
+static __int128_t __llmul(jit_word_t a, jit_word_t b)
+{
+    return (__int128_t)a * (__int128_t)b;
+}
+
+#  define QMUL_PROLOG()                                                \
+    do {                                                       \
+       (void)jit_get_reg(_O0|jit_class_gpr|jit_class_named);   \
+       (void)jit_get_reg(_O1|jit_class_gpr|jit_class_named);   \
+       if (r0 != _G2_REGNO && r1 != _G2_REGNO)                 \
+           stxi(BIAS(-8), _FP_REGNO, _G2_REGNO);               \
+       if (r0 != _G3_REGNO && r1 != _G3_REGNO)                 \
+           stxi(BIAS(-16), _FP_REGNO, _G3_REGNO);              \
+       if (r0 != _G4_REGNO && r1 != _G4_REGNO)                 \
+           stxi(BIAS(-24), _FP_REGNO, _G4_REGNO);              \
+    } while (0)
+
+#  define QMUL_EPILOG()                                                \
+    do {                                                       \
+       if (r0 != _G2_REGNO && r1 != _G2_REGNO)                 \
+           ldxi(_G2_REGNO, _FP_REGNO, BIAS(-8));               \
+       if (r0 != _G3_REGNO && r1 != _G3_REGNO)                 \
+           ldxi(_G3_REGNO, _FP_REGNO, BIAS(-16));              \
+       if (r0 != _G4_REGNO && r1 != _G4_REGNO)                 \
+           ldxi(_G4_REGNO, _FP_REGNO, BIAS(-24));              \
+       (void)jit_unget_reg(_O0);                               \
+       (void)jit_unget_reg(_O1);                               \
+    } while (0)
+
+static void
+_qmulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3)
+{
+    QMUL_PROLOG();
+    movr(_O0_REGNO, r3);
+    movr(_O1_REGNO, r2);
+    calli((jit_word_t)__llmul);
+    movr(r0, _O1_REGNO);
+    movr(r1, _O0_REGNO);
+    QMUL_EPILOG();
+}
+
+static void
+_qmuli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0)
+{
+    QMUL_PROLOG();
+    movi(_O0_REGNO, i0);
+    movr(_O1_REGNO, r2);
+    calli((jit_word_t)__llmul);
+    movr(r0, _O1_REGNO);
+    movr(r1, _O0_REGNO);
+    QMUL_EPILOG();
+}
+
+static __uint128_t __ullmul(jit_uword_t a, jit_uword_t b)
+{
+    return (__uint128_t)a * (__uint128_t)b;
+}
+
+static void
+_qmulr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+        jit_int32_t r2, jit_int32_t r3)
+{
+    QMUL_PROLOG();
+    movr(_O0_REGNO, r3);
+    movr(_O1_REGNO, r2);
+    calli((jit_word_t)__ullmul);
+    movr(r0, _O1_REGNO);
+    movr(r1, _O0_REGNO);
+    QMUL_EPILOG();
+}
+
+static void
+_qmuli_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+        jit_int32_t r2, jit_word_t i0)
+{
+    QMUL_PROLOG();
+    movi(_O0_REGNO, i0);
+    movr(_O1_REGNO, r2);
+    calli((jit_word_t)__ullmul);
+    movr(r0, _O1_REGNO);
+    movr(r1, _O0_REGNO);
+    QMUL_EPILOG();
+}
+#  endif
+
+static void
+_divr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#  if __WORDSIZE == 32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    rshi(rn(reg), r1, 31);
+    WRY(rn(reg), 0);
+    SDIV(r1, r2, r0);
+    jit_unget_reg(reg);
+#  else
+    SDIVX(r1, r2, r0);
+#  endif
+}
+
+static void
+_divi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+#  if __WORDSIZE == 32
+    reg = jit_get_reg(jit_class_gpr);
+#  endif
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 32
+       rshi(rn(reg), r1, 31);
+       WRY(rn(reg), 0);
+       SDIVI(r1, i0, r0);
+#  else
+       SDIVXI(r1, i0, r0);
+#  endif
+    }
+    else {
+#  if __WORDSIZE == 64
+       reg = jit_get_reg(jit_class_gpr);
+#  endif
+       movi(rn(reg), i0);
+       divr(r0, r1, rn(reg));
+#  if __WORDSIZE == 64
+       jit_unget_reg(reg);
+#  endif
+    }
+#  if __WORDSIZE == 32
+    jit_unget_reg(reg);
+#  endif
+}
+
+static void
+_divr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#  if __WORDSIZE == 32
+    WRYI(0, 0);
+    UDIV(r1, r2, r0);
+#  else
+    UDIVX(r1, r2, r0);
+#  endif
+}
+
+static void
+_divi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 32
+       WRYI(0, 0);
+       UDIVI(r1, i0, r0);
+#  else
+       UDIVXI(r1, i0, r0);
+#  endif
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       divr_u(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_iqdivr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    jit_int32_t                sv0, rg0;
+    jit_int32_t                sv1, rg1;
+
+    if (r0 == r2 || r0 == r3) {
+       sv0 = jit_get_reg(jit_class_gpr);
+       rg0 = rn(sv0);
+    }
+    else
+       rg0 = r0;
+    if (r1 == r2 || r1 == r3) {
+       sv1 = jit_get_reg(jit_class_gpr);
+       rg1 = rn(sv1);
+    }
+    else
+       rg1 = r1;
+
+    if (sign)
+       divr(rg0, r2, r3);
+    else
+       divr_u(rg0, r2, r3);
+    mulr(rg1, r3, rg0);
+    subr(rg1, r2, rg1);
+    if (rg0 != r0) {
+       movr(r0, rg0);
+       jit_unget_reg(sv0);
+    }
+    if (rg1 != r1) {
+       movr(r1, rg1);
+       jit_unget_reg(sv1);
+    }
+}
+
+static void
+_iqdivi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    iqdivr(r0, r1, r2, rn(reg), sign);
+    jit_unget_reg(reg);
+}
+
+static void
+_remr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1 || r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       divr(rn(reg), r1, r2);
+       mulr(rn(reg), r2, rn(reg));
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       divr(r0, r1, r2);
+       mulr(r0, r2, r0);
+       subr(r0, r1, r0);
+    }
+}
+
+static void
+_remi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_remr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1 || r0 == r2) {
+       reg = jit_get_reg(jit_class_gpr);
+       divr_u(rn(reg), r1, r2);
+       mulr(rn(reg), r2, rn(reg));
+       subr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       divr_u(r0, r1, r2);
+       mulr(r0, r2, r0);
+       subr(r0, r1, r0);
+    }
+}
+
+static void
+_remi_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    remr_u(r0, r1, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       ANDI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       andr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       ORI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       orr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       XORI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       xorr(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_extr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, __WORDSIZE - 8);
+    rshi(r0, r0, __WORDSIZE - 8);
+}
+
+static void
+_extr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, __WORDSIZE - 16);
+    rshi(r0, r0, __WORDSIZE - 16);
+}
+
+static void
+_extr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, __WORDSIZE - 16);
+    rshi_u(r0, r0, __WORDSIZE - 16);
+}
+
+#if __WORDSIZE == 64
+static void
+_extr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, __WORDSIZE - 32);
+    rshi(r0, r0, __WORDSIZE - 32);
+}
+
+static void
+_extr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    lshi(r0, r1, __WORDSIZE - 32);
+    rshi_u(r0, r0, __WORDSIZE - 32);
+}
+#endif
+
+static void
+_cr(jit_state_t *_jit, jit_int32_t cc,
+    jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    CMP(r1, r2);
+#  if __WORDSIZE == 32
+    Ba(cc, 3);
+#  else
+    BPa(cc, 3);
+#  endif
+    movi(r0, 1);
+    movi(r0, 0);
+}
+
+static void
+_cw(jit_state_t *_jit, jit_int32_t cc,
+    jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+       CMPI(r1, i0);
+#  if __WORDSIZE == 32
+       Ba(cc, 3);
+#  else
+       BPa(cc, 3);
+#  endif
+       movi(r0, 1);
+       movi(r0, 0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       cr(cc, r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDSBI(0, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_c(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDUBI(0, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_uc(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDSHI(0, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_s(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDUHI(0, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_us(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 32
+       LDI(0, i0, r0);
+#  else
+       LDSWI(0, i0, r0);
+#  endif
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDUWI(0, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_ui(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldi_l(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDXI(0, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_l(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+#  endif
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDSBI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_c(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDUBI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_uc(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDSHI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_s(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDUHI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_us(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 32
+       LDI(r1, i0, r0);
+#  else
+       LDSWI(r1, i0, r0);
+#  endif
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_i(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDUWI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_ui(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDXI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_l(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+#  endif
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       STBI(r0, 0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_c(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       STHI(r0, 0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_s(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 32
+       STI(r0, 0, i0);
+#  else
+       STWI(r0, 0, i0);
+#  endif
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_i(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_sti_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       STXI(r0, 0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_l(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+#  endif
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       STBI(r1, r0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_c(r0, rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       STHI(r1, r0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_s(r0, rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 32
+       STI(r1, r0, i0);
+#  else
+       STWI(r1, r0, i0);
+#  endif
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_i(r0, rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_stxi_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       STXI(r1, r0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_l(r0, rn(reg), r1);
+       jit_unget_reg(reg);
+    }
+}
+#  endif
+
+static jit_word_t
+_br(jit_state_t *_jit, jit_int32_t cc,
+    jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    CMP(r0, r1);
+    w = _jit->pc.w;
+#  if __WORDSIZE == 32
+    B(cc, (i0 - w) >> 2);
+#  else
+    BP(cc, (i0 - w) >> 2);
+#  endif
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bw(jit_state_t *_jit, jit_int32_t cc,
+    jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (s13_p(i1)) {
+       CMPI(r0, i1);
+       w = _jit->pc.w;
+#  if __WORDSIZE == 32
+       B(cc, (i0 - w) >> 2);
+#  else
+       B(cc, (i0 - w) >> 2);
+#  endif
+       NOP();
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = br(cc, i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_b_asr(jit_state_t *_jit, jit_bool_t jif, jit_bool_t add, jit_bool_t sgn,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    if (add)
+       ADDcc(r0, r1, r0);
+    else
+       SUBcc(r0, r1, r0);
+    w = _jit->pc.w;
+#  if __WORDSIZE == 32
+    B(sgn ?
+      (jif ? SPARC_BVS : SPARC_BVC) :
+      (jif ? SPARC_BCS : SPARC_BCC),
+      (i0 - w) >> 2);
+#  else
+    BP(sgn ?
+       (jif ? SPARC_BPVS : SPARC_BPVC) :
+       (jif ? SPARC_BPCS : SPARC_BPCC),
+       (i0 - w) >> 2);
+#  endif
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_b_asw(jit_state_t *_jit, jit_bool_t jif, jit_bool_t add, jit_bool_t sgn,
+       jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (s13_p(i1)) {
+       if (add)
+           ADDIcc(r0, i1, r0);
+       else
+           SUBIcc(r0, i1, r0);
+       w = _jit->pc.w;
+#  if __WORDSIZE == 32
+       B(sgn ?
+         (jif ? SPARC_BVS : SPARC_BVC) :
+         (jif ? SPARC_BCS : SPARC_BCC),
+         (i0 - w) >> 2);
+#  else
+       BP(sgn ?
+          (jif ? SPARC_BPVS : SPARC_BPVC) :
+          (jif ? SPARC_BPCS : SPARC_BPCC),
+          (i0 - w) >> 2);
+#  endif
+       NOP();
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = b_asr(jif, add, sgn, i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static jit_word_t
+_bm_r(jit_state_t *_jit, jit_bool_t set,
+      jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    BTST(r0, r1);
+    w = _jit->pc.w;
+#  if __WORDSIZE == 32
+    B(set ? SPARC_BNZ : SPARC_BZ, (i0 - w) >> 2);
+#  else
+    BP(set ? SPARC_BPNE : SPARC_BPE, (i0 - w) >> 2);
+#  endif
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_bm_w(jit_state_t *_jit, jit_bool_t set,
+      jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    if (s13_p(i1)) {
+       BTSTI(r0, i1);
+       w = _jit->pc.w;
+#  if __WORDSIZE == 32
+       B(set ? SPARC_BNZ : SPARC_BZ, (i0 - w) >> 2);
+#  else
+       BP(set ? SPARC_BPNE : SPARC_BPE, (i0 - w) >> 2);
+#  endif
+       NOP();
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i1);
+       w = bm_r(set, i0, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    return (w);
+}
+
+static void
+_jmpr(jit_state_t *_jit, jit_int32_t r0)
+{
+    JMPL(0, r0, 0);
+    NOP();
+}
+
+static void
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    w = (i0 - _jit->pc.w) >> 2;
+    if (s22_p(w)) {
+       BA(w);
+       NOP();
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+       movi(rn(reg), i0);
+       jmpr(rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_jmpi_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    w = movi_p(rn(reg), i0);
+    jmpr(rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+static void
+_callr(jit_state_t *_jit, jit_int32_t r0)
+{
+    CALL(r0);
+    NOP();
+}
+
+static void
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    w = (i0 - _jit->pc.w) >> 2;
+    CALLI(w);
+    NOP();
+}
+
+static jit_word_t
+_calli_p(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    w = movi_p(rn(reg), i0);
+    callr(rn(reg));
+    jit_unget_reg(reg);
+    return (w);
+}
+
+#define OFF(n)         BIAS(((n) * sizeof(jit_word_t)))
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                reg;
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar)
+       _jitc->function->self.aoff &= -16;
+    /* align at 16 bytes boundary */
+    _jitc->function->stack = ((stack_framesize +
+                             _jitc->function->self.alen -
+                             _jitc->function->self.aoff) + 15) & -16;
+    SAVEI(_SP_REGNO, -_jitc->function->stack, _SP_REGNO);
+
+    /* (most) other backends do not save incoming arguments, so,
+     * only save locals here */
+    if (jit_regset_tstbit(&_jitc->function->regset, _L0))
+       stxi(OFF(0), _SP_REGNO, _L0_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _L1))
+       stxi(OFF(1), _SP_REGNO, _L1_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _L2))
+       stxi(OFF(2), _SP_REGNO, _L2_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _L3))
+       stxi(OFF(3), _SP_REGNO, _L3_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _L4))
+       stxi(OFF(4), _SP_REGNO, _L4_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _L5))
+       stxi(OFF(5), _SP_REGNO, _L5_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _L6))
+       stxi(OFF(6), _SP_REGNO, _L6_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _L7))
+       stxi(OFF(7), _SP_REGNO, _L7_REGNO);
+
+    if (_jitc->function->allocar) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), BIAS(_jitc->function->self.aoff));
+       /* Already "biased" by allocai */
+       stxi_i(_jitc->function->aoffoff, _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+    if (_jitc->function->self.call & jit_call_varargs) {
+       for (reg = _jitc->function->vagp; jit_arg_reg_p(reg); ++reg)
+           stxi(BIAS((16 + (__WORDSIZE == 32)) * sizeof(jit_word_t) +
+                     reg * sizeof(jit_word_t)), _FP_REGNO, rn(_I0 + reg));
+    }
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    if (_jitc->function->assume_frame)
+       return;
+    /* (most) other backends do not save incoming arguments, so,
+     * only save locals here */
+    if (jit_regset_tstbit(&_jitc->function->regset, _L0))
+       ldxi(_L0_REGNO, _FP_REGNO, _jitc->function->stack + OFF(0));
+    if (jit_regset_tstbit(&_jitc->function->regset, _L1))
+       ldxi(_L1_REGNO, _FP_REGNO, _jitc->function->stack + OFF(1));
+    if (jit_regset_tstbit(&_jitc->function->regset, _L2))
+       ldxi(_L2_REGNO, _FP_REGNO, _jitc->function->stack + OFF(2));
+    if (jit_regset_tstbit(&_jitc->function->regset, _L3))
+       ldxi(_L3_REGNO, _FP_REGNO, _jitc->function->stack + OFF(3));
+    if (jit_regset_tstbit(&_jitc->function->regset, _L4))
+       ldxi(_L4_REGNO, _FP_REGNO, _jitc->function->stack + OFF(4));
+    if (jit_regset_tstbit(&_jitc->function->regset, _L5))
+       ldxi(_L5_REGNO, _FP_REGNO, _jitc->function->stack + OFF(5));
+    if (jit_regset_tstbit(&_jitc->function->regset, _L6))
+       ldxi(_L6_REGNO, _FP_REGNO, _jitc->function->stack + OFF(6));
+    if (jit_regset_tstbit(&_jitc->function->regset, _L7))
+       ldxi(_L7_REGNO, _FP_REGNO, _jitc->function->stack + OFF(7));
+    RESTOREI(0, 0, 0);
+    RETL();
+    NOP();
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+    /* Initialize stack pointer to the first stack argument. */
+    if (jit_arg_reg_p(_jitc->function->vagp))
+       addi(r0, _FP_REGNO, BIAS((16 + (__WORDSIZE == 32) +
+                                 _jitc->function->vagp) *
+                                sizeof(jit_word_t)));
+    else
+       addi(r0, _FP_REGNO, BIAS(_jitc->function->self.size));
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Load argument. */
+    ldr(r0, r1);
+
+    /* Update vararg stack pointer. */
+    addi(r1, r1, sizeof(jit_word_t));
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_word_t instr, jit_word_t label)
+{
+    jit_instr_t                 i;
+    union {
+       jit_int32_t     *i;
+       jit_word_t       w;
+    } u;
+
+    u.w = instr;
+    i.v = u.i[0];
+
+    if (i.op.b == 0) {                         /* conditional branch */
+       if (i.op2.b == 2 || i.op2.b == 6) {     /* int or float condition */
+           i.disp22.b = (label - instr) >> 2;
+           u.i[0] = i.v;
+       }
+#  if __WORDSIZE == 64
+       else if (i.op2.b == 1) {
+           i.disp19.b = (label - instr) >> 2;
+           u.i[0] = i.v;
+       }
+#  endif
+       else if (i.op2.b == 4) {        /* movi_p */
+           /* SETHI */
+           i.imm22.b = HI((int)label);
+           u.i[0] = i.v;
+           i.v = u.i[1];
+           if (i.op.b == 2 && i.op3.b == 2) {
+               /* ORI */
+               i.simm13.b = LO(label);
+               u.i[1] = i.v;
+#  if __WORDSIZE == 64
+               i.v = u.i[2];
+               assert(i.op2.b == 4);
+               label = (label >> 32) & 0xffffffff;
+               i.imm22.b = HI((int)label);
+               u.i[2] = i.v;
+               i.v = u.i[3];
+               assert(i.op.b == 2 && i.op3.b == 2);
+               /* ORI */
+               i.simm13.b = LO(label);
+               u.i[3] = i.v;
+#  endif
+           }
+           else
+               abort();
+       }
+       else
+           abort();
+    }
+    else
+       abort();
+}
+#endif
diff --git a/deps/lightning/lib/jit_sparc-fpu.c b/deps/lightning/lib/jit_sparc-fpu.c
new file mode 100644 (file)
index 0000000..ae2cbab
--- /dev/null
@@ -0,0 +1,1499 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  if __WORDSIZE == 32
+#    define FPR(r)                     (r)
+#    define CLASS_SNG                  jit_class_fpr
+#    define CLASS_DBL                  jit_class_fpr
+#  else
+#    define single_precision_p(r)      ((r) >= 0 && (r) <= 31)
+#    define FPR(r)                     ((r) > 31 ? (r) - 31 : (r))
+#    define CLASS_SNG                  (jit_class_fpr | jit_class_sng)
+#    define CLASS_DBL                  (jit_class_fpr | jit_class_dbl)
+#  endif
+#  define LDF(rs1, rs2, rd)            f3r(3, FPR(rd), 32, FPR(rs1), FPR(rs2))
+#  define LDFI(rs1, imm, rd)           f3i(3, FPR(rd), 32, FPR(rs1), imm)
+#  define LDDF(rs1, rs2, rd)           f3r(3, FPR(rd), 35, FPR(rs1), FPR(rs2))
+#  define LDDFI(rs1, imm, rd)          f3i(3, FPR(rd), 35, FPR(rs1), imm)
+#  define LDFSR(rs1, rs2, rd)          f3r(3, FPR(rd), 33, FPR(rs1), FPR(rs2))
+#  define LDFSRI(rs1, imm, rd)         f3i(3, FPR(rd), 33, FPR(rs1), imm)
+#  define STF(rd, rs1, rs2)            f3r(3, FPR(rd), 36, FPR(rs1), FPR(rs2))
+#  define STFI(rd, rs1, imm)           f3i(3, FPR(rd), 36, FPR(rs1), imm)
+#  define STDF(rd, rs1, rs2)           f3r(3, FPR(rd), 39, FPR(rs1), FPR(rs2))
+#  define STDFI(rd, rs1, imm)          f3i(3, FPR(rd), 39, FPR(rs1), imm)
+#  define STFSR(rd, rs1, rs2)          f3r(3, FPR(rd), 37, FPR(rs1), FPR(rs2))
+#  define STFSRI(rd, rs1, imm)         f3i(3, FPR(rd), 37, FPR(rs1), imm)
+#  define STDFQ(rd, rs1, rs2)          f3r(3, FPR(rd), 38, FPR(rs1), FPR(rs2))
+#  define STFDFQ(rd, rs1, imm)         f3i(3, FPR(rd), 38, FPR(rs1), imm)
+#  define SPARC_FBA                    8       /* always - 1 */
+#  define SPARC_FBN                    0       /* never - 0 */
+#  define SPARC_FBU                    7       /* unordered - U */
+#  define SPARC_FBG                    6       /* greater - G */
+#  define SPARC_FBUG                   5       /* unordered or greater - G or U */
+#  define SPARC_FBL                    4       /* less - L */
+#  define SPARC_FBUL                   3       /* unordered or less - L or U */
+#  define SPARC_FBLG                   2       /* less or greater - L or G */
+#  define SPARC_FBNE                   1       /* not equal - L or G or U */
+#  define SPARC_FBNZ                   SPARC_FBNE
+#  define SPARC_FBE                    9       /* equal - E */
+#  define SPARC_FBZ                    SPARC_FBE
+#  define SPARC_FBUE                   10      /* unordered or equal - E or U */
+#  define SPARC_FBGE                   11      /* greater or equal - E or G */
+#  define SPARC_FBUGE                  12      /* unordered or greater or equal - E or G or U */
+#  define SPARC_FBLE                   13      /* less or equal - E or L */
+#  define SPARC_FBULE                  14      /* unordered or less or equal - E or L or U */
+#  define SPARC_FBO                    15      /* ordered - E or L or G */
+#  define FB(cc, imm)                  f2b(0, 0, cc, 6, imm)
+#  define FBa(cc, imm)                 f2b(0, 1, cc, 6, imm)
+#  define FBA(imm)                     FB(SPARC_FBA, imm)
+#  define FBAa(imm)                    FBa(SPARC_FBA, imm)
+#  define FBN(imm)                     FB(SPARC_FBN, imm)
+#  define FBNa(imm)                    FBa(SPARC_FBN, imm)
+#  define FBU(imm)                     FB(SPARC_FBU, imm)
+#  define FBUa(imm)                    FBa(SPARC_FBU, imm)
+#  define FBG(imm)                     FB(SPARC_FBG, imm)
+#  define FBGa(imm)                    FBa(SPARC_FBG, imm)
+#  define FBUG(imm)                    FB(SPARC_FBUG, imm)
+#  define FBUGa(imm)                   FBa(SPARC_FBUG, imm)
+#  define FBL(imm)                     FB(SPARC_FBL, imm)
+#  define FBLa(imm)                    FBa(SPARC_FBL, imm)
+#  define FBUL(imm)                    FB(SPARC_FBUL, imm)
+#  define FBULa(imm)                   FBa(SPARC_FBUL, imm)
+#  define FBLG(imm)                    FB(SPARC_FBLG, imm)
+#  define FBLGa(imm)                   FBa(SPARC_FBLG, imm)
+#  define FBNE(imm)                    FB(SPARC_FBNE, imm)
+#  define FBNEa(imm)                   FBa(SPARC_FBNE, imm)
+#  define FBE(imm)                     FB(SPARC_FBE, imm)
+#  define FBEa(imm)                    FBa(SPARC_FBE, imm)
+#  define FBUE(imm)                    FB(SPARC_FBUE, imm)
+#  define FBUEa(imm)                   FBa(SPARC_FBUE, imm)
+#  define FBLE(imm)                    FB(SPARC_FBLE, imm)
+#  define FBLEa(imm)                   FBa(SPARC_FBLE, imm)
+#  define FBO(imm)                     FB(SPARC_FBO, imm)
+#  define FBOa(imm)                    FBa(SPARC_FBO, imm)
+#  define FPop1(rd, rs1, opf, rs2)     f3f(rd, 52, rs1, opf, rs2)
+#  define FPop2(rd, rs1, opf, rs2)     f3f(rd, 53, rs1, opf, rs2)
+#  define f3f(rd, op3, rs1, opf, rs2)  _f3f(_jit, rd, op3, rs1, opf, rs2)
+static void
+_f3f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t, jit_int32_t,jit_int32_t);
+#  define FITOS(rs2, rd)               FPop1(rd, 0, 196, rs2)
+#  define FITOD(rs2, rd)               FPop1(rd, 0, 200, rs2)
+#  define FITOQ(rs2, rd)               FPop1(rd, 0, 204, rs2)
+#  if __WORDSIZE == 64
+#    define FXTOS(rs2, rd)             FPop1(rd, 0, 132, rs2)
+#    define FXTOD(rs2, rd)             FPop1(rd, 0, 136, rs2)
+#    define FxTOQ(rs2, rd)             FPop1(rd, 0, 140, rs2)
+#  endif
+#  define FSTOI(rs2, rd)               FPop1(rd, 0, 209, rs2)
+#  define FDTOI(rs2, rd)               FPop1(rd, 0, 210, rs2)
+#  define FQTOI(rs2, rd)               FPop1(rd, 0, 211, rs2)
+#  define FSTOX(rs2, rd)               FPop1(rd, 0, 129, rs2)
+#  define FDTOX(rs2, rd)               FPop1(rd, 0, 130, rs2)
+#  define FQTOX(rs2, rd)               FPop1(rd, 0, 131, rs2)
+#  define FSTOD(rs2, rd)               FPop1(rd, 0, 201, rs2)
+#  define FSTOQ(rs2, rd)               FPop1(rd, 0, 205, rs2)
+#  define FDTOS(rs2, rd)               FPop1(rd, 0, 198, rs2)
+#  define FDTOQ(rs2, rd)               FPop1(rd, 0, 206, rs2)
+#  define FQTOS(rs2, rd)               FPop1(rd, 0, 199, rs2)
+#  define FQTOD(rs2, rd)               FPop1(rd, 0, 203, rs2)
+#  define FMOVS(rs2, rd)               FPop1(rd, 0,   1, rs2)
+#  define FMOVD(rs2, rd)               FPop1(rd, 0,   2, rs2)
+#  define FMOVQ(rs2, rd)               FPop1(rd, 0,   3, rs2)
+#  define FNEGS(rs2, rd)               FPop1(rd, 0,   5, rs2)
+#  define FNEGD(rs2, rd)               FPop1(rd, 0,   6, rs2)
+#  define FNEGQ(rs2, rd)               FPop1(rd, 0,   7, rs2)
+#  define FABSS(rs2, rd)               FPop1(rd, 0,   9, rs2)
+#  define FABSD(rs2, rd)               FPop1(rd, 0,  10, rs2)
+#  define FABSQ(rs2, rd)               FPop1(rd, 0,  11, rs2)
+#  define FSQRTS(rs2, rd)              FPop1(rd, 0,  41, rs2)
+#  define FSQRTD(rs2, rd)              FPop1(rd, 0,  42, rs2)
+#  define FSQRTQ(rs2, rd)              FPop1(rd, 0,  43, rs2)
+#  define SPARC_FADDS                  65
+#  define SPARC_FADDD                  66
+#  define SPARC_FADDQ                  67
+#  define SPARC_FSUBS                  69
+#  define SPARC_FSUBD                  70
+#  define SPARC_FSUBQ                  71
+#  define SPARC_FMULS                  73
+#  define SPARC_FMULD                  74
+#  define SPARC_FMULQ                  75
+#  define SPARC_FSMULD                 105
+#  define SPARC_FDMULQ                 110
+#  define SPARC_FDIVS                  77
+#  define SPARC_FDIVD                  78
+#  define SPARC_FDIVQ                  79
+#  define FADDS(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FADDS, rs2)
+#  define FADDD(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FADDD, rs2)
+#  define FADDQ(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FADDQ, rs2)
+#  define FSUBS(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FSUBS, rs2)
+#  define FSUBD(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FSUBD, rs2)
+#  define FSUBQ(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FSUBQ, rs2)
+#  define FMULS(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FMULS, rs2)
+#  define FMULD(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FMULD, rs2)
+#  define FMULQ(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FMULQ, rs2)
+#  define FSMULD(rs1, rs2, rd)         FPop1(rd, rs1,  SPARC_FSMULD, rs2)
+#  define FDMULQ(rs1, rs2, rd)         FPop1(rd, rs1,  SPARC_FDMULQ, rs2)
+#  define FDIVS(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FDIVS, rs2)
+#  define FDIVD(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FDIVD, rs2)
+#  define FDIVQ(rs1, rs2, rd)          FPop1(rd, rs1,  SPARC_FDIVQ, rs2)
+#  define SPARC_FCMPS                  81
+#  define SPARC_FCMPD                  82
+#  define SPARC_FCMPQ                  83
+#  define SPARC_FCMPES                 85
+#  define SPARC_FCMPED                 86
+#  define SPARC_FCMPEQ                 87
+#  define FCMPS(rs1, rs2)              FPop2(0, rs1, SPARC_FCMPS, rs2)
+#  define FCMPD(rs1, rs2)              FPop2(0, rs1, SPARC_FCMPD, rs2)
+#  define FCMPQ(rs1, rs2)              FPop2(0, rs1, SPARC_FCMPQ, rs2)
+#  define FCMPES(rs1, rs2)             FPop2(0, rs1, SPARC_FCMPES, rs2)
+#  define FCMPED(rs1, rs2)             FPop2(0, rs1, SPARC_FCMPED, rs2)
+#  define FCMPEQ(rs1, rs2)             FPop2(0, rs1, SPARC_FCMPEQ, rs2)
+#  define CPop1(rd, rs1, opc, rs2)     f3f(rd, 54, rs1, opf, rs2)
+#  define CPop2(rd, rs1, opc, rs2)     f3f(rd, 55, rs1, opf, rs2)
+#  define extr_f(r0, r1)               _extr_f(_jit, r0, r1)
+static void _extr_f(jit_state_t*, jit_int32_t, jit_int32_t);
+#  if __WORDSIZSE == 32
+#    define truncr_f(r0, r1)           truncr_f_i(r0, r1)
+#  define truncr_d(r0, r1)             truncr_d_i(r0, r1)
+#  else
+#    define truncr_f(r0, r1)           truncr_f_l(r0, r1)
+#  define truncr_d(r0, r1)             truncr_d_l(r0, r1)
+#  endif
+#  define truncr_f_i(r0, r1)           _truncr_f_i(_jit, r0, r1)
+static void _truncr_f_i(jit_state_t*, jit_int32_t, jit_int32_t);
+#  if __WORDSIZE == 64
+#    define truncr_f_l(r0, r1)         _truncr_f_l(_jit, r0, r1)
+static void _truncr_f_l(jit_state_t*, jit_int32_t, jit_int32_t);
+#  endif
+#  if __WORDSIZE == 32
+#    define extr_d_f(r0, r1)           FDTOS(r1, r0)
+#  else
+#    define extr_d_f(r0, r1)           _extr_d_f(_jit, r0, r1)
+static void _extr_d_f(jit_state_t*, jit_int32_t, jit_int32_t);
+#  endif
+#  define movi_f(r0, i0)               _movi_f(_jit, r0, i0)
+#  if __WORDSIZE == 32
+#    define movr_f(r0, r1)             FMOVS(r1, r0)
+#  else
+#    define movr_f(r0, r1)             _movr_f(_jit, r0, r1)
+static void _movr_f(jit_state_t*, jit_int32_t, jit_int32_t);
+#  endif
+static void _movi_f(jit_state_t*, jit_int32_t, jit_float32_t*);
+#  if __WORDSIZE == 32
+#    define negr_f(r0, r1)             FNEGS(r1, r0)
+#    define absr_f(r0, r1)             FABSS(r1, r0)
+#    define sqrtr_f(r0, r1)            FSQRTS(r1, r0)
+#  else
+#    define negr_f(r0, r1)             _negr_f(_jit, r0, r1)
+static void _negr_f(jit_state_t*, jit_int32_t, jit_int32_t);
+#    define absr_f(r0, r1)             _absr_f(_jit, r0, r1)
+static void _absr_f(jit_state_t*, jit_int32_t, jit_int32_t);
+#    define sqrtr_f(r0, r1)            _sqrtr_f(_jit, r0, r1)
+static void _sqrtr_f(jit_state_t*, jit_int32_t, jit_int32_t);
+#  endif
+#  define extr_d(r0, r1)               _extr_d(_jit, r0, r1)
+static void _extr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define truncr_d_i(r0, r1)           _truncr_d_i(_jit, r0, r1)
+static void _truncr_d_i(jit_state_t*, jit_int32_t, jit_int32_t);
+#  if __WORDSIZE == 64
+#    define truncr_d_l(r0, r1)         _truncr_d_l(_jit, r0, r1)
+static void _truncr_d_l(jit_state_t*, jit_int32_t, jit_int32_t);
+#  endif
+#  if __WORDSIZE == 32
+#    define extr_f_d(r0, r1)           FSTOD(r1, r0)
+#  else
+#    define extr_f_d(r0, r1)           _extr_f_d(_jit, r0, r1)
+static void _extr_f_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  endif
+#  define movi_d(r0, i0)               _movi_d(_jit, r0, i0)
+static void _movi_d(jit_state_t*, jit_int32_t, jit_float64_t*);
+#  if __WORDSIZE == 32
+#  define movr_d(r0, r1)               _movr_d(_jit, r0, r1)
+static void _movr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define negr_d(r0, r1)               _negr_d(_jit, r0, r1)
+static void _negr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define absr_d(r0, r1)               _absr_d(_jit, r0, r1)
+static void _absr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  else
+#    define movr_d(r0, r1)             FMOVD(r1, r0)
+#    define negr_d(r0, r1)             FNEGD(r1, r0)
+#    define absr_d(r0, r1)             FABSD(r1, r0)
+#  endif
+#  define sqrtr_d(r0, r1)              FSQRTD(r1, r0)
+#  define fop1f(op, r0, r1, i0)                _fop1f(_jit, op, r0, r1, i0)
+static void _fop1f(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define rfop1f(op, r0, r1, i0)       _rfop1f(_jit, op, r0, r1, i0)
+static void _rfop1f(jit_state_t*,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define fop1d(op, r0, r1, i0)                _fop1d(_jit, op, r0, r1, i0)
+static void _fop1d(jit_state_t*,jit_int32_t,
+                  jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define rfop1d(op, r0, r1, i0)       _rfop1d(_jit, op, r0, r1, i0)
+static void _rfop1d(jit_state_t*,jit_int32_t,
+                   jit_int32_t,jit_int32_t,jit_float64_t*);
+#  if __WORDSIZE == 32
+#    define addr_f(r0, r1, r2)         FADDS(r1, r2, r0)
+#    define subr_f(r0, r1, r2)         FSUBS(r1, r2, r0)
+#    define mulr_f(r0, r1, r2)         FMULS(r1, r2, r0)
+#    define divr_f(r0, r1, r2)         FDIVS(r1, r2, r0)
+#  else
+#    define fop2f(op, r0, r1, r2)      _fop2f(_jit, op, r0, r1, r2)
+static void _fop2f(jit_state_t*, jit_int32_t,
+                  jit_int32_t, jit_int32_t, jit_int32_t);
+#    define addr_f(r0, r1, r2)         fop2f(SPARC_FADDS, r0, r1, r2)
+#    define subr_f(r0, r1, r2)         fop2f(SPARC_FSUBS, r0, r1, r2)
+#    define mulr_f(r0, r1, r2)         fop2f(SPARC_FMULS, r0, r1, r2)
+#    define divr_f(r0, r1, r2)         fop2f(SPARC_FDIVS, r0, r1, r2)
+#  endif
+#  define addi_f(r0, r1, i0)           fop1f(SPARC_FADDS, r0, r1, i0)
+#  define subi_f(r0, r1, i0)           fop1f(SPARC_FSUBS, r0, r1, i0)
+#  define rsbr_f(r0, r1, r2)           subr_f(r0, r2, r1)
+#  define rsbi_f(r0, r1, i0)           rfop1f(SPARC_FSUBS, r0, r1, i0)
+#  define rsbr_d(r0, r1, r2)           subr_d(r0, r2, r1)
+#  define rsbi_d(r0, r1, i0)           rfop1d(SPARC_FSUBD, r0, r1, i0)
+#  define muli_f(r0, r1, i0)           fop1f(SPARC_FMULS, r0, r1, i0)
+#  define divi_f(r0, r1, i0)           fop1f(SPARC_FDIVS, r0, r1, i0)
+#  define addr_d(r0, r1, r2)           FADDD(r1, r2, r0)
+#  define addi_d(r0, r1, i0)           fop1d(SPARC_FADDD, r0, r1, i0)
+#  define subr_d(r0, r1, r2)           FSUBD(r1, r2, r0)
+#  define subi_d(r0, r1, i0)           fop1d(SPARC_FSUBD, r0, r1, i0)
+#  define rsbr_d(r0, r1, r2)           subr_d(r0, r2, r1)
+#  define rsbi_d(r0, r1, i0)           rfop1d(SPARC_FSUBD, r0, r1, i0)
+#  define mulr_d(r0, r1, r2)           FMULD(r1, r2, r0)
+#  define muli_d(r0, r1, i0)           fop1d(SPARC_FMULD, r0, r1, i0)
+#  define divr_d(r0, r1, r2)           FDIVD(r1, r2, r0)
+#  define divi_d(r0, r1, i0)           fop1d(SPARC_FDIVD, r0, r1, i0)
+#define fcr(cc, r0, r1, r2)            _fcr(_jit, cc, r0, r1, r2)
+static void _fcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define fcw(cc, r0, r1, i0)            _fcw(_jit, cc, r0, r1, i0)
+static void
+_fcw(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define ltr_f(r0, r1, r2)            fcr(SPARC_FBL, r0, r1, r2)
+#  define lti_f(r0, r1, i0)            fcw(SPARC_FBL, r0, r1, i0)
+#  define ler_f(r0, r1, r2)            fcr(SPARC_FBLE, r0, r1, r2)
+#  define lei_f(r0, r1, i0)            fcw(SPARC_FBLE, r0, r1, i0)
+#  define eqr_f(r0, r1, r2)            fcr(SPARC_FBE, r0, r1, r2)
+#  define eqi_f(r0, r1, i0)            fcw(SPARC_FBE, r0, r1, i0)
+#  define ger_f(r0, r1, r2)            fcr(SPARC_FBGE, r0, r1, r2)
+#  define gei_f(r0, r1, i0)            fcw(SPARC_FBGE, r0, r1, i0)
+#  define gtr_f(r0, r1, r2)            fcr(SPARC_FBG, r0, r1, r2)
+#  define gti_f(r0, r1, i0)            fcw(SPARC_FBG, r0, r1, i0)
+#  define ner_f(r0, r1, r2)            fcr(SPARC_FBNE, r0, r1, r2)
+#  define nei_f(r0, r1, i0)            fcw(SPARC_FBNE, r0, r1, i0)
+#  define unltr_f(r0, r1, r2)          fcr(SPARC_FBUL, r0, r1, r2)
+#  define unlti_f(r0, r1, i0)          fcw(SPARC_FBUL, r0, r1, i0)
+#  define unler_f(r0, r1, r2)          fcr(SPARC_FBULE, r0, r1, r2)
+#  define unlei_f(r0, r1, i0)          fcw(SPARC_FBULE, r0, r1, i0)
+#  define uneqr_f(r0, r1, r2)          fcr(SPARC_FBUE, r0, r1, r2)
+#  define uneqi_f(r0, r1, i0)          fcw(SPARC_FBUE, r0, r1, i0)
+#  define unger_f(r0, r1, r2)          fcr(SPARC_FBUGE, r0, r1, r2)
+#  define ungei_f(r0, r1, i0)          fcw(SPARC_FBUGE, r0, r1, i0)
+#  define ungtr_f(r0, r1, r2)          fcr(SPARC_FBUG, r0, r1, r2)
+#  define ungti_f(r0, r1, i0)          fcw(SPARC_FBUG, r0, r1, i0)
+#  define ltgtr_f(r0, r1, r2)          fcr(SPARC_FBLG, r0, r1, r2)
+#  define ltgti_f(r0, r1, i0)          fcw(SPARC_FBLG, r0, r1, i0)
+#  define ordr_f(r0, r1, r2)           fcr(SPARC_FBO, r0, r1, r2)
+#  define ordi_f(r0, r1, i0)           fcw(SPARC_FBO, r0, r1, i0)
+#  define unordr_f(r0, r1, r2)         fcr(SPARC_FBU, r0, r1, r2)
+#  define unordi_f(r0, r1, i0)         fcw(SPARC_FBU, r0, r1, i0)
+#define dcr(cc, r0, r1, r2)            _dcr(_jit, cc, r0, r1, r2)
+static void _dcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#define dcw(cc, r0, r1, i0)            _dcw(_jit, cc, r0, r1, i0)
+static void
+_dcw(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define ltr_d(r0, r1, r2)            dcr(SPARC_FBL, r0, r1, r2)
+#  define lti_d(r0, r1, i0)            dcw(SPARC_FBL, r0, r1, i0)
+#  define ler_d(r0, r1, r2)            dcr(SPARC_FBLE, r0, r1, r2)
+#  define lei_d(r0, r1, i0)            dcw(SPARC_FBLE, r0, r1, i0)
+#  define eqr_d(r0, r1, r2)            dcr(SPARC_FBE, r0, r1, r2)
+#  define eqi_d(r0, r1, i0)            dcw(SPARC_FBE, r0, r1, i0)
+#  define ger_d(r0, r1, r2)            dcr(SPARC_FBGE, r0, r1, r2)
+#  define gei_d(r0, r1, i0)            dcw(SPARC_FBGE, r0, r1, i0)
+#  define gtr_d(r0, r1, r2)            dcr(SPARC_FBG, r0, r1, r2)
+#  define gti_d(r0, r1, i0)            dcw(SPARC_FBG, r0, r1, i0)
+#  define ner_d(r0, r1, r2)            dcr(SPARC_FBNE, r0, r1, r2)
+#  define nei_d(r0, r1, i0)            dcw(SPARC_FBNE, r0, r1, i0)
+#  define unltr_d(r0, r1, r2)          dcr(SPARC_FBUL, r0, r1, r2)
+#  define unlti_d(r0, r1, i0)          dcw(SPARC_FBUL, r0, r1, i0)
+#  define unler_d(r0, r1, r2)          dcr(SPARC_FBULE, r0, r1, r2)
+#  define unlei_d(r0, r1, i0)          dcw(SPARC_FBULE, r0, r1, i0)
+#  define uneqr_d(r0, r1, r2)          dcr(SPARC_FBUE, r0, r1, r2)
+#  define uneqi_d(r0, r1, i0)          dcw(SPARC_FBUE, r0, r1, i0)
+#  define unger_d(r0, r1, r2)          dcr(SPARC_FBUGE, r0, r1, r2)
+#  define ungei_d(r0, r1, i0)          dcw(SPARC_FBUGE, r0, r1, i0)
+#  define ungtr_d(r0, r1, r2)          dcr(SPARC_FBUG, r0, r1, r2)
+#  define ungti_d(r0, r1, i0)          dcw(SPARC_FBUG, r0, r1, i0)
+#  define ltgtr_d(r0, r1, r2)          dcr(SPARC_FBLG, r0, r1, r2)
+#  define ltgti_d(r0, r1, i0)          dcw(SPARC_FBLG, r0, r1, i0)
+#  define ordr_d(r0, r1, r2)           dcr(SPARC_FBO, r0, r1, r2)
+#  define ordi_d(r0, r1, i0)           dcw(SPARC_FBO, r0, r1, i0)
+#  define unordr_d(r0, r1, r2)         dcr(SPARC_FBU, r0, r1, r2)
+#  define unordi_d(r0, r1, i0)         dcw(SPARC_FBU, r0, r1, i0)
+#  if __WORDSIZE == 32
+#    define ldr_f(r0, r1)              LDF(r1, 0, r0)
+#  else
+#  define ldr_f(r0, r1)                        _ldr_f(_jit, r0, r1)
+static void _ldr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  endif
+#  define ldi_f(r0, i0)                        _ldi_f(_jit, r0, i0)
+static void _ldi_f(jit_state_t*,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define ldxr_f(r0, r1, r2)         LDF(r1, r2, r0)
+#  else
+#  define ldxr_f(r0, r1, r2)           _ldxr_f(_jit, r0, r1, r2)
+static void _ldxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  endif
+#  define ldxi_f(r0, r1, i0)           _ldxi_f(_jit, r0, r1, i0)
+static void _ldxi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  if __WORDSIZE == 32
+#    define str_f(r0, r1)              STF(r1, r0, 0)
+#  else
+#  define str_f(r0, r1)                        _str_f(_jit, r0, r1)
+static void _str_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  endif
+#  define sti_f(r0, i0)                        _sti_f(_jit, r0, i0)
+static void _sti_f(jit_state_t*,jit_word_t,jit_int32_t);
+#  if __WORDSIZE == 32
+#    define stxr_f(r0, r1, r2)         STF(r2, r1, r0)
+#  else
+#  define stxr_f(r0, r1, r2)           _stxr_f(_jit, r0, r1, r2)
+static void _stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  endif
+#  define stxi_f(r0, r1, i0)           _stxi_f(_jit, r0, r1, i0)
+static void _stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define ldr_d(r0, r1)                        LDDF(r1, 0, r0)
+#  define ldi_d(r0, i0)                        _ldi_d(_jit, r0, i0)
+static void _ldi_d(jit_state_t*,jit_int32_t,jit_word_t);
+#  define ldxr_d(r0, r1, r2)           LDDF(r1, r2, r0)
+#  define ldxi_d(r0, r1, i0)           _ldxi_d(_jit, r0, r1, i0)
+static void _ldxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define str_d(r0, r1)                        STDF(r1, r0, 0)
+#  define sti_d(r0, i0)                        _sti_d(_jit, r0, i0)
+static void _sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#  define stxr_d(r0, r1, r2)           STDF(r2, r1, r0)
+#  define stxi_d(r0, r1, i0)           _stxi_d(_jit, r0, r1, i0)
+static void _stxi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define fbr(cc, i0, r0, r1)          _fbr(_jit, cc, i0, r0, r1)
+static jit_word_t
+_fbr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#  define fbw(cc, i0, r0, i1)          _fbw(_jit, cc, i0, r0, i1)
+static jit_word_t
+_fbw(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_float32_t*);
+#  define bltr_f(i0, r0, r1)           fbr(SPARC_FBL, i0, r0, r1)
+#  define blti_f(i0, r0, i1)           fbw(SPARC_FBL, i0, r0, i1)
+#  define bler_f(i0, r0, r1)           fbr(SPARC_FBLE, i0, r0, r1)
+#  define blei_f(i0, r0, i1)           fbw(SPARC_FBLE, i0, r0, i1)
+#  define beqr_f(i0, r0, r1)           fbr(SPARC_FBE, i0, r0, r1)
+#  define beqi_f(i0, r0, i1)           fbw(SPARC_FBE, i0, r0, i1)
+#  define bger_f(i0, r0, r1)           fbr(SPARC_FBGE, i0, r0, r1)
+#  define bgei_f(i0, r0, i1)           fbw(SPARC_FBGE, i0, r0, i1)
+#  define bgtr_f(i0, r0, r1)           fbr(SPARC_FBG, i0, r0, r1)
+#  define bgti_f(i0, r0, i1)           fbw(SPARC_FBG, i0, r0, i1)
+#  define bner_f(i0, r0, r1)           fbr(SPARC_FBNE, i0, r0, r1)
+#  define bnei_f(i0, r0, i1)           fbw(SPARC_FBNE, i0, r0, i1)
+#  define bunltr_f(i0, r0, r1)         fbr(SPARC_FBUL, i0, r0, r1)
+#  define bunlti_f(i0, r0, i1)         fbw(SPARC_FBUL, i0, r0, i1)
+#  define bunler_f(i0, r0, r1)         fbr(SPARC_FBULE, i0, r0, r1)
+#  define bunlei_f(i0, r0, i1)         fbw(SPARC_FBULE, i0, r0, i1)
+#  define buneqr_f(i0, r0, r1)         fbr(SPARC_FBUE, i0, r0, r1)
+#  define buneqi_f(i0, r0, i1)         fbw(SPARC_FBUE, i0, r0, i1)
+#  define bunger_f(i0, r0, r1)         fbr(SPARC_FBUGE, i0, r0, r1)
+#  define bungei_f(i0, r0, i1)         fbw(SPARC_FBUGE, i0, r0, i1)
+#  define bungtr_f(i0, r0, r1)         fbr(SPARC_FBUG, i0, r0, r1)
+#  define bungti_f(i0, r0, i1)         fbw(SPARC_FBUG, i0, r0, i1)
+#  define bltgtr_f(i0, r0, r1)         fbr(SPARC_FBLG, i0, r0, r1)
+#  define bltgti_f(i0, r0, i1)         fbw(SPARC_FBLG, i0, r0, i1)
+#  define bordr_f(i0, r0, r1)          fbr(SPARC_FBO, i0, r0, r1)
+#  define bordi_f(i0, r0, i1)          fbw(SPARC_FBO, i0, r0, i1)
+#  define bunordr_f(i0, r0, r1)                fbr(SPARC_FBU, i0, r0, r1)
+#  define bunordi_f(i0, r0, i1)                fbw(SPARC_FBU, i0, r0, i1)
+#  define dbr(cc, i0, r0, r1)          _dbr(_jit, cc, i0, r0, r1)
+static jit_word_t
+_dbr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#  define dbw(cc, i0, r0, i1)          _dbw(_jit, cc, i0, r0, i1)
+static jit_word_t
+_dbw(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_float64_t*);
+#  define bltr_d(i0, r0, r1)           dbr(SPARC_FBL, i0, r0, r1)
+#  define blti_d(i0, r0, i1)           dbw(SPARC_FBL, i0, r0, i1)
+#  define bler_d(i0, r0, r1)           dbr(SPARC_FBLE, i0, r0, r1)
+#  define blei_d(i0, r0, i1)           dbw(SPARC_FBLE, i0, r0, i1)
+#  define beqr_d(i0, r0, r1)           dbr(SPARC_FBE, i0, r0, r1)
+#  define beqi_d(i0, r0, i1)           dbw(SPARC_FBE, i0, r0, i1)
+#  define bger_d(i0, r0, r1)           dbr(SPARC_FBGE, i0, r0, r1)
+#  define bgei_d(i0, r0, i1)           dbw(SPARC_FBGE, i0, r0, i1)
+#  define bgtr_d(i0, r0, r1)           dbr(SPARC_FBG, i0, r0, r1)
+#  define bgti_d(i0, r0, i1)           dbw(SPARC_FBG, i0, r0, i1)
+#  define bner_d(i0, r0, r1)           dbr(SPARC_FBNE, i0, r0, r1)
+#  define bnei_d(i0, r0, i1)           dbw(SPARC_FBNE, i0, r0, i1)
+#  define bunltr_d(i0, r0, r1)         dbr(SPARC_FBUL, i0, r0, r1)
+#  define bunlti_d(i0, r0, i1)         dbw(SPARC_FBUL, i0, r0, i1)
+#  define bunler_d(i0, r0, r1)         dbr(SPARC_FBULE, i0, r0, r1)
+#  define bunlei_d(i0, r0, i1)         dbw(SPARC_FBULE, i0, r0, i1)
+#  define buneqr_d(i0, r0, r1)         dbr(SPARC_FBUE, i0, r0, r1)
+#  define buneqi_d(i0, r0, i1)         dbw(SPARC_FBUE, i0, r0, i1)
+#  define bunger_d(i0, r0, r1)         dbr(SPARC_FBUGE, i0, r0, r1)
+#  define bungei_d(i0, r0, i1)         dbw(SPARC_FBUGE, i0, r0, i1)
+#  define bungtr_d(i0, r0, r1)         dbr(SPARC_FBUG, i0, r0, r1)
+#  define bungti_d(i0, r0, i1)         dbw(SPARC_FBUG, i0, r0, i1)
+#  define bltgtr_d(i0, r0, r1)         dbr(SPARC_FBLG, i0, r0, r1)
+#  define bltgti_d(i0, r0, i1)         dbw(SPARC_FBLG, i0, r0, i1)
+#  define bordr_d(i0, r0, r1)          dbr(SPARC_FBO, i0, r0, r1)
+#  define bordi_d(i0, r0, i1)          dbw(SPARC_FBO, i0, r0, i1)
+#  define bunordr_d(i0, r0, r1)                dbr(SPARC_FBU, i0, r0, r1)
+#  define bunordi_d(i0, r0, i1)                dbw(SPARC_FBU, i0, r0, i1)
+#  define vaarg_d(r0, r1)              _vaarg_d(_jit, r0, r1)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#endif
+
+#if CODE
+static void
+_f3f(jit_state_t *_jit, jit_int32_t rd,
+     jit_int32_t op3, jit_int32_t rs1, jit_int32_t opf, jit_int32_t rs2)
+{
+    jit_instr_t                v;
+#  if __WORDSIZE == 64
+    if (rd > 31) {
+       assert(rd <= 63 && (rd & 1) == 0);
+       rd -= 31;
+    }
+    if (rs1 > 31) {
+       assert(rs1 <= 63 && (rs1 & 1) == 0);
+       rs1 -= 31;
+    }
+    if (rs2 > 31) {
+       assert(rs2 <= 63 && (rs2 & 1) == 0);
+       rs2 -= 31;
+    }
+#  endif
+    assert(!(rd  & 0xffffffe0));
+    assert(!(op3 & 0xffffffc0));
+    assert(!(rs1 & 0xffffffe0));
+    assert(!(opf & 0xfffffe00));
+    assert(!(rs2 & 0xffffffe0));
+    v.op.b    = 2;
+    v.rd.b    = rd;
+    v.op3.b   = op3;
+    v.rs1.b   = rs1;
+    v.opf.b   = opf;
+    v.rs2.b   = rs2;
+    ii(v.v);
+}
+
+#  if __WORDSIZE == 64
+static void
+_movr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0, t1;
+    if (r0 != r1) {
+       if (single_precision_p(r0)) {
+           if (single_precision_p(r1))
+               FMOVS(r1, r0);
+           else {
+               t1 = jit_get_reg(CLASS_SNG);
+               movr_d(rn(t1), r1);
+               FMOVS(rn(t1), r0);
+               jit_unget_reg(t1);
+           }
+       }
+       else {
+           if (single_precision_p(r1)) {
+               t0 = jit_get_reg(CLASS_SNG);
+               FMOVS(r1, rn(t0));
+               movr_d(r0, rn(t0));
+               jit_unget_reg(t0);
+           }
+           else {
+               t1 = jit_get_reg(CLASS_SNG);
+               movr_d(rn(t1), r1);
+               FMOVS(rn(t1), rn(t1));
+               movr_d(r0, rn(t1));
+               jit_unget_reg(t1);
+           }
+       }
+    }
+}
+
+static void
+_negr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0, t1;
+    if (single_precision_p(r0)) {
+       if (single_precision_p(r1))
+           FNEGS(r1, r0);
+       else {
+           t1 = jit_get_reg(CLASS_SNG);
+           movr_d(rn(t1), r1);
+           FNEGS(rn(t1), r0);
+           jit_unget_reg(t1);
+       }
+    }
+    else {
+       if (single_precision_p(r1)) {
+           t0 = jit_get_reg(CLASS_SNG);
+           FNEGS(r1, rn(t0));
+           movr_d(r0, rn(t0));
+           jit_unget_reg(t0);
+       }
+       else {
+           t1 = jit_get_reg(CLASS_SNG);
+           movr_d(rn(t1), r1);
+           FNEGS(rn(t1), rn(t1));
+           movr_d(r0, rn(t1));
+           jit_unget_reg(t1);
+       }
+    }
+}
+
+static void
+_absr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0, t1;
+    if (single_precision_p(r0)) {
+       if (single_precision_p(r1))
+           FABSS(r1, r0);
+       else {
+           t1 = jit_get_reg(CLASS_SNG);
+           movr_d(rn(t1), r1);
+           FABSS(rn(t1), r0);
+           jit_unget_reg(t1);
+       }
+    }
+    else {
+       if (single_precision_p(r1)) {
+           t0 = jit_get_reg(CLASS_SNG);
+           FABSS(r1, rn(t0));
+           movr_d(r0, rn(t0));
+           jit_unget_reg(t0);
+       }
+       else {
+           t1 = jit_get_reg(CLASS_SNG);
+           movr_d(rn(t1), r1);
+           FABSS(rn(t1), rn(t1));
+           movr_d(r0, rn(t1));
+           jit_unget_reg(t1);
+       }
+    }
+}
+
+static void
+_sqrtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                t0, t1;
+    if (single_precision_p(r0)) {
+       if (single_precision_p(r1))
+           FSQRTS(r1, r0);
+       else {
+           t1 = jit_get_reg(CLASS_SNG);
+           movr_d(rn(t1), r1);
+           FSQRTS(rn(t1), r0);
+           jit_unget_reg(t1);
+       }
+    }
+    else {
+       if (single_precision_p(r1)) {
+           t0 = jit_get_reg(CLASS_SNG);
+           FSQRTS(r1, rn(t0));
+           movr_d(r0, rn(t0));
+           jit_unget_reg(t0);
+       }
+       else {
+           t1 = jit_get_reg(CLASS_SNG);
+           movr_d(rn(t1), r1);
+           FSQRTS(rn(t1), rn(t1));
+           movr_d(r0, rn(t1));
+           jit_unget_reg(t1);
+       }
+    }
+}
+#  endif
+
+#  if __WORDSIZE == 64
+static void
+_extr_d_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (!single_precision_p(r0)) {
+       reg = jit_get_reg(CLASS_SNG);
+       movr_d(rn(reg), r0);
+       FDTOS(r1, rn(reg));
+       movr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       FDTOS(r1, r0);
+}
+#  endif
+
+static void
+_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t      i;
+       jit_float32_t    f;
+    } data;
+    jit_int32_t                 reg;
+
+    if (_jitc->no_data) {
+       data.f = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), data.i & 0xffffffff);
+       stxi_i(BIAS(-8), _FP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+       ldxi_f(r0, _FP_REGNO, BIAS(-8));
+    }
+    else
+       ldi_f(r0, (jit_word_t)i0);
+}
+
+#  if __WORDSIZE == 64
+static void
+_extr_f_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (!single_precision_p(r1)) {
+       reg = jit_get_reg(CLASS_SNG);
+       movr_d(rn(reg), r1);
+       FSTOD(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+    else
+       FSTOD(r1, r0);
+}
+#  endif
+
+static void
+_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+#  if __WORDSIZE == 32
+       jit_int32_t      i[2];
+#  else
+       jit_word_t       w;
+#  endif
+       jit_float64_t    d;
+    } data;
+    jit_int32_t                 reg;
+
+    if (_jitc->no_data) {
+       data.d = *i0;
+       reg = jit_get_reg(jit_class_gpr);
+# if __WORDSIZE == 32
+       movi(rn(reg), data.i[0]);
+#  else
+       movi(rn(reg), data.w);
+#  endif
+       stxi(BIAS(-8), _FP_REGNO, rn(reg));
+#  if __WORDSIZE == 32
+       movi(rn(reg), data.i[1]);
+       stxi_i(BIAS(-4), _FP_REGNO, rn(reg));
+#  endif
+       jit_unget_reg(reg);
+       ldxi_d(r0, _FP_REGNO, BIAS(-8));
+    }
+    else
+       ldi_d(r0, (jit_word_t)i0);
+}
+
+#  if __WORDSIZE == 32
+static void
+_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(!(r0 & 1));
+    assert(!(r1 & 1));
+    if (r0 != r1) {
+       FMOVS(r1, r0);
+       FMOVS(r1 + 1, r0 + 1);
+    }
+}
+
+static void
+_negr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(!(r0 & 1));
+    assert(!(r1 & 1));
+    FNEGS(r1, r0);
+    if (r0 != r1)
+       FMOVS(r1 + 1, r0 + 1);
+}
+
+static void
+_absr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(!(r0 & 1));
+    assert(!(r1 & 1));
+    FABSS(r1, r0);
+    if (r0 != r1)
+       FMOVS(r1 + 1, r0 + 1);
+}
+#  endif
+
+#  if __WORDSIZE == 64
+#    define single_rrr(NAME, CODE)                                     \
+static void                                                            \
+NAME(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)        \
+{                                                                      \
+    jit_int32_t                x0, t0, x1, t1, x2, t2, mask = 0;               \
+    if (!single_precision_p(r0)) {                                     \
+       mask |= 1;                                                      \
+       t0 = jit_get_reg(CLASS_SNG);                                    \
+       x0 = rn(t0);                                                    \
+       if (r0 == r1) {                                                 \
+           x1 = x0;                                                    \
+           movr_d(x1, r1);                                             \
+           if (r0 == r2)                                               \
+               x2 = x0;                                                \
+       }                                                               \
+       else if (r0 == r2) {                                            \
+           x2 = x0;                                                    \
+           movr_d(x2, r2);                                             \
+       }                                                               \
+    }                                                                  \
+    else                                                               \
+       x0 = r0;                                                        \
+    if (!single_precision_p(r1)) {                                     \
+       if (r0 != r1) {                                                 \
+           mask |= 2;                                                  \
+           t1 = jit_get_reg(CLASS_SNG);                                \
+           x1 = rn(t1);                                                \
+           movr_d(x1, r1);                                             \
+           if (r1 == r2)                                               \
+               x2 = x1;                                                \
+       }                                                               \
+    }                                                                  \
+    else                                                               \
+       x1 = r1;                                                        \
+    if (!single_precision_p(r2)) {                                     \
+       if (r0 != r2 && r1 != r2) {                                     \
+           mask |= 4;                                                  \
+           t2 = jit_get_reg(CLASS_SNG);                                \
+           x2 = rn(t2);                                                \
+           movr_d(x2, r2);                                             \
+       }                                                               \
+    }                                                                  \
+    else                                                               \
+       x2 = r2;                                                        \
+    CODE(x1, x2, x0);                                                  \
+    if (mask & 1) {                                                    \
+       movr_d(r0, x0);                                                 \
+       jit_unget_reg(t0);                                              \
+    }                                                                  \
+    if (mask & 2)                                                      \
+       jit_unget_reg(t1);                                              \
+    if (mask & 4)                                                      \
+       jit_unget_reg(t2);                                              \
+}
+
+static void
+_fop2f(jit_state_t *_jit, jit_int32_t op,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                x0, t0, x1, t1, x2, t2, mask = 0;
+    if (!single_precision_p(r0)) {
+       mask |= 1;
+       t0 = jit_get_reg(CLASS_SNG);
+       x0 = rn(t0);
+       if (r0 == r1) {
+           x1 = x0;
+           movr_d(x1, r1);
+           if (r0 == r2)
+               x2 = x0;
+       }
+       else if (r0 == r2) {
+           x2 = x0;
+           movr_d(x2, r2);
+       }
+    }
+    else
+       x0 = r0;
+    if (!single_precision_p(r1)) {
+       if (r0 != r1) {
+           mask |= 2;
+           t1 = jit_get_reg(CLASS_SNG);
+           x1 = rn(t1);
+           movr_d(x1, r1);
+           if (r1 == r2)
+               x2 = x1;
+       }
+    }
+    else
+       x1 = r1;
+    if (!single_precision_p(r2)) {
+       if (r0 != r2 && r1 != r2) {
+           mask |= 4;
+           t2 = jit_get_reg(CLASS_SNG);
+           x2 = rn(t2);
+           movr_d(x2, r2);
+       }
+    }
+    else
+       x2 = r2;
+    FPop1(x0, x1,  op, x2);
+    if (mask & 1) {
+       movr_d(r0, x0);
+       jit_unget_reg(t0);
+    }
+    if (mask & 2)
+       jit_unget_reg(t1);
+    if (mask & 4)
+       jit_unget_reg(t2);
+}
+#  endif
+
+static void
+_fop1f(jit_state_t *_jit, jit_int32_t op,
+       jit_int32_t r0, jit_int32_t r1, jit_float32_t *i0)
+{
+    jit_int32_t                reg;
+#  if __WORDSIZE == 64
+    jit_int32_t                x0, t0, x1, t1, mask = 0;
+#  endif
+    reg = jit_get_reg(CLASS_SNG);
+    movi_f(rn(reg), i0);
+#  if __WORDSIZE == 64
+    if (!single_precision_p(r0)) {
+       mask |= 1;
+       t0 = jit_get_reg(CLASS_SNG);
+       x0 = rn(t0);
+       if (r0 == r1) {
+           x1 = x0;
+           movr_d(x1, r1);
+       }
+    }
+    else
+       x0 = r0;
+    if (!single_precision_p(r1)) {
+       if (r0 != r1) {
+           mask |= 2;
+           t1 = jit_get_reg(CLASS_SNG);
+           x1 = rn(t1);
+           movr_d(x1, r1);
+       }
+    }
+    else
+       x1 = r1;
+    FPop1(x0, x1, op, rn(reg));
+    if (mask & 1) {
+       movr_d(r0, x0);
+       jit_unget_reg(t0);
+    }
+    if (mask & 2)
+       jit_unget_reg(t1);
+#  else
+    FPop1(r0, r1, op, rn(reg));
+#  endif
+    jit_unget_reg(reg);
+}
+
+static void
+_rfop1f(jit_state_t *_jit, jit_int32_t op,
+       jit_int32_t r0, jit_int32_t r1, jit_float32_t *i0)
+{
+    jit_int32_t                reg;
+#  if __WORDSIZE == 64
+    jit_int32_t                x0, t0, x1, t1, mask = 0;
+#  endif
+    reg = jit_get_reg(CLASS_SNG);
+    movi_f(rn(reg), i0);
+#  if __WORDSIZE == 64
+    if (!single_precision_p(r0)) {
+       mask |= 1;
+       t0 = jit_get_reg(CLASS_SNG);
+       x0 = rn(t0);
+       if (r0 == r1) {
+           x1 = x0;
+           movr_d(x1, r1);
+       }
+    }
+    else
+       x0 = r0;
+    if (!single_precision_p(r1)) {
+       if (r0 != r1) {
+           mask |= 2;
+           t1 = jit_get_reg(CLASS_SNG);
+           x1 = rn(t1);
+           movr_d(x1, r1);
+       }
+    }
+    else
+       x1 = r1;
+    FPop1(x0, rn(reg), op, x1);
+    if (mask & 1) {
+       movr_d(r0, x0);
+       jit_unget_reg(t0);
+    }
+    if (mask & 2)
+       jit_unget_reg(t1);
+#  else
+    FPop1(r0, rn(reg), op, r1);
+#  endif
+    jit_unget_reg(reg);
+}
+
+static void
+_fop1d(jit_state_t *_jit, jit_int32_t op,
+       jit_int32_t r0, jit_int32_t r1, jit_float64_t *i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(CLASS_DBL);
+    movi_d(rn(reg), i0);
+    FPop1(r0, r1, op, rn(reg));
+    jit_unget_reg(reg);
+}
+
+static void
+_rfop1d(jit_state_t *_jit, jit_int32_t op,
+       jit_int32_t r0, jit_int32_t r1, jit_float64_t *i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(CLASS_DBL);
+    movi_d(rn(reg), i0);
+    FPop1(r0, rn(reg), op, r1);
+    jit_unget_reg(reg);
+}
+
+static void
+_extr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi(BIAS(-8), _FP_REGNO, r1);
+#  if __WORDSIZE == 32
+    ldxi_f(r0, _FP_REGNO, BIAS(-8));
+    FITOS(r0, r0);
+#  else
+    ldxi_d(r0, _FP_REGNO, BIAS(-8));
+    if (!single_precision_p(r0)) {
+       jit_int32_t     reg;
+       reg = jit_get_reg(CLASS_SNG);
+       movr_d(rn(reg), r0);
+       FXTOS(rn(reg), rn(reg));
+       movr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       FXTOS(r0, r0);
+#  endif
+}
+
+static void
+_truncr_f_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(CLASS_SNG);
+#  if __WORDSIZE == 64
+    if (!single_precision_p(r1)) {
+       movr_d(rn(reg), r1);
+       FSTOI(rn(reg), rn(reg));
+    }
+    else
+#  endif
+       FSTOI(r1, rn(reg));
+    stxi_f(BIAS(-8), _FP_REGNO, rn(reg));
+    ldxi_i(r0, _FP_REGNO, BIAS(-8));
+    jit_unget_reg(reg);
+}
+
+#  if __WORDSIZE == 64
+static void
+_truncr_f_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(CLASS_SNG);
+#  if __WORDSIZE == 64
+    if (!single_precision_p(r1)) {
+       movr_d(rn(reg), r1);
+       FSTOX(rn(reg), rn(reg));
+    }
+    else
+#  endif
+       FSTOX(r1, rn(reg));
+    stxi_d(BIAS(-8), _FP_REGNO, rn(reg));
+    ldxi_l(r0, _FP_REGNO, BIAS(-8));
+    jit_unget_reg(reg);
+}
+#  endif
+
+static void
+_fcr(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#  if __WORDSIZE == 64
+    jit_int32_t                x0, t0, x1, t1, mask = 0;
+    if (!single_precision_p(r1)) {
+       mask |= 1;
+       t0 = jit_get_reg(CLASS_SNG);
+       x0 = rn(t0);
+       movr_d(x0, r1);
+    }
+    else
+       x0 = r1;
+    if (r1 == r2)
+       x1 = x0;
+    else if (!single_precision_p(r2)) {
+       mask |= 2;
+       t1 = jit_get_reg(CLASS_SNG);
+       x1 = rn(t1);
+       movr_d(x1, r2);
+    }
+    else
+       x1 = r2;
+    FCMPS(x0, x1);
+    if (mask & 1)
+       jit_unget_reg(t0);
+    if (mask & 2)
+       jit_unget_reg(t1);
+#  else
+    FCMPS(r1, r2);
+#  endif
+    FBa(cc, 3);
+    movi(r0, 1);
+    movi(r0, 0);
+}
+
+static void
+_fcw(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_float32_t *i0)
+{
+    jit_int32_t                reg;
+#  if __WORDSIZE == 64
+    jit_int32_t                x0, t0, mask = 0;
+    if (!single_precision_p(r1)) {
+       mask |= 1;
+       t0 = jit_get_reg(CLASS_SNG);
+       x0 = rn(t0);
+       movr_d(x0, r1);
+    }
+    else
+       x0 = r1;
+#  endif
+    reg = jit_get_reg(CLASS_SNG);
+    movi_f(rn(reg), i0);
+#  if __WORDSIZE == 64
+    FCMPS(x0, rn(reg));
+    if (mask & 1)
+       jit_unget_reg(t0);
+#  else
+    FCMPS(r1, rn(reg));
+#  endif
+    jit_unget_reg(reg);
+    FBa(cc, 3);
+    movi(r0, 1);
+    movi(r0, 0);
+}
+
+static void
+_dcr(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    FCMPD(r1, r2);
+    FBa(cc, 3);
+    movi(r0, 1);
+    movi(r0, 0);
+}
+
+static void
+_dcw(jit_state_t *_jit, jit_int32_t cc,
+     jit_int32_t r0, jit_int32_t r1, jit_float64_t *i0)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(CLASS_DBL);
+    movi_d(rn(reg), i0);
+    FCMPD(r1, rn(reg));
+    jit_unget_reg(reg);
+    FBa(cc, 3);
+    movi(r0, 1);
+    movi(r0, 0);
+}
+
+#  if __WORDSIZE == 64
+static void
+_ldr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (!single_precision_p(r0)) {
+       reg = jit_get_reg(CLASS_SNG);
+       LDF(r1, 0, rn(reg));
+       movr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       LDF(r1, 0, r0);
+}
+#  endif
+
+static void
+_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 64
+       if (!single_precision_p(r0)) {
+           reg = jit_get_reg(CLASS_SNG);
+           LDFI(0, i0, rn(reg));
+           movr_d(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       else
+#  endif
+           LDFI(0, i0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (!single_precision_p(r0)) {
+       reg = jit_get_reg(CLASS_SNG);
+       LDF(r1, r2, rn(reg));
+       movr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else
+       LDF(r1, r2, r0);
+}
+#  endif
+
+static void
+_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 64
+       if (!single_precision_p(r0)) {
+           reg = jit_get_reg(CLASS_SNG);
+           LDFI(r1, i0, rn(reg));
+           movr_d(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       else
+#  endif
+           LDFI(r1, i0, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_f(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_str_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (!single_precision_p(r1)) {
+       reg = jit_get_reg(CLASS_SNG);
+       movr_d(rn(reg), r1);
+       STF(rn(reg), r0, 0);
+       jit_unget_reg(reg);
+    }
+    else
+       STF(r1, r0, 0);
+}
+# endif
+
+static void
+_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 64
+       if (!single_precision_p(r0)) {
+           reg = jit_get_reg(CLASS_SNG);
+           movr_d(rn(reg), r0);
+           STFI(rn(reg), 0, i0);
+           jit_unget_reg(reg);
+       }
+       else
+#  endif
+           STFI(r0, 0, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_f(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+#  if __WORDSIZE == 64
+static void
+_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (!single_precision_p(r2)) {
+       reg = jit_get_reg(CLASS_SNG);
+       movr_d(rn(reg), r2);
+       STF(rn(reg), r1, r0);
+       jit_unget_reg(reg);
+    }
+    else
+       STF(r2, r1, r0);
+}
+# endif
+
+static void
+_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0)) {
+#  if __WORDSIZE == 64
+       if (!single_precision_p(r1)) {
+           reg = jit_get_reg(CLASS_SNG);
+           movr_d(rn(reg), r1);
+           STFI(rn(reg), r0, i0);
+           jit_unget_reg(reg);
+       }
+       else
+#  endif
+           STFI(r1, r0, i0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_f(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_extr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi(BIAS(-8), _FP_REGNO, r1);
+#  if __WORDSIZE == 32
+    stxi(BIAS(-4), _FP_REGNO, 0);
+#  endif
+    ldxi_d(r0, _FP_REGNO, BIAS(-8));
+#  if __WORDSIZE == 32
+    FITOD(r0, r0);
+#  else
+    FXTOD(r0, r0);
+#  endif
+}
+
+static void
+_truncr_d_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(CLASS_SNG);
+#  if __WORDSIZE == 64
+    if (!single_precision_p(r1)) {
+       movr_d(rn(reg), r1);
+       FDTOI(rn(reg), rn(reg));
+    }
+    else
+#  endif
+       FDTOI(r1, rn(reg));
+    stxi_d(BIAS(-8), _FP_REGNO, rn(reg));
+    ldxi_i(r0, _FP_REGNO, BIAS(-8));
+    jit_unget_reg(reg);
+}
+
+#  if __WORDSIZE == 64
+static void
+_truncr_d_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    reg = jit_get_reg(CLASS_DBL);
+    FDTOX(r1, rn(reg));
+    stxi_d(BIAS(-8), _FP_REGNO, rn(reg));
+    ldxi_l(r0, _FP_REGNO, BIAS(-8));
+    jit_unget_reg(reg);
+}
+#  endif
+
+static void
+_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDDFI(0, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t i0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       LDDFI(r1, i0, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_d(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       STDFI(r0, 0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_d(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxi_d(jit_state_t *_jit, jit_int32_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (s13_p(i0))
+       STDFI(r1, r0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_d(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_fbr(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0,jit_int32_t r1)
+{
+#  if __WORDSIZE == 64
+    jit_int32_t                x0, t0, x1, t1, mask = 0;
+#  endif
+    jit_word_t         w;
+#  if __WORDSIZE == 64
+    if (!single_precision_p(r0)) {
+       mask |= 1;
+       t0 = jit_get_reg(CLASS_SNG);
+       x0 = rn(t0);
+       movr_d(x0, r0);
+    }
+    else
+       x0 = r0;
+    if (r0 == r1)
+       x1 = x0;
+    else if (!single_precision_p(r1)) {
+       mask |= 2;
+       t1 = jit_get_reg(CLASS_SNG);
+       x1 = rn(t1);
+       movr_d(x1, r1);
+    }
+    else
+       x1 = r1;
+    FCMPS(x0, x1);
+    if (mask & 1)
+       jit_unget_reg(t0);
+    if (mask & 2)
+       jit_unget_reg(t1);
+#  else
+    FCMPS(r0, r1);
+#  endif
+    w = _jit->pc.w;
+    FB(cc, (i0 - w) >> 2);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_fbw(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_float32_t *i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+#  if __WORDSIZE == 64
+    jit_int32_t                x0, t0, mask = 0;
+    if (!single_precision_p(r0)) {
+       mask |= 1;
+       t0 = jit_get_reg(CLASS_SNG);
+       x0 = rn(t0);
+       movr_d(x0, r0);
+    }
+    else
+       x0 = r0;
+#  endif
+    reg = jit_get_reg(CLASS_SNG);
+    movi_f(rn(reg), i1);
+#  if __WORDSIZE == 64
+    FCMPS(x0, rn(reg));
+    if (mask & 1)
+       jit_unget_reg(t0);
+#  else
+    FCMPS(r0, rn(reg));
+#  endif
+    jit_unget_reg(reg);
+    w = _jit->pc.w;
+    FB(cc, (i0 - w) >> 2);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_dbr(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         w;
+    FCMPD(r0, r1);
+    w = _jit->pc.w;
+    FB(cc, (i0 - w) >> 2);
+    NOP();
+    return (w);
+}
+
+static jit_word_t
+_dbw(jit_state_t *_jit, jit_int32_t cc,
+     jit_word_t i0, jit_int32_t r0, jit_float64_t *i1)
+{
+    jit_word_t         w;
+    jit_int32_t                reg;
+    reg = jit_get_reg(CLASS_DBL);
+    movi_d(rn(reg), i1);
+    FCMPD(r0, rn(reg));
+    jit_unget_reg(reg);
+    w = _jit->pc.w;
+    FB(cc, (i0 - w) >> 2);
+    NOP();
+    return (w);
+}
+
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Load argument. */
+    ldr_d(r0, r1);
+
+    /* Update vararg stack pointer. */
+    addi(r1, r1, 8);
+}
+#endif
diff --git a/deps/lightning/lib/jit_sparc-sz.c b/deps/lightning/lib/jit_sparc-sz.c
new file mode 100644 (file)
index 0000000..ac683b6
--- /dev/null
@@ -0,0 +1,803 @@
+#if __WORDSIZE == 32
+#define JIT_INSTR_MAX 44
+    0, /* data */
+    0, /* live */
+    0, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    0, /* label */
+    36,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    4, /* va_start */
+    8, /* va_arg */
+    8, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    12,        /* addi */
+    4, /* addcr */
+    12,        /* addci */
+    4, /* addxr */
+    4, /* addxi */
+    4, /* subr */
+    12,        /* subi */
+    4, /* subcr */
+    12,        /* subci */
+    4, /* subxr */
+    4, /* subxi */
+    16,        /* rsbi */
+    4, /* mulr */
+    12,        /* muli */
+    8, /* qmulr */
+    16,        /* qmuli */
+    8, /* qmulr_u */
+    16,        /* qmuli_u */
+    12,        /* divr */
+    20,        /* divi */
+    8, /* divr_u */
+    16,        /* divi_u */
+    28,        /* qdivr */
+    24,        /* qdivi */
+    24,        /* qdivr_u */
+    20,        /* qdivi_u */
+    20,        /* remr */
+    28,        /* remi */
+    16,        /* remr_u */
+    24,        /* remi_u */
+    4, /* andr */
+    12,        /* andi */
+    4, /* orr */
+    12,        /* ori */
+    4, /* xorr */
+    12,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    16,        /* ltr */
+    16,        /* lti */
+    16,        /* ltr_u */
+    16,        /* lti_u */
+    16,        /* ler */
+    16,        /* lei */
+    16,        /* ler_u */
+    16,        /* lei_u */
+    16,        /* eqr */
+    16,        /* eqi */
+    16,        /* ger */
+    16,        /* gei */
+    16,        /* ger_u */
+    16,        /* gei_u */
+    16,        /* gtr */
+    16,        /* gti */
+    16,        /* gtr_u */
+    16,        /* gti_u */
+    16,        /* ner */
+    16,        /* nei */
+    4, /* movr */
+    8, /* movi */
+    8, /* extr_c */
+    4, /* extr_uc */
+    8, /* extr_s */
+    8, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    8, /* htonr_us */
+    4, /* htonr_ui */
+    0, /* htonr_ul */
+    4, /* ldr_c */
+    12,        /* ldi_c */
+    4, /* ldr_uc */
+    12,        /* ldi_uc */
+    4, /* ldr_s */
+    12,        /* ldi_s */
+    4, /* ldr_us */
+    12,        /* ldi_us */
+    4, /* ldr_i */
+    12,        /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    4, /* ldxr_c */
+    8, /* ldxi_c */
+    4, /* ldxr_uc */
+    8, /* ldxi_uc */
+    4, /* ldxr_s */
+    8, /* ldxi_s */
+    4, /* ldxr_us */
+    8, /* ldxi_us */
+    4, /* ldxr_i */
+    8, /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    4, /* str_c */
+    12,        /* sti_c */
+    4, /* str_s */
+    12,        /* sti_s */
+    4, /* str_i */
+    12,        /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    4, /* stxr_c */
+    8, /* stxi_c */
+    4, /* stxr_s */
+    8, /* stxi_s */
+    4, /* stxr_i */
+    8, /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    12,        /* bltr */
+    12,        /* blti */
+    12,        /* bltr_u */
+    12,        /* blti_u */
+    12,        /* bler */
+    12,        /* blei */
+    12,        /* bler_u */
+    12,        /* blei_u */
+    12,        /* beqr */
+    20,        /* beqi */
+    12,        /* bger */
+    12,        /* bgei */
+    12,        /* bger_u */
+    12,        /* bgei_u */
+    12,        /* bgtr */
+    12,        /* bgti */
+    12,        /* bgtr_u */
+    12,        /* bgti_u */
+    12,        /* bner */
+    20,        /* bnei */
+    12,        /* bmsr */
+    12,        /* bmsi */
+    12,        /* bmcr */
+    12,        /* bmci */
+    12,        /* boaddr */
+    12,        /* boaddi */
+    12,        /* boaddr_u */
+    12,        /* boaddi_u */
+    12,        /* bxaddr */
+    12,        /* bxaddi */
+    12,        /* bxaddr_u */
+    12,        /* bxaddi_u */
+    12,        /* bosubr */
+    12,        /* bosubi */
+    12,        /* bosubr_u */
+    12,        /* bosubi_u */
+    12,        /* bxsubr */
+    12,        /* bxsubi */
+    12,        /* bxsubr_u */
+    12,        /* bxsubi_u */
+    8, /* jmpr */
+    16,        /* jmpi */
+    8, /* callr */
+    16,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    44,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    4, /* addr_f */
+    16,        /* addi_f */
+    4, /* subr_f */
+    16,        /* subi_f */
+    16,        /* rsbi_f */
+    4, /* mulr_f */
+    16,        /* muli_f */
+    4, /* divr_f */
+    16,        /* divi_f */
+    4, /* negr_f */
+    4, /* absr_f */
+    4, /* sqrtr_f */
+    16,        /* ltr_f */
+    32,        /* lti_f */
+    16,        /* ler_f */
+    32,        /* lei_f */
+    16,        /* eqr_f */
+    32,        /* eqi_f */
+    16,        /* ger_f */
+    32,        /* gei_f */
+    16,        /* gtr_f */
+    32,        /* gti_f */
+    16,        /* ner_f */
+    32,        /* nei_f */
+    16,        /* unltr_f */
+    32,        /* unlti_f */
+    16,        /* unler_f */
+    32,        /* unlei_f */
+    16,        /* uneqr_f */
+    32,        /* uneqi_f */
+    16,        /* unger_f */
+    32,        /* ungei_f */
+    16,        /* ungtr_f */
+    32,        /* ungti_f */
+    16,        /* ltgtr_f */
+    32,        /* ltgti_f */
+    16,        /* ordr_f */
+    32,        /* ordi_f */
+    16,        /* unordr_f */
+    32,        /* unordi_f */
+    12,        /* truncr_f_i */
+    0, /* truncr_f_l */
+    12,        /* extr_f */
+    4, /* extr_d_f */
+    4, /* movr_f */
+    16,        /* movi_f */
+    4, /* ldr_f */
+    12,        /* ldi_f */
+    4, /* ldxr_f */
+    8, /* ldxi_f */
+    4, /* str_f */
+    12,        /* sti_f */
+    4, /* stxr_f */
+    8, /* stxi_f */
+    12,        /* bltr_f */
+    24,        /* blti_f */
+    12,        /* bler_f */
+    24,        /* blei_f */
+    12,        /* beqr_f */
+    24,        /* beqi_f */
+    12,        /* bger_f */
+    24,        /* bgei_f */
+    12,        /* bgtr_f */
+    24,        /* bgti_f */
+    12,        /* bner_f */
+    28,        /* bnei_f */
+    12,        /* bunltr_f */
+    28,        /* bunlti_f */
+    12,        /* bunler_f */
+    28,        /* bunlei_f */
+    12,        /* buneqr_f */
+    28,        /* buneqi_f */
+    12,        /* bunger_f */
+    28,        /* bungei_f */
+    12,        /* bungtr_f */
+    28,        /* bungti_f */
+    12,        /* bltgtr_f */
+    24,        /* bltgti_f */
+    12,        /* bordr_f */
+    24,        /* bordi_f */
+    12,        /* bunordr_f */
+    28,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    24,        /* addi_d */
+    4, /* subr_d */
+    24,        /* subi_d */
+    24,        /* rsbi_d */
+    4, /* mulr_d */
+    24,        /* muli_d */
+    4, /* divr_d */
+    24,        /* divi_d */
+    8, /* negr_d */
+    8, /* absr_d */
+    4, /* sqrtr_d */
+    16,        /* ltr_d */
+    40,        /* lti_d */
+    16,        /* ler_d */
+    40,        /* lei_d */
+    16,        /* eqr_d */
+    40,        /* eqi_d */
+    16,        /* ger_d */
+    40,        /* gei_d */
+    16,        /* gtr_d */
+    40,        /* gti_d */
+    16,        /* ner_d */
+    40,        /* nei_d */
+    16,        /* unltr_d */
+    40,        /* unlti_d */
+    16,        /* unler_d */
+    40,        /* unlei_d */
+    16,        /* uneqr_d */
+    40,        /* uneqi_d */
+    16,        /* unger_d */
+    40,        /* ungei_d */
+    16,        /* ungtr_d */
+    40,        /* ungti_d */
+    16,        /* ltgtr_d */
+    40,        /* ltgti_d */
+    16,        /* ordr_d */
+    40,        /* ordi_d */
+    16,        /* unordr_d */
+    40,        /* unordi_d */
+    12,        /* truncr_d_i */
+    0, /* truncr_d_l */
+    16,        /* extr_d */
+    4, /* extr_f_d */
+    8, /* movr_d */
+    24,        /* movi_d */
+    4, /* ldr_d */
+    12,        /* ldi_d */
+    4, /* ldxr_d */
+    8, /* ldxi_d */
+    4, /* str_d */
+    12,        /* sti_d */
+    4, /* stxr_d */
+    8, /* stxi_d */
+    12,        /* bltr_d */
+    32,        /* blti_d */
+    12,        /* bler_d */
+    32,        /* blei_d */
+    12,        /* beqr_d */
+    32,        /* beqi_d */
+    12,        /* bger_d */
+    32,        /* bgei_d */
+    12,        /* bgtr_d */
+    32,        /* bgti_d */
+    12,        /* bner_d */
+    36,        /* bnei_d */
+    12,        /* bunltr_d */
+    36,        /* bunlti_d */
+    12,        /* bunler_d */
+    36,        /* bunlei_d */
+    12,        /* buneqr_d */
+    36,        /* buneqi_d */
+    12,        /* bunger_d */
+    36,        /* bungei_d */
+    12,        /* bungtr_d */
+    36,        /* bungti_d */
+    12,        /* bltgtr_d */
+    32,        /* bltgti_d */
+    12,        /* bordr_d */
+    32,        /* bordi_d */
+    12,        /* bunordr_d */
+    36,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __WORDSIZE */
+
+#if __WORDSIZE == 64
+#define JIT_INSTR_MAX 64
+    0, /* data */
+    0, /* live */
+    4, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    4, /* label */
+    36,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    4, /* va_start */
+    8, /* va_arg */
+    8, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    28,        /* addi */
+    24,        /* addcr */
+    48,        /* addci */
+    52,        /* addxr */
+    52,        /* addxi */
+    4, /* subr */
+    28,        /* subi */
+    24,        /* subcr */
+    48,        /* subci */
+    52,        /* subxr */
+    52,        /* subxi */
+    32,        /* rsbi */
+    4, /* mulr */
+    28,        /* muli */
+    48,        /* qmulr */
+    64,        /* qmuli */
+    48,        /* qmulr_u */
+    64,        /* qmuli_u */
+    4, /* divr */
+    28,        /* divi */
+    4, /* divr_u */
+    28,        /* divi_u */
+    20,        /* qdivr */
+    16,        /* qdivi */
+    20,        /* qdivr_u */
+    16,        /* qdivi_u */
+    12,        /* remr */
+    36,        /* remi */
+    12,        /* remr_u */
+    36,        /* remi_u */
+    4, /* andr */
+    28,        /* andi */
+    4, /* orr */
+    28,        /* ori */
+    4, /* xorr */
+    28,        /* xori */
+    4, /* lshr */
+    4, /* lshi */
+    4, /* rshr */
+    4, /* rshi */
+    4, /* rshr_u */
+    4, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    16,        /* ltr */
+    16,        /* lti */
+    16,        /* ltr_u */
+    16,        /* lti_u */
+    16,        /* ler */
+    16,        /* lei */
+    16,        /* ler_u */
+    16,        /* lei_u */
+    16,        /* eqr */
+    16,        /* eqi */
+    16,        /* ger */
+    16,        /* gei */
+    16,        /* ger_u */
+    16,        /* gei_u */
+    16,        /* gtr */
+    16,        /* gti */
+    16,        /* gtr_u */
+    16,        /* gti_u */
+    16,        /* ner */
+    16,        /* nei */
+    4, /* movr */
+    24,        /* movi */
+    8, /* extr_c */
+    4, /* extr_uc */
+    8, /* extr_s */
+    8, /* extr_us */
+    8, /* extr_i */
+    8, /* extr_ui */
+    8, /* htonr_us */
+    8, /* htonr_ui */
+    4, /* htonr_ul */
+    4, /* ldr_c */
+    28,        /* ldi_c */
+    4, /* ldr_uc */
+    28,        /* ldi_uc */
+    4, /* ldr_s */
+    28,        /* ldi_s */
+    4, /* ldr_us */
+    28,        /* ldi_us */
+    4, /* ldr_i */
+    28,        /* ldi_i */
+    4, /* ldr_ui */
+    28,        /* ldi_ui */
+    4, /* ldr_l */
+    28,        /* ldi_l */
+    4, /* ldxr_c */
+    24,        /* ldxi_c */
+    4, /* ldxr_uc */
+    24,        /* ldxi_uc */
+    4, /* ldxr_s */
+    24,        /* ldxi_s */
+    4, /* ldxr_us */
+    24,        /* ldxi_us */
+    4, /* ldxr_i */
+    24,        /* ldxi_i */
+    4, /* ldxr_ui */
+    24,        /* ldxi_ui */
+    4, /* ldxr_l */
+    24,        /* ldxi_l */
+    4, /* str_c */
+    28,        /* sti_c */
+    4, /* str_s */
+    28,        /* sti_s */
+    4, /* str_i */
+    28,        /* sti_i */
+    4, /* str_l */
+    28,        /* sti_l */
+    4, /* stxr_c */
+    24,        /* stxi_c */
+    4, /* stxr_s */
+    24,        /* stxi_s */
+    4, /* stxr_i */
+    24,        /* stxi_i */
+    4, /* stxr_l */
+    24,        /* stxi_l */
+    12,        /* bltr */
+    12,        /* blti */
+    12,        /* bltr_u */
+    12,        /* blti_u */
+    12,        /* bler */
+    12,        /* blei */
+    12,        /* bler_u */
+    12,        /* blei_u */
+    12,        /* beqr */
+    36,        /* beqi */
+    12,        /* bger */
+    12,        /* bgei */
+    12,        /* bger_u */
+    12,        /* bgei_u */
+    12,        /* bgtr */
+    12,        /* bgti */
+    12,        /* bgtr_u */
+    12,        /* bgti_u */
+    12,        /* bner */
+    36,        /* bnei */
+    12,        /* bmsr */
+    12,        /* bmsi */
+    12,        /* bmcr */
+    12,        /* bmci */
+    12,        /* boaddr */
+    12,        /* boaddi */
+    12,        /* boaddr_u */
+    12,        /* boaddi_u */
+    12,        /* bxaddr */
+    12,        /* bxaddi */
+    12,        /* bxaddr_u */
+    12,        /* bxaddi_u */
+    12,        /* bosubr */
+    12,        /* bosubi */
+    12,        /* bosubr_u */
+    12,        /* bosubi_u */
+    12,        /* bxsubr */
+    12,        /* bxsubi */
+    12,        /* bxsubr_u */
+    12,        /* bxsubi_u */
+    8, /* jmpr */
+    32,        /* jmpi */
+    8, /* callr */
+    32,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    44,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    16,        /* addr_f */
+    40,        /* addi_f */
+    24,        /* subr_f */
+    40,        /* subi_f */
+    40,        /* rsbi_f */
+    16,        /* mulr_f */
+    40,        /* muli_f */
+    16,        /* divr_f */
+    40,        /* divi_f */
+    12,        /* negr_f */
+    12,        /* absr_f */
+    12,        /* sqrtr_f */
+    24,        /* ltr_f */
+    48,        /* lti_f */
+    24,        /* ler_f */
+    48,        /* lei_f */
+    24,        /* eqr_f */
+    48,        /* eqi_f */
+    24,        /* ger_f */
+    48,        /* gei_f */
+    24,        /* gtr_f */
+    48,        /* gti_f */
+    24,        /* ner_f */
+    48,        /* nei_f */
+    24,        /* unltr_f */
+    48,        /* unlti_f */
+    24,        /* unler_f */
+    48,        /* unlei_f */
+    24,        /* uneqr_f */
+    48,        /* uneqi_f */
+    24,        /* unger_f */
+    48,        /* ungei_f */
+    24,        /* ungtr_f */
+    48,        /* ungti_f */
+    24,        /* ltgtr_f */
+    48,        /* ltgti_f */
+    24,        /* ordr_f */
+    48,        /* ordi_f */
+    24,        /* unordr_f */
+    48,        /* unordi_f */
+    16,        /* truncr_f_i */
+    16,        /* truncr_f_l */
+    20,        /* extr_f */
+    12,        /* extr_d_f */
+    16,        /* movr_f */
+    32,        /* movi_f */
+    8, /* ldr_f */
+    32,        /* ldi_f */
+    8, /* ldxr_f */
+    28,        /* ldxi_f */
+    8, /* str_f */
+    32,        /* sti_f */
+    8, /* stxr_f */
+    28,        /* stxi_f */
+    20,        /* bltr_f */
+    44,        /* blti_f */
+    20,        /* bler_f */
+    44,        /* blei_f */
+    28,        /* beqr_f */
+    60,        /* beqi_f */
+    20,        /* bger_f */
+    44,        /* bgei_f */
+    20,        /* bgtr_f */
+    44,        /* bgti_f */
+    20,        /* bner_f */
+    44,        /* bnei_f */
+    20,        /* bunltr_f */
+    44,        /* bunlti_f */
+    20,        /* bunler_f */
+    44,        /* bunlei_f */
+    20,        /* buneqr_f */
+    44,        /* buneqi_f */
+    20,        /* bunger_f */
+    44,        /* bungei_f */
+    20,        /* bungtr_f */
+    44,        /* bungti_f */
+    20,        /* bltgtr_f */
+    44,        /* bltgti_f */
+    20,        /* bordr_f */
+    44,        /* bordi_f */
+    20,        /* bunordr_f */
+    44,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    4, /* addr_d */
+    32,        /* addi_d */
+    4, /* subr_d */
+    32,        /* subi_d */
+    32,        /* rsbi_d */
+    4, /* mulr_d */
+    32,        /* muli_d */
+    4, /* divr_d */
+    32,        /* divi_d */
+    4, /* negr_d */
+    4, /* absr_d */
+    4, /* sqrtr_d */
+    16,        /* ltr_d */
+    48,        /* lti_d */
+    16,        /* ler_d */
+    48,        /* lei_d */
+    16,        /* eqr_d */
+    48,        /* eqi_d */
+    16,        /* ger_d */
+    48,        /* gei_d */
+    16,        /* gtr_d */
+    48,        /* gti_d */
+    16,        /* ner_d */
+    48,        /* nei_d */
+    16,        /* unltr_d */
+    48,        /* unlti_d */
+    16,        /* unler_d */
+    48,        /* unlei_d */
+    16,        /* uneqr_d */
+    48,        /* uneqi_d */
+    16,        /* unger_d */
+    48,        /* ungei_d */
+    16,        /* ungtr_d */
+    48,        /* ungti_d */
+    16,        /* ltgtr_d */
+    48,        /* ltgti_d */
+    16,        /* ordr_d */
+    48,        /* ordi_d */
+    16,        /* unordr_d */
+    48,        /* unordi_d */
+    16,        /* truncr_d_i */
+    12,        /* truncr_d_l */
+    12,        /* extr_d */
+    8, /* extr_f_d */
+    4, /* movr_d */
+    32,        /* movi_d */
+    4, /* ldr_d */
+    28,        /* ldi_d */
+    4, /* ldxr_d */
+    24,        /* ldxi_d */
+    4, /* str_d */
+    28,        /* sti_d */
+    4, /* stxr_d */
+    24,        /* stxi_d */
+    12,        /* bltr_d */
+    40,        /* blti_d */
+    12,        /* bler_d */
+    40,        /* blei_d */
+    12,        /* beqr_d */
+    40,        /* beqi_d */
+    12,        /* bger_d */
+    40,        /* bgei_d */
+    12,        /* bgtr_d */
+    40,        /* bgti_d */
+    12,        /* bner_d */
+    44,        /* bnei_d */
+    12,        /* bunltr_d */
+    44,        /* bunlti_d */
+    12,        /* bunler_d */
+    44,        /* bunlei_d */
+    12,        /* buneqr_d */
+    44,        /* buneqi_d */
+    12,        /* bunger_d */
+    44,        /* bungei_d */
+    12,        /* bungtr_d */
+    44,        /* bungti_d */
+    12,        /* bltgtr_d */
+    40,        /* bltgti_d */
+    12,        /* bordr_d */
+    40,        /* bordi_d */
+    12,        /* bunordr_d */
+    44,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __WORDSIZE */
diff --git a/deps/lightning/lib/jit_sparc.c b/deps/lightning/lib/jit_sparc.c
new file mode 100644 (file)
index 0000000..158c09d
--- /dev/null
@@ -0,0 +1,1924 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#define jit_arg_reg_p(i)               ((i) >= 0 && (i) < 6)
+#if __WORDSIZE == 32
+#  define jit_arg_d_reg_p(i)           ((i) >= 0 && (i) < 5)
+#  define BIAS(n)                      (n)
+#else
+#  define jit_arg_d_reg_p(i)           ((i) >= 0 && (i) < 16)
+#  define BIAS(n)                      ((n) + 2047)
+#endif
+
+/*
+ * Types
+ */
+typedef jit_pointer_t  jit_va_list_t;
+
+/*
+ * Prototypes
+ */
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+
+#define PROTO                          1
+#  include "jit_sparc-cpu.c"
+#  include "jit_sparc-fpu.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_register_t         _rvs[] = {
+    { 0x00,                            "%g0" },
+    { 0x01,                            "%g1" },
+    { rc(gpr) | 0x02,                  "%g2" },
+    { rc(gpr) | 0x03,                  "%g3" },
+    { rc(gpr) | 0x04,                  "%g4" },
+    { 0x05,                            "%g5" },
+    { 0x06,                            "%g6" },
+    { 0x07,                            "%g7" },
+    { rc(arg) | rc(gpr) | 0x08,                "%o0" },
+    { rc(arg) | rc(gpr) | 0x09,                "%o1" },
+    { rc(arg) | rc(gpr) | 0x0a,                "%o2" },
+    { rc(arg) | rc(gpr) | 0x0b,                "%o3" },
+    { rc(arg) | rc(gpr) | 0x0c,                "%o4" },
+    { rc(arg) | rc(gpr) | 0x0d,                "%o5" },
+    { rc(sav) | 0x0e,                  "%sp" },
+    { 0x0f,                            "%o7" },
+    { rc(sav) | rc(gpr) | 0x10,                "%l0" },
+    { rc(sav) | rc(gpr) | 0x11,                "%l1" },
+    { rc(sav) | rc(gpr) | 0x12,                "%l2" },
+    { rc(sav) | rc(gpr) | 0x13,                "%l3" },
+    { rc(sav) | rc(gpr) | 0x14,                "%l4" },
+    { rc(sav) | rc(gpr) | 0x15,                "%l5" },
+    { rc(sav) | rc(gpr) | 0x16,                "%l6" },
+    { rc(sav) | rc(gpr) | 0x17,                "%l7" },
+    { 0x18,                            "%i0" },
+    { 0x19,                            "%i1" },
+    { 0x1a,                            "%i2" },
+    { 0x1b,                            "%i3" },
+    { 0x1c,                            "%i4" },
+    { 0x1d,                            "%i5" },
+    { rc(sav) | 0x1e,                  "%fp" },
+    { 0x1f,                            "%i7" },
+#  if __WORDSIZE == 32
+    { rc(fpr) | 0x00,                  "%f0" },
+    { 0x01,                            "%f1" },
+    { rc(fpr) | 0x02,                  "%f2" },
+    { 0x03,                            "%f3" },
+    { rc(fpr) | 0x04,                  "%f4" },
+    { 0x05,                            "%f5" },
+    { rc(fpr) | 0x06,                  "%f6" },
+    { 0x07,                            "%f7" },
+    { rc(fpr) | 0x08,                  "%f8" },
+    { 0x09,                            "%f9" },
+    { rc(fpr) | 0x0a,                  "%f10" },
+    { 0x0b,                            "%f11" },
+    { rc(fpr) | 0x0c,                  "%f12" },
+    { 0x0d,                            "%f13" },
+    { rc(fpr) | 0x0e,                  "%f14" },
+    { 0x0f,                            "%f15" },
+#  else
+    { rc(fpr) | rc(dbl) | 0x3e,                "%f62" },
+    { rc(fpr) | rc(dbl) | 0x3c,                "%f60" },
+    { rc(fpr) | rc(dbl) | 0x3a,                "%f58" },
+    { rc(fpr) | rc(dbl) | 0x38,                "%f56" },
+    { rc(fpr) | rc(dbl) | 0x36,                "%f54" },
+    { rc(fpr) | rc(dbl) | 0x34,                "%f52" },
+    { rc(fpr) | rc(dbl) | 0x32,                "%f50" },
+    { rc(fpr) | rc(dbl) | 0x30,                "%f48" },
+    { rc(fpr) | rc(dbl) | 0x2e,                "%f46" },
+    { rc(fpr) | rc(dbl) | 0x2c,                "%f44" },
+    { rc(fpr) | rc(dbl) | 0x2a,                "%f42" },
+    { rc(fpr) | rc(dbl) | 0x28,                "%f40" },
+    { rc(fpr) | rc(dbl) | 0x26,                "%f38" },
+    { rc(fpr) | rc(dbl) | 0x24,                "%f36" },
+    { rc(fpr) | rc(dbl) | 0x22,                "%f34" },
+    { rc(fpr) | rc(dbl) | 0x20,                "%f32" },
+    { 0x1f,                            "%f31" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x1e,    "%f30" },
+    { 0x1d,                            "%f29" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x1c,    "%f28" },
+    { 0x1b,                            "%f27" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x1a,    "%f26" },
+    { 0x19,                            "%f25" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x18,    "%f24" },
+    { 0x17,                            "%f23" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x16,    "%f22" },
+    { 0x15,                            "%f21" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x14,    "%f20" },
+    { 0x13,                            "%f19" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x12,    "%f18" },
+    { 0x11,                            "%f17" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x10,    "%f16" },
+    { 0x0f,                            "%f15" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x0e,    "%f14" },
+    { 0x0d,                            "%f13" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x0c,    "%f12" },
+    { 0x0b,                            "%f11" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x0a,    "%f10" },
+    { 0x09,                            "%f9" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x08,    "%f8" },
+    { 0x07,                            "%f7" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x06,    "%f6" },
+    { 0x05,                            "%f5" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x04,    "%f4" },
+    { 0x03,                            "%f3" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x02,    "%f2" },
+    { 0x01,                            "%f1" },
+    { rc(arg)|rc(fpr)|rc(sng)|0x00,    "%f0" },
+#  endif
+    { _NOREG,                          "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+    _jitc->reglen = jit_size(_rvs) - 1;
+#  if __WORDSIZE == 64
+    jit_carry = _NOREG;
+#  endif
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                 offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = stack_framesize;
+    _jitc->function->self.argi = _jitc->function->self.argf =
+       _jitc->function->self.aoff = _jitc->function->self.alen = 0;
+    /* float conversion */
+#  if __WORDSIZE == 32
+    _jitc->function->self.aoff = -8;
+#  else
+    /* extra slots in case qmul is called */
+    _jitc->function->self.aoff = -24;
+#  endif
+     _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+    return (BIAS(_jitc->function->self.aoff));
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 reg;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    jit_negr(reg, v);
+    jit_andi(reg, reg, -16);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, reg);
+    jit_addr(_SP, _SP, reg);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(reg);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    if (JIT_RET != u)
+       jit_movr(JIT_RET, u);
+    jit_live(JIT_RET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    if (JIT_FRET != u)
+       jit_movr_f(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    if (JIT_FRET != u)
+       jit_movr_d(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+#  if __WORDSIZE == 32
+    if (u->code == jit_code_arg || u->code == jit_code_arg_f)
+       return (jit_arg_reg_p(u->u.w));
+    assert(u->code == jit_code_arg_d);
+    return (jit_arg_d_reg_p(u->u.w));
+#  else
+    if (u->code == jit_code_arg)
+       return (jit_arg_reg_p(u->u.w));
+    assert(u->code == jit_code_arg_d || u->code == jit_code_arg_f);
+    return (jit_arg_d_reg_p(u->u.w));
+#  endif
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare) {
+       jit_link_prepare();
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+    }
+    else {
+       jit_link_prolog();
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+
+       _jitc->function->vagp = _jitc->function->self.argi;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+#  if __WORDSIZE == 64
+       if (jit_arg_d_reg_p(_jitc->function->self.argi))
+           ++_jitc->function->self.argi;
+#   endif
+       offset = BIAS(_jitc->function->self.size);
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+    node = jit_new_node_ww(jit_code_arg, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+#  if __WORDSIZE == 64
+    jit_bool_t          inc;
+#  endif
+    assert(_jitc->function);
+#  if __WORDSIZE == 32
+    if (jit_arg_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+#  else
+    inc = !jit_arg_reg_p(_jitc->function->self.argi);
+    if (jit_arg_d_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else
+       offset = BIAS(_jitc->function->self.size);
+    if (inc)
+       _jitc->function->self.size += sizeof(jit_word_t);
+#  endif
+    node = jit_new_node_ww(jit_code_arg_f, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+#  if __WORDSIZE == 64
+    jit_bool_t          inc;
+#  endif
+    assert(_jitc->function);
+#  if __WORDSIZE == 32
+    if (jit_arg_d_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi;
+       _jitc->function->self.argi += 2;
+    }
+    else if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi++;
+       _jitc->function->self.size += sizeof(jit_float32_t);
+    }
+    else {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_float64_t);
+    }
+#  else
+    inc = !jit_arg_reg_p(_jitc->function->self.argi);
+    if (jit_arg_d_reg_p(_jitc->function->self.argi))
+       offset = _jitc->function->self.argi++;
+    else
+       offset = BIAS(_jitc->function->self.size);
+    if (inc)
+       _jitc->function->self.size += sizeof(jit_word_t);
+#  endif
+    node = jit_new_node_ww(jit_code_arg_d, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, _I0 + v->u.w);
+    else
+       jit_ldxi_c(u, JIT_FP,
+                  v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int8_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, _I0 + v->u.w);
+    else
+       jit_ldxi_uc(u, JIT_FP,
+                   v->u.w + (__WORDSIZE >> 3) - sizeof(jit_uint8_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, _I0 + v->u.w);
+    else
+       jit_ldxi_s(u, JIT_FP,
+                  v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int16_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, _I0 + v->u.w);
+    else
+       jit_ldxi_us(u, JIT_FP,
+                   v->u.w + (__WORDSIZE >> 3) - sizeof(jit_uint16_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w)) {
+#  if __WORDSIZE == 64
+       jit_extr_i(u, _I0 + v->u.w);
+#  else
+       jit_movr(u, _I0 + v->u.w);
+#  endif
+    }
+    else
+       jit_ldxi_i(u, JIT_FP,
+                  v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int32_t));
+    jit_dec_synth();
+}
+
+#  if __WORDSIZE == 64
+void
+_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_ui(u, _I0 + v->u.w);
+    else
+       jit_ldxi_ui(u, JIT_FP,
+                   v->u.w + (__WORDSIZE >> 3) - sizeof(jit_int32_t));
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, _I0 + v->u.w);
+    else
+       jit_ldxi_l(u, JIT_FP, v->u.w);
+    jit_dec_synth();
+}
+#  endif
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(_I0 + v->u.w, u);
+    else
+       jit_stxi(v->u.w, JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi(_I0 + v->u.w, u);
+    else {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    assert(_jitc->function);
+    jit_inc_synth_wp(getarg_f, u, v);
+#  if __WORDSIZE == 32
+    if (jit_arg_reg_p(v->u.w)) {
+       jit_stxi_i(-4, JIT_FP, _I0 + v->u.w);
+       jit_ldxi_f(u, JIT_FP, -4);
+    }
+#  else
+    if (jit_arg_d_reg_p(v->u.w)) {
+       jit_live(_F0 - (v->u.w << 1));  /* pair of registers is live */
+       jit_movr_f(u, (_F0 - (v->u.w << 1)) - 1);
+    }
+#  endif
+    else
+       jit_ldxi_f(u, JIT_FP, v->u.w + (__WORDSIZE >> 3) -
+                  sizeof(jit_float32_t));
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+#  if __WORDSIZE == 32
+    if (jit_arg_reg_p(v->u.w)) {
+       jit_stxi_f(-4, JIT_FP, u);
+       jit_ldxi_i(_I0 + v->u.w, JIT_FP, -4);
+    }
+#  else
+    if (jit_arg_d_reg_p(v->u.w)) {
+       jit_live(_F0 - (v->u.w << 1));  /* pair of registers is live */
+       jit_movr_f((_F0 - (v->u.w << 1)) - 1, u);
+    }
+#  endif
+    else
+       jit_stxi_f(v->u.w + (__WORDSIZE >> 3) -
+                  sizeof(jit_float32_t), JIT_FP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+#  if __WORDSIZE == 32
+    regno = jit_get_reg(jit_class_fpr);
+    jit_movi_f(regno, u);
+    if (jit_arg_reg_p(v->u.w)) {
+       jit_stxi_f(-4, JIT_FP, regno);
+       jit_ldxi_i(_I0 + v->u.w, JIT_FP, -4);
+    }
+    else
+       jit_stxi_f(v->u.w, JIT_FP, regno);
+    jit_unget_reg(regno);
+#  else
+    if (jit_arg_d_reg_p(v->u.w)) {
+       jit_live(_F0 - (v->u.w << 1));  /* pair of registers is live */
+       jit_movi_f((_F0 - (v->u.w << 1)) - 1, u);
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr | jit_class_sng);
+       jit_movi_f(regno, u);
+       jit_stxi_f(v->u.w + (__WORDSIZE >> 3) -
+                  sizeof(jit_float32_t), JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+#  endif
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    assert(_jitc->function);
+    jit_inc_synth_wp(getarg_d, u, v);
+    if (jit_arg_d_reg_p(v->u.w)) {
+#  if __WORDSIZE == 32
+       jit_stxi(-8, JIT_FP, _I0 + v->u.w);
+       jit_stxi(-4, JIT_FP, _I0 + v->u.w + 1);
+       jit_ldxi_d(u, JIT_FP, -8);
+#  else
+       jit_movr_d(u, _F0 - (v->u.w << 1));
+#  endif
+    }
+#  if __WORDSIZE == 32
+    else if (jit_arg_reg_p(v->u.w)) {
+       jit_stxi(-8, JIT_FP, _I0 + v->u.w);
+       jit_ldxi_f(u, JIT_FP, -8);
+       jit_ldxi_f(u + 1, JIT_FP, stack_framesize);
+    }
+#  endif
+    else {
+#  if __WORDSIZE == 32
+       jit_ldxi_f(u, JIT_FP, v->u.w);
+       jit_ldxi_f(u + 1, JIT_FP, v->u.w + 4);
+#  else
+       jit_ldxi_d(u, JIT_FP, v->u.w);
+#  endif
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+   jit_int32_t         regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+#  if __WORDSIZE == 32
+    if (jit_arg_d_reg_p(v->u.w)) {
+       jit_stxi_d(-8, JIT_FP, u);
+       jit_ldxi(_I0 + v->u.w, JIT_FP, -8);
+       jit_ldxi(_I0 + v->u.w + 1, JIT_FP, -4);
+    }
+    else if (jit_arg_reg_p(v->u.w)) {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_stxi_d(-8, JIT_FP, u);
+       jit_ldxi(_I0 + v->u.w, JIT_FP, -8);
+       jit_ldxi(regno, JIT_FP, -4);
+       jit_stxi(stack_framesize, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+    else if ((v->u.w & 7) == 0)
+       jit_stxi_d(v->u.w, JIT_FP, u);
+    else {
+       jit_stxi_d(-8, JIT_FP, u);
+       regno = jit_get_reg(jit_class_gpr);
+       jit_ldxi(regno, JIT_FP, -8);
+       jit_stxi(v->u.w, JIT_FP, regno);
+       jit_ldxi(regno, JIT_FP, -4);
+       jit_stxi(v->u.w + 4, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+#  else
+    if (jit_arg_d_reg_p(v->u.w))
+       jit_movr_d(_F0 - (v->u.w << 1), u);
+    else
+       jit_stxi_d(v->u.w, JIT_FP, u);
+#  endif
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+#  if __WORDSIZE == 32
+    jit_int32_t                gpr;
+#  endif
+   jit_int32_t         regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+#  if __WORDSIZE == 32
+    regno = jit_get_reg(jit_class_fpr);
+    jit_movi_d(regno, u);
+    if (jit_arg_d_reg_p(v->u.w)) {
+       jit_stxi_d(-8, JIT_FP, regno);
+       jit_ldxi(_I0 + v->u.w, JIT_FP, -8);
+       jit_ldxi(_I0 + v->u.w + 1, JIT_FP, -4);
+    }
+    else if (jit_arg_reg_p(v->u.w)) {
+       gpr = jit_get_reg(jit_class_gpr);
+       jit_stxi_d(-8, JIT_FP, regno);
+       jit_ldxi(_I0 + v->u.w, JIT_FP, -8);
+       jit_ldxi(gpr, JIT_FP, -4);
+       jit_stxi(stack_framesize, JIT_FP, gpr);
+       jit_unget_reg(gpr);
+    }
+    else if ((v->u.w & 7) == 0)
+       jit_stxi_d(v->u.w, JIT_FP, regno);
+    else {
+       jit_stxi_d(-8, JIT_FP, regno);
+       gpr = jit_get_reg(jit_class_gpr);
+       jit_ldxi(gpr, JIT_FP, -8);
+       jit_stxi(v->u.w, JIT_FP, gpr);
+       jit_ldxi(gpr, JIT_FP, -4);
+       jit_stxi(v->u.w + 4, JIT_FP, gpr);
+       jit_unget_reg(gpr);
+    }
+    jit_unget_reg(regno);
+#  else
+    if (jit_arg_d_reg_p(v->u.w))
+       jit_movi_d(_F0 - (v->u.w << 1), u);
+    else {
+       regno = jit_get_reg(jit_class_fpr | jit_class_dbl);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, JIT_FP, regno);
+       jit_unget_reg(regno);
+    }
+#  endif
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(_O0 + _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+#  if __WORDSIZE == 64
+       if (jit_arg_d_reg_p(_jitc->function->call.argi))
+           ++_jitc->function->call.argi;
+#  endif
+       jit_stxi(BIAS(_jitc->function->call.size + stack_framesize),
+                JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                regno;
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(_O0 + _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+    }
+    else {
+#  if __WORDSIZE == 64
+       if (jit_arg_d_reg_p(_jitc->function->call.argi))
+           ++_jitc->function->call.argi;
+#  endif
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(BIAS(_jitc->function->call.size + stack_framesize),
+                JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+#  if __WORDSIZE == 32
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_stxi_f(-8, JIT_FP, u);
+       jit_ldxi(_O0 + _jitc->function->call.argi, JIT_FP, -8);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size + stack_framesize,
+                  JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_float32_t);
+    }
+#  else
+    if ((_jitc->function->call.call & jit_call_varargs) &&
+       jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_stxi_f(BIAS(-8), JIT_FP, u);
+       jit_ldxi_i(_O0 + _jitc->function->call.argi, JIT_FP, BIAS(-8));
+       ++_jitc->function->call.argi;
+    }
+    else if (!(_jitc->function->call.call & jit_call_varargs) &&
+            jit_arg_d_reg_p(_jitc->function->call.argi)) {
+       /* pair of registers is live */
+       jit_live(_F0 - (_jitc->function->call.argi << 1));
+       jit_movr_f((_F0 - (_jitc->function->call.argi << 1)) - 1, u);
+       if (!jit_arg_reg_p(_jitc->function->call.argi))
+           _jitc->function->call.size += sizeof(jit_float64_t);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_f(BIAS(_jitc->function->call.size + stack_framesize + 4),
+                  JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+#  endif
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                regno;
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+#  if __WORDSIZE == 32
+    regno = jit_get_reg(jit_class_fpr);
+    jit_movi_f(regno, u);
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_stxi_f(-8, JIT_FP, regno);
+       jit_ldxi(_O0 + _jitc->function->call.argi, JIT_FP, -8);
+       _jitc->function->call.argi++;
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size + stack_framesize,
+                  JIT_SP, regno);
+       _jitc->function->call.size += sizeof(jit_float32_t);
+    }
+    jit_unget_reg(regno);
+#  else
+    if ((_jitc->function->call.call & jit_call_varargs) &&
+       jit_arg_reg_p(_jitc->function->call.argi)) {
+       regno = jit_get_reg(jit_class_fpr | jit_class_sng);
+       jit_movi_f(regno, u);
+       jit_stxi_f(BIAS(-8), JIT_FP, regno);
+       jit_ldxi_i(_O0 + _jitc->function->call.argi, JIT_FP, BIAS(-8));
+       ++_jitc->function->call.argi;
+       jit_unget_reg(regno);
+    }
+    else if (!(_jitc->function->call.call & jit_call_varargs) &&
+            jit_arg_d_reg_p(_jitc->function->call.argi)) {
+       /* pair of registers is live */
+       jit_live(_F0 - (_jitc->function->call.argi << 1));
+       jit_movi_f((_F0 - (_jitc->function->call.argi << 1)) - 1, u);
+       if (!jit_arg_reg_p(_jitc->function->call.argi))
+           _jitc->function->call.size += sizeof(jit_float64_t);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr | jit_class_sng);
+       jit_movi_f(regno, u);
+       jit_stxi_f(BIAS(_jitc->function->call.size + stack_framesize + 4),
+                  JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+#  endif
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+#  if __WORDSIZE == 32
+    if (jit_arg_d_reg_p(_jitc->function->call.argi)) {
+       jit_stxi_d(BIAS(-8), JIT_FP, u);
+       jit_ldxi(_O0 + _jitc->function->call.argi, JIT_FP, BIAS(-8));
+       jit_ldxi(_O0 + _jitc->function->call.argi + 1, JIT_FP, -4);
+       _jitc->function->call.argi += 2;
+    }
+    else if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_stxi_f(-8, JIT_FP, u);
+       jit_ldxi(_O0 + _jitc->function->call.argi, JIT_FP, -8);
+       ++_jitc->function->call.argi;
+       jit_stxi_f(stack_framesize, JIT_SP, u + 1);
+       _jitc->function->call.size += sizeof(jit_float32_t);
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size + stack_framesize,
+                  JIT_SP, u);
+       jit_stxi_f(_jitc->function->call.size + stack_framesize + 4,
+                  JIT_SP, u + 1);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+#  else
+    if ((_jitc->function->call.call & jit_call_varargs) &&
+       jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_stxi_d(BIAS(-8), JIT_FP, u);
+       jit_ldxi(_O0 + _jitc->function->call.argi, JIT_FP, BIAS(-8));
+       ++_jitc->function->call.argi;
+    }
+    else if (!(_jitc->function->call.call & jit_call_varargs) &&
+            jit_arg_d_reg_p(_jitc->function->call.argi)) {
+       jit_movr_d(_F0 - (_jitc->function->call.argi << 1), u);
+       if (!jit_arg_reg_p(_jitc->function->call.argi))
+           _jitc->function->call.size += sizeof(jit_float64_t);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       jit_stxi_d(BIAS(_jitc->function->call.size + stack_framesize),
+                  JIT_SP, u);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+#  endif
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                regno;
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+#  if __WORDSIZE == 32
+    regno = jit_get_reg(jit_class_fpr);
+    jit_movi_d(regno, u);
+    if (jit_arg_d_reg_p(_jitc->function->call.argi)) {
+       jit_stxi_d(BIAS(-8), JIT_FP, regno);
+       jit_ldxi(_O0 + _jitc->function->call.argi, JIT_FP, BIAS(-8));
+       jit_ldxi(_O0 + _jitc->function->call.argi + 1, JIT_FP, -4);
+       _jitc->function->call.argi += 2;
+    }
+    else if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_stxi_f(-8, JIT_FP, regno);
+       jit_ldxi(_O0 + _jitc->function->call.argi, JIT_FP, -8);
+       ++_jitc->function->call.argi;
+       jit_stxi_f(stack_framesize, JIT_SP, u + 1);
+       _jitc->function->call.size += sizeof(jit_float32_t);
+    }
+    else {
+       jit_stxi_f(_jitc->function->call.size + stack_framesize,
+                  JIT_SP, regno);
+       jit_stxi_f(_jitc->function->call.size + stack_framesize + 4,
+                  JIT_SP, regno + 1);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+    jit_unget_reg(regno);
+#  else
+    if ((_jitc->function->call.call & jit_call_varargs) &&
+       jit_arg_reg_p(_jitc->function->call.argi)) {
+       regno = jit_get_reg(jit_class_fpr | jit_class_dbl);
+       jit_movi_d(regno, u);
+       jit_stxi_d(BIAS(-8), JIT_FP, regno);
+       jit_ldxi(_O0 + _jitc->function->call.argi, JIT_FP, BIAS(-8));
+       ++_jitc->function->call.argi;
+       jit_unget_reg(regno);
+    }
+    else if (!(_jitc->function->call.call & jit_call_varargs) &&
+            jit_arg_d_reg_p(_jitc->function->call.argi)) {
+       jit_movi_d(_F0 - (_jitc->function->call.argi << 1), u);
+       if (!jit_arg_reg_p(_jitc->function->call.argi))
+           _jitc->function->call.size += sizeof(jit_float64_t);
+       ++_jitc->function->call.argi;
+    }
+    else {
+       regno = jit_get_reg(jit_class_fpr | jit_class_dbl);
+       jit_movi_d(regno, u);
+       jit_stxi_d(BIAS(_jitc->function->call.size + stack_framesize),
+                  JIT_SP, regno);
+       jit_unget_reg(regno);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+#  endif
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_int32_t                spec;
+
+    spec = jit_class(_rvs[regno].spec);
+    if ((spec & (jit_class_arg|jit_class_gpr)) ==
+       (jit_class_arg|jit_class_gpr)) {
+       regno -= _O0;
+       if (regno >= 0 && regno < node->v.w)
+           return (1);
+    }
+#  if __WORDSIZE == 64
+    if ((spec & (jit_class_arg|jit_class_fpr)) ==
+       (jit_class_arg|jit_class_fpr)) {
+       regno = _F0 - (regno >> 1);
+       if (regno >= 0 && regno < node->v.w)
+           return (1);
+    }
+#  endif
+
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_node_t         *call;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    call = jit_callr(r0);
+    call->v.w = _jitc->function->self.argi;
+    call->w.w = _jitc->function->self.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+    node = jit_calli(i0);
+    node->v.w = _jitc->function->call.argi;
+    node->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_c, r0);
+    jit_extr_c(r0, _O0);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_uc, r0);
+    jit_extr_uc(r0, _O0);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_s, r0);
+    jit_extr_s(r0, _O0);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_us, r0);
+    jit_extr_us(r0, _O0);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+#  if __WORDSIZE == 32
+    if (r0 != _O0)
+       jit_movr(r0, _O0);
+#  else
+    jit_extr_i(r0, _O0);
+#  endif
+    jit_dec_synth();
+}
+
+#  if __WORDSIZE == 64
+void
+_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+    if (r0 != _O0)
+       jit_extr_ui(r0, _O0);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+    if (r0 != _O0)
+       jit_movr(r0, _O0);
+    jit_dec_synth();
+}
+#  endif
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_f, r0);
+    if (r0 != JIT_FRET)
+       jit_movr_f(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_d, r0);
+    if (r0 != JIT_FRET)
+       jit_movr_d(r0, JIT_FRET);
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_int32_t                 value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_int32_t      patch_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.patch_offset = 0;
+
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_rf(name)                                                  \
+           case jit_code_##name##i##type:                              \
+               assert(node->flag & jit_flag_data);                     \
+               name##_f(rn(node->u.w),                                 \
+               (jit_float32_t *)node->v.n->u.w);                       \
+               break
+#define case_rd(name)                                                  \
+           case jit_code_##name##i_d:                                  \
+               assert(node->flag & jit_flag_data);                     \
+               name##_d(rn(node->u.w),                                 \
+                        (jit_float64_t *)node->v.n->u.w);              \
+               break
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w),                            \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_rrf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               assert(node->flag & jit_flag_data);                     \
+               name##i##type(rn(node->u.w), rn(node->v.w),             \
+                             (jit_float##size##_t *)node->w.n->u.w);   \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brf(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w, rn(node->v.w),             \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w, rn(node->v.w),     \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if (node->u.w == sizeof(jit_word_t) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               if ((node->link || (node->flag & jit_flag_use)) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rr(trunc, _f_i);
+               case_rr(trunc, _d_i);
+#if __WORDSIZE == 64
+               case_rr(trunc, _f_l);
+               case_rr(trunc, _d_l);
+#endif
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+#if __WORDSIZE == 64
+               case_rr(ld, _ui);
+               case_rw(ld, _ui);
+               case_rr(ld, _l);
+               case_rw(ld, _l);
+#endif
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+#if __WORDSIZE == 64
+               case_rrr(ldx, _ui);
+               case_rrw(ldx, _ui);
+               case_rrr(ldx, _l);
+               case_rrw(ldx, _l);
+#endif
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+#if __WORDSIZE == 64
+               case_rr(st, _l);
+               case_wr(st, _l);
+#endif
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+#if __WORDSIZE == 64
+               case_rrr(stx, _l);
+               case_wrr(stx, _l);
+#endif
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+#if __WORDSIZE == 64
+               case_rr(hton, _ul);
+#endif
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+#if __WORDSIZE == 64
+               case_rr(ext, _i);
+               case_rr(ext, _ui);
+#endif
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), node->v.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rr(neg,);
+               case_rr(com,);
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_rrr(add, _f);
+               case_rrf(add, _f, 32);
+               case_rrr(sub, _f);
+               case_rrf(sub, _f, 32);
+               case_rrf(rsb, _f, 32);
+               case_rrr(mul, _f);
+               case_rrf(mul, _f, 32);
+               case_rrr(div, _f);
+               case_rrf(div, _f, 32);
+               case_rr(abs, _f);
+               case_rr(neg, _f);
+               case_rr(sqrt, _f);
+               case_rr(ext, _f);
+               case_rr(ext, _d_f);
+               case_rrr(lt, _f);
+               case_rrf(lt, _f, 32);
+               case_rrr(le, _f);
+               case_rrf(le, _f, 32);
+               case_rrr(eq, _f);
+               case_rrf(eq, _f, 32);
+               case_rrr(ge, _f);
+               case_rrf(ge, _f, 32);
+               case_rrr(gt, _f);
+               case_rrf(gt, _f, 32);
+               case_rrr(ne, _f);
+               case_rrf(ne, _f, 32);
+               case_rrr(unlt, _f);
+               case_rrf(unlt, _f, 32);
+               case_rrr(unle, _f);
+               case_rrf(unle, _f, 32);
+               case_rrr(uneq, _f);
+               case_rrf(uneq, _f, 32);
+               case_rrr(unge, _f);
+               case_rrf(unge, _f, 32);
+               case_rrr(ungt, _f);
+               case_rrf(ungt, _f, 32);
+               case_rrr(ltgt, _f);
+               case_rrf(ltgt, _f, 32);
+               case_rrr(ord, _f);
+               case_rrf(ord, _f, 32);
+               case_rrr(unord, _f);
+               case_rrf(unord, _f, 32);
+               case_rr(ld, _f);
+               case_rw(ld, _f);
+               case_rrr(ldx, _f);
+               case_rrw(ldx, _f);
+               case_rr(st, _f);
+               case_wr(st, _f);
+               case_rrr(stx, _f);
+               case_wrr(stx, _f);
+               case_rr(mov, _f);
+           case jit_code_movi_f:
+               assert(node->flag & jit_flag_data);
+               movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               break;
+               case_brr(blt, _f);
+               case_brf(blt, _f, 32);
+               case_brr(ble, _f);
+               case_brf(ble, _f, 32);
+               case_brr(beq, _f);
+               case_brf(beq, _f, 32);
+               case_brr(bge, _f);
+               case_brf(bge, _f, 32);
+               case_brr(bgt, _f);
+               case_brf(bgt, _f, 32);
+               case_brr(bne, _f);
+               case_brf(bne, _f, 32);
+               case_brr(bunlt, _f);
+               case_brf(bunlt, _f, 32);
+               case_brr(bunle, _f);
+               case_brf(bunle, _f, 32);
+               case_brr(buneq, _f);
+               case_brf(buneq, _f, 32);
+               case_brr(bunge, _f);
+               case_brf(bunge, _f, 32);
+               case_brr(bungt, _f);
+               case_brf(bungt, _f, 32);
+               case_brr(bltgt, _f);
+               case_brf(bltgt, _f, 32);
+               case_brr(bord, _f);
+               case_brf(bord, _f, 32);
+               case_brr(bunord, _f);
+               case_brf(bunord, _f, 32);
+               case_rrr(add, _d);
+               case_rrf(add, _d, 64);
+               case_rrr(sub, _d);
+               case_rrf(sub, _d, 64);
+               case_rrf(rsb, _d, 64);
+               case_rrr(mul, _d);
+               case_rrf(mul, _d, 64);
+               case_rrr(div, _d);
+               case_rrf(div, _d, 64);
+               case_rr(abs, _d);
+               case_rr(neg, _d);
+               case_rr(sqrt, _d);
+               case_rr(ext, _d);
+               case_rr(ext, _f_d);
+               case_rrr(lt, _d);
+               case_rrf(lt, _d, 64);
+               case_rrr(le, _d);
+               case_rrf(le, _d, 64);
+               case_rrr(eq, _d);
+               case_rrf(eq, _d, 64);
+               case_rrr(ge, _d);
+               case_rrf(ge, _d, 64);
+               case_rrr(gt, _d);
+               case_rrf(gt, _d, 64);
+               case_rrr(ne, _d);
+               case_rrf(ne, _d, 64);
+               case_rrr(unlt, _d);
+               case_rrf(unlt, _d, 64);
+               case_rrr(unle, _d);
+               case_rrf(unle, _d, 64);
+               case_rrr(uneq, _d);
+               case_rrf(uneq, _d, 64);
+               case_rrr(unge, _d);
+               case_rrf(unge, _d, 64);
+               case_rrr(ungt, _d);
+               case_rrf(ungt, _d, 64);
+               case_rrr(ltgt, _d);
+               case_rrf(ltgt, _d, 64);
+               case_rrr(ord, _d);
+               case_rrf(ord, _d, 64);
+               case_rrr(unord, _d);
+               case_rrf(unord, _d, 64);
+               case_rr(ld, _d);
+               case_rw(ld, _d);
+               case_rrr(ldx, _d);
+               case_rrw(ldx, _d);
+               case_rr(st, _d);
+               case_wr(st, _d);
+               case_rrr(stx, _d);
+               case_wrr(stx, _d);
+               case_rr(mov, _d);
+           case jit_code_movi_d:
+               assert(node->flag & jit_flag_data);
+               movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               break;
+               case_brr(blt, _d);
+               case_brf(blt, _d, 64);
+               case_brr(ble, _d);
+               case_brf(ble, _d, 64);
+               case_brr(beq, _d);
+               case_brf(beq, _d, 64);
+               case_brr(bge, _d);
+               case_brf(bge, _d, 64);
+               case_brr(bgt, _d);
+               case_brf(bgt, _d, 64);
+               case_brr(bne, _d);
+               case_brf(bne, _d, 64);
+               case_brr(bunlt, _d);
+               case_brf(bunlt, _d, 64);
+               case_brr(bunle, _d);
+               case_brf(bunle, _d, 64);
+               case_brr(buneq, _d);
+               case_brf(buneq, _d, 64);
+               case_brr(bunge, _d);
+               case_brf(bunge, _d, 64);
+               case_brr(bungt, _d);
+               case_brf(bungt, _d, 64);
+               case_brr(bltgt, _d);
+               case_brf(bltgt, _d, 64);
+               case_brr(bord, _d);
+               case_brf(bord, _d, 64);
+               case_brr(bunord, _d);
+               case_brf(bunord, _d, 64);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi_p(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   word = calli_p(temp->u.w);
+                   if (!(temp->flag & jit_flag_patch))
+                       patch(word, node);
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+           restart_function:
+               _jitc->again = 0;
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+                   goto restart_function;
+               }
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_live:                 case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:
+#if __WORDSIZE == 64
+           case jit_code_getarg_ui:            case jit_code_getarg_l:
+#endif
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+#if __WORDSIZE == 64
+           case jit_code_retval_ui:            case jit_code_retval_l:
+#endif
+           case jit_code_retval_f:             case jit_code_retval_d:
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           default:
+               abort();
+       }
+#  if __WORDSIZE == 64
+       if (jit_carry != _NOREG) {
+           switch (node->code) {
+               case jit_code_note:
+               case jit_code_addcr:            case jit_code_addci:
+               case jit_code_addxr:            case jit_code_addxi:
+               case jit_code_subcr:            case jit_code_subci:
+               case jit_code_subxr:            case jit_code_subxi:
+                   break;
+               default:
+                   jit_unget_reg(jit_carry);
+                   jit_carry = _NOREG;
+                   break;
+           }
+       }
+#  endif
+       jit_regarg_clr(node, value);
+#  if __WORDSIZE == 64
+       if (jit_regset_cmp_ui(&_jitc->regarg, 0) != 0) {
+           assert(jit_regset_scan1(&_jitc->regarg, 0) == jit_carry);
+           assert(jit_regset_scan1(&_jitc->regarg, jit_carry + 1) == ULONG_MAX);
+       }
+       assert(_jitc->synth == 0);
+#  else
+       assert(_jitc->regarg == 0 && _jitc->synth == 0);
+#  endif
+       jit_reglive(node);
+    }
+#undef case_brf
+#undef case_brw
+#undef case_brr
+#undef case_wrr
+#undef case_rrf
+#undef case_rrrw
+#undef case_rrw
+#undef case_rrrr
+#undef case_rrr
+#undef case_rf
+#undef case_wr
+#undef case_rw
+#undef case_rr
+
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(_jitc->patches.ptr[offset].inst, word);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_sparc-cpu.c"
+#  include "jit_sparc-fpu.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_gpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    ldxi(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_gpr_t r1)
+{
+    stxi(i0, rn(r0), rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_fpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_fpr_t r1)
+{
+    stxi_d(i0, rn(r0), rn(r1));
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+    assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       memset(_jitc->patches.ptr + _jitc->patches.length, 0,
+              1024 * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
diff --git a/deps/lightning/lib/jit_x86-cpu.c b/deps/lightning/lib/jit_x86-cpu.c
new file mode 100644 (file)
index 0000000..4627783
--- /dev/null
@@ -0,0 +1,3842 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+/* avoid using it due to partial stalls */
+#define USE_INC_DEC                    0
+
+#if PROTO
+#  if __X32 || __X64_32
+#    define WIDE                       0
+#    define ldi(u, v)                  ldi_i(u, v)
+#    define ldr(u, v)                  ldr_i(u, v)
+#    define ldxr(u, v, w)              ldxr_i(u, v, w)
+#    define ldxi(u, v, w)              ldxi_i(u, v, w)
+#    define sti(u, v)                  sti_i(u, v)
+#    define stxi(u, v, w)              stxi_i(u, v, w)
+#    define can_sign_extend_int_p(im)  1
+#    define can_zero_extend_int_p(im)  1
+#    define fits_uint32_p(im)          1
+#  else
+#    define WIDE                       1
+#    define ldi(u, v)                  ldi_l(u, v)
+#    define ldr(u, v)                  ldr_l(u, v)
+#    define ldxr(u, v, w)              ldxr_l(u, v, w)
+#    define ldxi(u, v, w)              ldxi_l(u, v, w)
+#    define sti(u, v)                  sti_l(u, v)
+#    define stxi(u, v, w)              stxi_l(u, v, w)
+#    define can_sign_extend_int_p(im)                                  \
+       (((im) >= 0 && (long long)(im) <=  0x7fffffffLL) ||             \
+        ((im) <  0 && (long long)(im) >  -0x80000000LL))
+#    define can_zero_extend_int_p(im)                                  \
+       ((im) >= 0 && (im) < 0x80000000LL)
+#    define fits_uint32_p(im)          (((im) & 0xffffffff00000000LL) == 0)
+#  endif
+#  if __X32 || __CYGWIN__ || __X64_32 || _WIN32
+#      define reg8_p(rn)                                               \
+      ((rn) >= _RAX_REGNO && (rn) <= _RBX_REGNO)
+#  else
+#      define reg8_p(rn)               1
+#  endif
+#  define _RAX_REGNO                   0
+#  define _RCX_REGNO                   1
+#  define _RDX_REGNO                   2
+#  define _RBX_REGNO                   3
+#  define _RSP_REGNO                   4
+#  define _RBP_REGNO                   5
+#  define _RSI_REGNO                   6
+#  define _RDI_REGNO                   7
+#  define _R8_REGNO                    8
+#  define _R9_REGNO                    9
+#  define _R10_REGNO                   10
+#  define _R11_REGNO                   11
+#  define _R12_REGNO                   12
+#  define _R13_REGNO                   13
+#  define _R14_REGNO                   14
+#  define _R15_REGNO                   15
+#  define r7(reg)                      ((reg) & 7)
+#  define r8(reg)                      ((reg) & 15)
+#  define _SCL1                                0x00
+#  define _SCL2                                0x01
+#  define _SCL4                                0x02
+#  define _SCL8                                0x03
+#  define X86_ADD                      0
+#  define X86_OR                       1 << 3
+#  define X86_ADC                      2 << 3
+#  define X86_SBB                      3 << 3
+#  define X86_AND                      4 << 3
+#  define X86_SUB                      5 << 3
+#  define X86_XOR                      6 << 3
+#  define X86_CMP                      7 << 3
+#  define X86_ROL                      0
+#  define X86_ROR                      1
+#  define X86_RCL                      2
+#  define X86_RCR                      3
+#  define X86_SHL                      4
+#  define X86_SHR                      5
+#  define X86_SAR                      7
+#  define X86_NOT                      2
+#  define X86_NEG                      3
+#  define X86_MUL                      4
+#  define X86_IMUL                     5
+#  define X86_DIV                      6
+#  define X86_IDIV                     7
+#  define X86_CC_O                     0x0
+#  define X86_CC_NO                    0x1
+#  define X86_CC_NAE                   0x2
+#  define X86_CC_B                     0x2
+#  define X86_CC_C                     0x2
+#  define X86_CC_AE                    0x3
+#  define X86_CC_NB                    0x3
+#  define X86_CC_NC                    0x3
+#  define X86_CC_E                     0x4
+#  define X86_CC_Z                     0x4
+#  define X86_CC_NE                    0x5
+#  define X86_CC_NZ                    0x5
+#  define X86_CC_BE                    0x6
+#  define X86_CC_NA                    0x6
+#  define X86_CC_A                     0x7
+#  define X86_CC_NBE                   0x7
+#  define X86_CC_S                     0x8
+#  define X86_CC_NS                    0x9
+#  define X86_CC_P                     0xa
+#  define X86_CC_PE                    0xa
+#  define X86_CC_NP                    0xb
+#  define X86_CC_PO                    0xb
+#  define X86_CC_L                     0xc
+#  define X86_CC_NGE                   0xc
+#  define X86_CC_GE                    0xd
+#  define X86_CC_NL                    0xd
+#  define X86_CC_LE                    0xe
+#  define X86_CC_NG                    0xe
+#  define X86_CC_G                     0xf
+#  define X86_CC_NLE                   0xf
+#  define mrm(md, r, m)                        *_jit->pc.uc++ = (md<<6) | (r<<3) | m
+#  define sib(sc, i, b)                        *_jit->pc.uc++ = (sc<<6) | (i<<3) | b
+#  define ic(c)                                *_jit->pc.uc++ = c
+#  define is(s)                                *_jit->pc.us++ = s
+#  define ii(i)                                *_jit->pc.ui++ = i
+#  if __X64 && !__X64_32
+#    define il(l)                      *_jit->pc.ul++ = l
+#  else
+#    define il(l)                      ii(l)
+#  endif
+#  define patch_abs(instr, label)                                      \
+       *(jit_word_t *)(instr - sizeof(jit_word_t)) = label
+#  define patch_rel(instr, label)                                      \
+       *(jit_int32_t *)(instr - 4) = label - instr
+#  define patch_rel_char(instr, label)                                 \
+       *(jit_int8_t *)(instr - 1) = label - instr
+#  define rex(l, w, r, x, b)           _rex(_jit, l, w, r, x, b)
+static void
+_rex(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define rx(rd, md, rb, ri, ms)       _rx(_jit, rd, md, rb, ri, ms)
+static void
+_rx(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define nop(n)                       _nop(_jit, n)
+static void _nop(jit_state_t*, jit_int32_t);
+#  define emms()                       is(0x770f)
+#  define lea(md, rb, ri, ms, rd)      _lea(_jit, md, rb, ri, ms, rd)
+static void
+_lea(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define pushr(r0)                    _pushr(_jit, r0)
+static void _pushr(jit_state_t*, jit_int32_t) maybe_unused;
+#  define popr(r0)                     _popr(_jit, r0)
+static void _popr(jit_state_t*, jit_int32_t) maybe_unused;
+#  define xchgr(r0, r1)                        _xchgr(_jit, r0, r1)
+static void _xchgr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define testr(r0, r1)                        _testr(_jit, r0, r1)
+static void _testr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define testi(r0, i0)                        _testi(_jit, r0, i0)
+static void _testi(jit_state_t*, jit_int32_t, jit_word_t);
+#  define cc(code, r0)                 _cc(_jit, code, r0)
+static void _cc(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define icmpr(r0, r1)                        alur(X86_CMP, r0, r1)
+#  define alur(code, r0, r1)           _alur(_jit, code, r0, r1)
+static void _alur(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define icmpi(r0, i0)                        alui(X86_CMP, r0, i0)
+#  define alui(code, r0, i0)           _alui(_jit, code, r0, i0)
+static void _alui(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define iaddr(r0, r1)                        alur(X86_ADD, r0, r1)
+#  define save(r0)                     _save(_jit, r0)
+static void _save(jit_state_t*, jit_int32_t);
+#  define load(r0)                     _load(_jit, r0)
+static void _load(jit_state_t*, jit_int32_t);
+#  define addr(r0, r1, r2)             _addr(_jit, r0, r1, r2)
+static void _addr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define iaddi(r0, i0)                        alui(X86_ADD, r0, i0)
+#  define addi(r0, r1, i0)             _addi(_jit, r0, r1, i0)
+static void _addi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#define addcr(r0, r1, r2)              _addcr(_jit, r0, r1, r2)
+static void _addcr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#define addci(r0, r1, i0)              _addci(_jit, r0, r1, i0)
+static void _addci(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define iaddxr(r0, r1)               alur(X86_ADC, r0, r1)
+#  define addxr(r0, r1, r2)            _addxr(_jit, r0, r1, r2)
+static void _addxr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define iaddxi(r0, i0)               alui(X86_ADC, r0, i0)
+#  define addxi(r0, r1, i0)            _addxi(_jit, r0, r1, i0)
+static void _addxi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define isubr(r0, r1)                        alur(X86_SUB, r0, r1)
+#  define subr(r0, r1, r2)             _subr(_jit, r0, r1, r2)
+static void _subr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define isubi(r0, i0)                        alui(X86_SUB, r0, i0)
+#  define subi(r0, r1, i0)             _subi(_jit, r0, r1, i0)
+static void _subi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define subcr(r0, r1, r2)            _subcr(_jit, r0, r1, r2)
+static void _subcr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define subci(r0, r1, i0)            _subci(_jit, r0, r1, i0)
+static void _subci(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define isubxr(r0, r1)               alur(X86_SBB, r0, r1)
+#  define subxr(r0, r1, r2)            _subxr(_jit, r0, r1, r2)
+static void _subxr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define isubxi(r0, i0)               alui(X86_SBB, r0, i0)
+#  define subxi(r0, r1, i0)            _subxi(_jit, r0, r1, i0)
+static void _subxi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define rsbi(r0, r1, i0)             _rsbi(_jit, r0, r1, i0)
+static void _rsbi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t);
+#  define imulr(r0, r1)                        _imulr(_jit, r0, r1)
+static void _imulr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define imuli(r0, r1, i0)            _imuli(_jit, r0, r1, i0)
+static void _imuli(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define mulr(r0, r1, r2)             _mulr(_jit, r0, r1, r2)
+static void _mulr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define muli(r0, r1, i0)             _muli(_jit, r0, r1, i0)
+static void _muli(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define umulr(r0)                    unr(X86_IMUL, r0)
+#  define umulr_u(r0)                  unr(X86_MUL, r0)
+#  define qmulr(r0, r1, r2, r3)                _iqmulr(_jit, r0, r1, r2, r3, 1)
+#  define qmulr_u(r0, r1, r2, r3)      _iqmulr(_jit, r0, r1, r2, r3, 0)
+#  define iqmulr(r0, r1, r2, r3, sign) _iqmulr(_jit, r0, r1, r2, r3, sign)
+static void _iqmulr(jit_state_t*, jit_int32_t, jit_int32_t,
+                   jit_int32_t,jit_int32_t, jit_bool_t);
+#  define qmuli(r0, r1, r2, i0)                _iqmuli(_jit, r0, r1, r2, i0, 1)
+#  define qmuli_u(r0, r1, r2, i0)      _iqmuli(_jit, r0, r1, r2, i0, 0)
+#  define iqmuli(r0, r1, r2, i0, sign) _iqmuli(_jit, r0, r1, r2, i0, sign)
+static void _iqmuli(jit_state_t*, jit_int32_t, jit_int32_t,
+                   jit_int32_t,jit_word_t, jit_bool_t);
+#  define sign_extend_rdx_rax()                _sign_extend_rdx_rax(_jit)
+static void _sign_extend_rdx_rax(jit_state_t*);
+#  define idivr(r0)                    unr(X86_IDIV, r0)
+#  define idivr_u(r0)                  unr(X86_DIV, r0)
+#  define divremr(r0, r1, r2, i0, i1)  _divremr(_jit, r0, r1, r2, i0, i1)
+static void
+_divremr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,
+        jit_bool_t,jit_bool_t);
+#  define divremi(r0, r1, i0, i1, i2)  _divremi(_jit, r0, r1, i0, i1, i2)
+static void
+_divremi(jit_state_t*,jit_int32_t,jit_int32_t,jit_word_t,jit_bool_t,jit_bool_t);
+#  define divr(r0, r1, r2)             divremr(r0, r1, r2, 1, 1)
+#  define divi(r0, r1, i0)             divremi(r0, r1, i0, 1, 1)
+#  define divr_u(r0, r1, r2)           divremr(r0, r1, r2, 0, 1)
+#  define divi_u(r0, r1, i0)           divremi(r0, r1, i0, 0, 1)
+#  define qdivr(r0, r1, r2, r3)                _iqdivr(_jit, r0, r1, r2, r3, 1)
+#  define qdivr_u(r0, r1, r2, r3)      _iqdivr(_jit, r0, r1, r2, r3, 0)
+#  define iqdivr(r0, r1, r2, r3, sign) _iqdivr(_jit, r0, r1, r2, r3, sign)
+static void _iqdivr(jit_state_t*, jit_int32_t, jit_int32_t,
+                   jit_int32_t,jit_int32_t, jit_bool_t);
+#  define qdivi(r0, r1, r2, i0)                _iqdivi(_jit, r0, r1, r2, i0, 1)
+#  define qdivi_u(r0, r1, r2, i0)      _iqdivi(_jit, r0, r1, r2, i0, 0)
+#  define iqdivi(r0, r1, r2, i0, sign) _iqdivi(_jit, r0, r1, r2, i0, sign)
+static void _iqdivi(jit_state_t*, jit_int32_t, jit_int32_t,
+                   jit_int32_t,jit_word_t, jit_bool_t);
+#  define remr(r0, r1, r2)             divremr(r0, r1, r2, 1, 0)
+#  define remi(r0, r1, i0)             divremi(r0, r1, i0, 1, 0)
+#  define remr_u(r0, r1, r2)           divremr(r0, r1, r2, 0, 0)
+#  define remi_u(r0, r1, i0)           divremi(r0, r1, i0, 0, 0)
+#  define iandr(r0, r1)                        alur(X86_AND, r0, r1)
+#  define andr(r0, r1, r2)             _andr(_jit, r0, r1, r2)
+static void _andr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define iandi(r0, i0)                        alui(X86_AND, r0, i0)
+#  define andi(r0, r1, i0)             _andi(_jit, r0, r1, i0)
+static void _andi(jit_state_t*, jit_int32_t,jit_int32_t,jit_word_t);
+#  define iorr(r0, r1)                 alur(X86_OR, r0, r1)
+#  define orr(r0, r1, r2)              _orr(_jit, r0, r1, r2)
+static void _orr(jit_state_t*, jit_int32_t,jit_int32_t,jit_int32_t);
+#  define iori(r0, i0)                 alui(X86_OR, r0, i0)
+#  define ori(r0, r1, i0)              _ori(_jit, r0, r1, i0)
+static void _ori(jit_state_t*, jit_int32_t,jit_int32_t,jit_word_t);
+#  define ixorr(r0, r1)                        alur(X86_XOR, r0, r1)
+#  define xorr(r0, r1, r2)             _xorr(_jit, r0, r1, r2)
+static void _xorr(jit_state_t*, jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ixori(r0, i0)                        alui(X86_XOR, r0, i0)
+#  define xori(r0, r1, i0)             _xori(_jit, r0, r1, i0)
+static void _xori(jit_state_t*, jit_int32_t,jit_int32_t,jit_word_t);
+#  define irotshr(code, r0)            _irotshr(_jit, code, r0)
+static void _irotshr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define rotshr(code, r0, r1, r2)     _rotshr(_jit, code, r0, r1, r2)
+static void
+_rotshr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define irotshi(code, r0, i0)                _irotshi(_jit, code, r0, i0)
+static void _irotshi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define rotshi(code, r0, r1, i0)     _rotshi(_jit, code, r0, r1, i0)
+static void
+_rotshi(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_word_t);
+#  define lshr(r0, r1, r2)             rotshr(X86_SHL, r0, r1, r2)
+#  define lshi(r0, r1, i0)             _lshi(_jit, r0, r1, i0)
+static void _lshi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define rshr(r0, r1, r2)             rotshr(X86_SAR, r0, r1, r2)
+#  define rshi(r0, r1, i0)             rotshi(X86_SAR, r0, r1, i0)
+#  define rshr_u(r0, r1, r2)           rotshr(X86_SHR, r0, r1, r2)
+#  define rshi_u(r0, r1, i0)           rotshi(X86_SHR, r0, r1, i0)
+#  define unr(code, r0)                        _unr(_jit, code, r0)
+static void _unr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define inegr(r0)                    unr(X86_NEG, r0)
+#  define negr(r0, r1)                 _negr(_jit, r0, r1)
+static void _negr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define icomr(r0)                    unr(X86_NOT, r0)
+#  define comr(r0, r1)                 _comr(_jit, r0, r1)
+static void _comr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  if USE_INC_DEC
+#    define incr(r0, r1)               _incr(_jit, r0, r1)
+static void _incr(jit_state_t*, jit_int32_t, jit_int32_t);
+#    define decr(r0, r1)               _decr(_jit, r0, r1)
+static void _decr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  endif
+#  define cr(code, r0, r1, r2)         _cr(_jit, code, r0, r1, r2)
+static void
+_cr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ci(code, r0, r1, i0)         _ci(_jit, code, r0, r1, i0)
+static void
+_ci(jit_state_t *_jit, jit_int32_t, jit_int32_t, jit_int32_t, jit_word_t);
+#  define ci0(code, r0, r1)            _ci0(_jit, code, r0, r1)
+static void _ci0(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ltr(r0, r1, r2)              _ltr(_jit, r0, r1, r2)
+static void _ltr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define lti(r0, r1, i0)                      _lti(_jit, r0, r1, i0)
+static void _lti(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define ltr_u(r0, r1, r2)            _ltr_u(_jit, r0, r1, r2)
+static void _ltr_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define lti_u(r0, r1, i0)            ci(X86_CC_B, r0, r1, i0)
+#  define ler(r0, r1, r2)              _ler(_jit, r0, r1, r2)
+static void _ler(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define lei(r0, r1, i0)              ci(X86_CC_LE, r0, r1, i0)
+#  define ler_u(r0, r1, r2)            _ler_u(_jit, r0, r1, r2)
+static void _ler_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define lei_u(r0, r1, i0)            _lei_u(_jit, r0, r1, i0)
+static void _lei_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define eqr(r0, r1, r2)              _eqr(_jit, r0, r1, r2)
+static void _eqr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define eqi(r0, r1, i0)              _eqi(_jit, r0, r1, i0)
+static void _eqi(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define ger(r0, r1, r2)              _ger(_jit, r0, r1, r2)
+static void _ger(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define gei(r0, r1, i0)              _gei(_jit, r0, r1, i0)
+static void _gei(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define ger_u(r0, r1, r2)            _ger_u(_jit, r0, r1, r2)
+static void _ger_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define gei_u(r0, r1, i0)            _gei_u(_jit, r0, r1, i0)
+static void _gei_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define gtr(r0, r1, r2)              _gtr(_jit, r0, r1, r2)
+static void _gtr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define gti(r0, r1, i0)              _ci(_jit, X86_CC_G, r0, r1, i0)
+#  define gtr_u(r0, r1, r2)            _gtr_u(_jit, r0, r1, r2)
+static void _gtr_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define gti_u(r0, r1, i0)            _gti_u(_jit, r0, r1, i0)
+static void _gti_u(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define ner(r0, r1, r2)              _ner(_jit, r0, r1, r2)
+static void _ner(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define nei(r0, r1, i0)              _nei(_jit, r0, r1, i0)
+static void _nei(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define movr(r0, r1)                 _movr(_jit, r0, r1)
+static void _movr(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define imovi(r0, i0)                        _imovi(_jit, r0, i0)
+static void _imovi(jit_state_t*, jit_int32_t, jit_word_t);
+#  define movi(r0, i0)                 _movi(_jit, r0, i0)
+static void _movi(jit_state_t*, jit_int32_t, jit_word_t);
+#  define movi_p(r0, i0)               _movi_p(_jit, r0, i0)
+static jit_word_t _movi_p(jit_state_t*, jit_int32_t, jit_word_t);
+#  define movcr(r0, r1)                        _movcr(_jit, r0, r1)
+static void _movcr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movcr_u(r0, r1)              _movcr_u(_jit, r0, r1)
+static void _movcr_u(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movsr(r0, r1)                        _movsr(_jit, r0, r1)
+static void _movsr(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define movsr_u(r0, r1)              _movsr_u(_jit, r0, r1)
+static void _movsr_u(jit_state_t*,jit_int32_t,jit_int32_t);
+#  if __X64 && !__X64_32
+#    define movir(r0, r1)              _movir(_jit, r0, r1)
+static void _movir(jit_state_t*,jit_int32_t,jit_int32_t);
+#    define movir_u(r0, r1)            _movir_u(_jit, r0, r1)
+static void _movir_u(jit_state_t*,jit_int32_t,jit_int32_t);
+#  endif
+#  define htonr_us(r0, r1)             _htonr_us(_jit, r0, r1)
+static void _htonr_us(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define htonr_ui(r0, r1)             _htonr_ui(_jit, r0, r1)
+static void _htonr_ui(jit_state_t*,jit_int32_t,jit_int32_t);
+#  if __X64 && !__X64_32
+#define htonr_ul(r0, r1)               _htonr_ul(_jit, r0, r1)
+static void _htonr_ul(jit_state_t*,jit_int32_t,jit_int32_t);
+#endif
+#  define extr_c(r0, r1)               _extr_c(_jit, r0, r1)
+static void _extr_c(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_uc(r0, r1)              _extr_uc(_jit, r0, r1)
+static void _extr_uc(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define extr_s(r0, r1)               movsr(r0, r1)
+#  define extr_us(r0, r1)              movsr_u(r0, r1)
+#  if __X64 && !__X64_32
+#    define extr_i(r0, r1)             movir(r0, r1)
+#    define extr_ui(r0, r1)            movir_u(r0, r1)
+#  endif
+#  define ldr_c(r0, r1)                        _ldr_c(_jit, r0, r1)
+static void _ldr_c(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define ldi_c(r0, i0)                        _ldi_c(_jit, r0, i0)
+static void _ldi_c(jit_state_t*, jit_int32_t, jit_word_t);
+#  define ldr_uc(r0, r1)               _ldr_uc(_jit, r0, r1)
+static void _ldr_uc(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define ldi_uc(r0, i0)               _ldi_uc(_jit, r0, i0)
+static void _ldi_uc(jit_state_t*, jit_int32_t, jit_word_t);
+#  define ldr_s(r0, r1)                        _ldr_s(_jit, r0, r1)
+static void _ldr_s(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define ldi_s(r0, i0)                        _ldi_s(_jit, r0, i0)
+static void _ldi_s(jit_state_t*, jit_int32_t, jit_word_t);
+#  define ldr_us(r0, r1)               _ldr_us(_jit, r0, r1)
+static void _ldr_us(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define ldi_us(r0, i0)               _ldi_us(_jit, r0, i0)
+static void _ldi_us(jit_state_t*, jit_int32_t, jit_word_t);
+#  if __X32 || !__X64_32
+#    define ldr_i(r0, r1)              _ldr_i(_jit, r0, r1)
+static void _ldr_i(jit_state_t*, jit_int32_t, jit_int32_t);
+#    define ldi_i(r0, i0)              _ldi_i(_jit, r0, i0)
+static void _ldi_i(jit_state_t*, jit_int32_t, jit_word_t);
+#  endif
+#  if __X64
+#    if __X64_32
+#      define ldr_i(r0, r1)            _ldr_ui(_jit, r0, r1)
+#      define ldi_i(r0, i0)            _ldi_ui(_jit, r0, i0)
+#    else
+#      define ldr_ui(r0, r1)           _ldr_ui(_jit, r0, r1)
+#      define ldi_ui(r0, i0)           _ldi_ui(_jit, r0, i0)
+#    endif
+static void _ldr_ui(jit_state_t*, jit_int32_t, jit_int32_t);
+static void _ldi_ui(jit_state_t*, jit_int32_t, jit_word_t);
+#    if !__X64_32
+#      define ldr_l(r0, r1)            _ldr_l(_jit, r0, r1)
+static void _ldr_l(jit_state_t*, jit_int32_t, jit_int32_t);
+#      define ldi_l(r0, i0)            _ldi_l(_jit, r0, i0)
+static void _ldi_l(jit_state_t*, jit_int32_t, jit_word_t);
+#    endif
+#  endif
+#  define ldxr_c(r0, r1, r2)           _ldxr_c(_jit, r0, r1, r2)
+static void _ldxr_c(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ldxi_c(r0, r1, i0)           _ldxi_c(_jit, r0, r1, i0)
+static void _ldxi_c(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define ldxr_uc(r0, r1, r2)          _ldxr_uc(_jit, r0, r1, r2)
+static void _ldxr_uc(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ldxi_uc(r0, r1, i0)          _ldxi_uc(_jit, r0, r1, i0)
+static void _ldxi_uc(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define ldxr_s(r0, r1, r2)           _ldxr_s(_jit, r0, r1, r2)
+static void _ldxr_s(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ldxi_s(r0, r1, i0)           _ldxi_s(_jit, r0, r1, i0)
+static void _ldxi_s(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define ldxr_us(r0, r1, r2)          _ldxr_us(_jit, r0, r1, r2)
+static void _ldxr_us(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define ldxi_us(r0, r1, i0)          _ldxi_us(_jit, r0, r1, i0)
+static void _ldxi_us(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  if __X32 || !__X64_32
+#    define ldxr_i(r0, r1, r2)         _ldxr_i(_jit, r0, r1, r2)
+static void _ldxr_i(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#    define ldxi_i(r0, r1, i0)         _ldxi_i(_jit, r0, r1, i0)
+static void _ldxi_i(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  endif
+#  if __X64
+#    if __X64_32
+#      define ldxr_i(r0, r1, r2)       _ldxr_ui(_jit, r0, r1, r2)
+#      define ldxi_i(r0, r1, i0)       _ldxi_ui(_jit, r0, r1, i0)
+#    else
+#      define ldxr_ui(r0, r1, r2)      _ldxr_ui(_jit, r0, r1, r2)
+#      define ldxi_ui(r0, r1, i0)      _ldxi_ui(_jit, r0, r1, i0)
+#    endif
+static void _ldxr_ui(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+static void _ldxi_ui(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#    if !__X64_32
+#      define ldxr_l(r0, r1, r2)       _ldxr_l(_jit, r0, r1, r2)
+static void _ldxr_l(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#      define ldxi_l(r0, r1, i0)       _ldxi_l(_jit, r0, r1, i0)
+static void _ldxi_l(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#    endif
+#  endif
+#  define str_c(r0, r1)                        _str_c(_jit, r0, r1)
+static void _str_c(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define sti_c(i0, r0)                        _sti_c(_jit, i0, r0)
+static void _sti_c(jit_state_t*, jit_word_t, jit_int32_t);
+#  define str_s(r0, r1)                        _str_s(_jit, r0, r1)
+static void _str_s(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define sti_s(i0, r0)                        _sti_s(_jit, i0, r0)
+static void _sti_s(jit_state_t*, jit_word_t, jit_int32_t);
+#  define str_i(r0, r1)                        _str_i(_jit, r0, r1)
+static void _str_i(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define sti_i(i0, r0)                        _sti_i(_jit, i0, r0)
+static void _sti_i(jit_state_t*, jit_word_t, jit_int32_t);
+#  if __X64 && !__X64_32
+#    define str_l(r0, r1)              _str_l(_jit, r0, r1)
+static void _str_l(jit_state_t*, jit_int32_t, jit_int32_t);
+#    define sti_l(i0, r0)              _sti_l(_jit, i0, r0)
+static void _sti_l(jit_state_t*, jit_word_t, jit_int32_t);
+#  endif
+#  define stxr_c(r0, r1, r2)           _stxr_c(_jit, r0, r1, r2)
+static void _stxr_c(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define stxi_c(i0, r0, r1)           _stxi_c(_jit, i0, r0, r1)
+static void _stxi_c(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define stxr_s(r0, r1, r2)           _stxr_s(_jit, r0, r1, r2)
+static void _stxr_s(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define stxi_s(i0, r0, r1)           _stxi_s(_jit, i0, r0, r1)
+static void _stxi_s(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define stxr_i(r0, r1, r2)           _stxr_i(_jit, r0, r1, r2)
+static void _stxr_i(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define stxi_i(i0, r0, r1)           _stxi_i(_jit, i0, r0, r1)
+static void _stxi_i(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  if __X64 && !__X64_32
+#    define stxr_l(r0, r1, r2)         _stxr_l(_jit, r0, r1, r2)
+static void _stxr_l(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#    define stxi_l(i0, r0, r1)         _stxi_l(_jit, i0, r0, r1)
+static void _stxi_l(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  endif
+#  define jcc(code, i0)                        _jcc(_jit, code, i0)
+#  define jo(i0)                       jcc(X86_CC_O, i0)
+#  define jno(i0)                      jcc(X86_CC_NO, i0)
+#  define jnae(i0)                     jcc(X86_CC_NAE, i0)
+#  define jb(i0)                       jcc(X86_CC_B, i0)
+#  define jc(i0)                       jcc(X86_CC_C, i0)
+#  define jae(i0)                      jcc(X86_CC_AE, i0)
+#  define jnb(i0)                      jcc(X86_CC_NB, i0)
+#  define jnc(i0)                      jcc(X86_CC_NC, i0)
+#  define je(i0)                       jcc(X86_CC_E, i0)
+#  define jz(i0)                       jcc(X86_CC_Z, i0)
+#  define jne(i0)                      jcc(X86_CC_NE, i0)
+#  define jnz(i0)                      jcc(X86_CC_NZ, i0)
+#  define jbe(i0)                      jcc(X86_CC_BE, i0)
+#  define jna(i0)                      jcc(X86_CC_NA, i0)
+#  define ja(i0)                       jcc(X86_CC_A, i0)
+#  define jnbe(i0)                     jcc(X86_CC_NBE, i0)
+#  define js(i0)                       jcc(X86_CC_S, i0)
+#  define jns(i0)                      jcc(X86_CC_NS, i0)
+#  define jp(i0)                       jcc(X86_CC_P, i0)
+#  define jpe(i0)                      jcc(X86_CC_PE, i0)
+#  define jnp(i0)                      jcc(X86_CC_NP, i0)
+#  define jpo(i0)                      jcc(X86_CC_PO, i0)
+#  define jl(i0)                       jcc(X86_CC_L, i0)
+#  define jnge(i0)                     jcc(X86_CC_NGE, i0)
+#  define jge(i0)                      jcc(X86_CC_GE, i0)
+#  define jnl(i0)                      jcc(X86_CC_NL, i0)
+#  define jle(i0)                      jcc(X86_CC_LE, i0)
+#  define jng(i0)                      jcc(X86_CC_NG, i0)
+#  define jg(i0)                       jcc(X86_CC_G, i0)
+#  define jnle(i0)                     jcc(X86_CC_NLE, i0)
+static void _jcc(jit_state_t*, jit_int32_t, jit_word_t);
+#  define jccs(code, i0)               _jccs(_jit, code, i0)
+#  define jos(i0)                      jccs(X86_CC_O, i0)
+#  define jnos(i0)                     jccs(X86_CC_NO, i0)
+#  define jnaes(i0)                    jccs(X86_CC_NAE, i0)
+#  define jbs(i0)                      jccs(X86_CC_B, i0)
+#  define jcs(i0)                      jccs(X86_CC_C, i0)
+#  define jaes(i0)                     jccs(X86_CC_AE, i0)
+#  define jnbs(i0)                     jccs(X86_CC_NB, i0)
+#  define jncs(i0)                     jccs(X86_CC_NC, i0)
+#  define jes(i0)                      jccs(X86_CC_E, i0)
+#  define jzs(i0)                      jccs(X86_CC_Z, i0)
+#  define jnes(i0)                     jccs(X86_CC_NE, i0)
+#  define jnzs(i0)                     jccs(X86_CC_NZ, i0)
+#  define jbes(i0)                     jccs(X86_CC_BE, i0)
+#  define jnas(i0)                     jccs(X86_CC_NA, i0)
+#  define jas(i0)                      jccs(X86_CC_A, i0)
+#  define jnbes(i0)                    jccs(X86_CC_NBE, i0)
+#  define jss(i0)                      jccs(X86_CC_S, i0)
+#  define jnss(i0)                     jccs(X86_CC_NS, i0)
+#  define jps(i0)                      jccs(X86_CC_P, i0)
+#  define jpes(i0)                     jccs(X86_CC_PE, i0)
+#  define jnps(i0)                     jccs(X86_CC_NP, i0)
+#  define jpos(i0)                     jccs(X86_CC_PO, i0)
+#  define jls(i0)                      jccs(X86_CC_L, i0)
+#  define jnges(i0)                    jccs(X86_CC_NGE, i0)
+#  define jges(i0)                     jccs(X86_CC_GE, i0)
+#  define jnls(i0)                     jccs(X86_CC_NL, i0)
+#  define jles(i0)                     jccs(X86_CC_LE, i0)
+#  define jngs(i0)                     jccs(X86_CC_NG, i0)
+#  define jgs(i0)                      jccs(X86_CC_G, i0)
+#  define jnles(i0)                    jccs(X86_CC_NLE, i0)
+static void _jccs(jit_state_t*, jit_int32_t, jit_word_t);
+#  define jcr(code, i0, r0, r1)                _jcr(_jit, code, i0, r0, r1)
+static void _jcr(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_int32_t);
+#  define jci(code, i0, r0, i1)                _jci(_jit, code, i0, r0, i1)
+static void _jci(jit_state_t*,jit_int32_t,jit_word_t,jit_int32_t,jit_word_t);
+#  define jci0(code, i0, r0)           _jci0(_jit, code, i0, r0)
+static void _jci0(jit_state_t*, jit_int32_t, jit_word_t, jit_int32_t);
+#  define bltr(i0, r0, r1)             _bltr(_jit, i0, r0, r1)
+static jit_word_t _bltr(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define blti(i0, r0, i1)             _blti(_jit, i0, r0, i1)
+static jit_word_t _blti(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define bltr_u(i0, r0, r1)           _bltr_u(_jit, i0, r0, r1)
+static jit_word_t _bltr_u(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define blti_u(i0, r0, i1)           _blti_u(_jit, i0, r0, i1)
+static jit_word_t _blti_u(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define bler(i0, r0, r1)             _bler(_jit, i0, r0, r1)
+static jit_word_t _bler(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define blei(i0, r0, i1)             _blei(_jit, i0, r0, i1)
+static jit_word_t _blei(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define bler_u(i0, r0, r1)           _bler_u(_jit, i0, r0, r1)
+static jit_word_t _bler_u(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define blei_u(i0, r0, i1)           _blei_u(_jit, i0, r0, i1)
+static jit_word_t _blei_u(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define beqr(i0, r0, r1)             _beqr(_jit, i0, r0, r1)
+static jit_word_t _beqr(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define beqi(i0, r0, i1)             _beqi(_jit, i0, r0, i1)
+static jit_word_t _beqi(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define bger(i0, r0, r1)             _bger(_jit, i0, r0, r1)
+static jit_word_t _bger(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define bgei(i0, r0, i1)             _bgei(_jit, i0, r0, i1)
+static jit_word_t _bgei(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define bger_u(i0, r0, r1)           _bger_u(_jit, i0, r0, r1)
+static jit_word_t _bger_u(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define bgei_u(i0, r0, i1)           _bgei_u(_jit, i0, r0, i1)
+static jit_word_t _bgei_u(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define bgtr(i0, r0, r1)             _bgtr(_jit, i0, r0, r1)
+static jit_word_t _bgtr(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define bgti(i0, r0, i1)             _bgti(_jit, i0, r0, i1)
+static jit_word_t _bgti(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define bgtr_u(i0, r0, r1)           _bgtr_u(_jit, i0, r0, r1)
+static jit_word_t _bgtr_u(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define bgti_u(i0, r0, i1)           _bgti_u(_jit, i0, r0, i1)
+static jit_word_t _bgti_u(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define bner(i0, r0, r1)             _bner(_jit, i0, r0, r1)
+static jit_word_t _bner(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define bnei(i0, r0, i1)             _bnei(_jit, i0, r0, i1)
+static jit_word_t _bnei(jit_state_t*, jit_word_t, jit_int32_t, jit_word_t);
+#  define bmsr(i0, r0, r1)             _bmsr(_jit, i0, r0, r1)
+static jit_word_t _bmsr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bmsi(i0, r0, i1)             _bmsi(_jit, i0, r0, i1)
+static jit_word_t _bmsi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bmcr(i0, r0, r1)             _bmcr(_jit, i0, r0, r1)
+static jit_word_t _bmcr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bmci(i0, r0, i1)             _bmci(_jit, i0, r0, i1)
+static jit_word_t _bmci(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define boaddr(i0, r0, r1)           _boaddr(_jit, i0, r0, r1)
+static jit_word_t _boaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define boaddi(i0, r0, i1)           _boaddi(_jit, i0, r0, i1)
+static jit_word_t _boaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define boaddr_u(i0, r0, r1)         _boaddr_u(_jit, i0, r0, r1)
+static jit_word_t _boaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define boaddi_u(i0, r0, i1)         _boaddi_u(_jit, i0, r0, i1)
+static jit_word_t _boaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxaddr(i0, r0, r1)           _bxaddr(_jit, i0, r0, r1)
+static jit_word_t _bxaddr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bxaddi(i0, r0, i1)           _bxaddi(_jit, i0, r0, i1)
+static jit_word_t _bxaddi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxaddr_u(i0, r0, r1)         _bxaddr_u(_jit, i0, r0, r1)
+static jit_word_t _bxaddr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bxaddi_u(i0, r0, i1)         _bxaddi_u(_jit, i0, r0, i1)
+static jit_word_t _bxaddi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bosubr(i0, r0, r1)           _bosubr(_jit, i0, r0, r1)
+static jit_word_t _bosubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bosubi(i0, r0, i1)           _bosubi(_jit, i0, r0, i1)
+static jit_word_t _bosubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bosubr_u(i0, r0, r1)         _bosubr_u(_jit, i0, r0, r1)
+static jit_word_t _bosubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bosubi_u(i0, r0, i1)         _bosubi_u(_jit, i0, r0, i1)
+static jit_word_t _bosubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxsubr(i0, r0, r1)           _bxsubr(_jit, i0, r0, r1)
+static jit_word_t _bxsubr(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bxsubi(i0, r0, i1)           _bxsubi(_jit, i0, r0, i1)
+static jit_word_t _bxsubi(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define bxsubr_u(i0, r0, r1)         _bxsubr_u(_jit, i0, r0, r1)
+static jit_word_t _bxsubr_u(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define bxsubi_u(i0, r0, i1)         _bxsubi_u(_jit, i0, r0, i1)
+static jit_word_t _bxsubi_u(jit_state_t*,jit_word_t,jit_int32_t,jit_word_t);
+#  define callr(r0)                    _callr(_jit, r0)
+static void _callr(jit_state_t*, jit_int32_t);
+#  define calli(i0)                    _calli(_jit, i0)
+static jit_word_t _calli(jit_state_t*, jit_word_t);
+#  define jmpr(r0)                     _jmpr(_jit, r0)
+static void _jmpr(jit_state_t*, jit_int32_t);
+#  define jmpi(i0)                     _jmpi(_jit, i0)
+static jit_word_t _jmpi(jit_state_t*, jit_word_t);
+#  define jmpsi(i0)                    _jmpsi(_jit, i0)
+static void _jmpsi(jit_state_t*, jit_uint8_t);
+#  define prolog(node)                 _prolog(_jit, node)
+static void _prolog(jit_state_t*, jit_node_t*);
+#  define epilog(node)                 _epilog(_jit, node)
+static void _epilog(jit_state_t*, jit_node_t*);
+#  define vastart(r0)                  _vastart(_jit, r0)
+static void _vastart(jit_state_t*, jit_int32_t);
+#  define vaarg(r0, r1)                        _vaarg(_jit, r0, r1)
+static void _vaarg(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define vaarg_d(r0, r1, i0)          _vaarg_d(_jit, r0, r1, i0)
+static void _vaarg_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_bool_t);
+#  define patch_at(node, instr, label) _patch_at(_jit, node, instr, label)
+static void _patch_at(jit_state_t*, jit_node_t*, jit_word_t, jit_word_t);
+#  if !defined(HAVE_FFSL)
+#    if __X32
+#      define ffsl(i)                  __builtin_ffs(i)
+#    else
+#      define ffsl(l)                  __builtin_ffsl(l)
+#    endif
+#  endif
+#endif
+
+#if CODE
+static void
+_rex(jit_state_t *_jit, jit_int32_t l, jit_int32_t w,
+     jit_int32_t r, jit_int32_t x, jit_int32_t b)
+{
+#if __X64
+    jit_int32_t        v = 0x40 | (w << 3);
+
+    if (r != _NOREG)
+       v |= (r & 8) >> 1;
+    if (x != _NOREG)
+       v |= (x & 8) >> 2;
+    if (b != _NOREG)
+       v |= (b & 8) >> 3;
+    if (l || v != 0x40)
+       ic(v);
+#endif
+}
+
+static void
+_rx(jit_state_t *_jit, jit_int32_t rd, jit_int32_t md,
+    jit_int32_t rb, jit_int32_t ri, jit_int32_t ms)
+{
+    if (ri == _NOREG) {
+       if (rb == _NOREG) {
+#if __X32
+           mrm(0x00, r7(rd), 0x05);
+#else
+           mrm(0x00, r7(rd), 0x04);
+           sib(_SCL1, 0x04, 0x05);
+#endif
+           ii(md);
+       }
+       else if (r7(rb) == _RSP_REGNO) {
+           if (md == 0) {
+               mrm(0x00, r7(rd), 0x04);
+               sib(ms, 0x04, 0x04);
+           }
+           else if ((jit_int8_t)md == md) {
+               mrm(0x01, r7(rd), 0x04);
+               sib(ms, 0x04, 0x04);
+               ic(md);
+           }
+           else {
+               mrm(0x02, r7(rd), 0x04);
+               sib(ms, 0x04, 0x04);
+               ii(md);
+           }
+       }
+       else {
+           if (md == 0 && r7(rb) != _RBP_REGNO)
+               mrm(0x00, r7(rd), r7(rb));
+           else if ((jit_int8_t)md == md) {
+               mrm(0x01, r7(rd), r7(rb));
+               ic(md);
+           }
+           else {
+               mrm(0x02, r7(rd), r7(rb));
+               ii(md);
+           }
+       }
+    }
+    else if (rb == _NOREG) {
+       mrm(0x00, r7(rd), 0x04);
+       sib(ms, r7(ri), 0x05);
+       ii(md);
+    }
+    else if (r8(ri) != _RSP_REGNO) {
+       if (md == 0 && r7(rb) != _RBP_REGNO) {
+           mrm(0x00, r7(rd), 0x04);
+           sib(ms, r7(ri), r7(rb));
+       }
+       else if ((jit_int8_t)md == md) {
+           mrm(0x01, r7(rd), 0x04);
+           sib(ms, r7(ri), r7(rb));
+           ic(md);
+       }
+       else {
+           mrm(0x02, r7(rd), 0x04);
+           sib(ms, r7(ri), r7(rb));
+           ic(md);
+       }
+    }
+    else {
+       fprintf(stderr, "illegal index register");
+       abort();
+    }
+}
+
+static void
+_nop(jit_state_t *_jit, jit_int32_t count)
+{
+    switch (count) {
+       case 0:
+           break;
+       case 1:         /* NOP */
+           ic(0x90);   break;
+       case 2:         /* 66 NOP */
+           ic(0x66);   ic(0x90);
+           break;
+       case 3:         /* NOP DWORD ptr [EAX] */
+           ic(0x0f);   ic(0x1f);       ic(0x00);
+           break;
+       case 4:         /* NOP DWORD ptr [EAX + 00H] */
+           ic(0x0f);   ic(0x1f);       ic(0x40);       ic(0x00);
+           break;
+       case 5:         /* NOP DWORD ptr [EAX + EAX*1 + 00H] */
+           ic(0x0f);   ic(0x1f);       ic(0x44);       ic(0x00);
+           ic(0x00);
+           break;
+       case 6:         /* 66 NOP DWORD ptr [EAX + EAX*1 + 00H] */
+           ic(0x66);   ic(0x0f);       ic(0x1f);       ic(0x44);
+           ic(0x00);   ic(0x00);
+           break;
+       case 7:         /* NOP DWORD ptr [EAX + 00000000H] */
+           ic(0x0f);   ic(0x1f);       ic(0x80);       ii(0x0000);
+           break;
+       case 8:         /* NOP DWORD ptr [EAX + EAX*1 + 00000000H] */
+           ic(0x0f);   ic(0x1f);       ic(0x84);       ic(0x00);
+           ii(0x0000);
+           break;
+       case 9:         /* 66 NOP DWORD ptr [EAX + EAX*1 + 00000000H] */
+           ic(0x66);   ic(0x0f);       ic(0x1f);       ic(0x84);
+           ic(0x00);   ii(0x0000);
+           break;
+       default:
+           abort();
+    }
+}
+
+static void
+_lea(jit_state_t *_jit, jit_int32_t md, jit_int32_t rb,
+     jit_int32_t ri, jit_int32_t ms, jit_int32_t rd)
+{
+    rex(0, WIDE, rd, ri, rb);
+    ic(0x8d);
+    rx(rd, md, rb, ri, ms);
+}
+
+static void
+_pushr(jit_state_t *_jit, jit_int32_t r0)
+{
+    rex(0, WIDE, 0, 0, r0);
+    ic(0x50 | r7(r0));
+}
+
+static void
+_popr(jit_state_t *_jit, jit_int32_t r0)
+{
+    rex(0, WIDE, 0, 0, r0);
+    ic(0x58 | r7(r0));
+}
+
+static void
+_xchgr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r1, _NOREG, r0);
+    ic(0x87);
+    mrm(0x03, r7(r1), r7(r0));
+}
+
+static void
+_testr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r1, _NOREG, r0);
+    ic(0x85);
+    mrm(0x03, r7(r1), r7(r0));
+}
+
+static void
+_testi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    rex(0, WIDE, _NOREG, _NOREG, r0);
+    if (r0 == _RAX_REGNO)
+       ic(0xa9);
+    else {
+       ic(0xf7);
+       mrm(0x03, 0x00, r7(r0));
+    }
+    ii(i0);
+}
+
+static void
+_cc(jit_state_t *_jit, jit_int32_t code, jit_int32_t r0)
+{
+    rex(0, 0, _NOREG, _NOREG, r0);
+    ic(0x0f);
+    ic(0x90 | code);
+    mrm(0x03, 0x00, r7(r0));
+}
+
+static void
+_alur(jit_state_t *_jit, jit_int32_t code, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r1, _NOREG, r0);
+    ic(code | 0x01);
+    mrm(0x03, r7(r1), r7(r0));
+}
+
+static void
+_alui(jit_state_t *_jit, jit_int32_t code, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, _NOREG, _NOREG, r0);
+       if ((jit_int8_t)i0 == i0) {
+           ic(0x83);
+           ic(0xc0 | code | r7(r0));
+           ic(i0);
+       }
+       else {
+           if (r0 == _RAX_REGNO)
+               ic(code | 0x05);
+           else {
+               ic(0x81);
+               ic(0xc0 | code | r7(r0));
+           }
+           ii(i0);
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       alur(code, r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_save(jit_state_t *_jit, jit_int32_t r0)
+{
+    if (!_jitc->function->regoff[r0]) {
+       _jitc->function->regoff[r0] = jit_allocai(sizeof(jit_word_t));
+       _jitc->again = 1;
+    }
+    assert(!jit_regset_tstbit(&_jitc->regsav, r0));
+    jit_regset_setbit(&_jitc->regsav, r0);
+    stxi(_jitc->function->regoff[r0], _RBP_REGNO, r0);
+}
+
+static void
+_load(jit_state_t *_jit, jit_int32_t r0)
+{
+    assert(_jitc->function->regoff[r0]);
+    assert(jit_regset_tstbit(&_jitc->regsav, r0));
+    jit_regset_clrbit(&_jitc->regsav, r0);
+    ldxi(r0, _RBP_REGNO, _jitc->function->regoff[r0]);
+}
+
+static void
+_addr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1)
+       iaddr(r0, r2);
+    else if (r0 == r2)
+       iaddr(r0, r1);
+    else
+       lea(0, r1, r2, _SCL1, r0);
+}
+
+static void
+_addi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       movr(r0, r1);
+#if USE_INC_DEC
+    else if (i0 == 1)
+       incr(r0, r1);
+    else if (i0 == -1)
+       decr(r0, r1);
+#endif
+    else if (can_sign_extend_int_p(i0)) {
+       if (r0 == r1)
+           iaddi(r0, i0);
+       else
+           lea(i0, r1, _NOREG, _SCL1, r0);
+    }
+    else if (r0 != r1) {
+       movi(r0, i0);
+       iaddr(r0, r1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       iaddr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_addcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       iaddr(r0, r1);
+    else {
+       movr(r0, r1);
+       iaddr(r0, r2);
+    }
+}
+
+static void
+_addci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       movr(r0, r1);
+       iaddi(r0, i0);
+    }
+    else if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       iaddr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movi(r0, i0);
+       iaddr(r0, r1);
+    }
+}
+
+static void
+_addxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r2)
+       iaddxr(r0, r1);
+    else {
+       movr(r0, r1);
+       iaddxr(r0, r2);
+    }
+}
+
+static void
+_addxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       movr(r0, r1);
+       iaddxi(r0, i0);
+    }
+    else if (r0 == r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       iaddxr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movi(r0, i0);
+       iaddxr(r0, r1);
+    }
+}
+
+static void
+_subr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       ixorr(r0, r0);
+    else if (r0 == r2) {
+       isubr(r0, r1);
+       inegr(r0);
+    }
+    else {
+       movr(r0, r1);
+       isubr(r0, r2);
+    }
+}
+
+static void
+_subi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       movr(r0, r1);
+#if USE_INC_DEC
+    else if (i0 == 1)
+       decr(r0, r1);
+    else if (i0 == -1)
+       incr(r0, r1);
+#endif
+    else if (can_sign_extend_int_p(i0)) {
+       if (r0 == r1)
+           isubi(r0, i0);
+       else
+           lea(-i0, r1, _NOREG, _SCL1, r0);
+    }
+    else if (r0 != r1) {
+       movi(r0, -i0);
+       iaddr(r0, r1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       isubr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_subcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2 && r0 != r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r0);
+       movr(r0, r1);
+       isubr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movr(r0, r1);
+       isubr(r0, r2);
+    }
+}
+
+static void
+_subci(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    movr(r0, r1);
+    if (can_sign_extend_int_p(i0))
+       isubi(r0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       isubr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_subxr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r2 && r0 != r1) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r0);
+       movr(r0, r1);
+       isubxr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       movr(r0, r1);
+       isubxr(r0, r2);
+    }
+}
+
+static void
+_subxi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    movr(r0, r1);
+    if (can_sign_extend_int_p(i0))
+       isubxi(r0, i0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       imovi(rn(reg), i0);
+       isubxr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_rsbi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    subi(r0, r1, i0);
+    negr(r0, r0);
+}
+
+static void
+_imulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x0f);
+    ic(0xaf);
+    mrm(0x03, r7(r0), r7(r1));
+}
+
+static void
+_imuli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, r0, _NOREG, r1);
+       if ((jit_int8_t)i0 == i0) {
+           ic(0x6b);
+           mrm(0x03, r7(r0), r7(r1));
+           ic(i0);
+       }
+       else {
+           ic(0x69);
+           mrm(0x03, r7(r0), r7(r1));
+           ii(i0);
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       imulr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_mulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1)
+       imulr(r0, r2);
+    else if (r0 == r2)
+       imulr(r0, r1);
+    else {
+       movr(r0, r1);
+       imulr(r0, r2);
+    }
+}
+
+static void
+_muli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    switch (i0) {
+       case 0:
+           ixorr(r0, r0);
+           break;
+       case 1:
+           movr(r0, r1);
+           break;
+       case -1:
+           negr(r0, r1);
+           break;
+       case 2:
+           lea(0, _NOREG, r1, _SCL2, r0);
+           break;
+       case 4:
+           lea(0, _NOREG, r1, _SCL4, r0);
+           break;
+       case 8:
+           lea(0, _NOREG, r1, _SCL8, r0);
+           break;
+       default:
+           if (i0 > 0 && !(i0 & (i0 - 1)))
+               lshi(r0, r1, ffsl(i0) - 1);
+           else if (can_sign_extend_int_p(i0))
+               imuli(r0, r1, i0);
+           else if (r0 != r1) {
+               movi(r0, i0);
+               imulr(r0, r1);
+           }
+           else
+               imuli(r0, r0, i0);
+           break;
+    }
+}
+
+#define savset(rn)                                                     \
+    if (r0 != rn) {                                                    \
+       sav |= 1 << rn;                                                 \
+       if (r1 != rn && r2 != rn)                                       \
+           set |= 1 << rn;                                             \
+    }
+#define isavset(rn)                                                    \
+    if (r0 != rn) {                                                    \
+       sav |= 1 << rn;                                                 \
+       if (r1 != rn)                                                   \
+           set |= 1 << rn;                                             \
+    }
+#define qsavset(rn)                                                    \
+    if (r0 != rn && r1 != rn) {                                                \
+       sav |= 1 << rn;                                                 \
+       if (r2 != rn && r3 != rn)                                       \
+           set |= 1 << rn;                                             \
+    }
+#define allocr(rn, rv)                                                 \
+    if (set & (1 << rn))                                               \
+       (void)jit_get_reg(rv|jit_class_gpr|jit_class_named);            \
+    if (sav & (1 << rn)) {                                             \
+       if ( jit_regset_tstbit(&_jitc->regsav, rv) ||                   \
+           !jit_regset_tstbit(&_jitc->reglive, rv))                    \
+           sav &= ~(1 << rn);                                          \
+       else                                                            \
+           save(rv);                                                   \
+    }
+#define clear(rn, rv)                                                  \
+    if (set & (1 << rn))                                               \
+       jit_unget_reg(rv);                                              \
+    if (sav & (1 << rn))                                               \
+       load(rv);
+static void
+_iqmulr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    jit_int32_t                mul;
+    jit_int32_t                sav;
+    jit_int32_t                set;
+
+    sav = set = 0;
+    qsavset(_RDX_REGNO);
+    qsavset(_RAX_REGNO);
+    allocr(_RDX_REGNO, _RDX);
+    allocr(_RAX_REGNO, _RAX);
+
+    if (r3 == _RAX_REGNO)
+       mul = r2;
+    else {
+       mul = r3;
+       movr(_RAX_REGNO, r2);
+    }
+    if (sign)
+       umulr(mul);
+    else
+       umulr_u(mul);
+
+    if (r0 == _RDX_REGNO && r1 == _RAX_REGNO)
+       xchgr(_RAX_REGNO, _RDX_REGNO);
+    else {
+       if (r0 != _RDX_REGNO)
+           movr(r0, _RAX_REGNO);
+       movr(r1, _RDX_REGNO);
+       if (r0 == _RDX_REGNO)
+           movr(r0, _RAX_REGNO);
+    }
+
+    clear(_RDX_REGNO, _RDX);
+    clear(_RAX_REGNO, _RAX);
+}
+
+static void
+_iqmuli(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+
+    if (i0 == 0) {
+       ixorr(r0, r0);
+       ixorr(r1, r1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       if (sign)
+           qmulr(r0, r1, r2, rn(reg));
+       else
+           qmulr_u(r0, r1, r2, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sign_extend_rdx_rax(jit_state_t *_jit)
+{
+    rex(0, WIDE, 0, 0, 0);
+    ic(0x99);
+}
+
+static void
+_divremr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2,
+        jit_bool_t sign, jit_bool_t divide)
+{
+    jit_int32_t                div;
+    jit_int32_t                reg;
+    jit_int32_t                set;
+    jit_int32_t                sav;
+    jit_int32_t                use;
+
+    sav = set = use = 0;
+    savset(_RDX_REGNO);
+    savset(_RAX_REGNO);
+    allocr(_RDX_REGNO, _RDX);
+    allocr(_RAX_REGNO, _RAX);
+
+    if (r2 == _RAX_REGNO) {
+       if (r0 == _RAX_REGNO || r0 == _RDX_REGNO) {
+           if ((reg = jit_get_reg(jit_class_gpr|jit_class_chk)) == JIT_NOREG)
+               reg = jit_get_reg((r1 == _RCX_REGNO ? _RBX : _RCX) |
+                                 jit_class_gpr|jit_class_named);
+           use = 1;
+           div = rn(reg);
+           movr(div, _RAX_REGNO);
+           if (r1 != _RAX_REGNO)
+               movr(_RAX_REGNO, r1);
+       }
+       else {
+           if (r0 == r1)
+               xchgr(r0, _RAX_REGNO);
+           else {
+               if (r0 != _RAX_REGNO)
+                   movr(r0, _RAX_REGNO);
+               if (r1 != _RAX_REGNO)
+                   movr(_RAX_REGNO, r1);
+           }
+           div = r0;
+       }
+    }
+    else if (r2 == _RDX_REGNO) {
+       if (r0 == _RAX_REGNO || r0 == _RDX_REGNO) {
+           if ((reg = jit_get_reg(jit_class_gpr|jit_class_chk)) == JIT_NOREG)
+               reg = jit_get_reg((r1 == _RCX_REGNO ? _RBX : _RCX) |
+                                 jit_class_gpr|jit_class_named);
+           use = 1;
+           div = rn(reg);
+           movr(div, _RDX_REGNO);
+           if (r1 != _RAX_REGNO)
+               movr(_RAX_REGNO, r1);
+       }
+       else {
+           if (r1 != _RAX_REGNO)
+               movr(_RAX_REGNO, r1);
+           movr(r0, _RDX_REGNO);
+           div = r0;
+       }
+    }
+    else {
+       if (r1 != _RAX_REGNO)
+           movr(_RAX_REGNO, r1);
+       div = r2;
+    }
+
+    if (sign) {
+       sign_extend_rdx_rax();
+       idivr(div);
+    }
+    else {
+       ixorr(_RDX_REGNO, _RDX_REGNO);
+       idivr_u(div);
+    }
+
+    if (use)
+       jit_unget_reg(reg);
+
+    if (divide)
+       movr(r0, _RAX_REGNO);
+    else
+       movr(r0, _RDX_REGNO);
+
+    clear(_RDX_REGNO, _RDX);
+    clear(_RAX_REGNO, _RAX);
+}
+
+static void
+_divremi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0,
+        jit_bool_t sign, jit_bool_t divide)
+{
+    jit_int32_t                reg;
+    jit_int32_t                div;
+    jit_int32_t                sav;
+    jit_int32_t                set;
+    jit_int32_t                use;
+
+    if (divide) {
+       switch (i0) {
+           case 1:
+               movr(r0, r1);
+               return;
+           case -1:
+               if (sign) {
+                   negr(r0, r1);
+                   return;
+               }
+               break;
+           default:
+               if (i0 > 0 && !(i0 & (i0 - 1))) {
+                   movr(r0, r1);
+                   if (sign)
+                       rshi(r0, r0, ffsl(i0) - 1);
+                   else
+                       rshi_u(r0, r0, ffsl(i0) - 1);
+                   return;
+               }
+               break;
+       }
+    }
+    else if (i0 == 1 || (sign && i0 == -1)) {
+       ixorr(r0, r0);
+       return;
+    }
+    else if (!sign && i0 > 0 && !(i0 & (i0 - 1))) {
+       if (can_sign_extend_int_p(i0)) {
+           movr(r0, r1);
+           iandi(r0, i0 - 1);
+       }
+       else if (r0 != r1) {
+           movi(r0, i0 - 1);
+           iandr(r0, r1);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0 - 1);
+           iandr(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+       return;
+    }
+
+    sav = set = use = 0;
+    isavset(_RDX_REGNO);
+    isavset(_RAX_REGNO);
+    allocr(_RDX_REGNO, _RDX);
+    allocr(_RAX_REGNO, _RAX);
+
+    if (r0 == _RAX_REGNO || r0 == _RDX_REGNO || r0 == r1) {
+       if ((reg = jit_get_reg(jit_class_gpr|jit_class_chk)) == JIT_NOREG)
+           reg = jit_get_reg((r1 == _RCX_REGNO ? _RBX : _RCX) |
+                             jit_class_gpr|jit_class_named);
+       use = 1;
+       div = rn(reg);
+    }
+    else
+       div = r0;
+
+    movi(div, i0);
+    movr(_RAX_REGNO, r1);
+
+    if (sign) {
+       sign_extend_rdx_rax();
+       idivr(div);
+    }
+    else {
+       ixorr(_RDX_REGNO, _RDX_REGNO);
+       idivr_u(div);
+    }
+
+    if (use)
+       jit_unget_reg(reg);
+
+    if (divide)
+       movr(r0, _RAX_REGNO);
+    else
+       movr(r0, _RDX_REGNO);
+
+    clear(_RDX_REGNO, _RDX);
+    clear(_RAX_REGNO, _RAX);
+}
+
+static void
+_iqdivr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_int32_t r3, jit_bool_t sign)
+{
+    jit_int32_t                div;
+    jit_int32_t                reg;
+    jit_int32_t                sav;
+    jit_int32_t                set;
+    jit_int32_t                use;
+
+    sav = set = use = 0;
+    qsavset(_RDX_REGNO);
+    qsavset(_RAX_REGNO);
+    allocr(_RDX_REGNO, _RDX);
+    allocr(_RAX_REGNO, _RAX);
+    if (r3 == _RAX_REGNO) {
+       if (r0 == _RAX_REGNO || r0 == _RDX_REGNO) {
+           if ((reg = jit_get_reg(jit_class_gpr|jit_class_chk)) == JIT_NOREG)
+               reg = jit_get_reg((r1 == _RCX_REGNO ? _RBX : _RCX) |
+                                 jit_class_gpr|jit_class_named);
+           use = 1;
+           div = rn(reg);
+           movr(div, _RAX_REGNO);
+           if (r2 != _RAX_REGNO)
+               movr(_RAX_REGNO, r2);
+       }
+       else {
+           if (r0 == r2)
+               xchgr(r0, _RAX_REGNO);
+           else {
+               if (r0 != _RAX_REGNO)
+                   movr(r0, _RAX_REGNO);
+               if (r2 != _RAX_REGNO)
+                   movr(_RAX_REGNO, r2);
+           }
+           div = r0;
+       }
+    }
+    else if (r3 == _RDX_REGNO) {
+       if (r0 == _RAX_REGNO || r0 == _RDX_REGNO) {
+           if ((reg = jit_get_reg(jit_class_gpr|jit_class_chk)) == JIT_NOREG)
+               reg = jit_get_reg((r1 == _RCX_REGNO ? _RBX : _RCX) |
+                                 jit_class_gpr|jit_class_named);
+           use = 1;
+           div = rn(reg);
+           movr(div, _RDX_REGNO);
+           if (r2 != _RAX_REGNO)
+               movr(_RAX_REGNO, r2);
+       }
+       else {
+           if (r2 != _RAX_REGNO)
+               movr(_RAX_REGNO, r2);
+           movr(r0, _RDX_REGNO);
+           div = r0;
+       }
+    }
+    else {
+       if (r2 != _RAX_REGNO)
+           movr(_RAX_REGNO, r2);
+       div = r3;
+    }
+    if (sign) {
+       sign_extend_rdx_rax();
+       idivr(div);
+    }
+    else {
+       ixorr(_RDX_REGNO, _RDX_REGNO);
+       idivr_u(div);
+    }
+    if (use)
+       jit_unget_reg(reg);
+
+    if (r0 == _RDX_REGNO && r1 == _RAX_REGNO)
+       xchgr(_RAX_REGNO, _RDX_REGNO);
+    else {
+       if (r0 != _RDX_REGNO)
+           movr(r0, _RAX_REGNO);
+       movr(r1, _RDX_REGNO);
+       if (r0 == _RDX_REGNO)
+           movr(r0, _RAX_REGNO);
+    }
+
+    clear(_RDX_REGNO, _RDX);
+    clear(_RAX_REGNO, _RAX);
+}
+
+static void
+_iqdivi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1,
+       jit_int32_t r2, jit_word_t i0, jit_bool_t sign)
+{
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr);
+    movi(rn(reg), i0);
+    if (sign)
+       qdivr(r0, r1, r2, rn(reg));
+    else
+       qdivr_u(r0, r1, r2, rn(reg));
+    jit_unget_reg(reg);
+}
+#undef clear
+#undef allocr
+#undef savset
+
+static void
+_andr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movr(r0, r1);
+    else if (r0 == r1)
+       iandr(r0, r2);
+    else if (r0 == r2)
+       iandr(r0, r1);
+    else {
+       movr(r0, r1);
+       iandr(r0, r2);
+    }
+}
+
+static void
+_andi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+
+    if (i0 == 0)
+       ixorr(r0, r0);
+    else if (i0 == -1)
+       movr(r0, r1);
+    else if (r0 == r1) {
+       if (can_sign_extend_int_p(i0))
+           iandi(r0, i0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), i0);
+           iandr(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       movi(r0, i0);
+       iandr(r0, r1);
+    }
+}
+
+static void
+_orr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movr(r0, r1);
+    else if (r0 == r1)
+       iorr(r0, r2);
+    else if (r0 == r2)
+       iorr(r0, r1);
+    else {
+       movr(r0, r1);
+       iorr(r0, r2);
+    }
+}
+
+static void
+_ori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (i0 == -1)
+       movi(r0, -1);
+    else if (can_sign_extend_int_p(i0)) {
+       movr(r0, r1);
+       iori(r0, i0);
+    }
+    else if (r0 != r1) {
+       movi(r0, i0);
+       iorr(r0, r1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       iorr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_xorr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       ixorr(r0, r0);
+    else if (r0 == r1)
+       ixorr(r0, r2);
+    else if (r0 == r2)
+       ixorr(r0, r1);
+    else {
+       movr(r0, r1);
+       ixorr(r0, r2);
+    }
+}
+
+static void
+_xori(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (i0 == -1)
+       comr(r0, r1);
+    else if (can_sign_extend_int_p(i0)) {
+       movr(r0, r1);
+       ixori(r0, i0);
+    }
+    else if (r0 != r1) {
+       movi(r0, i0);
+       ixorr(r0, r1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ixorr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_irotshr(jit_state_t *_jit, jit_int32_t code, jit_int32_t r0)
+{
+    rex(0, WIDE, _RCX_REGNO, _NOREG, r0);
+    ic(0xd3);
+    mrm(0x03, code, r7(r0));
+}
+
+static void
+_rotshr(jit_state_t *_jit, jit_int32_t code,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_int32_t                use;
+
+    if (r0 == _RCX_REGNO) {
+       reg = jit_get_reg(jit_class_gpr);
+       movr(rn(reg), r1);
+       if (r2 != _RCX_REGNO)
+           movr(_RCX_REGNO, r2);
+       irotshr(code, rn(reg));
+       movr(_RCX_REGNO, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else if (r2 != _RCX_REGNO) {
+       use = !jit_reg_free_p(_RCX);
+       if (use) {
+           reg = jit_get_reg(jit_class_gpr);
+           movr(rn(reg), _RCX_REGNO);
+       }
+       else
+           reg = 0;
+       if (r1 == _RCX_REGNO) {
+           if (r0 == r2)
+               xchgr(r0, _RCX_REGNO);
+           else {
+               movr(r0, r1);
+               movr(_RCX_REGNO, r2);
+           }
+       }
+       else {
+           movr(_RCX_REGNO, r2);
+           movr(r0, r1);
+       }
+       irotshr(code, r0);
+       if (use) {
+           movr(_RCX_REGNO, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       movr(r0, r1);
+       irotshr(code, r0);
+    }
+}
+
+static void
+_irotshi(jit_state_t *_jit, jit_int32_t code, jit_int32_t r0, jit_word_t i0)
+{
+    rex(0, WIDE, _NOREG, _NOREG, r0);
+    if (i0 == 1) {
+       ic(0xd1);
+       mrm(0x03, code, r7(r0));
+    }
+    else {
+       ic(0xc1);
+       mrm(0x03, code, r7(r0));
+       ic(i0);
+    }
+}
+
+static void
+_rotshi(jit_state_t *_jit, jit_int32_t code,
+       jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    movr(r0, r1);
+    if (i0)
+       irotshi(code, r0, i0);
+}
+
+static void
+_lshi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0 == 0)
+       movr(r0, r1);
+    else if (i0 <= 3)
+       lea(0, _NOREG, r1, i0 == 1 ? _SCL2 : i0 == 2 ? _SCL4 : _SCL8, r0);
+    else
+       rotshi(X86_SHL, r0, r1, i0);
+}
+
+static void
+_unr(jit_state_t *_jit, jit_int32_t code, jit_int32_t r0)
+{
+    rex(0, WIDE, _NOREG, _NOREG, r0);
+    ic(0xf7);
+    mrm(0x03, code, r7(r0));
+}
+
+static void
+_negr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)
+       inegr(r0);
+    else {
+       ixorr(r0, r0);
+       isubr(r0, r1);
+    }
+}
+
+static void
+_comr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    movr(r0, r1);
+    icomr(r0);
+}
+
+#if USE_INC_DEC
+static void
+_incr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    movr(r0, r1);
+#  if __X64
+    rex(0, WIDE, _NOREG, _NOREG, r0);
+    ic(0xff);
+    ic(0xc0 | r7(r0));
+#  else
+    ic(0x40 | r7(r0));
+#  endif
+}
+
+static void
+_decr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    movr(r0, r1);
+#  if __X64
+    rex(0, WIDE, _NOREG, _NOREG, r0);
+    ic(0xff);
+    ic(0xc8 | r7(r0));
+#  else
+    ic(0x48 | r7(r0));
+#  endif
+}
+#endif
+
+static void
+_cr(jit_state_t *_jit,
+    jit_int32_t code, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    jit_bool_t         same;
+    if (reg8_p(r0)) {
+       same = r0 == r1 || r0 == r2;
+       if (!same)
+           ixorr(r0, r0);
+       icmpr(r1, r2);
+       if (same)
+           imovi(r0, 0);
+       cc(code, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_rg8);
+       ixorr(rn(reg), rn(reg));
+       icmpr(r1, r2);
+       cc(code, rn(reg));
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ci(jit_state_t *_jit,
+    jit_int32_t code, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    jit_bool_t         same;
+    if (reg8_p(r0)) {
+       same = r0 == r1;
+       if (!same)
+           ixorr(r0, r0);
+       icmpi(r1, i0);
+       if (same)
+           imovi(r0, 0);
+       cc(code, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_rg8);
+       ixorr(rn(reg), rn(reg));
+       icmpi(r1, i0);
+       cc(code, rn(reg));
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ci0(jit_state_t *_jit, jit_int32_t code, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    jit_bool_t         same;
+    if (reg8_p(r0)) {
+       same = r0 == r1;
+       if (!same)
+           ixorr(r0, r0);
+       testr(r1, r1);
+       if (same)
+           imovi(r0, 0);
+       cc(code, r0);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_rg8);
+       ixorr(rn(reg), rn(reg));
+       testr(r1, r1);
+       cc(code, rn(reg));
+       movr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ltr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 0);
+    else
+       cr(X86_CC_L, r0, r1, r2);
+}
+
+static void
+_lti(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0)
+       ci(X86_CC_L, r0, r1, i0);
+    else
+       ci0(X86_CC_S, r0, r1);
+}
+
+static void
+_ltr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 0);
+    else
+       cr(X86_CC_B, r0, r1, r2);
+}
+
+static void
+_ler(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       cr(X86_CC_LE, r0, r1, r2);
+}
+
+static void
+_ler_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       cr(X86_CC_BE, r0, r1, r2);
+}
+
+static void
+_lei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0)
+       ci(X86_CC_BE, r0, r1, i0);
+    else
+       ci0(X86_CC_E, r0, r1);
+}
+
+static void
+_eqr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       cr(X86_CC_E, r0, r1, r2);
+}
+
+static void
+_eqi(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0)
+       ci(X86_CC_E, r0, r1, i0);
+    else
+       ci0(X86_CC_E, r0, r1);
+}
+
+static void
+_ger(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       cr(X86_CC_GE, r0, r1, r2);
+}
+
+static void
+_gei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0)
+       ci(X86_CC_GE, r0, r1, i0);
+    else
+       ci0(X86_CC_NS, r0, r1);
+}
+
+static void
+_ger_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       cr(X86_CC_AE, r0, r1, r2);
+}
+
+static void
+_gei_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0)
+       ci(X86_CC_AE, r0, r1, i0);
+    else
+       ci0(X86_CC_NB, r0, r1);
+}
+
+static void
+_gtr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 0);
+    else
+       cr(X86_CC_G, r0, r1, r2);
+}
+
+static void
+_gtr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 0);
+    else
+       cr(X86_CC_A, r0, r1, r2);
+}
+
+static void
+_gti_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0)
+       ci(X86_CC_A, r0, r1, i0);
+    else
+       ci0(X86_CC_NE, r0, r1);
+}
+
+static void
+_ner(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 0);
+    else
+       cr(X86_CC_NE, r0, r1, r2);
+}
+
+static void
+_nei(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    if (i0)
+       ci(X86_CC_NE, r0, r1, i0);
+    else
+       ci0(X86_CC_NE, r0, r1);
+}
+
+static void
+_movr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1) {
+       rex(0, 1, r1, _NOREG, r0);
+       ic(0x89);
+       ic(0xc0 | (r1 << 3) | r7(r0));
+    }
+}
+
+static void
+_imovi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+#if __X64
+#  if !__X64_32
+    if (fits_uint32_p(i0)) {
+#  endif
+       rex(0, 0, _NOREG, _NOREG, r0);
+       ic(0xb8 | r7(r0));
+       ii(i0);
+#  if !__X64_32
+    }
+    else {
+       rex(0, 1, _NOREG, _NOREG, r0);
+       ic(0xb8 | r7(r0));
+       il(i0);
+    }
+#  endif
+#else
+    ic(0xb8 | r7(r0));
+    ii(i0);
+#endif
+}
+
+static void
+_movi(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    if (i0)
+       imovi(r0, i0);
+    else
+       ixorr(r0, r0);
+}
+
+static jit_word_t
+_movi_p(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    rex(0, WIDE, _NOREG, _NOREG, r0);
+    ic(0xb8 | r7(r0));
+    il(i0);
+    return (_jit->pc.w);
+}
+
+static void
+_movcr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x0f);
+    ic(0xbe);
+    mrm(0x03, r7(r0), r7(r1));
+}
+
+static void
+_movcr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x0f);
+    ic(0xb6);
+    mrm(0x03, r7(r0), r7(r1));
+}
+
+static void
+_movsr(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x0f);
+    ic(0xbf);
+    mrm(0x03, r7(r0), r7(r1));
+}
+
+static void
+_movsr_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x0f);
+    ic(0xb7);
+    mrm(0x03, r7(r0), r7(r1));
+}
+
+#if __X64
+static void
+_movir(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, 1, r0, _NOREG, r1);
+    ic(0x63);
+    mrm(0x03, r7(r0), r7(r1));
+}
+
+static void
+_movir_u(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, 0, r1, _NOREG, r0);
+    ic(0x89);
+    ic(0xc0 | (r1 << 3) | r7(r0));
+}
+#endif
+
+static void
+_htonr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    extr_us(r0, r1);
+    ic(0x66);
+    rex(0, 0, _NOREG, _NOREG, r0);
+    ic(0xc1);
+    mrm(0x03, X86_ROR, r7(r0));
+    ic(8);
+}
+
+static void
+_htonr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    movr(r0, r1);
+    rex(0, 0, _NOREG, _NOREG, r0);
+    ic(0x0f);
+    ic(0xc8 | r7(r0));
+}
+
+#if __X64 && !__X64_32
+static void
+_htonr_ul(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    movr(r0, r1);
+    rex(0, 1, _NOREG, _NOREG, r0);
+    ic(0x0f);
+    ic(0xc8 | r7(r0));
+}
+#endif
+
+static void
+_extr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (reg8_p(r1))
+       movcr(r0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_rg8);
+       movr(rn(reg), r1);
+       movcr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_extr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (reg8_p(r1))
+       movcr_u(r0, r1);
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_rg8);
+       movr(rn(reg), r1);
+       movcr_u(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x0f);
+    ic(0xbe);
+    rx(r0, 0, r1, _NOREG, _SCL1);
+}
+
+static void
+_ldi_c(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, r0, _NOREG, _NOREG);
+       ic(0x0f);
+       ic(0xbe);
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_c(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x0f);
+    ic(0xb6);
+    rx(r0, 0, r1, _NOREG, _SCL1);
+}
+
+static void
+_ldi_uc(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, r0, _NOREG, _NOREG);
+       ic(0x0f);
+       ic(0xb6);
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_uc(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x0f);
+    ic(0xbf);
+    rx(r0, 0, r1, _NOREG, _SCL1);
+}
+
+static void
+_ldi_s(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, r0, _NOREG, _NOREG);
+       ic(0x0f);
+       ic(0xbf);
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_s(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x0f);
+    ic(0xb7);
+    rx(r0, 0, r1, _NOREG, _SCL1);
+}
+
+static void
+_ldi_us(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, r0, _NOREG, _NOREG);
+       ic(0x0f);
+       ic(0xb7);
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_us(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#if __X32 || !__X64_32
+static void
+_ldr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#if __X64
+    rex(0, WIDE, r0, _NOREG, r1);
+    ic(0x63);
+#else
+    ic(0x8b);
+#endif
+    rx(r0, 0, r1, _NOREG, _SCL1);
+}
+
+static void
+_ldi_i(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+#if __X64
+       rex(0, WIDE, r0, _NOREG, _NOREG);
+       ic(0x63);
+#else
+       ic(0x8b);
+#endif
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_i(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+#endif
+
+#if __X64
+static void
+_ldr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, 0, r0, _NOREG, r1);
+    ic(0x63);
+    rx(r0, 0, r1, _NOREG, _SCL1);
+}
+
+static void
+_ldi_ui(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, 0, r0, _NOREG, _NOREG);
+       ic(0x63);
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_ui(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if !__X64_32
+static void
+_ldr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, 1, r0, _NOREG, r1);
+    ic(0x8b);
+    rx(r0, 0, r1, _NOREG, _SCL1);
+}
+
+static void
+_ldi_l(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, 1, r0, _NOREG, _NOREG);
+       ic(0x8b);
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldr_l(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+#  endif
+#endif
+
+static void
+_ldxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    addr(r0, r1, r2);
+    ldr_c(r0, r0);
+#else
+    rex(0, WIDE, r0, r1, r2);
+    ic(0x0f);
+    ic(0xbe);
+    rx(r0, 0, r2, r1, _SCL1);
+#endif
+}
+
+static void
+_ldxi_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, r0, _NOREG, r1);
+       ic(0x0f);
+       ic(0xbe);
+       rx(r0, i0, r1, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_c(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    addr(r0, r1, r2);
+    ldr_uc(r0, r0);
+#else
+    rex(0, WIDE, r0, r1, r2);
+    ic(0x0f);
+    ic(0xb6);
+    rx(r0, 0, r2, r1, _SCL1);
+#endif
+}
+
+static void
+_ldxi_uc(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, r0, _NOREG, r1);
+       ic(0x0f);
+       ic(0xb6);
+       rx(r0, i0, r1, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_uc(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    addr(r0, r1, r2);
+    ldr_s(r0, r0);
+#else
+    rex(0, WIDE, r0, r1, r2);
+    ic(0x0f);
+    ic(0xbf);
+    rx(r0, 0, r2, r1, _SCL1);
+#endif
+}
+
+static void
+_ldxi_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, r0, _NOREG, r1);
+       ic(0x0f);
+       ic(0xbf);
+       rx(r0, i0, r1, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_s(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_ldxr_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    addr(r0, r1, r2);
+    ldr_us(r0, r0);
+#else
+    rex(0, WIDE, r0, r1, r2);
+    ic(0x0f);
+    ic(0xb7);
+    rx(r0, 0, r2, r1, _SCL1);
+#endif
+}
+
+static void
+_ldxi_us(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, WIDE, r0, _NOREG, r1);
+       ic(0x0f);
+       ic(0xb7);
+       rx(r0, i0, r1, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_us(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#if __X64 || !__X64_32
+static void
+_ldxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64
+    rex(0, WIDE, r0, r1, r2);
+    ic(0x63);
+#else
+    ic(0x8b);
+#endif
+    rx(r0, 0, r2, r1, _SCL1);
+}
+
+static void
+_ldxi_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+#if __X64
+       rex(0, WIDE, r0, _NOREG, r1);
+       ic(0x63);
+#else
+       ic(0x8b);
+#endif
+       rx(r0, i0, r1, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_i(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+#endif
+
+#if __X64
+static void
+_ldxr_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    addr(r0, r1, r2);
+    /* to avoid confusion with macro renames */
+    _ldr_ui(_jit, r0, r0);
+#else
+    rex(0, 0, r0, r1, r2);
+    ic(0x8b);
+    rx(r0, 0, r2, r1, _SCL1);
+#endif
+}
+
+static void
+_ldxi_ui(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, 0, r0, _NOREG, r1);
+       ic(0x8b);
+       rx(r0, i0, r1, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_ui(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+#  if !__X64_32
+static void
+_ldxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    rex(0, 1, r0, r1, r2);
+    ic(0x8b);
+    rx(r0, 0, r2, r1, _SCL1);
+}
+
+static void
+_ldxi_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, 1, r0, _NOREG, r1);
+       ic(0x8b);
+       rx(r0, i0, r1, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       ldxr_l(r0, r1, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+#  endif
+#endif
+
+static void
+_str_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (reg8_p(r1)) {
+       rex(0, 0, r1, _NOREG, r0);
+       ic(0x88);
+       rx(r1, 0, r0, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_rg8);
+       movr(rn(reg), r1);
+       rex(0, 0, rn(reg), _NOREG, r0);
+       ic(0x88);
+       rx(rn(reg), 0, r0, _NOREG, _SCL1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sti_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       if (reg8_p(r0)) {
+           rex(0, 0, r0, _NOREG, _NOREG);
+           ic(0x88);
+           rx(r0, i0, _NOREG, _NOREG, _SCL1);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr|jit_class_rg8);
+           movr(rn(reg), r0);
+           rex(0, 0, rn(reg), _NOREG, _NOREG);
+           ic(0x88);
+           rx(rn(reg), i0, _NOREG, _NOREG, _SCL1);
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_c(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_str_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    ic(0x66);
+    rex(0, 0, r1, _NOREG, r0);
+    ic(0x89);
+    rx(r1, 0, r0, _NOREG, _SCL1);
+}
+
+static void
+_sti_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       ic(0x66);
+       rex(0, 0, r0, _NOREG, _NOREG);
+       ic(0x89);
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_s(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_str_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, 0, r1, _NOREG, r0);
+    ic(0x89);
+    rx(r1, 0, r0, _NOREG, _SCL1);
+}
+
+static void
+_sti_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, 0, r0, _NOREG, _NOREG);
+       ic(0x89);
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_i(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+#if __X64 && !__X64_32
+static void
+_str_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, 1, r1, _NOREG, r0);
+    ic(0x89);
+    rx(r1, 0, r0, _NOREG, _SCL1);
+}
+
+static void
+_sti_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, 1, r0, _NOREG, _NOREG);
+       ic(0x89);
+       rx(r0, i0, _NOREG, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       str_l(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+#endif
+
+static void
+_stxr_c(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+#if __X64_32
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_c(rn(reg), r2);
+    jit_unget_reg(reg);
+#else
+    if (reg8_p(r2)) {
+       rex(0, 0, r2, r1, r0);
+       ic(0x88);
+       rx(r2, 0, r0, r1, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr|jit_class_rg8);
+       movr(rn(reg), r2);
+       rex(0, 0, rn(reg), r1, r0);
+       ic(0x88);
+       rx(rn(reg), 0, r0, r1, _SCL1);
+       jit_unget_reg(reg);
+    }
+#endif
+}
+
+static void
+_stxi_c(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       if (reg8_p(r1)) {
+           rex(0, 0, r1, _NOREG, r0);
+           ic(0x88);
+           rx(r1, i0, r0, _NOREG, _SCL1);
+       }
+       else {
+           reg = jit_get_reg(jit_class_gpr|jit_class_rg8);
+           movr(rn(reg), r1);
+           rex(0, 0, rn(reg), _NOREG, r0);
+           ic(0x88);
+           rx(rn(reg), i0, r0, _NOREG, _SCL1);
+           jit_unget_reg(reg);
+       }
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_c(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_s(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_s(rn(reg), r2);
+    jit_unget_reg(reg);
+#else
+    ic(0x66);
+    rex(0, 0, r2, r1, r0);
+    ic(0x89);
+    rx(r2, 0, r0, r1, _SCL1);
+#endif
+}
+
+static void
+_stxi_s(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       ic(0x66);
+       rex(0, 0, r1, _NOREG, r0);
+       ic(0x89);
+       rx(r1, i0, r0, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_s(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_stxr_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    str_i(rn(reg), r2);
+    jit_unget_reg(reg);
+#else
+    rex(0, 0, r2, r1, r0);
+    ic(0x89);
+    rx(r2, 0, r0, r1, _SCL1);
+#endif
+}
+
+static void
+_stxi_i(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, 0, r1, _NOREG, r0);
+       ic(0x89);
+       rx(r1, i0, r0, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_i(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+
+#if __X64 && !__X64_32
+static void
+_stxr_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    rex(0, 1, r2, r1, r0);
+    ic(0x89);
+    rx(r2, 0, r0, r1, _SCL1);
+}
+
+static void
+_stxi_l(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       rex(0, 1, r1, _NOREG, r0);
+       ic(0x89);
+       rx(r1, i0, r0, _NOREG, _SCL1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       stxr_l(rn(reg), r0, r1);
+       jit_unget_reg(reg);
+    }
+}
+#endif
+
+static void
+_jccs(jit_state_t *_jit, jit_int32_t code, jit_word_t i0)
+{
+    jit_word_t         w;
+    ic(0x70 | code);
+    w = i0 - (_jit->pc.w + 1);
+    ic(w);
+}
+
+static void
+_jcc(jit_state_t *_jit, jit_int32_t code, jit_word_t i0)
+{
+    jit_word_t         w;
+    ic(0x0f);
+    ic(0x80 | code);
+    w = i0 - (_jit->pc.w + 4);
+    ii(w);
+}
+
+static void
+_jcr(jit_state_t *_jit,
+     jit_int32_t code, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    alur(X86_CMP, r0, r1);
+    jcc(code, i0);
+}
+
+static void
+_jci(jit_state_t *_jit,
+     jit_int32_t code, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    alui(X86_CMP, r0, i1);
+    jcc(code, i0);
+}
+
+static void
+_jci0(jit_state_t *_jit, jit_int32_t code, jit_word_t i0, jit_int32_t r0)
+{
+    testr(r0, r0);
+    jcc(code, i0);
+}
+
+static jit_word_t
+_bltr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jcr(X86_CC_L, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_blti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    if (i1)            jci (X86_CC_L, i0, r0, i1);
+    else               jci0(X86_CC_S, i0, r0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bltr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jcr(X86_CC_B, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_blti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    if (i1)            jci (X86_CC_B, i0, r0, i1);
+    else               jci0(X86_CC_B, i0, r0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bler(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)      jmpi(i0);
+    else               jcr (X86_CC_LE, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_blei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    if (i1)            jci (X86_CC_LE, i0, r0, i1);
+    else               jci0(X86_CC_LE, i0, r0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bler_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)      jmpi(i0);
+    else               jcr (X86_CC_BE, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_blei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    if (i1)            jci (X86_CC_BE, i0, r0, i1);
+    else               jci0(X86_CC_BE, i0, r0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_beqr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)      jmpi(i0);
+    else               jcr (X86_CC_E, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_beqi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    if (i1)            jci (X86_CC_E, i0, r0, i1);
+    else               jci0(X86_CC_E, i0, r0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bger(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)      jmpi(i0);
+    else               jcr (X86_CC_GE, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bgei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    if (i1)            jci (X86_CC_GE, i0, r0, i1);
+    else               jci0(X86_CC_NS, i0, r0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bger_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)      jmpi(i0);
+    else               jcr (X86_CC_AE, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bgei_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    if (i1)            jci (X86_CC_AE, i0, r0, i1);
+    else               jmpi(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bgtr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jcr(X86_CC_G, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bgti(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jci(X86_CC_G, i0, r0, i1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bgtr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jcr(X86_CC_A, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bgti_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    if (i1)            jci (X86_CC_A, i0, r0, i1);
+    else               jci0(X86_CC_NE, i0, r0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bner(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jcr(X86_CC_NE, i0, r0, r1);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bnei(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    if (i1)            jci (X86_CC_NE, i0, r0, i1);
+    else               jci0(X86_CC_NE, i0, r0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bmsr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    testr(r0, r1);
+    jnz(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bmsi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_int_p(i1))
+       testi(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       testr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    jnz(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bmcr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    testr(r0, r1);
+    jz(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bmci(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_zero_extend_int_p(i1))
+       testi(r0, i1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i1);
+       testr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    jz(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_boaddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    iaddr(r0, r1);
+    jo(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_boaddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i1)) {
+       iaddi(r0, i1);
+       jo(i0);
+       return (_jit->pc.w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    jit_unget_reg(reg);
+    return (boaddr(i0, r0, rn(reg)));
+}
+
+static jit_word_t
+_boaddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    iaddr(r0, r1);
+    jc(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_boaddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i1)) {
+       iaddi(r0, i1);
+       jc(i0);
+       return (_jit->pc.w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    jit_unget_reg(reg);
+    return (boaddr_u(i0, r0, rn(reg)));
+}
+
+static jit_word_t
+_bxaddr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    iaddr(r0, r1);
+    jno(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bxaddi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i1)) {
+       iaddi(r0, i1);
+       jno(i0);
+       return (_jit->pc.w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    jit_unget_reg(reg);
+    return (bxaddr(i0, r0, rn(reg)));
+}
+
+static jit_word_t
+_bxaddr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    iaddr(r0, r1);
+    jnc(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bxaddi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i1)) {
+       iaddi(r0, i1);
+       jnc(i0);
+       return (_jit->pc.w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    jit_unget_reg(reg);
+    return (bxaddr_u(i0, r0, rn(reg)));
+}
+
+static jit_word_t
+_bosubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    isubr(r0, r1);
+    jo(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bosubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i1)) {
+       isubi(r0, i1);
+       jo(i0);
+       return (_jit->pc.w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    jit_unget_reg(reg);
+    return (bosubr(i0, r0, rn(reg)));
+}
+
+static jit_word_t
+_bosubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    isubr(r0, r1);
+    jc(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bosubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i1)) {
+       isubi(r0, i1);
+       jc(i0);
+       return (_jit->pc.w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    jit_unget_reg(reg);
+    return (bosubr_u(i0, r0, rn(reg)));
+}
+
+static jit_word_t
+_bxsubr(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    isubr(r0, r1);
+    jno(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bxsubi(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i1)) {
+       isubi(r0, i1);
+       jno(i0);
+       return (_jit->pc.w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    jit_unget_reg(reg);
+    return (bxsubr(i0, r0, rn(reg)));
+}
+
+static jit_word_t
+_bxsubr_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    isubr(r0, r1);
+    jnc(i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_bxsubi_u(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_word_t i1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i1)) {
+       isubi(r0, i1);
+       jnc(i0);
+       return (_jit->pc.w);
+    }
+    reg = jit_get_reg(jit_class_gpr|jit_class_nospill);
+    movi(rn(reg), i1);
+    jit_unget_reg(reg);
+    return (bxsubr_u(i0, r0, rn(reg)));
+}
+
+static void
+_callr(jit_state_t *_jit, jit_int32_t r0)
+{
+    rex(0, 0, _NOREG, _NOREG, r0);
+    ic(0xff);
+    mrm(0x03, 0x02, r7(r0));
+}
+
+static jit_word_t
+_calli(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         word;
+#if __X64
+    jit_int32_t                reg;
+
+    reg = jit_get_reg(jit_class_gpr);
+    word = movi_p(rn(reg), i0);
+    callr(rn(reg));
+    jit_unget_reg(reg);
+#else
+    jit_word_t         w;
+    ic(0xe8);
+    w = i0 - (_jit->pc.w + 4);
+    ii(w);
+    word = _jit->pc.w;
+#endif
+    return (word);
+}
+
+static void
+_jmpr(jit_state_t *_jit, jit_int32_t r0)
+{
+    rex(0, WIDE, _NOREG, _NOREG, r0);
+    ic(0xff);
+    mrm(0x03, 0x04, r7(r0));
+}
+
+static jit_word_t
+_jmpi(jit_state_t *_jit, jit_word_t i0)
+{
+    jit_word_t         w;
+    ic(0xe9);
+    w = i0 - (_jit->pc.w + 4);
+    ii(w);
+    return (_jit->pc.w);
+}
+
+static void
+_jmpsi(jit_state_t *_jit, jit_uint8_t i0)
+{
+    ic(0xeb);
+    ic(i0);
+}
+
+static void
+_prolog(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                reg;
+    if (_jitc->function->define_frame || _jitc->function->assume_frame) {
+       jit_int32_t     frame = -_jitc->function->frame;
+       assert(_jitc->function->self.aoff >= frame);
+       if (_jitc->function->assume_frame)
+           return;
+       _jitc->function->self.aoff = frame;
+    }
+    if (_jitc->function->allocar)
+       _jitc->function->self.aoff &= -16;
+#if __X64 && (__CYGWIN__ || _WIN32)
+    _jitc->function->stack = (((/* first 32 bytes must be allocated */
+                               (_jitc->function->self.alen > 32 ?
+                                _jitc->function->self.alen : 32) -
+                               /* align stack at 16 bytes */
+                               _jitc->function->self.aoff) + 15) & -16) +
+       stack_adjust;
+#else
+    _jitc->function->stack = (((_jitc->function->self.alen -
+                              _jitc->function->self.aoff) + 15) & -16) +
+       stack_adjust;
+#endif
+    subi(_RSP_REGNO, _RSP_REGNO, stack_framesize - REAL_WORDSIZE);
+    /* callee save registers */
+#if __X32
+    if (jit_regset_tstbit(&_jitc->function->regset, _RDI))
+       stxi(12, _RSP_REGNO, _RDI_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RSI))
+       stxi( 8, _RSP_REGNO, _RSI_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RBX))
+       stxi( 4, _RSP_REGNO, _RBX_REGNO);
+#else
+#  if __CYGWIN__ || _WIN32
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM15))
+       sse_stxi_d(136, _RSP_REGNO, _XMM15_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM14))
+       sse_stxi_d(128, _RSP_REGNO, _XMM14_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM13))
+       sse_stxi_d(120, _RSP_REGNO, _XMM13_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM12))
+       sse_stxi_d(112, _RSP_REGNO, _XMM12_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM11))
+       sse_stxi_d(104, _RSP_REGNO, _XMM11_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM10))
+       sse_stxi_d(96, _RSP_REGNO, _XMM10_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM9))
+       sse_stxi_d(88, _RSP_REGNO, _XMM9_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM8))
+       sse_stxi_d(80, _RSP_REGNO, _XMM8_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM7))
+       sse_stxi_d(72, _RSP_REGNO, _XMM7_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM6))
+       sse_stxi_d(64, _RSP_REGNO, _XMM6_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R15))
+       stxi(56, _RSP_REGNO, _R15_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R14))
+       stxi(48, _RSP_REGNO, _R14_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R13))
+       stxi(40, _RSP_REGNO, _R13_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R12))
+       stxi(32, _RSP_REGNO, _R12_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RSI))
+       stxi(24, _RSP_REGNO, _RSI_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RDI))
+       stxi(16, _RSP_REGNO, _RDI_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RBX))
+       stxi( 8, _RSP_REGNO, _RBX_REGNO);
+#  else
+    if (jit_regset_tstbit(&_jitc->function->regset, _RBX))
+       stxi(40, _RSP_REGNO, _RBX_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R12))
+       stxi(32, _RSP_REGNO, _R12_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R13))
+       stxi(24, _RSP_REGNO, _R13_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R14))
+       stxi(16, _RSP_REGNO, _R14_REGNO);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R15))
+       stxi( 8, _RSP_REGNO, _R15_REGNO);
+#  endif
+#endif
+    stxi(0, _RSP_REGNO, _RBP_REGNO);
+    movr(_RBP_REGNO, _RSP_REGNO);
+
+    /* alloca */
+    subi(_RSP_REGNO, _RSP_REGNO, _jitc->function->stack);
+    if (_jitc->function->allocar) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), _jitc->function->self.aoff);
+       stxi_i(_jitc->function->aoffoff, _RBP_REGNO, rn(reg));
+       jit_unget_reg(reg);
+    }
+
+#if __X64 && !(__CYGWIN__ || _WIN32)
+    if (_jitc->function->self.call & jit_call_varargs) {
+       jit_word_t      nofp_code;
+
+       /* Save gp registers in the save area, if any is a vararg */
+       for (reg = first_gp_from_offset(_jitc->function->vagp);
+            jit_arg_reg_p(reg); ++reg)
+           stxi(_jitc->function->vaoff + first_gp_offset +
+                reg * 8, _RBP_REGNO, rn(JIT_RA0 - reg));
+
+       reg = first_fp_from_offset(_jitc->function->vafp);
+       if (jit_arg_f_reg_p(reg)) {
+           /* Skip over if no float registers were passed as argument */
+           /* test %al, %al */
+           ic(0x84);
+           ic(0xc0);
+           jes(0);
+           nofp_code = _jit->pc.w;
+
+           /* Save fp registers in the save area, if any is a vararg */
+           /* Note that the full 16 byte xmm is not saved, because
+            * lightning only handles float and double, and, while
+            * attempting to provide a va_list compatible pointer as
+            * jit_va_start return, does not guarantee it (on all ports). */
+           for (; jit_arg_f_reg_p(reg); ++reg)
+               sse_stxi_d(_jitc->function->vaoff + first_fp_offset +
+                          reg * va_fp_increment, _RBP_REGNO, rn(_XMM0 - reg));
+
+           patch_rel_char(nofp_code, _jit->pc.w);
+       }
+    }
+#endif
+}
+
+static void
+_epilog(jit_state_t *_jit, jit_node_t *node)
+{
+    if (_jitc->function->assume_frame)
+       return;
+    /* callee save registers */
+    movr(_RSP_REGNO, _RBP_REGNO);
+#if __X32
+    if (jit_regset_tstbit(&_jitc->function->regset, _RDI))
+       ldxi(_RDI_REGNO, _RSP_REGNO, 12);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RSI))
+       ldxi(_RSI_REGNO, _RSP_REGNO,  8);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RBX))
+       ldxi(_RBX_REGNO, _RSP_REGNO,  4);
+#else
+#  if __CYGWIN__ || _WIN32
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM15))
+       sse_ldxi_d(_XMM15_REGNO, _RSP_REGNO, 136);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM14))
+       sse_ldxi_d(_XMM14_REGNO, _RSP_REGNO, 128);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM13))
+       sse_ldxi_d(_XMM13_REGNO, _RSP_REGNO, 120);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM12))
+       sse_ldxi_d(_XMM12_REGNO, _RSP_REGNO, 112);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM11))
+       sse_ldxi_d(_XMM11_REGNO, _RSP_REGNO, 104);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM10))
+       sse_ldxi_d(_XMM10_REGNO, _RSP_REGNO, 96);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM9))
+       sse_ldxi_d(_XMM9_REGNO, _RSP_REGNO, 88);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM8))
+       sse_ldxi_d(_XMM8_REGNO, _RSP_REGNO, 80);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM7))
+       sse_ldxi_d(_XMM7_REGNO, _RSP_REGNO, 72);
+    if (jit_regset_tstbit(&_jitc->function->regset, _XMM6))
+       sse_ldxi_d(_XMM6_REGNO, _RSP_REGNO, 64);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R15))
+       ldxi(_R15_REGNO, _RSP_REGNO, 56);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R14))
+       ldxi(_R14_REGNO, _RSP_REGNO, 48);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R13))
+       ldxi(_R13_REGNO, _RSP_REGNO, 40);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R12))
+       ldxi(_R12_REGNO, _RSP_REGNO, 32);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RSI))
+       ldxi(_RSI_REGNO, _RSP_REGNO, 24);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RDI))
+       ldxi(_RDI_REGNO, _RSP_REGNO, 16);
+    if (jit_regset_tstbit(&_jitc->function->regset, _RBX))
+       ldxi(_RBX_REGNO, _RSP_REGNO,  8);
+#  else
+    if (jit_regset_tstbit(&_jitc->function->regset, _RBX))
+       ldxi(_RBX_REGNO, _RSP_REGNO, 40);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R12))
+       ldxi(_R12_REGNO, _RSP_REGNO, 32);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R13))
+       ldxi(_R13_REGNO, _RSP_REGNO, 24);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R14))
+       ldxi(_R14_REGNO, _RSP_REGNO, 16);
+    if (jit_regset_tstbit(&_jitc->function->regset, _R15))
+       ldxi(_R15_REGNO, _RSP_REGNO,  8);
+#  endif
+#endif
+    ldxi(_RBP_REGNO, _RSP_REGNO, 0);
+    addi(_RSP_REGNO, _RSP_REGNO, stack_framesize - REAL_WORDSIZE);
+
+    ic(0xc3);
+}
+
+static void
+_vastart(jit_state_t *_jit, jit_int32_t r0)
+{
+#if __X32 || __CYGWIN__ || _WIN32
+    assert(_jitc->function->self.call & jit_call_varargs);
+    addi(r0, _RBP_REGNO, _jitc->function->self.size);
+#else
+    jit_int32_t                reg;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    /* Return jit_va_list_t in the register argument */
+    addi(r0, _RBP_REGNO, _jitc->function->vaoff);
+    reg = jit_get_reg(jit_class_gpr);
+
+    /* Initialize gp offset in the save area. */
+    movi(rn(reg), _jitc->function->vagp);
+    stxi_i(offsetof(jit_va_list_t, gpoff), r0, rn(reg));
+
+    /* Initialize fp offset in the save area. */
+    movi(rn(reg), _jitc->function->vafp);
+    stxi_i(offsetof(jit_va_list_t, fpoff), r0, rn(reg));
+
+    /* Initialize overflow pointer to the first stack argument. */
+    addi(rn(reg), _RBP_REGNO, _jitc->function->self.size);
+    stxi(offsetof(jit_va_list_t, over), r0, rn(reg));
+
+    /* Initialize register save area pointer. */
+    addi(rn(reg), r0, first_gp_offset);
+    stxi(offsetof(jit_va_list_t, save), r0, rn(reg));
+
+    jit_unget_reg(reg);
+#endif
+}
+
+static void
+_vaarg(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#if __X32 || __CYGWIN__ || _WIN32
+    assert(_jitc->function->self.call & jit_call_varargs);
+    ldr(r0, r1);
+    addi(r1, r1, va_gp_increment);
+#else
+    jit_int32_t                rg0;
+    jit_int32_t                rg1;
+    jit_word_t         ge_code;
+    jit_word_t         lt_code;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg(jit_class_gpr);
+    rg1 = jit_get_reg(jit_class_gpr);
+
+    /* Load the gp offset in save area in the first temporary. */
+    ldxi_i(rn(rg0), r1, offsetof(jit_va_list_t, gpoff));
+
+    /* Jump over if there are no remaining arguments in the save area. */
+    icmpi(rn(rg0), va_gp_max_offset);
+    jaes(0);
+    ge_code = _jit->pc.w;
+
+    /* Load the save area pointer in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, save));
+
+    /* Load the vararg argument in the first argument. */
+    ldxr(r0, rn(rg1), rn(rg0));
+
+    /* Update the gp offset. */
+    addi(rn(rg0), rn(rg0), 8);
+    stxi_i(offsetof(jit_va_list_t, gpoff), r1, rn(rg0));
+
+    /* Will only need one temporary register below. */
+    jit_unget_reg(rg1);
+
+    /* Jump over overflow code. */
+    jmpsi(0);
+    lt_code = _jit->pc.w;
+
+    /* Where to land if argument is in overflow area. */
+    patch_rel_char(ge_code, _jit->pc.w);
+
+    /* Load overflow pointer. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, over));
+
+    /* Load argument. */
+    ldr(r0, rn(rg0));
+
+    /* Update overflow pointer. */
+    addi(rn(rg0), rn(rg0), va_gp_increment);
+    stxi(offsetof(jit_va_list_t, over), r1, rn(rg0));
+
+    /* Where to land if argument is in save area. */
+    patch_rel_char(lt_code, _jit->pc.w);
+
+    jit_unget_reg(rg0);
+#endif
+}
+
+/* The x87 boolean argument tells if will put the result in a x87
+ * register if non false, in a sse register otherwise. */
+static void
+_vaarg_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_bool_t x87)
+{
+#if __X32 || __CYGWIN__ || _WIN32
+    assert(_jitc->function->self.call & jit_call_varargs);
+    if (x87)
+       x87_ldr_d(r0, r1);
+    else
+       sse_ldr_d(r0, r1);
+    addi(r1, r1, 8);
+#else
+    jit_int32_t                rg0;
+    jit_int32_t                rg1;
+    jit_word_t         ge_code;
+    jit_word_t         lt_code;
+
+    assert(_jitc->function->self.call & jit_call_varargs);
+
+    rg0 = jit_get_reg(jit_class_gpr);
+    rg1 = jit_get_reg(jit_class_gpr);
+
+    /* Load the fp offset in save area in the first temporary. */
+    ldxi_i(rn(rg0), r1, offsetof(jit_va_list_t, fpoff));
+
+    /* Jump over if there are no remaining arguments in the save area. */
+    icmpi(rn(rg0), va_fp_max_offset);
+    jaes(0);
+    ge_code = _jit->pc.w;
+
+    /* Load the save area pointer in the second temporary. */
+    ldxi(rn(rg1), r1, offsetof(jit_va_list_t, save));
+
+    /* Load the vararg argument in the first argument. */
+    if (x87)
+       x87_ldxr_d(r0, rn(rg1), rn(rg0));
+    else
+       sse_ldxr_d(r0, rn(rg1), rn(rg0));
+
+    /* Update the fp offset. */
+    addi(rn(rg0), rn(rg0), va_fp_increment);
+    stxi_i(offsetof(jit_va_list_t, fpoff), r1, rn(rg0));
+
+    /* Will only need one temporary register below. */
+    jit_unget_reg(rg1);
+
+    /* Jump over overflow code. */
+    jmpsi(0);
+    lt_code = _jit->pc.w;
+
+    /* Where to land if argument is in overflow area. */
+    patch_rel_char(ge_code, _jit->pc.w);
+
+    /* Load overflow pointer. */
+    ldxi(rn(rg0), r1, offsetof(jit_va_list_t, over));
+
+    /* Load argument. */
+    if (x87)
+       x87_ldr_d(r0, rn(rg0));
+    else
+       sse_ldr_d(r0, rn(rg0));
+
+    /* Update overflow pointer. */
+    addi(rn(rg0), rn(rg0), 8);
+    stxi(offsetof(jit_va_list_t, over), r1, rn(rg0));
+
+    /* Where to land if argument is in save area. */
+    patch_rel_char(lt_code, _jit->pc.w);
+
+    jit_unget_reg(rg0);
+#endif
+}
+
+static void
+_patch_at(jit_state_t *_jit, jit_node_t *node,
+         jit_word_t instr, jit_word_t label)
+{
+    switch (node->code) {
+#  if __X64
+       case jit_code_calli:
+#  endif
+       case jit_code_movi:
+           patch_abs(instr, label);
+           break;
+       default:
+           patch_rel(instr, label);
+           break;
+    }
+}
+#endif
diff --git a/deps/lightning/lib/jit_x86-sse.c b/deps/lightning/lib/jit_x86-sse.c
new file mode 100644 (file)
index 0000000..d09bda9
--- /dev/null
@@ -0,0 +1,1569 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  if __X32
+#    define sse_address_p(i0)          1
+#  else
+#    if __X64_32
+#      define sse_address_p(i0)                ((jit_word_t)(i0) >= 0)
+#    else
+#      define sse_address_p(i0)                can_sign_extend_int_p(i0)
+#    endif
+#  endif
+#  define _XMM6_REGNO                  6
+#  define _XMM7_REGNO                  7
+#  define _XMM8_REGNO                  8
+#  define _XMM9_REGNO                  9
+#  define _XMM10_REGNO                 10
+#  define _XMM11_REGNO                 11
+#  define _XMM12_REGNO                 12
+#  define _XMM13_REGNO                 13
+#  define _XMM14_REGNO                 14
+#  define _XMM15_REGNO                 15
+#define X86_SSE_MOV                    0x10
+#define X86_SSE_MOV1                   0x11
+#define X86_SSE_MOVLP                  0x12
+#define X86_SSE_MOVHP                  0x16
+#define X86_SSE_MOVA                   0x28
+#define X86_SSE_CVTIS                  0x2a
+#define X86_SSE_CVTTSI                 0x2c
+#define X86_SSE_CVTSI                  0x2d
+#define X86_SSE_UCOMI                  0x2e
+#define X86_SSE_COMI                   0x2f
+#define X86_SSE_ROUND                  0x3a
+#define X86_SSE_SQRT                   0x51
+#define X86_SSE_RSQRT                  0x52
+#define X86_SSE_RCP                    0x53
+#define X86_SSE_AND                    0x54
+#define X86_SSE_ANDN                   0x55
+#define X86_SSE_OR                     0x56
+#define X86_SSE_XOR                    0x57
+#define X86_SSE_ADD                    0x58
+#define X86_SSE_MUL                    0x59
+#define X86_SSE_CVTSD                  0x5a
+#define X86_SSE_CVTDT                  0x5b
+#define X86_SSE_SUB                    0x5c
+#define X86_SSE_MIN                    0x5d
+#define X86_SSE_DIV                    0x5e
+#define X86_SSE_MAX                    0x5f
+#define X86_SSE_X2G                    0x6e
+#define X86_SSE_EQB                    0x74
+#define X86_SSE_EQW                    0x75
+#define X86_SSE_EQD                    0x76
+#define X86_SSE_G2X                    0x7e
+#define X86_SSE_MOV2                   0xd6
+#  define sser(c,r0,r1)                        _sser(_jit,c,r0,r1)
+static void _sser(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ssexr(p,c,r0,r1)             _ssexr(_jit,p,c,r0,r1)
+static void _ssexr(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define ssexi(c,r0,m,i)              _ssexi(_jit,c,r0,m,i)
+static void _ssexi(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define addssr(r0, r1)               ssexr(0xf3, X86_SSE_ADD, r0, r1)
+#  define addsdr(r0, r1)               ssexr(0xf2, X86_SSE_ADD, r0, r1)
+#  define subssr(r0, r1)               ssexr(0xf3, X86_SSE_SUB, r0, r1)
+#  define subsdr(r0, r1)               ssexr(0xf2, X86_SSE_SUB, r0, r1)
+#  define mulssr(r0, r1)               ssexr(0xf3, X86_SSE_MUL, r0, r1)
+#  define mulsdr(r0, r1)               ssexr(0xf2, X86_SSE_MUL, r0, r1)
+#  define divssr(r0, r1)               ssexr(0xf3, X86_SSE_DIV, r0, r1)
+#  define divsdr(r0, r1)               ssexr(0xf2, X86_SSE_DIV, r0, r1)
+#  define andpsr(r0, r1)               sser(       X86_SSE_AND, r0, r1)
+#  define andpdr(r0, r1)               ssexr(0x66, X86_SSE_AND, r0, r1)
+#  define sse_truncr_f_i(r0, r1)       ssexr(0xf3, X86_SSE_CVTTSI, r0, r1)
+#  define sse_truncr_d_i(r0, r1)       ssexr(0xf2, X86_SSE_CVTTSI, r0, r1)
+#  if __X64
+#    define sse_truncr_f_l(r0, r1)     sselxr(0xf3, X86_SSE_CVTTSI, r0, r1)
+#    define sse_truncr_d_l(r0, r1)     sselxr(0xf2, X86_SSE_CVTTSI, r0, r1)
+#    define sse_extr_f(r0, r1)         sselxr(0xf3, X86_SSE_CVTIS, r0, r1)
+#    define sse_extr_d(r0, r1)         sselxr(0xf2, X86_SSE_CVTIS, r0, r1)
+#  else
+#    define sse_extr_f(r0, r1)         ssexr(0xf3, X86_SSE_CVTIS, r0, r1)
+#    define sse_extr_d(r0, r1)         ssexr(0xf2, X86_SSE_CVTIS, r0, r1)
+#  endif
+#  define sse_extr_f_d(r0, r1)         ssexr(0xf3, X86_SSE_CVTSD, r0, r1)
+#  define sse_extr_d_f(r0, r1)         ssexr(0xf2, X86_SSE_CVTSD, r0, r1)
+#  define ucomissr(r0,r1)              sser(X86_SSE_UCOMI,r0,r1)
+#  define ucomisdr(r0,r1)              ssexr(0x66,X86_SSE_UCOMI,r0,r1)
+#  define xorpsr(r0,r1)                        sser(X86_SSE_XOR,r0,r1)
+#  define xorpdr(r0,r1)                        ssexr(0x66,X86_SSE_XOR,r0,r1)
+#  define movdlxr(r0,r1)               ssexr(0x66, X86_SSE_X2G,r0,r1)
+#  define pcmpeqlr(r0, r1)             ssexr(0x66, X86_SSE_EQD, r0, r1)
+#  define psrl(r0, i0)                 ssexi(0x72, r0, 0x02, i0)
+#  define psrq(r0, i0)                 ssexi(0x73, r0, 0x02, i0)
+#  define psll(r0, i0)                 ssexi(0x72, r0, 0x06, i0)
+#  define pslq(r0, i0)                 ssexi(0x73, r0, 0x06, i0)
+#  define movdqxr(r0,r1)               sselxr(0x66,X86_SSE_X2G,r0,r1)
+#  if __X64 && !__X64_32
+#    define sselxr(p,c,r0,r1)          _sselxr(_jit,p,c,r0,r1)
+static void
+_sselxr(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t, jit_int32_t);
+#  else
+#    define sselxr(p,c,r0,r1)          ssexr(p,c,r0,r1)
+#  endif
+#  define ssexrx(p,c,md,rb,ri,ms,rd)   _ssexrx(_jit,p,c,md,rb,ri,ms,rd)
+#  define movssmr(md,rb,ri,ms,rd)      ssexrx(0xf3,X86_SSE_MOV,md,rb,ri,ms,rd)
+#  define movsdmr(md,rb,ri,ms,rd)      ssexrx(0xf2,X86_SSE_MOV,md,rb,ri,ms,rd)
+#  define movssrm(rs,md,mb,mi,ms)      ssexrx(0xf3,X86_SSE_MOV1,md,mb,mi,ms,rs)
+#  define movsdrm(rs,md,mb,mi,ms)      ssexrx(0xf2,X86_SSE_MOV1,md,mb,mi,ms,rs)
+static void
+_ssexrx(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t,
+       jit_int32_t, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_addr_f(r0, r1, r2)       _sse_addr_f(_jit, r0, r1, r2)
+static void _sse_addr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_addi_f(r0, r1, i0)       _sse_addi_f(_jit, r0, r1, i0)
+static void _sse_addi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_addr_d(r0, r1, r2)       _sse_addr_d(_jit, r0, r1, r2)
+static void _sse_addr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_addi_d(r0, r1, i0)       _sse_addi_d(_jit, r0, r1, i0)
+static void _sse_addi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_subr_f(r0, r1, r2)       _sse_subr_f(_jit, r0, r1, r2)
+static void _sse_subr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_subi_f(r0, r1, i0)       _sse_subi_f(_jit, r0, r1, i0)
+static void _sse_subi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_subr_d(r0, r1, r2)       _sse_subr_d(_jit, r0, r1, r2)
+static void _sse_subr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_subi_d(r0, r1, i0)       _sse_subi_d(_jit, r0, r1, i0)
+static void _sse_subi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_rsbr_f(r0, r1, r2)       sse_subr_f(r0, r2, r1)
+#  define sse_rsbi_f(r0, r1, i0)       _sse_rsbi_f(_jit, r0, r1, i0)
+static void _sse_rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_rsbr_d(r0, r1, r2)       sse_subr_d(r0, r2, r1)
+#  define sse_rsbi_d(r0, r1, i0)       _sse_rsbi_d(_jit, r0, r1, i0)
+static void _sse_rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_mulr_f(r0, r1, r2)       _sse_mulr_f(_jit, r0, r1, r2)
+static void _sse_mulr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_muli_f(r0, r1, i0)       _sse_muli_f(_jit, r0, r1, i0)
+static void _sse_muli_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_mulr_d(r0, r1, r2)       _sse_mulr_d(_jit, r0, r1, r2)
+static void _sse_mulr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_muli_d(r0, r1, i0)       _sse_muli_d(_jit, r0, r1, i0)
+static void _sse_muli_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_divr_f(r0, r1, r2)       _sse_divr_f(_jit, r0, r1, r2)
+static void _sse_divr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_divi_f(r0, r1, i0)       _sse_divi_f(_jit, r0, r1, i0)
+static void _sse_divi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_divr_d(r0, r1, r2)       _sse_divr_d(_jit, r0, r1, r2)
+static void _sse_divr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_divi_d(r0, r1, i0)       _sse_divi_d(_jit, r0, r1, i0)
+static void _sse_divi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_absr_f(r0, r1)           _sse_absr_f(_jit, r0, r1)
+static void _sse_absr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sse_absr_d(r0, r1)           _sse_absr_d(_jit, r0, r1)
+static void _sse_absr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sse_negr_f(r0, r1)           _sse_negr_f(_jit, r0, r1)
+static void _sse_negr_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sse_negr_d(r0, r1)           _sse_negr_d(_jit, r0, r1)
+static void _sse_negr_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define sse_sqrtr_f(r0, r1)          ssexr(0xf3, X86_SSE_SQRT, r0, r1)
+#  define sse_sqrtr_d(r0, r1)          ssexr(0xf2, X86_SSE_SQRT, r0, r1)
+#  define ssecmpf(code, r0, r1, r2)    _ssecmp(_jit, 0, code, r0, r1, r2)
+#  define ssecmpd(code, r0, r1, r2)    _ssecmp(_jit, 1, code, r0, r1, r2)
+static void
+_ssecmp(jit_state_t*, jit_bool_t, jit_int32_t,
+       jit_int32_t, jit_int32_t, jit_int32_t);
+#define sse_movr_f(r0,r1)              _sse_movr_f(_jit,r0,r1)
+static void _sse_movr_f(jit_state_t*, jit_int32_t, jit_int32_t);
+#define sse_movi_f(r0,i0)              _sse_movi_f(_jit,r0,i0)
+static void _sse_movi_f(jit_state_t*, jit_int32_t, jit_float32_t*);
+#  define sse_lti_f(r0, r1, i0)                _sse_lti_f(_jit, r0, r1, i0)
+static void _sse_lti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_ltr_f(r0, r1, r2)                ssecmpf(X86_CC_A, r0, r1, r2)
+#  define sse_lei_f(r0, r1, i0)                _sse_lei_f(_jit, r0, r1, i0)
+static void _sse_lei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_ler_f(r0, r1, r2)                ssecmpf(X86_CC_AE, r0, r1, r2)
+#  define sse_eqi_f(r0, r1, i0)                _sse_eqi_f(_jit, r0, r1, i0)
+static void _sse_eqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_eqr_f(r0, r1, r2)                _sse_eqr_f(_jit, r0, r1, r2)
+static void _sse_eqr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_gei_f(r0, r1, i0)                _sse_gei_f(_jit, r0, r1, i0)
+static void _sse_gei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_ger_f(r0, r1, r2)                ssecmpf(X86_CC_AE, r0, r2, r1)
+#  define sse_gti_f(r0, r1, i0)                _sse_gti_f(_jit, r0, r1, i0)
+static void _sse_gti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_gtr_f(r0, r1, r2)                ssecmpf(X86_CC_A, r0, r2, r1)
+#  define sse_nei_f(r0, r1, i0)                _sse_nei_f(_jit, r0, r1, i0)
+static void _sse_nei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_ner_f(r0, r1, r2)                _sse_ner_f(_jit, r0, r1, r2)
+static void _sse_ner_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_unlti_f(r0, r1, i0)      _sse_unlti_f(_jit, r0, r1, i0)
+static void _sse_unlti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_unltr_f(r0, r1, r2)      ssecmpf(X86_CC_NAE, r0, r2, r1)
+#  define sse_unlei_f(r0, r1, i0)      _sse_unlei_f(_jit, r0, r1, i0)
+static void _sse_unlei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_unler_f(r0, r1, r2)      _sse_unler_f(_jit, r0, r1, r2)
+#  define sse_uneqi_f(r0, r1, i0)      _sse_uneqi_f(_jit, r0, r1, i0)
+static void _sse_uneqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+static void _sse_unler_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_uneqr_f(r0, r1, r2)      _sse_uneqr_f(_jit, r0, r1, r2)
+static void _sse_uneqr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_ungei_f(r0, r1, i0)      _sse_ungei_f(_jit, r0, r1, i0)
+static void _sse_ungei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_unger_f(r0, r1, r2)      _sse_unger_f(_jit, r0, r1, r2)
+static void _sse_unger_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_ungti_f(r0, r1, i0)      _sse_ungti_f(_jit, r0, r1, i0)
+static void _sse_ungti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_ungtr_f(r0, r1, r2)      ssecmpf(X86_CC_NAE, r0, r1, r2)
+#  define sse_ltgti_f(r0, r1, i0)      _sse_ltgti_f(_jit, r0, r1, i0)
+static void _sse_ltgti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_ltgtr_f(r0, r1, r2)      _sse_ltgtr_f(_jit, r0, r1, r2)
+static void _sse_ltgtr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_ordi_f(r0, r1, i0)       _sse_ordi_f(_jit, r0, r1, i0)
+static void _sse_ordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_ordr_f(r0, r1, r2)       ssecmpf(X86_CC_NP, r0, r2, r1)
+#  define sse_unordi_f(r0, r1, i0)     _sse_unordi_f(_jit, r0, r1, i0)
+static void _sse_unordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define sse_unordr_f(r0, r1, r2)     ssecmpf(X86_CC_P, r0, r2, r1)
+#  define sse_ldr_f(r0, r1)            movssmr(0, r1, _NOREG, _SCL1, r0)
+#  define sse_ldi_f(r0, i0)            _sse_ldi_f(_jit, r0, i0)
+static void _sse_ldi_f(jit_state_t*, jit_int32_t, jit_word_t);
+#  define sse_ldxr_f(r0, r1, r2)       _sse_ldxr_f(_jit, r0, r1, r2)
+static void _sse_ldxr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_ldxi_f(r0, r1, i0)       _sse_ldxi_f(_jit, r0, r1, i0)
+static void _sse_ldxi_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define sse_str_f(r0, r1)            movssrm(r1, 0, r0, _NOREG, _SCL1)
+#  define sse_sti_f(i0, r0)            _sse_sti_f(_jit, i0, r0)
+static void _sse_sti_f(jit_state_t*, jit_word_t,jit_int32_t);
+#  define sse_stxr_f(r0, r1, r2)       _sse_stxr_f(_jit, r0, r1, r2)
+static void _sse_stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_stxi_f(i0, r0, r1)       _sse_stxi_f(_jit, i0, r0, r1)
+static void _sse_stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bltr_f(i0, r0, r1)       _sse_bltr_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bltr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_blti_f(i0, r0, i1)       _sse_blti_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_blti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bler_f(i0, r0, r1)       _sse_bler_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bler_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_blei_f(i0, r0, i1)       _sse_blei_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_blei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_beqr_f(i0, r0, r1)       _sse_beqr_f(_jit, i0, r0, r1)
+static jit_word_t _sse_beqr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_beqi_f(i0, r0, i1)       _sse_beqi_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_beqi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bger_f(i0, r0, r1)       _sse_bger_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bger_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bgei_f(i0, r0, i1)       _sse_bgei_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bgei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bgtr_f(i0, r0, r1)       _sse_bgtr_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bgtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bgti_f(i0, r0, i1)       _sse_bgti_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bgti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bner_f(i0, r0, r1)       _sse_bner_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bner_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bnei_f(i0, r0, i1)       _sse_bnei_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bnei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bunltr_f(i0, r0, r1)     _sse_bunltr_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bunltr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bunlti_f(i0, r0, i1)     _sse_bunlti_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bunlti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bunler_f(i0, r0, r1)     _sse_bunler_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bunler_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bunlei_f(i0, r0, i1)     _sse_bunlei_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bunlei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_buneqr_f(i0, r0, r1)     _sse_buneqr_f(_jit, i0, r0, r1)
+static jit_word_t _sse_buneqr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_buneqi_f(i0, r0, i1)     _sse_buneqi_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_buneqi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bunger_f(i0, r0, r1)     _sse_bunger_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bunger_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bungei_f(i0, r0, i1)     _sse_bungei_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bungei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bungtr_f(i0, r0, r1)     _sse_bungtr_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bungtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bungti_f(i0, r0, i1)     _sse_bungti_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bungti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bltgtr_f(i0, r0, r1)     _sse_bltgtr_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bltgtr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bltgti_f(i0, r0, i1)     _sse_bltgti_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bltgti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bordr_f(i0, r0, r1)      _sse_bordr_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bordr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bordi_f(i0, r0, i1)      _sse_bordi_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bordi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define sse_bunordr_f(i0, r0, r1)    _sse_bunordr_f(_jit, i0, r0, r1)
+static jit_word_t _sse_bunordr_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bunordi_f(i0, r0, i1)    _sse_bunordi_f(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bunordi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#define sse_movr_d(r0,r1)              _sse_movr_d(_jit,r0,r1)
+static void _sse_movr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#define sse_movi_d(r0,i0)              _sse_movi_d(_jit,r0,i0)
+static void _sse_movi_d(jit_state_t*, jit_int32_t, jit_float64_t*);
+#  define sse_ltr_d(r0, r1, r2)                ssecmpd(X86_CC_A, r0, r1, r2)
+#  define sse_lti_d(r0, r1, i0)                _sse_lti_d(_jit, r0, r1, i0)
+static void _sse_lti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_ler_d(r0, r1, r2)                ssecmpd(X86_CC_AE, r0, r1, r2)
+#  define sse_lei_d(r0, r1, i0)                _sse_lei_d(_jit, r0, r1, i0)
+static void _sse_lei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_eqr_d(r0, r1, r2)                _sse_eqr_d(_jit, r0, r1, r2)
+static void _sse_eqr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_eqi_d(r0, r1, i0)                _sse_eqi_d(_jit, r0, r1, i0)
+static void _sse_eqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_ger_d(r0, r1, r2)                ssecmpd(X86_CC_AE, r0, r2, r1)
+#  define sse_gei_d(r0, r1, i0)                _sse_gei_d(_jit, r0, r1, i0)
+static void _sse_gei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_gtr_d(r0, r1, r2)                ssecmpd(X86_CC_A, r0, r2, r1)
+#  define sse_gti_d(r0, r1, i0)                _sse_gti_d(_jit, r0, r1, i0)
+static void _sse_gti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_ner_d(r0, r1, r2)                _sse_ner_d(_jit, r0, r1, r2)
+static void _sse_ner_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_nei_d(r0, r1, i0)                _sse_nei_d(_jit, r0, r1, i0)
+static void _sse_nei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_unltr_d(r0, r1, r2)      ssecmpd(X86_CC_NAE, r0, r2, r1)
+#  define sse_unlti_d(r0, r1, i0)      _sse_unlti_d(_jit, r0, r1, i0)
+static void _sse_unlti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_unler_d(r0, r1, r2)      _sse_unler_d(_jit, r0, r1, r2)
+static void _sse_unler_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_unlei_d(r0, r1, i0)      _sse_unlei_d(_jit, r0, r1, i0)
+static void _sse_unlei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_uneqr_d(r0, r1, r2)      _sse_uneqr_d(_jit, r0, r1, r2)
+static void _sse_uneqr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_uneqi_d(r0, r1, i0)      _sse_uneqi_d(_jit, r0, r1, i0)
+static void _sse_uneqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_unger_d(r0, r1, r2)      _sse_unger_d(_jit, r0, r1, r2)
+static void _sse_unger_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_ungei_d(r0, r1, i0)      _sse_ungei_d(_jit, r0, r1, i0)
+static void _sse_ungei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_ungtr_d(r0, r1, r2)      ssecmpd(X86_CC_NAE, r0, r1, r2)
+#  define sse_ungti_d(r0, r1, i0)      _sse_ungti_d(_jit, r0, r1, i0)
+static void _sse_ungti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_ltgtr_d(r0, r1, r2)      _sse_ltgtr_d(_jit, r0, r1, r2)
+static void _sse_ltgtr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_ltgti_d(r0, r1, i0)      _sse_ltgti_d(_jit, r0, r1, i0)
+static void _sse_ltgti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_ordr_d(r0, r1, r2)       ssecmpd(X86_CC_NP, r0, r2, r1)
+#  define sse_ordi_d(r0, r1, i0)       _sse_ordi_d(_jit, r0, r1, i0)
+static void _sse_ordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_unordr_d(r0, r1, r2)     ssecmpd(X86_CC_P, r0, r2, r1)
+#  define sse_unordi_d(r0, r1, i0)     _sse_unordi_d(_jit, r0, r1, i0)
+static void _sse_unordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define sse_ldr_d(r0, r1)            movsdmr(0, r1, _NOREG, _SCL1, r0)
+#  define sse_ldi_d(r0, i0)            _sse_ldi_d(_jit, r0, i0)
+static void _sse_ldi_d(jit_state_t*, jit_int32_t, jit_word_t);
+#  define sse_ldxr_d(r0, r1, r2)       _sse_ldxr_d(_jit, r0, r1, r2)
+static void _sse_ldxr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define sse_ldxi_d(r0, r1, i0)       _sse_ldxi_d(_jit, r0, r1, i0)
+static void _sse_ldxi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define sse_bltr_d(i0, r0, r1)       _sse_bltr_d(_jit, i0, r0, r1)
+#  define sse_str_d(r0, r1)            movsdrm(r1, 0, r0, _NOREG, _SCL1)
+#  define sse_sti_d(i0, r0)            _sse_sti_d(_jit, i0, r0)
+static void _sse_sti_d(jit_state_t*, jit_word_t,jit_int32_t);
+#  define sse_stxr_d(r0, r1, r2)       _sse_stxr_d(_jit, r0, r1, r2)
+static void _sse_stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define sse_stxi_d(i0, r0, r1)       _sse_stxi_d(_jit, i0, r0, r1)
+static void _sse_stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+static jit_word_t _sse_bltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_blti_d(i0, r0, i1)       _sse_blti_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_blti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bler_d(i0, r0, r1)       _sse_bler_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_blei_d(i0, r0, i1)       _sse_blei_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_blei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_beqr_d(i0, r0, r1)       _sse_beqr_d(_jit, i0, r0, r1)
+static jit_word_t _sse_beqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_beqi_d(i0, r0, i1)       _sse_beqi_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_beqi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bger_d(i0, r0, r1)       _sse_bger_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bgei_d(i0, r0, i1)       _sse_bgei_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bgei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bgtr_d(i0, r0, r1)       _sse_bgtr_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bgti_d(i0, r0, i1)       _sse_bgti_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bgti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bner_d(i0, r0, r1)       _sse_bner_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bner_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bnei_d(i0, r0, i1)       _sse_bnei_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bnei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bunltr_d(i0, r0, r1)     _sse_bunltr_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bunltr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bunlti_d(i0, r0, i1)     _sse_bunlti_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bunlti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bunler_d(i0, r0, r1)     _sse_bunler_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bunler_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bunlei_d(i0, r0, i1)     _sse_bunlei_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bunlei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_buneqr_d(i0, r0, r1)     _sse_buneqr_d(_jit, i0, r0, r1)
+static jit_word_t _sse_buneqr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_buneqi_d(i0, r0, i1)     _sse_buneqi_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_buneqi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bunger_d(i0, r0, r1)     _sse_bunger_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bunger_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bungei_d(i0, r0, i1)     _sse_bungei_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bungei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bungtr_d(i0, r0, r1)     _sse_bungtr_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bungtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bungti_d(i0, r0, i1)     _sse_bungti_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bungti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bltgtr_d(i0, r0, r1)     _sse_bltgtr_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bltgtr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bltgti_d(i0, r0, i1)     _sse_bltgti_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bltgti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bordr_d(i0, r0, r1)      _sse_bordr_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bordi_d(i0, r0, i1)      _sse_bordi_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bordi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define sse_bunordr_d(i0, r0, r1)    _sse_bunordr_d(_jit, i0, r0, r1)
+static jit_word_t _sse_bunordr_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define sse_bunordi_d(i0, r0, i1)    _sse_bunordi_d(_jit, i0, r0, i1)
+static jit_word_t
+_sse_bunordi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#endif
+
+#if CODE
+#  define fpr_opi(name, type, size)                                    \
+static void                                                            \
+_sse_##name##i_##type(jit_state_t *_jit,                               \
+                     jit_int32_t r0, jit_int32_t r1,                   \
+                     jit_float##size##_t *i0)                          \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|jit_class_xpr); \
+    assert(jit_sse_reg_p(reg));                                                \
+    sse_movi_##type(rn(reg), i0);                                      \
+    sse_##name##r_##type(r0, r1, rn(reg));                             \
+    jit_unget_reg(reg);                                                        \
+}
+#  define fpr_bopi(name, type, size)                                   \
+static jit_word_t                                                      \
+_sse_b##name##i_##type(jit_state_t *_jit,                              \
+                      jit_word_t i0, jit_int32_t r0,                   \
+                      jit_float##size##_t *i1)                         \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|jit_class_xpr|  \
+                                         jit_class_nospill);           \
+    assert(jit_sse_reg_p(reg));                                                \
+    sse_movi_##type(rn(reg), i1);                                      \
+    word = sse_b##name##r_##type(i0, r0, rn(reg));                     \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+#  define fopi(name)                   fpr_opi(name, f, 32)
+#  define fbopi(name)                  fpr_bopi(name, f, 32)
+#  define dopi(name)                   fpr_opi(name, d, 64)
+#  define dbopi(name)                  fpr_bopi(name, d, 64)
+static void
+_sser(jit_state_t *_jit, jit_int32_t c, jit_int32_t r0, jit_int32_t r1)
+{
+    rex(0, 0, r0, 0, r1);
+    ic(0x0f);
+    ic(c);
+    mrm(0x03, r7(r0), r7(r1));
+}
+
+static void
+_ssexr(jit_state_t *_jit, jit_int32_t p, jit_int32_t c,
+       jit_int32_t r0, jit_int32_t r1)
+{
+    ic(p);
+    rex(0, 0, r0, 0, r1);
+    ic(0x0f);
+    ic(c);
+    mrm(0x03, r7(r0), r7(r1));
+}
+
+static void
+_ssexi(jit_state_t *_jit, jit_int32_t c, jit_int32_t r0,
+       jit_int32_t m, jit_int32_t i)
+{
+    ic(0x66);
+    rex(0, 0, 0, 0, r0);
+    ic(0x0f);
+    ic(c);
+    mrm(0x03, r7(m), r7(r0));
+    ic(i);
+}
+
+#if __X64
+static void
+_sselxr(jit_state_t *_jit, jit_int32_t p, jit_int32_t c,
+       jit_int32_t r0, jit_int32_t r1)
+{
+    ic(p);
+    rex(0, 1, r0, 0, r1);
+    ic(0x0f);
+    ic(c);
+    mrm(0x03, r7(r0), r7(r1));
+}
+#endif
+
+static void
+_ssexrx(jit_state_t *_jit, jit_int32_t px, jit_int32_t code, jit_int32_t md,
+       jit_int32_t rb, jit_int32_t ri, jit_int32_t ms, jit_int32_t rd)
+{
+    ic(px);
+    rex(0, 0, rd, ri, rb);
+    ic(0x0f);
+    ic(code);
+    rx(rd, md, rb, ri, ms);
+}
+
+static void
+_sse_addr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1)
+       addssr(r0, r2);
+    else if (r0 == r2)
+       addssr(r0, r1);
+    else {
+       sse_movr_f(r0, r1);
+       addssr(r0, r2);
+    }
+}
+
+fopi(add)
+
+static void
+_sse_addr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1)
+       addsdr(r0, r2);
+    else if (r0 == r2)
+       addsdr(r0, r1);
+    else {
+       sse_movr_d(r0, r1);
+       addsdr(r0, r2);
+    }
+}
+
+dopi(add)
+
+static void
+_sse_subr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1)
+       subssr(r0, r2);
+    else if (r0 == r2) {
+       reg = jit_get_reg(jit_class_fpr|jit_class_xpr);
+       sse_movr_f(rn(reg), r0);
+       sse_movr_f(r0, r1);
+       subssr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       sse_movr_f(r0, r1);
+       subssr(r0, r2);
+    }
+}
+
+fopi(sub)
+
+static void
+_sse_subr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1)
+       subsdr(r0, r2);
+    else if (r0 == r2) {
+       reg = jit_get_reg(jit_class_fpr|jit_class_xpr);
+       sse_movr_d(rn(reg), r0);
+       sse_movr_d(r0, r1);
+       subsdr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       sse_movr_d(r0, r1);
+       subsdr(r0, r2);
+    }
+}
+
+dopi(sub)
+
+fopi(rsb)
+
+dopi(rsb)
+
+static void
+_sse_mulr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1)
+       mulssr(r0, r2);
+    else if (r0 == r2)
+       mulssr(r0, r1);
+    else {
+       sse_movr_f(r0, r1);
+       mulssr(r0, r2);
+    }
+}
+
+fopi(mul)
+
+static void
+_sse_mulr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1)
+       mulsdr(r0, r2);
+    else if (r0 == r2)
+       mulsdr(r0, r1);
+    else {
+       sse_movr_d(r0, r1);
+       mulsdr(r0, r2);
+    }
+}
+
+dopi(mul)
+
+static void
+_sse_divr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1)
+       divssr(r0, r2);
+    else if (r0 == r2) {
+       reg = jit_get_reg(jit_class_fpr|jit_class_xpr);
+       sse_movr_f(rn(reg), r0);
+       sse_movr_f(r0, r1);
+       divssr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       sse_movr_f(r0, r1);
+       divssr(r0, r2);
+    }
+}
+
+fopi(div)
+
+static void
+_sse_divr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_int32_t                reg;
+    if (r0 == r1)
+       divsdr(r0, r2);
+    else if (r0 == r2) {
+       reg = jit_get_reg(jit_class_fpr|jit_class_xpr);
+       sse_movr_d(rn(reg), r0);
+       sse_movr_d(r0, r1);
+       divsdr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       sse_movr_d(r0, r1);
+       divsdr(r0, r2);
+    }
+}
+
+dopi(div)
+
+static void
+_sse_absr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_fpr|jit_class_xpr);
+       pcmpeqlr(rn(reg), rn(reg));
+       psrl(rn(reg), 1);
+       andpsr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       pcmpeqlr(r0, r0);
+       psrl(r0, 1);
+       andpsr(r0, r1);
+    }
+}
+
+static void
+_sse_absr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (r0 == r1) {
+       reg = jit_get_reg(jit_class_fpr|jit_class_xpr);
+       pcmpeqlr(rn(reg), rn(reg));
+       psrq(rn(reg), 1);
+       andpdr(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+    else {
+       pcmpeqlr(r0, r0);
+       psrq(r0, 1);
+       andpdr(r0, r1);
+    }
+}
+
+static void
+_sse_negr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                freg, ireg;
+    ireg = jit_get_reg(jit_class_gpr);
+    imovi(rn(ireg), 0x80000000);
+    if (r0 == r1) {
+       freg = jit_get_reg(jit_class_fpr|jit_class_xpr);
+       movdlxr(rn(freg), rn(ireg));
+       xorpsr(r0, rn(freg));
+       jit_unget_reg(freg);
+    }
+    else {
+       movdlxr(r0, rn(ireg));
+       xorpsr(r0, r1);
+    }
+    jit_unget_reg(ireg);
+}
+
+static void
+_sse_negr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                freg, ireg;
+    ireg = jit_get_reg(jit_class_gpr);
+    imovi(rn(ireg), 0x80000000);
+    if (r0 == r1) {
+       freg = jit_get_reg(jit_class_fpr|jit_class_xpr);
+       movdlxr(rn(freg), rn(ireg));
+       pslq(rn(freg), 32);
+       xorpdr(r0, rn(freg));
+       jit_unget_reg(freg);
+    }
+    else {
+       movdlxr(r0, rn(ireg));
+       pslq(r0, 32);
+       xorpdr(r0, r1);
+    }
+    jit_unget_reg(ireg);
+}
+
+static void
+_ssecmp(jit_state_t *_jit, jit_bool_t d, jit_int32_t code,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_bool_t         rc;
+    jit_int32_t                reg;
+    if ((rc = reg8_p(r0)))
+       reg = r0;
+    else {
+       reg = _RAX_REGNO;
+       movr(r0, reg);
+    }
+    ixorr(reg, reg);
+    if (d)
+       ucomisdr(r2, r1);
+    else
+       ucomissr(r2, r1);
+    cc(code, reg);
+    if (!rc)
+       xchgr(r0, reg);
+}
+
+static void
+_sse_movr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       ssexr(0xf3, X86_SSE_MOV, r0, r1);
+}
+
+static void
+_sse_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t      i;
+       jit_float32_t    f;
+    } data;
+    jit_int32_t                 reg;
+    jit_bool_t          ldi;
+
+    data.f = *i0;
+    if (data.f == 0.0 && !(data.i & 0x80000000))
+       xorpsr(r0, r0);
+    else {
+       ldi = !_jitc->no_data;
+#if __X64
+       /* if will allocate a register for offset, just use immediate */
+       if (ldi && !sse_address_p(i0))
+           ldi = 0;
+#endif
+       if (ldi)
+           sse_ldi_f(r0, (jit_word_t)i0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), data.i);
+           movdlxr(r0, rn(reg));
+           jit_unget_reg(reg);
+       }
+    }
+}
+
+fopi(lt)
+fopi(le)
+
+static void
+_sse_eqr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_bool_t         rc;
+    jit_int32_t                reg;
+    jit_word_t         jp_code;
+    if ((rc = reg8_p(r0)))
+       reg = r0;
+    else {
+       reg = _RAX_REGNO;
+       movr(r0, _RAX_REGNO);
+    }
+    ixorr(reg, reg);
+    ucomissr(r2, r1);
+    jpes(0);
+    jp_code = _jit->pc.w;
+    cc(X86_CC_E, reg);
+    patch_rel_char(jp_code, _jit->pc.w);
+    if (!rc)
+       xchgr(r0, reg);
+}
+
+fopi(eq)
+fopi(ge)
+fopi(gt)
+
+static void
+_sse_ner_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_bool_t         rc;
+    jit_int32_t                reg;
+    jit_word_t         jp_code;
+    if ((rc = reg8_p(r0)))
+       reg = r0;
+    else {
+       reg = _RAX_REGNO;
+       movr(r0, _RAX_REGNO);
+    }
+    imovi(reg, 1);
+    ucomissr(r2, r1);
+    jpes(0);
+    jp_code = _jit->pc.w;
+    cc(X86_CC_NE, reg);
+    patch_rel_char(jp_code, _jit->pc.w);
+    if (!rc)
+       xchgr(r0, reg);
+}
+
+fopi(ne)
+fopi(unlt)
+
+static void
+_sse_unler_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       ssecmpf(X86_CC_NA, r0, r2, r1);
+}
+
+fopi(unle)
+
+static void
+_sse_uneqr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       ssecmpf(X86_CC_E, r0, r1, r2);
+}
+
+fopi(uneq)
+
+static void
+_sse_unger_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       ssecmpf(X86_CC_NA, r0, r1, r2);
+}
+
+fopi(unge)
+fopi(ungt)
+
+static void
+_sse_ltgtr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       ixorr(r0, r0);
+    else
+       ssecmpf(X86_CC_NE, r0, r1, r2);
+}
+
+fopi(ltgt)
+fopi(ord)
+fopi(unord)
+
+static void
+_sse_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (sse_address_p(i0))
+       movssmr(i0, _NOREG, _NOREG, _SCL1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       sse_ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sse_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    sse_ldr_f(r0, rn(reg));
+    jit_unget_reg(reg);
+#else
+    movssmr(0, r1, r2, _SCL1, r0);
+#endif
+}
+
+static void
+_sse_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0))
+       movssmr(i0, r1, _NOREG, _SCL1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+#if __X64_32
+       addi(rn(reg), r1, i0);
+       sse_ldr_f(r0, rn(reg));
+#else
+       movi(rn(reg), i0);
+       sse_ldxr_f(r0, r1, rn(reg));
+#endif
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sse_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (sse_address_p(i0))
+       movssrm(r0, i0, _NOREG, _NOREG, _SCL1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       sse_str_f(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sse_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    sse_str_f(rn(reg), r2);
+    jit_unget_reg(reg);
+#else
+    movssrm(r2, 0, r0, r1, _SCL1);
+#endif
+}
+
+static void
+_sse_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0))
+       movssrm(r1, i0, r0, _NOREG, _SCL1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+#if __X64_32
+       addi(rn(reg), r0, i0);
+       sse_str_f(rn(reg), r1);
+#else
+       movi(rn(reg), i0);
+       sse_stxr_f(rn(reg), r0, r1);
+#endif
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_sse_bltr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomissr(r1, r0);
+    ja(i0);
+    return (_jit->pc.w);
+}
+fbopi(lt)
+
+static jit_word_t
+_sse_bler_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomissr(r1, r0);
+    jae(i0);
+    return (_jit->pc.w);
+}
+fbopi(le)
+
+static jit_word_t
+_sse_beqr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         jp_code;
+    ucomissr(r0, r1);
+    jps(0);
+    jp_code = _jit->pc.w;
+    je(i0);
+    patch_rel_char(jp_code, _jit->pc.w);
+    return (_jit->pc.w);
+}
+fbopi(eq)
+
+static jit_word_t
+_sse_bger_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomissr(r0, r1);
+    jae(i0);
+    return (_jit->pc.w);
+}
+fbopi(ge)
+
+static jit_word_t
+_sse_bgtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomissr(r0, r1);
+    ja(i0);
+    return (_jit->pc.w);
+}
+fbopi(gt)
+
+static jit_word_t
+_sse_bner_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         jp_code;
+    jit_word_t         jz_code;
+    ucomissr(r0, r1);
+    jps(0);
+    jp_code = _jit->pc.w;
+    jzs(0);
+    jz_code = _jit->pc.w;
+    patch_rel_char(jp_code, _jit->pc.w);
+    jmpi(i0);
+    patch_rel_char(jz_code, _jit->pc.w);
+    return (_jit->pc.w);
+}
+fbopi(ne)
+
+static jit_word_t
+_sse_bunltr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomissr(r0, r1);
+    jnae(i0);
+    return (_jit->pc.w);
+}
+fbopi(unlt)
+
+static jit_word_t
+_sse_bunler_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)
+       jmpi(i0);
+    else {
+       ucomissr(r0, r1);
+       jna(i0);
+    }
+    return (_jit->pc.w);
+}
+fbopi(unle)
+
+static jit_word_t
+_sse_buneqr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)
+       jmpi(i0);
+    else {
+       ucomissr(r0, r1);
+       je(i0);
+    }
+    return (_jit->pc.w);
+}
+fbopi(uneq)
+
+static jit_word_t
+_sse_bunger_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)
+       jmpi(i0);
+    else {
+       ucomissr(r1, r0);
+       jna(i0);
+    }
+    return (_jit->pc.w);
+}
+fbopi(unge)
+
+static jit_word_t
+_sse_bungtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomissr(r1, r0);
+    jnae(i0);
+    return (_jit->pc.w);
+}
+fbopi(ungt)
+
+static jit_word_t
+_sse_bltgtr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomissr(r0, r1);
+    jne(i0);
+    return (_jit->pc.w);
+}
+fbopi(ltgt)
+
+static jit_word_t
+_sse_bordr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomissr(r0, r1);
+    jnp(i0);
+    return (_jit->pc.w);
+}
+fbopi(ord)
+
+static jit_word_t
+_sse_bunordr_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomissr(r0, r1);
+    jp(i0);
+    return (_jit->pc.w);
+}
+fbopi(unord)
+
+dopi(lt)
+dopi(le)
+
+static void
+_sse_eqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_bool_t         rc;
+    jit_int32_t                reg;
+    jit_word_t         jp_code;
+    if ((rc = reg8_p(r0)))
+       reg = r0;
+    else {
+       reg = _RAX_REGNO;
+       movr(r0, _RAX_REGNO);
+    }
+    ixorr(reg, reg);
+    ucomisdr(r2, r1);
+    jpes(0);
+    jp_code = _jit->pc.w;
+    cc(X86_CC_E, reg);
+    patch_rel_char(jp_code, _jit->pc.w);
+    if (!rc)
+       xchgr(r0, reg);
+}
+
+dopi(eq)
+dopi(ge)
+dopi(gt)
+
+static void
+_sse_ner_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_bool_t         rc;
+    jit_int32_t                reg;
+    jit_word_t         jp_code;
+    if ((rc = reg8_p(r0)))
+       reg = r0;
+    else {
+       reg = _RAX_REGNO;
+       movr(r0, _RAX_REGNO);
+    }
+    imovi(reg, 1);
+    ucomisdr(r2, r1);
+    jpes(0);
+    jp_code = _jit->pc.w;
+    cc(X86_CC_NE, reg);
+    patch_rel_char(jp_code, _jit->pc.w);
+    if (!rc)
+       xchgr(r0, reg);
+}
+
+dopi(ne)
+dopi(unlt)
+
+static void
+_sse_unler_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       ssecmpd(X86_CC_NA, r0, r2, r1);
+}
+
+dopi(unle)
+
+static void
+_sse_uneqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       ssecmpd(X86_CC_E, r0, r1, r2);
+}
+
+dopi(uneq)
+
+static void
+_sse_unger_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       ssecmpd(X86_CC_NA, r0, r1, r2);
+}
+
+dopi(unge)
+dopi(ungt)
+
+static void
+_sse_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       ixorr(r0, r0);
+    else
+       ssecmpd(X86_CC_NE, r0, r1, r2);
+}
+
+dopi(ltgt)
+dopi(ord)
+dopi(unord)
+
+static void
+_sse_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1)
+       ssexr(0xf2, X86_SSE_MOV, r0, r1);
+}
+
+static void
+_sse_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+       jit_int32_t      ii[2];
+       jit_word_t       w;
+       jit_float64_t    d;
+    } data;
+    jit_int32_t                 reg;
+    jit_bool_t          ldi;
+
+    data.d = *i0;
+    if (data.d == 0.0 && !(data.ii[1] & 0x80000000))
+       xorpdr(r0, r0);
+    else {
+       ldi = !_jitc->no_data;
+#if __X64
+       /* if will allocate a register for offset, just use immediate */
+       if (ldi && !sse_address_p(i0))
+           ldi = 0;
+#endif
+       if (ldi)
+           sse_ldi_d(r0, (jit_word_t)i0);
+       else {
+           reg = jit_get_reg(jit_class_gpr);
+#if __X64 && !__X64_32
+           movi(rn(reg), data.w);
+           movdqxr(r0, rn(reg));
+           jit_unget_reg(reg);
+#else
+           movi(rn(reg), data.ii[0]);
+           stxi_i(CVT_OFFSET, _RBP_REGNO, rn(reg));
+           movi(rn(reg), data.ii[1]);
+           stxi_i(CVT_OFFSET + 4, _RBP_REGNO, rn(reg));
+           jit_unget_reg(reg);
+           sse_ldxi_d(r0, _RBP_REGNO, CVT_OFFSET);
+#endif
+       }
+    }
+}
+
+static void
+_sse_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (sse_address_p(i0))
+       movsdmr(i0, _NOREG, _NOREG, _SCL1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       sse_ldr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sse_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    sse_ldr_d(r0, rn(reg));
+    jit_unget_reg(reg);
+#else
+    movsdmr(0, r1, r2, _SCL1, r0);
+#endif
+}
+
+static void
+_sse_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0))
+       movsdmr(i0, r1, _NOREG, _SCL1, r0);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+#if __X64_32
+       addi(rn(reg), r1, i0);
+       sse_ldr_d(r0, rn(reg));
+#else
+       movi(rn(reg), i0);
+       sse_ldxr_d(r0, r1, rn(reg));
+#endif
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sse_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (sse_address_p(i0))
+       movsdrm(r0, i0, _NOREG, _NOREG, _SCL1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       sse_str_d(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_sse_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    sse_str_d(rn(reg), r2);
+    jit_unget_reg(reg);
+#else
+    movsdrm(r2, 0, r0, r1, _SCL1);
+#endif
+}
+
+static void
+_sse_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0))
+       movsdrm(r1, i0, r0, _NOREG, _SCL1);
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+#if __X64_32
+       addi(rn(reg), r0, i0);
+       sse_str_d(rn(reg), r1);
+#else
+       movi(rn(reg), i0);
+       sse_stxr_f(rn(reg), r0, r1);
+#endif
+       jit_unget_reg(reg);
+    }
+}
+
+static jit_word_t
+_sse_bltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomisdr(r1, r0);
+    ja(i0);
+    return (_jit->pc.w);
+}
+dbopi(lt)
+
+static jit_word_t
+_sse_bler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomisdr(r1, r0);
+    jae(i0);
+    return (_jit->pc.w);
+}
+dbopi(le)
+
+static jit_word_t
+_sse_beqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         jp_code;
+    ucomisdr(r0, r1);
+    jps(0);
+    jp_code = _jit->pc.w;
+    je(i0);
+    patch_rel_char(jp_code, _jit->pc.w);
+    return (_jit->pc.w);
+}
+dbopi(eq)
+
+static jit_word_t
+_sse_bger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomisdr(r0, r1);
+    jae(i0);
+    return (_jit->pc.w);
+}
+dbopi(ge)
+
+static jit_word_t
+_sse_bgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomisdr(r0, r1);
+    ja(i0);
+    return (_jit->pc.w);
+}
+dbopi(gt)
+
+static jit_word_t
+_sse_bner_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_word_t         jp_code;
+    jit_word_t         jz_code;
+    ucomisdr(r0, r1);
+    jps(0);
+    jp_code = _jit->pc.w;
+    jzs(0);
+    jz_code = _jit->pc.w;
+    patch_rel_char(jp_code, _jit->pc.w);
+    jmpi(i0);
+    patch_rel_char(jz_code, _jit->pc.w);
+    return (_jit->pc.w);
+}
+dbopi(ne)
+
+static jit_word_t
+_sse_bunltr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomisdr(r0, r1);
+    jnae(i0);
+    return (_jit->pc.w);
+}
+dbopi(unlt)
+
+static jit_word_t
+_sse_bunler_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)
+       jmpi(i0);
+    else {
+       ucomisdr(r0, r1);
+       jna(i0);
+    }
+    return (_jit->pc.w);
+}
+dbopi(unle)
+
+static jit_word_t
+_sse_buneqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)
+       jmpi(i0);
+    else {
+       ucomisdr(r0, r1);
+       je(i0);
+    }
+    return (_jit->pc.w);
+}
+dbopi(uneq)
+
+static jit_word_t
+_sse_bunger_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1)
+       jmpi(i0);
+    else {
+       ucomisdr(r1, r0);
+       jna(i0);
+    }
+    return (_jit->pc.w);
+}
+dbopi(unge)
+
+static jit_word_t
+_sse_bungtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomisdr(r1, r0);
+    jnae(i0);
+    return (_jit->pc.w);
+}
+dbopi(ungt)
+
+static jit_word_t
+_sse_bltgtr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomisdr(r0, r1);
+    jne(i0);
+    return (_jit->pc.w);
+}
+dbopi(ltgt)
+
+static jit_word_t
+_sse_bordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomisdr(r0, r1);
+    jnp(i0);
+    return (_jit->pc.w);
+}
+dbopi(ord)
+
+static jit_word_t
+_sse_bunordr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    ucomisdr(r0, r1);
+    jp(i0);
+    return (_jit->pc.w);
+}
+dbopi(unord)
+#  undef fopi
+#  undef fbopi
+#  undef bopi
+#  undef dbopi
+#  undef fpr_bopi
+#  undef fpr_opi
+#endif
diff --git a/deps/lightning/lib/jit_x86-sz.c b/deps/lightning/lib/jit_x86-sz.c
new file mode 100644 (file)
index 0000000..663b840
--- /dev/null
@@ -0,0 +1,1610 @@
+
+#if __X32
+#define JIT_INSTR_MAX 42
+    0, /* data */
+    0, /* live */
+    3, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    3, /* label */
+    34,        /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    3, /* va_start */
+    5, /* va_arg */
+    7, /* va_arg_d */
+    0, /* va_end */
+    3, /* addr */
+    6, /* addi */
+    4, /* addcr */
+    6, /* addci */
+    4, /* addxr */
+    5, /* addxi */
+    4, /* subr */
+    6, /* subi */
+    6, /* subcr */
+    6, /* subci */
+    6, /* subxr */
+    5, /* subxi */
+    8, /* rsbi */
+    5, /* mulr */
+    7, /* muli */
+    20,        /* qmulr */
+    25,        /* qmuli */
+    20,        /* qmulr_u */
+    25,        /* qmuli_u */
+    21,        /* divr */
+    24,        /* divi */
+    22,        /* divr_u */
+    25,        /* divi_u */
+    23,        /* qdivr */
+    26,        /* qdivi */
+    24,        /* qdivr_u */
+    27,        /* qdivi_u */
+    21,        /* remr */
+    24,        /* remi */
+    22,        /* remr_u */
+    25,        /* remi_u */
+    4, /* andr */
+    7, /* andi */
+    4, /* orr */
+    8, /* ori */
+    4, /* xorr */
+    8, /* xori */
+    16,        /* lshr */
+    7, /* lshi */
+    16,        /* rshr */
+    5, /* rshi */
+    16,        /* rshr_u */
+    5, /* rshi_u */
+    4, /* negr */
+    4, /* comr */
+    15,        /* ltr */
+    16,        /* lti */
+    15,        /* ltr_u */
+    16,        /* lti_u */
+    15,        /* ler */
+    16,        /* lei */
+    15,        /* ler_u */
+    16,        /* lei_u */
+    15,        /* eqr */
+    16,        /* eqi */
+    15,        /* ger */
+    16,        /* gei */
+    15,        /* ger_u */
+    16,        /* gei_u */
+    15,        /* gtr */
+    16,        /* gti */
+    15,        /* gtr_u */
+    16,        /* gti_u */
+    15,        /* ner */
+    16,        /* nei */
+    2, /* movr */
+    5, /* movi */
+    11,        /* extr_c */
+    11,        /* extr_uc */
+    3, /* extr_s */
+    3, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    7, /* htonr_us */
+    4, /* htonr_ui */
+    0, /* htonr_ul */
+    3, /* ldr_c */
+    7, /* ldi_c */
+    3, /* ldr_uc */
+    7, /* ldi_uc */
+    3, /* ldr_s */
+    7, /* ldi_s */
+    3, /* ldr_us */
+    7, /* ldi_us */
+    2, /* ldr_i */
+    6, /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    4, /* ldxr_c */
+    7, /* ldxi_c */
+    4, /* ldxr_uc */
+    7, /* ldxi_uc */
+    4, /* ldxr_s */
+    7, /* ldxi_s */
+    4, /* ldxr_us */
+    7, /* ldxi_us */
+    3, /* ldxr_i */
+    6, /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    10,        /* str_c */
+    14,        /* sti_c */
+    3, /* str_s */
+    7, /* sti_s */
+    2, /* str_i */
+    6, /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    11,        /* stxr_c */
+    11,        /* stxi_c */
+    4, /* stxr_s */
+    7, /* stxi_s */
+    3, /* stxr_i */
+    6, /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    8, /* bltr */
+    9, /* blti */
+    8, /* bltr_u */
+    9, /* blti_u */
+    8, /* bler */
+    12,        /* blei */
+    8, /* bler_u */
+    9, /* blei_u */
+    8, /* beqr */
+    12,        /* beqi */
+    8, /* bger */
+    9, /* bgei */
+    8, /* bger_u */
+    9, /* bgei_u */
+    8, /* bgtr */
+    9, /* bgti */
+    8, /* bgtr_u */
+    9, /* bgti_u */
+    8, /* bner */
+    12,        /* bnei */
+    8, /* bmsr */
+    12,        /* bmsi */
+    8, /* bmcr */
+    12,        /* bmci */
+    8, /* boaddr */
+    9, /* boaddi */
+    8, /* boaddr_u */
+    9, /* boaddi_u */
+    8, /* bxaddr */
+    9, /* bxaddi */
+    8, /* bxaddr_u */
+    9, /* bxaddi_u */
+    8, /* bosubr */
+    9, /* bosubi */
+    8, /* bosubr_u */
+    9, /* bosubi_u */
+    8, /* bxsubr */
+    9, /* bxsubi */
+    8, /* bxsubr_u */
+    9, /* bxsubi_u */
+    2, /* jmpr */
+    5, /* jmpi */
+    2, /* callr */
+    5, /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    24,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    8, /* addr_f */
+    19,        /* addi_f */
+    12,        /* subr_f */
+    19,        /* subi_f */
+    21,        /* rsbi_f */
+    8, /* mulr_f */
+    19,        /* muli_f */
+    12,        /* divr_f */
+    19,        /* divi_f */
+    12,        /* negr_f */
+    12,        /* absr_f */
+    6, /* sqrtr_f */
+    13,        /* ltr_f */
+    27,        /* lti_f */
+    13,        /* ler_f */
+    27,        /* lei_f */
+    15,        /* eqr_f */
+    29,        /* eqi_f */
+    13,        /* ger_f */
+    27,        /* gei_f */
+    13,        /* gtr_f */
+    27,        /* gti_f */
+    18,        /* ner_f */
+    32,        /* nei_f */
+    13,        /* unltr_f */
+    27,        /* unlti_f */
+    13,        /* unler_f */
+    27,        /* unlei_f */
+    13,        /* uneqr_f */
+    27,        /* uneqi_f */
+    13,        /* unger_f */
+    27,        /* ungei_f */
+    13,        /* ungtr_f */
+    27,        /* ungti_f */
+    13,        /* ltgtr_f */
+    27,        /* ltgti_f */
+    13,        /* ordr_f */
+    27,        /* ordi_f */
+    13,        /* unordr_f */
+    27,        /* unordi_f */
+    8, /* truncr_f_i */
+    0, /* truncr_f_l */
+    8, /* extr_f */
+    4, /* extr_d_f */
+    10,        /* movr_f */
+    19,        /* movi_f */
+    4, /* ldr_f */
+    8, /* ldi_f */
+    5, /* ldxr_f */
+    8, /* ldxi_f */
+    6, /* str_f */
+    10,        /* sti_f */
+    7, /* stxr_f */
+    8, /* stxi_f */
+    10,        /* bltr_f */
+    23,        /* blti_f */
+    10,        /* bler_f */
+    23,        /* blei_f */
+    12,        /* beqr_f */
+    25,        /* beqi_f */
+    10,        /* bger_f */
+    23,        /* bgei_f */
+    10,        /* bgtr_f */
+    23,        /* bgti_f */
+    13,        /* bner_f */
+    26,        /* bnei_f */
+    10,        /* bunltr_f */
+    23,        /* bunlti_f */
+    10,        /* bunler_f */
+    23,        /* bunlei_f */
+    10,        /* buneqr_f */
+    23,        /* buneqi_f */
+    10,        /* bunger_f */
+    23,        /* bungei_f */
+    10,        /* bungtr_f */
+    23,        /* bungti_f */
+    10,        /* bltgtr_f */
+    23,        /* bltgti_f */
+    10,        /* bordr_f */
+    23,        /* bordi_f */
+    10,        /* bunordr_f */
+    23,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    10,        /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    8, /* addr_d */
+    26,        /* addi_d */
+    12,        /* subr_d */
+    26,        /* subi_d */
+    30,        /* rsbi_d */
+    8, /* mulr_d */
+    26,        /* muli_d */
+    12,        /* divr_d */
+    26,        /* divi_d */
+    18,        /* negr_d */
+    13,        /* absr_d */
+    6, /* sqrtr_d */
+    13,        /* ltr_d */
+    37,        /* lti_d */
+    13,        /* ler_d */
+    37,        /* lei_d */
+    15,        /* eqr_d */
+    39,        /* eqi_d */
+    13,        /* ger_d */
+    37,        /* gei_d */
+    13,        /* gtr_d */
+    37,        /* gti_d */
+    18,        /* ner_d */
+    42,        /* nei_d */
+    13,        /* unltr_d */
+    37,        /* unlti_d */
+    13,        /* unler_d */
+    37,        /* unlei_d */
+    13,        /* uneqr_d */
+    37,        /* uneqi_d */
+    13,        /* unger_d */
+    37,        /* ungei_d */
+    13,        /* ungtr_d */
+    37,        /* ungti_d */
+    13,        /* ltgtr_d */
+    37,        /* ltgti_d */
+    13,        /* ordr_d */
+    37,        /* ordi_d */
+    13,        /* unordr_d */
+    37,        /* unordi_d */
+    8, /* truncr_d_i */
+    0, /* truncr_d_l */
+    8, /* extr_d */
+    4, /* extr_f_d */
+    10,        /* movr_d */
+    24,        /* movi_d */
+    4, /* ldr_d */
+    8, /* ldi_d */
+    5, /* ldxr_d */
+    8, /* ldxi_d */
+    6, /* str_d */
+    10,        /* sti_d */
+    7, /* stxr_d */
+    8, /* stxi_d */
+    10,        /* bltr_d */
+    28,        /* blti_d */
+    10,        /* bler_d */
+    28,        /* blei_d */
+    12,        /* beqr_d */
+    30,        /* beqi_d */
+    10,        /* bger_d */
+    28,        /* bgei_d */
+    10,        /* bgtr_d */
+    28,        /* bgti_d */
+    13,        /* bner_d */
+    31,        /* bnei_d */
+    10,        /* bunltr_d */
+    28,        /* bunlti_d */
+    10,        /* bunler_d */
+    28,        /* bunlei_d */
+    10,        /* buneqr_d */
+    28,        /* buneqi_d */
+    10,        /* bunger_d */
+    28,        /* bungei_d */
+    10,        /* bungtr_d */
+    28,        /* bungti_d */
+    10,        /* bltgtr_d */
+    28,        /* bltgti_d */
+    10,        /* bordr_d */
+    28,        /* bordi_d */
+    10,        /* bunordr_d */
+    28,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    10,        /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif
+
+#if __X64
+#if __CYGWIN__ || _WIN32
+#define JIT_INSTR_MAX 130
+    0, /* data */
+    0, /* live */
+    6, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    7, /* label */
+    130,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    7, /* va_start */
+    7, /* va_arg */
+    9, /* va_arg_d */
+    0, /* va_end */
+    4, /* addr */
+    13,        /* addi */
+    6, /* addcr */
+    13,        /* addci */
+    6, /* addxr */
+    7, /* addxi */
+    6, /* subr */
+    13,        /* subi */
+    9, /* subcr */
+    13,        /* subci */
+    9, /* subxr */
+    7, /* subxi */
+    16,        /* rsbi */
+    7, /* mulr */
+    14,        /* muli */
+    20,        /* qmulr */
+    30,        /* qmuli */
+    20,        /* qmulr_u */
+    30,        /* qmuli_u */
+    22,        /* divr */
+    29,        /* divi */
+    23,        /* divr_u */
+    30,        /* divi_u */
+    25,        /* qdivr */
+    32,        /* qdivi */
+    26,        /* qdivr_u */
+    33,        /* qdivi_u */
+    22,        /* remr */
+    29,        /* remi */
+    23,        /* remr_u */
+    30,        /* remi_u */
+    6, /* andr */
+    13,        /* andi */
+    6, /* orr */
+    13,        /* ori */
+    6, /* xorr */
+    13,        /* xori */
+    9, /* lshr */
+    8, /* lshi */
+    9, /* rshr */
+    7, /* rshi */
+    9, /* rshr_u */
+    7, /* rshi_u */
+    6, /* negr */
+    6, /* comr */
+    13,        /* ltr */
+    14,        /* lti */
+    13,        /* ltr_u */
+    14,        /* lti_u */
+    13,        /* ler */
+    14,        /* lei */
+    13,        /* ler_u */
+    14,        /* lei_u */
+    13,        /* eqr */
+    14,        /* eqi */
+    13,        /* ger */
+    14,        /* gei */
+    13,        /* ger_u */
+    14,        /* gei_u */
+    13,        /* gtr */
+    14,        /* gti */
+    13,        /* gtr_u */
+    14,        /* gti_u */
+    13,        /* ner */
+    14,        /* nei */
+    3, /* movr */
+    10,        /* movi */
+    7, /* extr_c */
+    7, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    3, /* extr_i */
+    3, /* extr_ui */
+    9, /* htonr_us */
+    6, /* htonr_ui */
+    6, /* htonr_ul */
+    4, /* ldr_c */
+    15,        /* ldi_c */
+    4, /* ldr_uc */
+    15,        /* ldi_uc */
+    4, /* ldr_s */
+    15,        /* ldi_s */
+    4, /* ldr_us */
+    15,        /* ldi_us */
+    3, /* ldr_i */
+    14,        /* ldi_i */
+    3, /* ldr_ui */
+    14,        /* ldi_ui */
+    3, /* ldr_l */
+    14,        /* ldi_l */
+    5, /* ldxr_c */
+    8, /* ldxi_c */
+    5, /* ldxr_uc */
+    8, /* ldxi_uc */
+    5, /* ldxr_s */
+    8, /* ldxi_s */
+    5, /* ldxr_us */
+    8, /* ldxi_us */
+    4, /* ldxr_i */
+    7, /* ldxi_i */
+    4, /* ldxr_ui */
+    6, /* ldxi_ui */
+    4, /* ldxr_l */
+    7, /* ldxi_l */
+    6, /* str_c */
+    17,        /* sti_c */
+    4, /* str_s */
+    15,        /* sti_s */
+    3, /* str_i */
+    14,        /* sti_i */
+    3, /* str_l */
+    14,        /* sti_l */
+    7, /* stxr_c */
+    7, /* stxi_c */
+    5, /* stxr_s */
+    7, /* stxi_s */
+    4, /* stxr_i */
+    6, /* stxi_i */
+    4, /* stxr_l */
+    8, /* stxi_l */
+    9, /* bltr */
+    10,        /* blti */
+    9, /* bltr_u */
+    10,        /* blti_u */
+    9, /* bler */
+    13,        /* blei */
+    9, /* bler_u */
+    10,        /* blei_u */
+    9, /* beqr */
+    19,        /* beqi */
+    9, /* bger */
+    10,        /* bgei */
+    9, /* bger_u */
+    10,        /* bgei_u */
+    9, /* bgtr */
+    10,        /* bgti */
+    9, /* bgtr_u */
+    10,        /* bgti_u */
+    9, /* bner */
+    19,        /* bnei */
+    9, /* bmsr */
+    13,        /* bmsi */
+    9, /* bmcr */
+    13,        /* bmci */
+    9, /* boaddr */
+    10,        /* boaddi */
+    9, /* boaddr_u */
+    10,        /* boaddi_u */
+    9, /* bxaddr */
+    10,        /* bxaddi */
+    9, /* bxaddr_u */
+    10,        /* bxaddi_u */
+    9, /* bosubr */
+    10,        /* bosubi */
+    9, /* bosubr_u */
+    10,        /* bosubi_u */
+    9, /* bxsubr */
+    10,        /* bxsubi */
+    9, /* bxsubr_u */
+    10,        /* bxsubi_u */
+    3, /* jmpr */
+    5, /* jmpi */
+    3, /* callr */
+    13,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    124,       /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    10,        /* addr_f */
+    21,        /* addi_f */
+    15,        /* subr_f */
+    21,        /* subi_f */
+    27,        /* rsbi_f */
+    10,        /* mulr_f */
+    21,        /* muli_f */
+    15,        /* divr_f */
+    21,        /* divi_f */
+    15,        /* negr_f */
+    15,        /* absr_f */
+    5, /* sqrtr_f */
+    16,        /* ltr_f */
+    31,        /* lti_f */
+    16,        /* ler_f */
+    31,        /* lei_f */
+    18,        /* eqr_f */
+    33,        /* eqi_f */
+    16,        /* ger_f */
+    31,        /* gei_f */
+    16,        /* gtr_f */
+    31,        /* gti_f */
+    20,        /* ner_f */
+    35,        /* nei_f */
+    16,        /* unltr_f */
+    31,        /* unlti_f */
+    16,        /* unler_f */
+    31,        /* unlei_f */
+    16,        /* uneqr_f */
+    31,        /* uneqi_f */
+    16,        /* unger_f */
+    31,        /* ungei_f */
+    16,        /* ungtr_f */
+    31,        /* ungti_f */
+    16,        /* ltgtr_f */
+    31,        /* ltgti_f */
+    16,        /* ordr_f */
+    31,        /* ordi_f */
+    16,        /* unordr_f */
+    31,        /* unordi_f */
+    5, /* truncr_f_i */
+    5, /* truncr_f_l */
+    5, /* extr_f */
+    5, /* extr_d_f */
+    5, /* movr_f */
+    15,        /* movi_f */
+    5, /* ldr_f */
+    16,        /* ldi_f */
+    6, /* ldxr_f */
+    8, /* ldxi_f */
+    5, /* str_f */
+    16,        /* sti_f */
+    6, /* stxr_f */
+    9, /* stxi_f */
+    10,        /* bltr_f */
+    21,        /* blti_f */
+    10,        /* bler_f */
+    24,        /* blei_f */
+    12,        /* beqr_f */
+    27,        /* beqi_f */
+    10,        /* bger_f */
+    25,        /* bgei_f */
+    10,        /* bgtr_f */
+    25,        /* bgti_f */
+    13,        /* bner_f */
+    28,        /* bnei_f */
+    10,        /* bunltr_f */
+    25,        /* bunlti_f */
+    10,        /* bunler_f */
+    25,        /* bunlei_f */
+    10,        /* buneqr_f */
+    25,        /* buneqi_f */
+    10,        /* bunger_f */
+    25,        /* bungei_f */
+    10,        /* bungtr_f */
+    25,        /* bungti_f */
+    10,        /* bltgtr_f */
+    25,        /* bltgti_f */
+    10,        /* bordr_f */
+    25,        /* bordi_f */
+    10,        /* bunordr_f */
+    25,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    10,        /* addr_d */
+    25,        /* addi_d */
+    15,        /* subr_d */
+    25,        /* subi_d */
+    27,        /* rsbi_d */
+    10,        /* mulr_d */
+    25,        /* muli_d */
+    15,        /* divr_d */
+    25,        /* divi_d */
+    22,        /* negr_d */
+    16,        /* absr_d */
+    5, /* sqrtr_d */
+    17,        /* ltr_d */
+    32,        /* lti_d */
+    17,        /* ler_d */
+    32,        /* lei_d */
+    19,        /* eqr_d */
+    34,        /* eqi_d */
+    17,        /* ger_d */
+    32,        /* gei_d */
+    17,        /* gtr_d */
+    32,        /* gti_d */
+    21,        /* ner_d */
+    36,        /* nei_d */
+    17,        /* unltr_d */
+    32,        /* unlti_d */
+    17,        /* unler_d */
+    32,        /* unlei_d */
+    17,        /* uneqr_d */
+    32,        /* uneqi_d */
+    17,        /* unger_d */
+    32,        /* ungei_d */
+    17,        /* ungtr_d */
+    32,        /* ungti_d */
+    17,        /* ltgtr_d */
+    32,        /* ltgti_d */
+    17,        /* ordr_d */
+    32,        /* ordi_d */
+    17,        /* unordr_d */
+    32,        /* unordi_d */
+    5, /* truncr_d_i */
+    5, /* truncr_d_l */
+    5, /* extr_d */
+    5, /* extr_f_d */
+    5, /* movr_d */
+    15,        /* movi_d */
+    5, /* ldr_d */
+    16,        /* ldi_d */
+    6, /* ldxr_d */
+    8, /* ldxi_d */
+    5, /* str_d */
+    16,        /* sti_d */
+    6, /* stxr_d */
+    9, /* stxi_d */
+    11,        /* bltr_d */
+    26,        /* blti_d */
+    11,        /* bler_d */
+    26,        /* blei_d */
+    13,        /* beqr_d */
+    28,        /* beqi_d */
+    11,        /* bger_d */
+    26,        /* bgei_d */
+    11,        /* bgtr_d */
+    26,        /* bgti_d */
+    14,        /* bner_d */
+    29,        /* bnei_d */
+    11,        /* bunltr_d */
+    26,        /* bunlti_d */
+    11,        /* bunler_d */
+    26,        /* bunlei_d */
+    11,        /* buneqr_d */
+    26,        /* buneqi_d */
+    11,        /* bunger_d */
+    26,        /* bungei_d */
+    11,        /* bungtr_d */
+    26,        /* bungti_d */
+    11,        /* bltgtr_d */
+    26,        /* bltgti_d */
+    11,        /* bordr_d */
+    26,        /* bordi_d */
+    11,        /* bunordr_d */
+    26,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#else
+
+#  if __X64_32
+#define JIT_INSTR_MAX 108
+    0, /* data */
+    0, /* live */
+    3, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    3, /* label */
+    108,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    41,        /* va_start */
+    45,        /* va_arg */
+    54,        /* va_arg_d */
+    0, /* va_end */
+    5, /* addr */
+    7, /* addi */
+    6, /* addcr */
+    7, /* addci */
+    6, /* addxr */
+    7, /* addxi */
+    6, /* subr */
+    7, /* subi */
+    9, /* subcr */
+    7, /* subci */
+    9, /* subxr */
+    7, /* subxi */
+    10,        /* rsbi */
+    7, /* mulr */
+    8, /* muli */
+    18,        /* qmulr */
+    24,        /* qmuli */
+    18,        /* qmulr_u */
+    24,        /* qmuli_u */
+    19,        /* divr */
+    22,        /* divi */
+    20,        /* divr_u */
+    23,        /* divi_u */
+    22,        /* qdivr */
+    25,        /* qdivi */
+    23,        /* qdivr_u */
+    26,        /* qdivi_u */
+    19,        /* remr */
+    22,        /* remi */
+    20,        /* remr_u */
+    23,        /* remi_u */
+    6, /* andr */
+    9, /* andi */
+    6, /* orr */
+    10,        /* ori */
+    6, /* xorr */
+    10,        /* xori */
+    9, /* lshr */
+    8, /* lshi */
+    9, /* rshr */
+    7, /* rshi */
+    9, /* rshr_u */
+    7, /* rshi_u */
+    6, /* negr */
+    6, /* comr */
+    13,        /* ltr */
+    14,        /* lti */
+    13,        /* ltr_u */
+    14,        /* lti_u */
+    13,        /* ler */
+    14,        /* lei */
+    13,        /* ler_u */
+    14,        /* lei_u */
+    13,        /* eqr */
+    14,        /* eqi */
+    13,        /* ger */
+    14,        /* gei */
+    13,        /* ger_u */
+    14,        /* gei_u */
+    13,        /* gtr */
+    14,        /* gti */
+    13,        /* gtr_u */
+    14,        /* gti_u */
+    13,        /* ner */
+    14,        /* nei */
+    3, /* movr */
+    6, /* movi */
+    7, /* extr_c */
+    7, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    0, /* extr_i */
+    0, /* extr_ui */
+    9, /* htonr_us */
+    6, /* htonr_ui */
+    0, /* htonr_ul */
+    5, /* ldr_c */
+    9, /* ldi_c */
+    5, /* ldr_uc */
+    9, /* ldi_uc */
+    5, /* ldr_s */
+    9, /* ldi_s */
+    5, /* ldr_us */
+    9, /* ldi_us */
+    4, /* ldr_i */
+    8, /* ldi_i */
+    0, /* ldr_ui */
+    0, /* ldi_ui */
+    0, /* ldr_l */
+    0, /* ldi_l */
+    9, /* ldxr_c */
+    7, /* ldxi_c */
+    9, /* ldxr_uc */
+    7, /* ldxi_uc */
+    9, /* ldxr_s */
+    7, /* ldxi_s */
+    9, /* ldxr_us */
+    7, /* ldxi_us */
+    8, /* ldxr_i */
+    7, /* ldxi_i */
+    0, /* ldxr_ui */
+    0, /* ldxi_ui */
+    0, /* ldxr_l */
+    0, /* ldxi_l */
+    7, /* str_c */
+    11,        /* sti_c */
+    5, /* str_s */
+    9, /* sti_s */
+    4, /* str_i */
+    8, /* sti_i */
+    0, /* str_l */
+    0, /* sti_l */
+    12,        /* stxr_c */
+    7, /* stxi_c */
+    10,        /* stxr_s */
+    7, /* stxi_s */
+    9, /* stxr_i */
+    6, /* stxi_i */
+    0, /* stxr_l */
+    0, /* stxi_l */
+    9, /* bltr */
+    10,        /* blti */
+    9, /* bltr_u */
+    10,        /* blti_u */
+    9, /* bler */
+    12,        /* blei */
+    9, /* bler_u */
+    10,        /* blei_u */
+    9, /* beqr */
+    13,        /* beqi */
+    9, /* bger */
+    10,        /* bgei */
+    9, /* bger_u */
+    10,        /* bgei_u */
+    9, /* bgtr */
+    10,        /* bgti */
+    9, /* bgtr_u */
+    10,        /* bgti_u */
+    9, /* bner */
+    13,        /* bnei */
+    9, /* bmsr */
+    13,        /* bmsi */
+    9, /* bmcr */
+    13,        /* bmci */
+    9, /* boaddr */
+    10,        /* boaddi */
+    9, /* boaddr_u */
+    10,        /* boaddi_u */
+    9, /* bxaddr */
+    10,        /* bxaddi */
+    9, /* bxaddr_u */
+    10,        /* bxaddi_u */
+    9, /* bosubr */
+    10,        /* bosubi */
+    9, /* bosubr_u */
+    10,        /* bosubi_u */
+    9, /* bxsubr */
+    10,        /* bxsubi */
+    9, /* bxsubr_u */
+    10,        /* bxsubi_u */
+    2, /* jmpr */
+    5, /* jmpi */
+    3, /* callr */
+    9, /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    34,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    10,        /* addr_f */
+    21,        /* addi_f */
+    15,        /* subr_f */
+    21,        /* subi_f */
+    26,        /* rsbi_f */
+    10,        /* mulr_f */
+    21,        /* muli_f */
+    15,        /* divr_f */
+    21,        /* divi_f */
+    15,        /* negr_f */
+    15,        /* absr_f */
+    5, /* sqrtr_f */
+    15,        /* ltr_f */
+    26,        /* lti_f */
+    15,        /* ler_f */
+    26,        /* lei_f */
+    17,        /* eqr_f */
+    28,        /* eqi_f */
+    15,        /* ger_f */
+    26,        /* gei_f */
+    15,        /* gtr_f */
+    26,        /* gti_f */
+    20,        /* ner_f */
+    31,        /* nei_f */
+    15,        /* unltr_f */
+    26,        /* unlti_f */
+    15,        /* unler_f */
+    26,        /* unlei_f */
+    15,        /* uneqr_f */
+    26,        /* uneqi_f */
+    15,        /* unger_f */
+    26,        /* ungei_f */
+    15,        /* ungtr_f */
+    26,        /* ungti_f */
+    15,        /* ltgtr_f */
+    26,        /* ltgti_f */
+    15,        /* ordr_f */
+    26,        /* ordi_f */
+    15,        /* unordr_f */
+    26,        /* unordi_f */
+    5, /* truncr_f_i */
+    0, /* truncr_f_l */
+    5, /* extr_f */
+    5, /* extr_d_f */
+    5, /* movr_f */
+    11,        /* movi_f */
+    6, /* ldr_f */
+    10,        /* ldi_f */
+    11,        /* ldxr_f */
+    9, /* ldxi_f */
+    6, /* str_f */
+    10,        /* sti_f */
+    11,        /* stxr_f */
+    9, /* stxi_f */
+    10,        /* bltr_f */
+    21,        /* blti_f */
+    10,        /* bler_f */
+    21,        /* blei_f */
+    12,        /* beqr_f */
+    23,        /* beqi_f */
+    10,        /* bger_f */
+    21,        /* bgei_f */
+    10,        /* bgtr_f */
+    21,        /* bgti_f */
+    13,        /* bner_f */
+    24,        /* bnei_f */
+    10,        /* bunltr_f */
+    21,        /* bunlti_f */
+    10,        /* bunler_f */
+    21,        /* bunlei_f */
+    10,        /* buneqr_f */
+    21,        /* buneqi_f */
+    10,        /* bunger_f */
+    21,        /* bungei_f */
+    10,        /* bungtr_f */
+    21,        /* bungti_f */
+    10,        /* bltgtr_f */
+    21,        /* bltgti_f */
+    10,        /* bordr_f */
+    21,        /* bordi_f */
+    10,        /* bunordr_f */
+    21,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    10,        /* addr_d */
+    33,        /* addi_d */
+    15,        /* subr_d */
+    33,        /* subi_d */
+    38,        /* rsbi_d */
+    10,        /* mulr_d */
+    33,        /* muli_d */
+    15,        /* divr_d */
+    33,        /* divi_d */
+    22,        /* negr_d */
+    16,        /* absr_d */
+    5, /* sqrtr_d */
+    16,        /* ltr_d */
+    39,        /* lti_d */
+    16,        /* ler_d */
+    39,        /* lei_d */
+    18,        /* eqr_d */
+    41,        /* eqi_d */
+    16,        /* ger_d */
+    39,        /* gei_d */
+    16,        /* gtr_d */
+    39,        /* gti_d */
+    21,        /* ner_d */
+    44,        /* nei_d */
+    16,        /* unltr_d */
+    39,        /* unlti_d */
+    16,        /* unler_d */
+    39,        /* unlei_d */
+    16,        /* uneqr_d */
+    39,        /* uneqi_d */
+    16,        /* unger_d */
+    39,        /* ungei_d */
+    16,        /* ungtr_d */
+    39,        /* ungti_d */
+    16,        /* ltgtr_d */
+    39,        /* ltgti_d */
+    16,        /* ordr_d */
+    39,        /* ordi_d */
+    16,        /* unordr_d */
+    39,        /* unordi_d */
+    5, /* truncr_d_i */
+    0, /* truncr_d_l */
+    5, /* extr_d */
+    5, /* extr_f_d */
+    5, /* movr_d */
+    23,        /* movi_d */
+    6, /* ldr_d */
+    10,        /* ldi_d */
+    11,        /* ldxr_d */
+    9, /* ldxi_d */
+    6, /* str_d */
+    10,        /* sti_d */
+    11,        /* stxr_d */
+    9, /* stxi_d */
+    11,        /* bltr_d */
+    34,        /* blti_d */
+    11,        /* bler_d */
+    34,        /* blei_d */
+    13,        /* beqr_d */
+    36,        /* beqi_d */
+    11,        /* bger_d */
+    34,        /* bgei_d */
+    11,        /* bgtr_d */
+    34,        /* bgti_d */
+    14,        /* bner_d */
+    37,        /* bnei_d */
+    11,        /* bunltr_d */
+    34,        /* bunlti_d */
+    11,        /* bunler_d */
+    34,        /* bunlei_d */
+    11,        /* buneqr_d */
+    34,        /* buneqi_d */
+    11,        /* bunger_d */
+    34,        /* bungei_d */
+    11,        /* bungtr_d */
+    34,        /* bungti_d */
+    11,        /* bltgtr_d */
+    34,        /* bltgti_d */
+    11,        /* bordr_d */
+    34,        /* bordi_d */
+    11,        /* bunordr_d */
+    34,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+
+#  else
+#define JIT_INSTR_MAX 115
+    0, /* data */
+    0, /* live */
+    6, /* align */
+    0, /* save */
+    0, /* load */
+    0, /* #name */
+    0, /* #note */
+    7, /* label */
+    115,       /* prolog */
+    0, /* ellipsis */
+    0, /* va_push */
+    0, /* allocai */
+    0, /* allocar */
+    0, /* arg */
+    0, /* getarg_c */
+    0, /* getarg_uc */
+    0, /* getarg_s */
+    0, /* getarg_us */
+    0, /* getarg_i */
+    0, /* getarg_ui */
+    0, /* getarg_l */
+    0, /* putargr */
+    0, /* putargi */
+    42,        /* va_start */
+    41,        /* va_arg */
+    50,        /* va_arg_d */
+    0, /* va_end */
+    5, /* addr */
+    13,        /* addi */
+    6, /* addcr */
+    13,        /* addci */
+    6, /* addxr */
+    7, /* addxi */
+    6, /* subr */
+    13,        /* subi */
+    9, /* subcr */
+    13,        /* subci */
+    9, /* subxr */
+    7, /* subxi */
+    16,        /* rsbi */
+    7, /* mulr */
+    14,        /* muli */
+    20,        /* qmulr */
+    30,        /* qmuli */
+    20,        /* qmulr_u */
+    30,        /* qmuli_u */
+    22,        /* divr */
+    29,        /* divi */
+    23,        /* divr_u */
+    30,        /* divi_u */
+    25,        /* qdivr */
+    32,        /* qdivi */
+    26,        /* qdivr_u */
+    33,        /* qdivi_u */
+    22,        /* remr */
+    29,        /* remi */
+    23,        /* remr_u */
+    30,        /* remi_u */
+    6, /* andr */
+    13,        /* andi */
+    6, /* orr */
+    13,        /* ori */
+    6, /* xorr */
+    13,        /* xori */
+    9, /* lshr */
+    8, /* lshi */
+    9, /* rshr */
+    7, /* rshi */
+    9, /* rshr_u */
+    7, /* rshi_u */
+    6, /* negr */
+    6, /* comr */
+    13,        /* ltr */
+    14,        /* lti */
+    13,        /* ltr_u */
+    14,        /* lti_u */
+    13,        /* ler */
+    14,        /* lei */
+    13,        /* ler_u */
+    14,        /* lei_u */
+    13,        /* eqr */
+    14,        /* eqi */
+    13,        /* ger */
+    14,        /* gei */
+    13,        /* ger_u */
+    14,        /* gei_u */
+    13,        /* gtr */
+    14,        /* gti */
+    13,        /* gtr_u */
+    14,        /* gti_u */
+    13,        /* ner */
+    14,        /* nei */
+    3, /* movr */
+    10,        /* movi */
+    4, /* extr_c */
+    4, /* extr_uc */
+    4, /* extr_s */
+    4, /* extr_us */
+    3, /* extr_i */
+    3, /* extr_ui */
+    9, /* htonr_us */
+    6, /* htonr_ui */
+    6, /* htonr_ul */
+    5, /* ldr_c */
+    9, /* ldi_c */
+    5, /* ldr_uc */
+    9, /* ldi_uc */
+    5, /* ldr_s */
+    9, /* ldi_s */
+    5, /* ldr_us */
+    9, /* ldi_us */
+    4, /* ldr_i */
+    8, /* ldi_i */
+    4, /* ldr_ui */
+    8, /* ldi_ui */
+    4, /* ldr_l */
+    8, /* ldi_l */
+    6, /* ldxr_c */
+    8, /* ldxi_c */
+    6, /* ldxr_uc */
+    8, /* ldxi_uc */
+    6, /* ldxr_s */
+    8, /* ldxi_s */
+    6, /* ldxr_us */
+    8, /* ldxi_us */
+    5, /* ldxr_i */
+    7, /* ldxi_i */
+    5, /* ldxr_ui */
+    6, /* ldxi_ui */
+    5, /* ldxr_l */
+    7, /* ldxi_l */
+    4, /* str_c */
+    8, /* sti_c */
+    5, /* str_s */
+    9, /* sti_s */
+    4, /* str_i */
+    8, /* sti_i */
+    4, /* str_l */
+    8, /* sti_l */
+    5, /* stxr_c */
+    6, /* stxi_c */
+    6, /* stxr_s */
+    7, /* stxi_s */
+    5, /* stxr_i */
+    6, /* stxi_i */
+    5, /* stxr_l */
+    7, /* stxi_l */
+    9, /* bltr */
+    10,        /* blti */
+    9, /* bltr_u */
+    10,        /* blti_u */
+    9, /* bler */
+    13,        /* blei */
+    9, /* bler_u */
+    10,        /* blei_u */
+    9, /* beqr */
+    19,        /* beqi */
+    9, /* bger */
+    10,        /* bgei */
+    9, /* bger_u */
+    10,        /* bgei_u */
+    9, /* bgtr */
+    10,        /* bgti */
+    9, /* bgtr_u */
+    10,        /* bgti_u */
+    9, /* bner */
+    19,        /* bnei */
+    9, /* bmsr */
+    13,        /* bmsi */
+    9, /* bmcr */
+    13,        /* bmci */
+    9, /* boaddr */
+    10,        /* boaddi */
+    9, /* boaddr_u */
+    10,        /* boaddi_u */
+    9, /* bxaddr */
+    10,        /* bxaddi */
+    9, /* bxaddr_u */
+    10,        /* bxaddi_u */
+    9, /* bosubr */
+    10,        /* bosubi */
+    9, /* bosubr_u */
+    10,        /* bosubi_u */
+    9, /* bxsubr */
+    10,        /* bxsubi */
+    9, /* bxsubr_u */
+    10,        /* bxsubi_u */
+    3, /* jmpr */
+    5, /* jmpi */
+    3, /* callr */
+    13,        /* calli */
+    0, /* prepare */
+    0, /* pushargr */
+    0, /* pushargi */
+    0, /* finishr */
+    0, /* finishi */
+    0, /* ret */
+    0, /* retr */
+    0, /* reti */
+    0, /* retval_c */
+    0, /* retval_uc */
+    0, /* retval_s */
+    0, /* retval_us */
+    0, /* retval_i */
+    0, /* retval_ui */
+    0, /* retval_l */
+    37,        /* epilog */
+    0, /* arg_f */
+    0, /* getarg_f */
+    0, /* putargr_f */
+    0, /* putargi_f */
+    10,        /* addr_f */
+    21,        /* addi_f */
+    15,        /* subr_f */
+    21,        /* subi_f */
+    30,        /* rsbi_f */
+    10,        /* mulr_f */
+    21,        /* muli_f */
+    15,        /* divr_f */
+    21,        /* divi_f */
+    15,        /* negr_f */
+    15,        /* absr_f */
+    5, /* sqrtr_f */
+    11,        /* ltr_f */
+    26,        /* lti_f */
+    11,        /* ler_f */
+    26,        /* lei_f */
+    13,        /* eqr_f */
+    28,        /* eqi_f */
+    11,        /* ger_f */
+    26,        /* gei_f */
+    11,        /* gtr_f */
+    26,        /* gti_f */
+    16,        /* ner_f */
+    31,        /* nei_f */
+    11,        /* unltr_f */
+    26,        /* unlti_f */
+    11,        /* unler_f */
+    26,        /* unlei_f */
+    11,        /* uneqr_f */
+    26,        /* uneqi_f */
+    11,        /* unger_f */
+    26,        /* ungei_f */
+    11,        /* ungtr_f */
+    26,        /* ungti_f */
+    11,        /* ltgtr_f */
+    26,        /* ltgti_f */
+    11,        /* ordr_f */
+    26,        /* ordi_f */
+    11,        /* unordr_f */
+    26,        /* unordi_f */
+    5, /* truncr_f_i */
+    5, /* truncr_f_l */
+    5, /* extr_f */
+    5, /* extr_d_f */
+    5, /* movr_f */
+    15,        /* movi_f */
+    6, /* ldr_f */
+    10,        /* ldi_f */
+    7, /* ldxr_f */
+    9, /* ldxi_f */
+    6, /* str_f */
+    10,        /* sti_f */
+    7, /* stxr_f */
+    9, /* stxi_f */
+    10,        /* bltr_f */
+    21,        /* blti_f */
+    10,        /* bler_f */
+    25,        /* blei_f */
+    12,        /* beqr_f */
+    27,        /* beqi_f */
+    10,        /* bger_f */
+    25,        /* bgei_f */
+    10,        /* bgtr_f */
+    25,        /* bgti_f */
+    13,        /* bner_f */
+    28,        /* bnei_f */
+    10,        /* bunltr_f */
+    25,        /* bunlti_f */
+    10,        /* bunler_f */
+    25,        /* bunlei_f */
+    10,        /* buneqr_f */
+    25,        /* buneqi_f */
+    10,        /* bunger_f */
+    25,        /* bungei_f */
+    10,        /* bungtr_f */
+    25,        /* bungti_f */
+    10,        /* bltgtr_f */
+    25,        /* bltgti_f */
+    10,        /* bordr_f */
+    25,        /* bordi_f */
+    10,        /* bunordr_f */
+    25,        /* bunordi_f */
+    0, /* pushargr_f */
+    0, /* pushargi_f */
+    0, /* retr_f */
+    0, /* reti_f */
+    0, /* retval_f */
+    0, /* arg_d */
+    0, /* getarg_d */
+    0, /* putargr_d */
+    0, /* putargi_d */
+    10,        /* addr_d */
+    25,        /* addi_d */
+    15,        /* subr_d */
+    25,        /* subi_d */
+    30,        /* rsbi_d */
+    10,        /* mulr_d */
+    25,        /* muli_d */
+    15,        /* divr_d */
+    25,        /* divi_d */
+    22,        /* negr_d */
+    16,        /* absr_d */
+    5, /* sqrtr_d */
+    12,        /* ltr_d */
+    27,        /* lti_d */
+    12,        /* ler_d */
+    27,        /* lei_d */
+    14,        /* eqr_d */
+    29,        /* eqi_d */
+    12,        /* ger_d */
+    27,        /* gei_d */
+    12,        /* gtr_d */
+    27,        /* gti_d */
+    17,        /* ner_d */
+    32,        /* nei_d */
+    12,        /* unltr_d */
+    27,        /* unlti_d */
+    12,        /* unler_d */
+    27,        /* unlei_d */
+    12,        /* uneqr_d */
+    27,        /* uneqi_d */
+    12,        /* unger_d */
+    27,        /* ungei_d */
+    12,        /* ungtr_d */
+    27,        /* ungti_d */
+    12,        /* ltgtr_d */
+    27,        /* ltgti_d */
+    12,        /* ordr_d */
+    27,        /* ordi_d */
+    12,        /* unordr_d */
+    27,        /* unordi_d */
+    5, /* truncr_d_i */
+    5, /* truncr_d_l */
+    5, /* extr_d */
+    5, /* extr_f_d */
+    5, /* movr_d */
+    15,        /* movi_d */
+    6, /* ldr_d */
+    10,        /* ldi_d */
+    7, /* ldxr_d */
+    9, /* ldxi_d */
+    6, /* str_d */
+    10,        /* sti_d */
+    7, /* stxr_d */
+    9, /* stxi_d */
+    11,        /* bltr_d */
+    26,        /* blti_d */
+    11,        /* bler_d */
+    26,        /* blei_d */
+    13,        /* beqr_d */
+    28,        /* beqi_d */
+    11,        /* bger_d */
+    26,        /* bgei_d */
+    11,        /* bgtr_d */
+    26,        /* bgti_d */
+    14,        /* bner_d */
+    29,        /* bnei_d */
+    11,        /* bunltr_d */
+    26,        /* bunlti_d */
+    11,        /* bunler_d */
+    26,        /* bunlei_d */
+    11,        /* buneqr_d */
+    26,        /* buneqi_d */
+    11,        /* bunger_d */
+    26,        /* bungei_d */
+    11,        /* bungtr_d */
+    26,        /* bungti_d */
+    11,        /* bltgtr_d */
+    26,        /* bltgti_d */
+    11,        /* bordr_d */
+    26,        /* bordi_d */
+    11,        /* bunordr_d */
+    26,        /* bunordi_d */
+    0, /* pushargr_d */
+    0, /* pushargi_d */
+    0, /* retr_d */
+    0, /* reti_d */
+    0, /* retval_d */
+    0, /* movr_w_f */
+    0, /* movr_ww_d */
+    0, /* movr_w_d */
+    0, /* movr_f_w */
+    0, /* movi_f_w */
+    0, /* movr_d_ww */
+    0, /* movi_d_ww */
+    0, /* movr_d_w */
+    0, /* movi_d_w */
+#endif /* __CYGWIN__ || _WIN32 */
+#  endif /* __X64_32 */
+#endif /* __X64 */
diff --git a/deps/lightning/lib/jit_x86-x87.c b/deps/lightning/lib/jit_x86-x87.c
new file mode 100644 (file)
index 0000000..4453bf3
--- /dev/null
@@ -0,0 +1,1344 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#if PROTO
+#  if __X32
+#    define x87_address_p(i0)          1
+#  else
+#    if __X64_32
+#      define x87_address_p(i0)                ((jit_word_t)(i0) >= 0)
+#    else
+#      define x87_address_p(i0)                can_sign_extend_int_p(i0)
+#    endif
+#  endif
+#  define _ST0_REGNO                   0
+#  define _ST1_REGNO                   1
+#  define _ST2_REGNO                   2
+#  define _ST3_REGNO                   3
+#  define _ST4_REGNO                   4
+#  define _ST5_REGNO                   5
+#  define _ST6_REGNO                   6
+#  define x87rx(code, md, rb, ri, ms)  _x87rx(_jit, code, md, rb, ri, ms)
+#  define fldcwm(md, rb, ri, ms)       x87rx(015, md, rb, ri, ms)
+#  define fstcwm(md, rb, ri, ms)       _fstcwm(_jit, md, rb, ri, ms)
+static void
+_fstcwm(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define fldsm(md, rb, ri, ms)                x87rx(010, md, rb, ri, ms)
+#  define fstsm(md, rb, ri, ms)                x87rx(012, md, rb, ri, ms)
+#  define fldlm(md, rb, ri, ms)                x87rx(050, md, rb, ri, ms)
+#  define fstlm(md, rb, ri, ms)                x87rx(052, md, rb, ri, ms)
+#  define fisttplm(md, rb, ri, ms)     x87rx(031, md, rb, ri, ms)
+#  define fistlm(md, rb, ri, ms)       x87rx(032, md, rb, ri, ms)
+#  define fisttpqm(md, rb, ri, ms)     x87rx(071, md, rb, ri, ms)
+#  define fildlm(md, rb, ri, ms)       x87rx(030, md, rb,ri, ms)
+#  define fildqm(md, rb, ri, ms)       x87rx(075, md, rb,ri, ms)
+static void
+_x87rx(jit_state_t*, jit_int32_t, jit_int32_t,
+       jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87ri(cc,r0)                 _x87ri(_jit,cc,r0)
+#  define fchs_()                      x87ri(014, 0)
+#  define fabs_()                      x87ri(014, 1)
+#  define fld1()                       x87ri(015, 0)
+#  define fldl2t()                     x87ri(015, 1)
+#  define fldl2e()                     x87ri(015, 2)
+#  define fldpi()                      x87ri(015, 3)
+#  define fldlg2()                     x87ri(015, 4)
+#  define fldln2()                     x87ri(015, 5)
+#  define fldz()                       x87ri(015, 6)
+#  define fsqrt_()                     x87ri(017, 2)
+#  define fldr(r0)                     x87ri(010, r0)
+#  define fxchr(r0)                    x87ri(011, r0)
+#  define fstr(r0)                     x87ri(052, r0)
+#  define fstpr(r0)                    x87ri(053, r0)
+#  define fucomir(r0)                  x87ri(035, r0)
+#  define fucomipr(r0)                 x87ri(075, r0)
+static void _x87ri(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define faddr(r0, r1)                        x87rri(000, r0, r1)
+#  define fmulr(r0, r1)                        x87rri(001, r0, r1)
+#  define fsubr(r0, r1)                        x87rri(004, r0, r1)
+#  define fsubrr(r0, r1)               x87rri(005, r0, r1)
+#  define fdivr(r0, r1)                        x87rri(006, r0, r1)
+#  define fdivrr(r0, r1)               x87rri(007, r0, r1)
+#  define x87rri(cc, r0, r1)           _x87rri(_jit, cc, r0, r1)
+static void _x87rri(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_addr_f(r0, r1, r2)       _x87_addr_d(_jit, r0, r1, r2)
+#  define x87_addi_f(r0, r1, i0)       _x87_addi_f(_jit, r0, r1, i0)
+static void _x87_addi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_addr_d(r0, r1, r2)       _x87_addr_d(_jit, r0, r1, r2)
+static void _x87_addr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_addi_d(r0, r1, i0)       _x87_addi_d(_jit, r0, r1, i0)
+static void _x87_addi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_subr_f(r0, r1, r2)       _x87_subr_d(_jit, r0, r1, r2)
+#  define x87_subi_f(r0, r1, i0)       _x87_subi_f(_jit, r0, r1, i0)
+static void _x87_subi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_subr_d(r0, r1, r2)       _x87_subr_d(_jit, r0, r1, r2)
+static void _x87_subr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_subi_d(r0, r1, i0)       _x87_subi_d(_jit, r0, r1, i0)
+static void _x87_subi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_rsbr_f(r0, r1, r2)       x87_subr_f(r0, r2, r1)
+#  define x87_rsbi_f(r0, r1, i0)       _x87_rsbi_f(_jit, r0, r1, i0)
+static void _x87_rsbi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_rsbr_d(r0, r1, r2)       x87_subr_d(r0, r2, r1)
+#  define x87_rsbi_d(r0, r1, i0)       _x87_rsbi_d(_jit, r0, r1, i0)
+static void _x87_rsbi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_mulr_f(r0, r1, r2)       _x87_mulr_d(_jit, r0, r1, r2)
+#  define x87_muli_f(r0, r1, i0)       _x87_muli_f(_jit, r0, r1, i0)
+static void _x87_muli_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_mulr_d(r0, r1, r2)       _x87_mulr_d(_jit, r0, r1, r2)
+static void _x87_mulr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_muli_d(r0, r1, i0)       _x87_muli_d(_jit, r0, r1, i0)
+static void _x87_muli_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_divr_f(r0, r1, r2)       _x87_divr_d(_jit, r0, r1, r2)
+#  define x87_divi_f(r0, r1, i0)       _x87_divi_f(_jit, r0, r1, i0)
+static void _x87_divi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_divr_d(r0, r1, r2)       _x87_divr_d(_jit, r0, r1, r2)
+static void _x87_divr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_divi_d(r0, r1, i0)       _x87_divi_d(_jit, r0, r1, i0)
+static void _x87_divi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_absr_f(r0, r1)           _x87_absr_d(_jit, r0, r1)
+#  define x87_absr_d(r0, r1)           _x87_absr_d(_jit, r0, r1)
+static void _x87_absr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define x87_negr_f(r0, r1)           _x87_negr_d(_jit, r0, r1)
+#  define x87_negr_d(r0, r1)           _x87_negr_d(_jit, r0, r1)
+static void _x87_negr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define x87_sqrtr_f(r0, r1)          _x87_sqrtr_d(_jit, r0, r1)
+#  define x87_sqrtr_d(r0, r1)          _x87_sqrtr_d(_jit, r0, r1)
+static void _x87_sqrtr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define x87_truncr_f_i(r0, r1)       _x87_truncr_d_i(_jit, r0, r1)
+#  define x87_truncr_d_i(r0, r1)       _x87_truncr_d_i(_jit, r0, r1)
+static void _x87_truncr_d_i(jit_state_t*, jit_int32_t, jit_int32_t);
+#  if __X64
+#    define x87_truncr_f_l(r0, r1)     _x87_truncr_d_l(_jit, r0, r1)
+#    define x87_truncr_d_l(r0, r1)     _x87_truncr_d_l(_jit, r0, r1)
+static void _x87_truncr_d_l(jit_state_t*, jit_int32_t, jit_int32_t);
+#  endif
+#  define x87_extr_f(r0, r1)           _x87_extr_d(_jit, r0, r1)
+#  define x87_extr_d(r0, r1)           _x87_extr_d(_jit, r0, r1)
+#  define x87_extr_f_d(r0, r1)         x87_movr_d(r0, r1)
+#  define x87_extr_d_f(r0, r1)         x87_movr_d(r0, r1)
+static void _x87_extr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define x87cmp(code, r0, r1, r2)     _x87cmp(_jit, code, r0, r1, r2)
+static void
+_x87cmp(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87cmp2(code, r0, r1, r2)    _x87cmp2(_jit, code, r0, r1, r2)
+static void
+_x87cmp2(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87jcc(code, i0, r0, r1)     _x87jcc(_jit, code, i0, r0, r1)
+static jit_word_t
+_x87jcc(jit_state_t*, jit_int32_t, jit_word_t, jit_int32_t, jit_int32_t);
+#  define x87jcc2(code, i0, r0, r1)    _x87jcc2(_jit, code, i0, r0, r1)
+static jit_word_t
+_x87jcc2(jit_state_t*, jit_int32_t, jit_word_t, jit_int32_t, jit_int32_t);
+#define x87_movi_f(r0,i0)              _x87_movi_f(_jit,r0,i0)
+static void _x87_movi_f(jit_state_t*, jit_int32_t, jit_float32_t*);
+#  define x87_ldr_f(r0, r1)            _x87_ldr_f(_jit, r0, r1)
+static void _x87_ldr_f(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define x87_ldi_f(r0, i0)            _x87_ldi_f(_jit, r0, i0)
+static void _x87_ldi_f(jit_state_t*, jit_int32_t, jit_word_t);
+#  define x87_ldxr_f(r0, r1, r2)       _x87_ldxr_f(_jit, r0, r1, r2)
+static void _x87_ldxr_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_ldxi_f(r0, r1, i0)       _x87_ldxi_f(_jit, r0, r1, i0)
+static void _x87_ldxi_f(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define x87_str_f(r0, r1)            _x87_str_f(_jit, r0, r1)
+static void _x87_str_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define x87_sti_f(i0, r0)            _x87_sti_f(_jit, i0, r0)
+static void _x87_sti_f(jit_state_t*,jit_word_t, jit_int32_t);
+#  define x87_stxr_f(r0, r1, r2)       _x87_stxr_f(_jit, r0, r1, r2)
+static void _x87_stxr_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define x87_stxi_f(i0, r0, r1)       _x87_stxi_f(_jit, i0, r0, r1)
+static void _x87_stxi_f(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define x87_ltr_f(r0, r1, r2)                x87cmp(X86_CC_A, r0, r2, r1)
+#  define x87_lti_f(r0, r1, i0)                _x87_lti_f(_jit, r0, r1, i0)
+static void _x87_lti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_ler_f(r0, r1, r2)                x87cmp(X86_CC_AE, r0, r2, r1)
+#  define x87_lei_f(r0, r1, i0)                _x87_lei_f(_jit, r0, r1, i0)
+static void _x87_lei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_eqr_f(r0, r1, r2)                x87_eqr_d(r0, r2, r1)
+#  define x87_eqi_f(r0, r1, i0)                _x87_eqi_f(_jit, r0, r1, i0)
+static void _x87_eqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_ger_f(r0, r1, r2)                x87cmp(X86_CC_AE, r0, r1, r2)
+#  define x87_gei_f(r0, r1, i0)                _x87_gei_f(_jit, r0, r1, i0)
+static void _x87_gei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_gtr_f(r0, r1, r2)                x87cmp(X86_CC_A, r0, r1, r2)
+#  define x87_gti_f(r0, r1, i0)                _x87_gti_f(_jit, r0, r1, i0)
+static void _x87_gti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_ner_f(r0, r1, r2)                x87_ner_d(r0, r2, r1)
+#  define x87_nei_f(r0, r1, i0)                _x87_nei_f(_jit, r0, r1, i0)
+static void _x87_nei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_unltr_f(r0, r1, r2)      x87cmp(X86_CC_NAE, r0, r1, r2)
+#  define x87_unlti_f(r0, r1, i0)      _x87_unlti_f(_jit, r0, r1, i0)
+static void _x87_unlti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_unler_f(r0, r1, r2)      x87cmp(X86_CC_NA, r0, r1, r2)
+#  define x87_unlei_f(r0, r1, i0)      _x87_unlei_f(_jit, r0, r1, i0)
+static void _x87_unlei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_uneqr_f(r0, r1, r2)      x87cmp2(X86_CC_E, r0, r1, r2)
+#  define x87_uneqi_f(r0, r1, i0)      _x87_uneqi_f(_jit, r0, r1, i0)
+static void _x87_uneqi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_unger_f(r0, r1, r2)      x87cmp(X86_CC_NA, r0, r2, r1)
+#  define x87_ungei_f(r0, r1, i0)      _x87_ungei_f(_jit, r0, r1, i0)
+static void _x87_ungei_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_ungtr_f(r0, r1, r2)      x87cmp(X86_CC_NAE, r0, r2, r1)
+#  define x87_ungti_f(r0, r1, i0)      _x87_ungti_f(_jit, r0, r1, i0)
+static void _x87_ungti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_ltgtr_f(r0, r1, r2)      x87_ltgtr_d(r0, r1, r2)
+#  define x87_ltgti_f(r0, r1, i0)      _x87_ltgti_f(_jit, r0, r1, i0)
+static void _x87_ltgti_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_ordr_f(r0, r1, r2)       x87cmp2(X86_CC_NP, r0, r2, r1)
+#  define x87_ordi_f(r0, r1, i0)       _x87_ordi_f(_jit, r0, r1, i0)
+static void _x87_ordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_unordr_f(r0, r1, r2)     x87cmp2(X86_CC_P, r0, r2, r1)
+#  define x87_unordi_f(r0, r1, i0)     _x87_unordi_f(_jit, r0, r1, i0)
+static void _x87_unordi_f(jit_state_t*,jit_int32_t,jit_int32_t,jit_float32_t*);
+#  define x87_ltr_d(r0, r1, r2)                x87cmp(X86_CC_A, r0, r2, r1)
+#  define x87_lti_d(r0, r1, i0)                _x87_lti_d(_jit, r0, r1, i0)
+static void _x87_lti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_ler_d(r0, r1, r2)                x87cmp(X86_CC_AE, r0, r2, r1)
+#  define x87_lei_d(r0, r1, i0)                _x87_lei_d(_jit, r0, r1, i0)
+static void _x87_lei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_eqr_d(r0, r1, r2)                _x87_eqr_d(_jit, r0, r2, r1)
+static void _x87_eqr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_eqi_d(r0, r1, i0)                _x87_eqi_d(_jit, r0, r1, i0)
+static void _x87_eqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_ger_d(r0, r1, r2)                x87cmp(X86_CC_AE, r0, r1, r2)
+#  define x87_gei_d(r0, r1, i0)                _x87_gei_d(_jit, r0, r1, i0)
+static void _x87_gei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_gtr_d(r0, r1, r2)                x87cmp(X86_CC_A, r0, r1, r2)
+#  define x87_gti_d(r0, r1, i0)                _x87_gti_d(_jit, r0, r1, i0)
+static void _x87_gti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_ner_d(r0, r1, r2)                _x87_ner_d(_jit, r0, r2, r1)
+static void _x87_ner_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_nei_d(r0, r1, i0)                _x87_nei_d(_jit, r0, r1, i0)
+static void _x87_nei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_unltr_d(r0, r1, r2)      x87cmp(X86_CC_NAE, r0, r1, r2)
+#  define x87_unlti_d(r0, r1, i0)      _x87_unlti_d(_jit, r0, r1, i0)
+static void _x87_unlti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_unler_d(r0, r1, r2)      x87cmp(X86_CC_NA, r0, r1, r2)
+#  define x87_unlei_d(r0, r1, i0)      _x87_unlei_d(_jit, r0, r1, i0)
+static void _x87_unlei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_uneqr_d(r0, r1, r2)      x87cmp2(X86_CC_E, r0, r1, r2)
+#  define x87_uneqi_d(r0, r1, i0)      _x87_uneqi_d(_jit, r0, r1, i0)
+static void _x87_uneqi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_unger_d(r0, r1, r2)      x87cmp(X86_CC_NA, r0, r2, r1)
+#  define x87_ungei_d(r0, r1, i0)      _x87_ungei_d(_jit, r0, r1, i0)
+static void _x87_ungei_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_ungtr_d(r0, r1, r2)      x87cmp(X86_CC_NAE, r0, r2, r1)
+#  define x87_ungti_d(r0, r1, i0)      _x87_ungti_d(_jit, r0, r1, i0)
+static void _x87_ungti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_ltgtr_d(r0, r1, r2)      _x87_ltgtr_d(_jit, r0, r1, r2)
+static void _x87_ltgtr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_ltgti_d(r0, r1, i0)      _x87_ltgti_d(_jit, r0, r1, i0)
+static void _x87_ltgti_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_ordr_d(r0, r1, r2)       x87cmp2(X86_CC_NP, r0, r2, r1)
+#  define x87_ordi_d(r0, r1, i0)       _x87_ordi_d(_jit, r0, r1, i0)
+static void _x87_ordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#  define x87_unordr_d(r0, r1, r2)     x87cmp2(X86_CC_P, r0, r2, r1)
+#  define x87_unordi_d(r0, r1, i0)     _x87_unordi_d(_jit, r0, r1, i0)
+static void _x87_unordi_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_float64_t*);
+#define x87_movr_f(r0,r1)              _x87_movr_d(_jit,r0,r1)
+#define x87_movr_d(r0,r1)              _x87_movr_d(_jit,r0,r1)
+static void _x87_movr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#define x87_movi_d(r0,i0)              _x87_movi_d(_jit,r0,i0)
+static void _x87_movi_d(jit_state_t*, jit_int32_t, jit_float64_t*);
+#  define x87_ldr_d(r0, r1)            _x87_ldr_d(_jit, r0, r1)
+static void _x87_ldr_d(jit_state_t*, jit_int32_t, jit_int32_t);
+#  define x87_ldi_d(r0, i0)            _x87_ldi_d(_jit, r0, i0)
+static void _x87_ldi_d(jit_state_t*, jit_int32_t, jit_word_t);
+#  define x87_ldxr_d(r0, r1, r2)       _x87_ldxr_d(_jit, r0, r1, r2)
+static void _x87_ldxr_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_int32_t);
+#  define x87_ldxi_d(r0, r1, i0)       _x87_ldxi_d(_jit, r0, r1, i0)
+static void _x87_ldxi_d(jit_state_t*, jit_int32_t, jit_int32_t, jit_word_t);
+#  define x87_str_d(r0, r1)            _x87_str_d(_jit, r0, r1)
+static void _x87_str_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#  define x87_sti_d(i0, r0)            _x87_sti_d(_jit, i0, r0)
+static void _x87_sti_d(jit_state_t*,jit_word_t,jit_int32_t);
+#  define x87_stxr_d(r0, r1, r2)       _x87_stxr_d(_jit, r0, r1, r2)
+static void _x87_stxr_d(jit_state_t*,jit_int32_t,jit_int32_t,jit_int32_t);
+#  define x87_stxi_d(i0, r0, r1)       _x87_stxi_d(_jit, i0, r0, r1)
+static void _x87_stxi_d(jit_state_t*,jit_word_t,jit_int32_t,jit_int32_t);
+#  define x87_bltr_f(i0, r0, r1)       x87jcc(X86_CC_A, i0, r1, r0)
+#  define x87_blti_f(i0, r0, i1)       _x87_blti_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_blti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bler_f(i0, r0, r1)       x87jcc(X86_CC_AE, i0, r1, r0)
+#  define x87_blei_f(i0, r0, i1)       _x87_blei_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_blei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_beqr_f(i0, r0, r1)       _x87_beqr_d(_jit, i0, r0, r1)
+#  define x87_beqi_f(i0, r0, i1)       _x87_beqi_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_beqi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bger_f(i0, r0, r1)       x87jcc(X86_CC_AE, i0, r0, r1)
+#  define x87_bgei_f(i0, r0, i1)       _x87_bgei_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bgei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bgtr_f(i0, r0, r1)       x87jcc(X86_CC_A, i0, r0, r1)
+#  define x87_bgti_f(i0, r0, i1)       _x87_bgti_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bgti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bner_f(i0, r0, r1)       _x87_bner_d(_jit, i0, r0, r1)
+#  define x87_bnei_f(i0, r0, i1)       _x87_bnei_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bnei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bunltr_f(i0, r0, r1)     x87jcc(X86_CC_NAE, i0, r0, r1)
+#  define x87_bunlti_f(i0, r0, i1)     _x87_bunlti_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bunlti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bunler_f(i0, r0, r1)     x87jcc(X86_CC_NA, i0, r0, r1)
+#  define x87_bunlei_f(i0, r0, i1)     _x87_bunlei_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bunlei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_buneqr_f(i0, r0, r1)     x87jcc2(X86_CC_E, i0, r0, r1)
+#  define x87_buneqi_f(i0, r0, i1)     _x87_buneqi_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_buneqi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bunger_f(i0, r0, r1)     x87jcc(X86_CC_NA, i0, r1, r0)
+#  define x87_bungei_f(i0, r0, i1)     _x87_bungei_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bungei_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bungtr_f(i0, r0, r1)     x87jcc(X86_CC_NAE, i0, r1, r0)
+#  define x87_bungti_f(i0, r0, i1)     _x87_bungti_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bungti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bltgtr_f(i0, r0, r1)     x87jcc2(X86_CC_NE, i0, r0, r1)
+#  define x87_bltgti_f(i0, r0, i1)     _x87_bltgti_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bltgti_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bordr_f(i0, r0, r1)      x87jcc2(X86_CC_NP, i0, r0, r1)
+#  define x87_bordi_f(i0, r0, i1)      _x87_bordi_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bordi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bunordr_f(i0, r0, r1)    x87jcc2(X86_CC_P, i0, r0, r1)
+#  define x87_bunordi_f(i0, r0, i1)    _x87_bunordi_f(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bunordi_f(jit_state_t*, jit_word_t, jit_int32_t, jit_float32_t*);
+#  define x87_bltr_d(i0, r0, r1)       x87jcc(X86_CC_A, i0, r1, r0)
+#  define x87_blti_d(i0, r0, i1)       _x87_blti_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_blti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bler_d(i0, r0, r1)       x87jcc(X86_CC_AE, i0, r1, r0)
+#  define x87_blei_d(i0, r0, i1)       _x87_blei_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_blei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_beqr_d(i0, r0, r1)       _x87_beqr_d(_jit, i0, r0, r1)
+static jit_word_t
+_x87_beqr_d(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define x87_beqi_d(i0, r0, i1)       _x87_beqi_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_beqi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bger_d(i0, r0, r1)       x87jcc(X86_CC_AE, i0, r0, r1)
+#  define x87_bgei_d(i0, r0, i1)       _x87_bgei_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bgei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bgtr_d(i0, r0, r1)       x87jcc(X86_CC_A, i0, r0, r1)
+#  define x87_bgti_d(i0, r0, i1)       _x87_bgti_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bgti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bner_d(i0, r0, r1)       _x87_bner_d(_jit, i0, r0, r1)
+static jit_word_t
+_x87_bner_d(jit_state_t*, jit_word_t, jit_int32_t, jit_int32_t);
+#  define x87_bnei_d(i0, r0, i1)       _x87_bnei_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bnei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bunltr_d(i0, r0, r1)     x87jcc(X86_CC_NAE, i0, r0, r1)
+#  define x87_bunlti_d(i0, r0, i1)     _x87_bunlti_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bunlti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bunler_d(i0, r0, r1)     x87jcc(X86_CC_NA, i0, r0, r1)
+#  define x87_bunlei_d(i0, r0, i1)     _x87_bunlei_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bunlei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_buneqr_d(i0, r0, r1)     x87jcc2(X86_CC_E, i0, r0, r1)
+#  define x87_buneqi_d(i0, r0, i1)     _x87_buneqi_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_buneqi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bunger_d(i0, r0, r1)     x87jcc(X86_CC_NA, i0, r1, r0)
+#  define x87_bungei_d(i0, r0, i1)     _x87_bungei_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bungei_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bungtr_d(i0, r0, r1)     x87jcc(X86_CC_NAE, i0, r1, r0)
+#  define x87_bungti_d(i0, r0, i1)     _x87_bungti_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bungti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bltgtr_d(i0, r0, r1)     x87jcc2(X86_CC_NE, i0, r0, r1)
+#  define x87_bltgti_d(i0, r0, i1)     _x87_bltgti_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bltgti_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bordr_d(i0, r0, r1)      x87jcc2(X86_CC_NP, i0, r0, r1)
+#  define x87_bordi_d(i0, r0, i1)      _x87_bordi_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bordi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#  define x87_bunordr_d(i0, r0, r1)    x87jcc2(X86_CC_P, i0, r0, r1)
+#  define x87_bunordi_d(i0, r0, i1)    _x87_bunordi_d(_jit, i0, r0, i1)
+static jit_word_t
+_x87_bunordi_d(jit_state_t*, jit_word_t, jit_int32_t, jit_float64_t*);
+#endif
+
+#if CODE
+#  define fpr_opi(name, type, size)                                    \
+static void                                                            \
+_x87_##name##i_##type(jit_state_t *_jit,                               \
+                     jit_int32_t r0, jit_int32_t r1,                   \
+                     jit_float##size##_t *i0)                          \
+{                                                                      \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr);               \
+    assert(jit_x87_reg_p(reg));                                                \
+    x87_movi_##type(rn(reg), i0);                                      \
+    x87_##name##r_##type(r0, r1, rn(reg));                             \
+    jit_unget_reg(reg);                                                        \
+}
+#  define fpr_bopi(name, type, size)                                   \
+static jit_word_t                                                      \
+_x87_b##name##i_##type(jit_state_t *_jit,                              \
+                      jit_word_t i0, jit_int32_t r0,                   \
+                      jit_float##size##_t *i1)                         \
+{                                                                      \
+    jit_word_t         word;                                           \
+    jit_int32_t                reg = jit_get_reg(jit_class_fpr|                \
+                                         jit_class_nospill);           \
+    assert(jit_x87_reg_p(reg));                                                \
+    x87_movi_##type(rn(reg), i1);                                      \
+    word = x87_b##name##r_##type(i0, r0, rn(reg));                     \
+    jit_unget_reg(reg);                                                        \
+    return (word);                                                     \
+}
+#  define fopi(name)                   fpr_opi(name, f, 32)
+#  define fbopi(name)                  fpr_bopi(name, f, 32)
+#  define dopi(name)                   fpr_opi(name, d, 64)
+#  define dbopi(name)                  fpr_bopi(name, d, 64)
+
+static void
+_fstcwm(jit_state_t *_jit, jit_int32_t md,
+       jit_int32_t rb, jit_int32_t ri, jit_int32_t ms)
+{
+    ic(0x9b);
+    rex(0, 1, rb, ri, _NOREG);
+    x87rx(017, md, rb, ri, ms);
+}
+
+static void
+_x87rx(jit_state_t *_jit, jit_int32_t code, jit_int32_t md,
+       jit_int32_t rb, jit_int32_t ri, jit_int32_t ms)
+{
+    rex(0, 1, rb, ri, _NOREG);
+    ic(0xd8 | (code >> 3));
+    rx((code & 7), md, rb, ri, ms);
+}
+
+static void
+_x87ri(jit_state_t *_jit, jit_int32_t code, jit_int32_t r0)
+{
+    ic(0xd8 | (code >> 3));
+    mrm(0x03, (code & 7), r0);
+}
+
+static void
+_x87rri(jit_state_t *_jit, jit_int32_t code, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r1 == _ST0_REGNO)
+       x87ri(code | 040, r0);
+    else {
+       assert(r0 == _ST0_REGNO);
+       x87ri(code, r1);
+    }
+}
+
+fopi(add)
+fopi(sub)
+fopi(rsb)
+fopi(mul)
+fopi(div)
+
+static void
+_x87_addr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1) {
+       if (r2 == _ST0_REGNO)
+           faddr(r0, _ST0_REGNO);
+       else if (r0 == _ST0_REGNO)
+           faddr(_ST0_REGNO, r2);
+       else {
+           fxchr(r0);
+           faddr(_ST0_REGNO, r0 == r2 ? _ST0_REGNO : r2);
+           fxchr(r0);
+       }
+    }
+    else if (r0 == r2) {
+       if (r1 == _ST0_REGNO)
+           faddr(r0, _ST0_REGNO);
+       else if (r0 == _ST0_REGNO)
+           faddr(_ST0_REGNO, r1);
+       else {
+           fxchr(r0);
+           faddr(_ST0_REGNO, r1);
+           fxchr(r0);
+       }
+    }
+    else {
+       fldr(r1);
+       faddr(_ST0_REGNO, r2 + 1);
+       fstpr(r0 + 1);
+    }
+}
+
+dopi(add)
+
+static void
+_x87_subr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1) {
+       if (r2 == _ST0_REGNO)
+           fsubrr(r0, _ST0_REGNO);
+       else if (r0 == _ST0_REGNO)
+           fsubr(_ST0_REGNO, r2);
+       else {
+           fxchr(r0);
+           fsubr(_ST0_REGNO, r0 == r2 ? _ST0_REGNO : r2);
+           fxchr(r0);
+       }
+    }
+    else if (r0 == r2) {
+       if (r1 == _ST0_REGNO)
+           fsubr(r0, _ST0_REGNO);
+       else if (r0 == _ST0_REGNO)
+           fsubrr(_ST0_REGNO, r1);
+       else {
+           fxchr(r0);
+           fsubrr(_ST0_REGNO, r1);
+           fxchr(r0);
+       }
+    }
+    else {
+       fldr(r1);
+       fsubr(_ST0_REGNO, r2 + 1);
+       fstpr(r0 + 1);
+    }
+}
+
+dopi(sub)
+
+dopi(rsb)
+
+static void
+_x87_mulr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1) {
+       if (r2 == _ST0_REGNO)
+           fmulr(r0, _ST0_REGNO);
+       else if (r0 == _ST0_REGNO)
+           fmulr(_ST0_REGNO, r2);
+       else {
+           fxchr(r0);
+           fmulr(_ST0_REGNO, r0 == r2 ? _ST0_REGNO : r2);
+           fxchr(r0);
+       }
+    }
+    else if (r0 == r2) {
+       if (r1 == _ST0_REGNO)
+           fmulr(r0, _ST0_REGNO);
+       else if (r0 == _ST0_REGNO)
+           fmulr(_ST0_REGNO, r1);
+       else {
+           fxchr(r0);
+           fmulr(_ST0_REGNO, r1);
+           fxchr(r0);
+       }
+    }
+    else {
+       fldr(r1);
+       fmulr(_ST0_REGNO, r2 + 1);
+       fstpr(r0 + 1);
+    }
+}
+
+dopi(mul)
+
+static void
+_x87_divr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r0 == r1) {
+       if (r2 == _ST0_REGNO)
+           fdivrr(r0, _ST0_REGNO);
+       else if (r0 == _ST0_REGNO)
+           fdivr(_ST0_REGNO, r2);
+       else {
+           fxchr(r0);
+           fdivr(_ST0_REGNO, r0 == r2 ? _ST0_REGNO : r2);
+           fxchr(r0);
+       }
+    }
+    else if (r0 == r2) {
+       if (r1 == _ST0_REGNO)
+           fdivr(r0, _ST0_REGNO);
+       else if (r0 == _ST0_REGNO)
+           fsubrr(_ST0_REGNO, r1);
+       else {
+           fxchr(r0);
+           fdivrr(_ST0_REGNO, r1);
+           fxchr(r0);
+       }
+    }
+    else {
+       fldr(r1);
+       fdivr(_ST0_REGNO, r2 + 1);
+       fstpr(r0 + 1);
+    }
+}
+
+dopi(div)
+
+static void
+_x87_absr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1) {
+       if (r1 == _ST0_REGNO)
+           fabs_();
+       else {
+           fxchr(r0);
+           fabs_();
+           fxchr(r0);
+       }
+    }
+    else {
+       fldr(r1);
+       fabs_();
+       fstpr(r0 + 1);
+    }
+}
+
+static void
+_x87_negr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1) {
+       if (r1 == _ST0_REGNO)
+           fchs_();
+       else {
+           fxchr(r0);
+           fchs_();
+           fxchr(r0);
+       }
+    }
+    else {
+       fldr(r1);
+       fchs_();
+       fstpr(r0 + 1);
+    }
+}
+
+static void
+_x87_sqrtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == r1) {
+       if (r1 == _ST0_REGNO)
+           fsqrt_();
+       else {
+           fxchr(r0);
+           fsqrt_();
+           fxchr(r0);
+       }
+    }
+    else {
+       fldr(r1);
+       fsqrt_();
+       fstpr(r0 + 1);
+    }
+}
+
+static void
+_x87_truncr_d_i(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+#if defined(sun)
+    /* for the sake of passing test cases in x87 mode, otherwise only sse
+     * is supported */
+    fstcwm(-4, _RBP_REGNO, _NOREG, _SCL1);
+    ldxi_s(r0, _RBP_REGNO, -4);
+    extr_uc(r0, r0);
+#  define FPCW_CHOP    0xc00
+    ori(r0, r0, FPCW_CHOP);
+    stxi_s(-8, _RBP_REGNO, r0);
+    fldcwm(-8, _RBP_REGNO, _NOREG, _SCL1);
+    if (r1 == _ST0_REGNO)
+       fistlm(CVT_OFFSET, _RBP_REGNO, _NOREG, _SCL1);
+    else {
+       fxchr(r1);
+       fistlm(CVT_OFFSET, _RBP_REGNO, _NOREG, _SCL1);
+       fxchr(r1);
+    }
+    fldcwm(-4, _RBP_REGNO, _NOREG, _SCL1);
+    ldxi(r0, _RBP_REGNO, CVT_OFFSET);
+#else
+    fldr(r1);
+    fisttplm(CVT_OFFSET, _RBP_REGNO, _NOREG, _SCL1);
+    ldxi_i(r0, _RBP_REGNO, CVT_OFFSET);
+#endif
+}
+
+#  if __X64
+static void
+_x87_truncr_d_l(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    fldr(r1);
+    fisttpqm(CVT_OFFSET, _RBP_REGNO, _NOREG, _SCL1);
+    ldxi(r0, _RBP_REGNO, CVT_OFFSET);
+}
+#  endif
+
+static void
+_x87_extr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    stxi(CVT_OFFSET, _RBP_REGNO, r1);
+#  if __X32
+    fildlm(CVT_OFFSET, _RBP_REGNO, _NOREG, _SCL1);
+#  else
+    fildqm(CVT_OFFSET, _RBP_REGNO, _NOREG, _SCL1);
+#  endif
+    fstpr(r0 + 1);
+}
+
+static void
+_x87cmp(jit_state_t *_jit, jit_int32_t code,
+       jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_bool_t         rc;
+    jit_int32_t                reg;
+    if ((rc = reg8_p(r0)))
+       reg = r0;
+    else {
+       reg = _RAX_REGNO;
+       movr(r0, reg);
+    }
+    ixorr(reg, reg);
+    if (r1 == _ST0_REGNO)
+       fucomir(r2);
+    else {
+       fldr(r1);
+       fucomipr(r2 + 1);
+    }
+    cc(code, reg);
+    if (!rc)
+       xchgr(r0, reg);
+}
+
+static void
+_x87cmp2(jit_state_t *_jit, jit_int32_t code,
+        jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_bool_t                 rc;
+    jit_int32_t                        reg;
+    jit_int32_t                        f1, f2;
+    if (r2 == _ST0_REGNO)      f1 = r2, f2 = r1;
+    else                       f1 = r1, f2 = r2;
+    if ((rc = reg8_p(r0)))
+       reg = r0;
+    else {
+       reg = _RAX_REGNO;
+       movr(r0, reg);
+    }
+    ixorr(reg, reg);
+    if (f1 == _ST0_REGNO)
+       fucomir(f2);
+    else {
+       fldr(f1);
+       fucomipr(f2 + 1);
+    }
+    cc(code, reg);
+    if (!rc)
+       xchgr(r0, reg);
+}
+
+static jit_word_t
+_x87jcc(jit_state_t *_jit, jit_int32_t code,
+       jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 == _ST0_REGNO)
+       fucomir(r1);
+    else {
+       fldr(r0);
+       fucomipr(r1 + 1);
+    }
+    jcc(code, i0);
+    return (_jit->pc.w);
+}
+
+static jit_word_t
+_x87jcc2(jit_state_t *_jit, jit_int32_t code,
+        jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                        f0, f1;
+    if (r1 == _ST0_REGNO)      f0 = r1, f1 = r0;
+    else                       f0 = r0, f1 = r1;
+    if (f0 == _ST0_REGNO)
+       fucomir(f1);
+    else {
+       fldr(f0);
+       fucomipr(f1 + 1);
+    }
+    jcc(code, i0);
+    return (_jit->pc.w);
+}
+
+fopi(lt)
+fopi(le)
+fopi(eq)
+fopi(ge)
+fopi(gt)
+fopi(ne)
+fopi(unlt)
+fopi(unle)
+fopi(uneq)
+fopi(unge)
+fopi(ungt)
+fopi(ltgt)
+fopi(ord)
+fopi(unord)
+fbopi(lt)
+fbopi(le)
+fbopi(eq)
+fbopi(ge)
+fbopi(gt)
+fbopi(ne)
+fbopi(unlt)
+fbopi(unle)
+fbopi(uneq)
+fbopi(unge)
+fbopi(ungt)
+fbopi(ltgt)
+fbopi(ord)
+fbopi(unord)
+
+static void
+_x87_movi_f(jit_state_t *_jit, jit_int32_t r0, jit_float32_t *i0)
+{
+    union {
+       jit_int32_t      i;
+       jit_float32_t    f;
+    } data;
+    jit_int32_t                 reg;
+
+    data.f = *i0;
+    if (data.f == 0.0 && !(data.i & 0x80000000))
+       fldz();
+    else if (data.f == 1.0)
+       fld1();
+    else if (data.f == 3.3219280948873623478703195458468f)
+       fldl2t();
+    else if (data.f == 1.4426950408889634073599246886656f)
+       fldl2e();
+    else if (data.f == 3.1415926535897932384626421096161f)
+       fldpi();
+    else if (data.f == 0.3010299956639811952137387498515f)
+       fldlg2();
+    else if (data.f == 0.6931471805599453094172323683399f)
+       fldln2();
+    else {
+       if (_jitc->no_data) {
+           reg = jit_get_reg(jit_class_gpr);
+           movi(rn(reg), data.i);
+           stxi_i(CVT_OFFSET, _RBP_REGNO, rn(reg));
+           jit_unget_reg(reg);
+           x87_ldxi_f(r0, _RBP_REGNO, CVT_OFFSET);
+       }
+       else
+           x87_ldi_f(r0, (jit_word_t)i0);
+       return;
+    }
+    fstpr(r0 + 1);
+}
+
+static void
+_x87_ldr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    fldsm(0, r1, _NOREG, _SCL1);
+    fstpr(r0 + 1);
+}
+
+static void
+_x87_ldi_f(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (x87_address_p(i0)) {
+       fldsm(i0, _NOREG, _NOREG, _SCL1);
+       fstpr(r0 + 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       x87_ldr_f(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_x87_ldxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    x87_ldr_f(r0, rn(reg));
+    jit_unget_reg(reg);
+#else
+    fldsm(0, r1, r2, _SCL1);
+    fstpr(r0 + 1);
+#endif
+}
+
+static void
+_x87_ldxi_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       fldsm(i0, r1, _NOREG, _SCL1);
+       fstpr(r0 + 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+#if __X64_32
+       addi(rn(reg), r1, i0);
+       x87_ldr_f(r0, rn(reg));
+#else
+       movi(rn(reg), i0);
+       x87_ldxr_f(r0, r1, rn(reg));
+#endif
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_x87_str_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r1 == _ST0_REGNO)
+       fstsm(0, r0, _NOREG, _SCL1);
+    else {
+       fxchr(r1);
+       fstsm(0, r0, _NOREG, _SCL1);
+       fxchr(r1);
+    }
+}
+
+static void
+_x87_sti_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (!x87_address_p(i0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       x87_str_f(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+    else if (r0 == _ST0_REGNO)
+       fstsm(i0, _NOREG, _NOREG, _SCL1);
+    else {
+       fxchr(r0);
+       fstsm(i0, _NOREG, _NOREG, _SCL1);
+       fxchr(r0);
+    }
+}
+
+static void
+_x87_stxr_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    x87_str_f(rn(reg), r2);
+    jit_unget_reg(reg);
+#else
+    if (r2 == _ST0_REGNO)
+       fstsm(0, r0, r1, _SCL1);
+    else {
+       fxchr(r2);
+       fstsm(0, r0, r1, _SCL1);
+       fxchr(r2);
+    }
+#endif
+}
+
+static void
+_x87_stxi_f(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (!can_sign_extend_int_p(i0)) {
+       reg = jit_get_reg(jit_class_gpr);
+#if __X64_32
+       addi(rn(reg), r0, i0);
+       x87_str_f(rn(reg), r1);
+#else
+       movi(rn(reg), i0);
+       x87_stxr_f(rn(reg), r0, r1);
+#endif
+       jit_unget_reg(reg);
+    }
+    else if (r1 == _ST0_REGNO)
+       fstsm(i0, r0, _NOREG, _SCL1);
+    else {
+       fxchr(r1);
+       fstsm(i0, r0, _NOREG, _SCL1);
+       fxchr(r1);
+    }
+}
+
+static void
+_x87_movr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r0 != r1) {
+       if (r1 == _ST0)
+           fstr(r0);
+       else if (r0 == _ST0) {
+           fxchr(r1);
+           fstr(r1);
+       }
+       else {
+           fldr(r1);
+           fstpr(r0 + 1);
+       }
+    }
+}
+
+static void
+_x87_movi_d(jit_state_t *_jit, jit_int32_t r0, jit_float64_t *i0)
+{
+    union {
+       jit_int32_t      ii[2];
+       jit_word_t       w;
+       jit_float64_t    d;
+    } data;
+    jit_int32_t                 reg;
+
+    data.d = *i0;
+    if (data.d == 0.0 && !(data.ii[1] & 0x80000000))
+       fldz();
+    else if (data.d == 1.0)
+       fld1();
+    else if (data.d == 3.3219280948873623478703195458468)
+       fldl2t();
+    else if (data.d == 1.4426950408889634073599246886656)
+       fldl2e();
+    else if (data.d == 3.1415926535897932384626421096161)
+       fldpi();
+    else if (data.d == 0.3010299956639811952137387498515)
+       fldlg2();
+    else if (data.d == 0.6931471805599453094172323683399)
+       fldln2();
+    else {
+       if (_jitc->no_data) {
+           reg = jit_get_reg(jit_class_gpr);
+#if __X32 || __X64_32
+           movi(rn(reg), data.ii[0]);
+           stxi_i(CVT_OFFSET, _RBP_REGNO, rn(reg));
+           movi(rn(reg), data.ii[1]);
+           stxi_i(CVT_OFFSET + 4, _RBP_REGNO, rn(reg));
+#else
+           movi(rn(reg), data.w);
+           stxi_l(CVT_OFFSET, _RBP_REGNO, rn(reg));
+#endif
+           jit_unget_reg(reg);
+           x87_ldxi_d(r0, _RBP_REGNO, CVT_OFFSET);
+       }
+       else
+           x87_ldi_d(r0, (jit_word_t)i0);
+       return;
+    }
+    fstpr(r0 + 1);
+}
+
+dopi(lt)
+dopi(le)
+
+static void
+_x87_eqr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_bool_t                 rc;
+    jit_word_t                 jp_code;
+    jit_int32_t                        reg, f1, f2;
+    if (r2 == _ST0_REGNO)      f1 = r2, f2 = r1;
+    else                       f1 = r1, f2 = r2;
+    if ((rc = reg8_p(r0)))
+       reg = r0;
+    else {
+       reg = _RAX_REGNO;
+       movr(r0, reg);
+    }
+    ixorr(reg, reg);
+    if (f1 == _ST0_REGNO)
+       fucomir(f2);
+    else {
+       fldr(f1);
+       fucomipr(f2 + 1);
+    }
+    jpes(0);
+    jp_code = _jit->pc.w;
+    cc(X86_CC_E, reg);
+    patch_rel_char(jp_code, _jit->pc.w);
+    if (!rc)
+       xchgr(r0, reg);
+}
+
+dopi(eq)
+dopi(ge)
+dopi(gt)
+
+static void
+_x87_ner_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    jit_bool_t                 rc;
+    jit_word_t                 jp_code;
+    jit_int32_t                        reg, f1, f2;
+    if (r2 == _ST0_REGNO)      f1 = r2, f2 = r1;
+    else                       f1 = r1, f2 = r2;
+    if ((rc = reg8_p(r0)))
+       reg = r0;
+    else {
+       reg = _RAX_REGNO;
+       movr(r0, reg);
+    }
+    imovi(reg, 1);
+    if (f1 == _ST0_REGNO)
+       fucomir(f2);
+    else {
+       fldr(f1);
+       fucomipr(f2 + 1);
+    }
+    jpes(0);
+    jp_code = _jit->pc.w;
+    cc(X86_CC_NE, reg);
+    patch_rel_char(jp_code, _jit->pc.w);
+    if (!rc)
+       xchgr(r0, reg);
+}
+
+dopi(ne)
+dopi(unlt)
+dopi(unle)
+dopi(uneq)
+dopi(unge)
+dopi(ungt)
+
+static void
+_x87_ltgtr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+    if (r1 == r2)
+       movi(r0, 1);
+    else
+       x87cmp2(X86_CC_NE, r0, r1, r2);
+}
+
+dopi(ltgt)
+dopi(ord)
+dopi(unord)
+
+static void
+_x87_ldr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    fldlm(0, r1, _NOREG, _SCL1);
+    fstpr(r0 + 1);
+}
+
+static void
+_x87_ldi_d(jit_state_t *_jit, jit_int32_t r0, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (x87_address_p(i0)) {
+       fldlm(i0, _NOREG, _NOREG, _SCL1);
+       fstpr(r0 + 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       x87_ldr_d(r0, rn(reg));
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_x87_ldxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r1, r2);
+    x87_ldr_d(r0, rn(reg));
+    jit_unget_reg(reg);
+#else
+    fldlm(0, r1, r2, _SCL1);
+    fstpr(r0 + 1);
+#endif
+}
+
+static void
+_x87_ldxi_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_word_t i0)
+{
+    jit_int32_t                reg;
+    if (can_sign_extend_int_p(i0)) {
+       fldlm(i0, r1, _NOREG, _SCL1);
+       fstpr(r0 + 1);
+    }
+    else {
+       reg = jit_get_reg(jit_class_gpr);
+#if __X64_32
+       addi(rn(reg), r1, i0);
+       x87_ldr_d(r0, rn(reg));
+#else
+       movi(rn(reg), i0);
+       x87_ldxr_d(r0, r1, rn(reg));
+#endif
+       jit_unget_reg(reg);
+    }
+}
+
+static void
+_x87_str_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    if (r1 == _ST0_REGNO)
+       fstlm(0, r0, _NOREG, _SCL1);
+    else {
+       fxchr(r1);
+       fstlm(0, r0, _NOREG, _SCL1);
+       fxchr(r1);
+    }
+}
+
+static void
+_x87_sti_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0)
+{
+    jit_int32_t                reg;
+    if (!x87_address_p(i0)) {
+       reg = jit_get_reg(jit_class_gpr);
+       movi(rn(reg), i0);
+       x87_str_d(rn(reg), r0);
+       jit_unget_reg(reg);
+    }
+    else if (r0 == _ST0_REGNO)
+       fstlm(i0, _NOREG, _NOREG, _SCL1);
+    else {
+       fxchr(r0);
+       fstlm(i0, _NOREG, _NOREG, _SCL1);
+       fxchr(r0);
+    }
+}
+
+static void
+_x87_stxr_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1, jit_int32_t r2)
+{
+#if __X64_32
+    jit_int32_t                reg;
+    reg = jit_get_reg(jit_class_gpr);
+    addr(rn(reg), r0, r1);
+    x87_str_d(rn(reg), r2);
+    jit_unget_reg(reg);
+#else
+    if (r2 == _ST0_REGNO)
+       fstlm(0, r0, r1, _SCL1);
+    else {
+       fxchr(r2);
+       fstlm(0, r0, r1, _SCL1);
+       fxchr(r2);
+    }
+#endif
+}
+
+static void
+_x87_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                reg;
+    if (!can_sign_extend_int_p(i0)) {
+       reg = jit_get_reg(jit_class_gpr);
+#if __X64_32
+       addi(rn(reg), r0, i0);
+       x87_str_d(rn(reg), r1);
+#else
+       movi(rn(reg), i0);
+       x87_stxr_d(rn(reg), r0, r1);
+#endif
+       jit_unget_reg(reg);
+    }
+    else if (r1 == _ST0_REGNO)
+       fstlm(i0, r0, _NOREG, _SCL1);
+    else {
+       fxchr(r1);
+       fstlm(i0, r0, _NOREG, _SCL1);
+       fxchr(r1);
+    }
+}
+
+dbopi(lt)
+dbopi(le)
+
+static jit_word_t
+_x87_beqr_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                        f0, f1;
+    jit_word_t                 jp_code;
+    if (r1 == _ST0_REGNO)      f0 = r1, f1 = r0;
+    else                       f0 = r0, f1 = r1;
+    if (f0 == _ST0_REGNO)
+       fucomir(f1);
+    else {
+       fldr(f0);
+       fucomipr(f1 + 1);
+    }
+    jpes(0);
+    jp_code = _jit->pc.w;
+    jcc(X86_CC_E, i0);
+    patch_rel_char(jp_code, _jit->pc.w);
+    return (_jit->pc.w);
+}
+dbopi(eq)
+dbopi(ge)
+dbopi(gt)
+
+static jit_word_t
+_x87_bner_d(jit_state_t *_jit, jit_word_t i0, jit_int32_t r0, jit_int32_t r1)
+{
+    jit_int32_t                        f0, f1;
+    jit_word_t                 jp_code;
+    jit_word_t                 jz_code;
+    if (r1 == _ST0_REGNO)      f0 = r1, f1 = r0;
+    else                       f0 = r0, f1 = r1;
+    if (f0 == _ST0_REGNO)
+       fucomir(f1);
+    else {
+       fldr(f0);
+       fucomipr(f1 + 1);
+    }
+    jpes(0);
+    jp_code = _jit->pc.w;
+    jzs(0);
+    jz_code = _jit->pc.w;
+    patch_rel_char(jp_code, _jit->pc.w);
+    jmpi(i0);
+    patch_rel_char(jz_code, _jit->pc.w);
+    return (_jit->pc.w);
+}
+dbopi(ne)
+dbopi(unlt)
+dbopi(unle)
+dbopi(uneq)
+dbopi(unge)
+dbopi(ungt)
+dbopi(ltgt)
+dbopi(ord)
+dbopi(unord)
+#  undef fopi
+#  undef fbopi
+#  undef dopi
+#  undef dbopi
+#  undef fpr_bopi
+#  undef fpr_opi
+#endif
diff --git a/deps/lightning/lib/jit_x86.c b/deps/lightning/lib/jit_x86.c
new file mode 100644 (file)
index 0000000..c34a117
--- /dev/null
@@ -0,0 +1,2264 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+
+#if __X32
+#  define jit_arg_reg_p(i)             0
+#  define jit_arg_f_reg_p(i)           0
+#  define stack_framesize              20
+#  define stack_adjust                 12
+#  define CVT_OFFSET                   -12
+#  define REAL_WORDSIZE                        4
+#  define va_gp_increment              4
+#  define va_fp_increment              8
+#else
+#  if __CYGWIN__ || _WIN32
+#    define jit_arg_reg_p(i)           ((i) >= 0 && (i) < 4)
+#    define jit_arg_f_reg_p(i)         jit_arg_reg_p(i)
+#    define stack_framesize            152
+#    define va_fp_increment            8
+#  else
+#    define jit_arg_reg_p(i)           ((i) >= 0 && (i) < 6)
+#    define jit_arg_f_reg_p(i)         ((i) >= 0 && (i) < 8)
+#    define stack_framesize            56
+#    define first_gp_argument          rdi
+#    define first_gp_offset            offsetof(jit_va_list_t, rdi)
+#    define first_gp_from_offset(gp)   ((gp) / 8)
+#    define last_gp_argument           r9
+#    define va_gp_max_offset                                           \
+       (offsetof(jit_va_list_t, r9) - offsetof(jit_va_list_t, rdi) + 8)
+#    define first_fp_argument          xmm0
+#    define first_fp_offset            offsetof(jit_va_list_t, xmm0)
+#    define last_fp_argument           xmm7
+#    define va_fp_max_offset                                           \
+       (offsetof(jit_va_list_t, xmm7) - offsetof(jit_va_list_t, rdi) + 16)
+#    define va_fp_increment            16
+#    define first_fp_from_offset(fp)   (((fp) - va_gp_max_offset) / 16)
+#  endif
+#  define va_gp_increment              8
+#  define stack_adjust                 8
+#  define CVT_OFFSET                   -8
+#  define REAL_WORDSIZE                        8
+#endif
+
+/*
+ * Types
+ */
+#if __X32 || __CYGWIN__ || _WIN32
+typedef jit_pointer_t jit_va_list_t;
+#else
+typedef struct jit_va_list {
+    jit_int32_t                gpoff;
+    jit_int32_t                fpoff;
+    jit_pointer_t      over;
+    jit_pointer_t      save;
+    /* Declared explicitly as int64 for the x32 abi */
+    jit_int64_t                rdi;
+    jit_int64_t                rsi;
+    jit_int64_t                rdx;
+    jit_int64_t                rcx;
+    jit_int64_t                r8;
+    jit_int64_t                r9;
+    jit_float64_t      xmm0;
+    jit_float64_t      _up0;
+    jit_float64_t      xmm1;
+    jit_float64_t      _up1;
+    jit_float64_t      xmm2;
+    jit_float64_t      _up2;
+    jit_float64_t      xmm3;
+    jit_float64_t      _up3;
+    jit_float64_t      xmm4;
+    jit_float64_t      _up4;
+    jit_float64_t      xmm5;
+    jit_float64_t      _up5;
+    jit_float64_t      xmm6;
+    jit_float64_t      _up6;
+    jit_float64_t      xmm7;
+    jit_float64_t      _up7;
+} jit_va_list_t;
+#endif
+
+/*
+ * Prototypes
+ */
+#define patch(instr, node)             _patch(_jit, instr, node)
+static void _patch(jit_state_t*,jit_word_t,jit_node_t*);
+#define sse_from_x87_f(r0, r1)         _sse_from_x87_f(_jit, r0, r1)
+static void _sse_from_x87_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#define sse_from_x87_d(r0, r1)         _sse_from_x87_d(_jit, r0, r1)
+static void _sse_from_x87_d(jit_state_t*,jit_int32_t,jit_int32_t);
+#define x87_from_sse_f(r0, r1)         _x87_from_sse_f(_jit, r0, r1)
+static void _x87_from_sse_f(jit_state_t*,jit_int32_t,jit_int32_t);
+#define x87_from_sse_d(r0, r1)         _x87_from_sse_d(_jit, r0, r1)
+static void _x87_from_sse_d(jit_state_t*,jit_int32_t,jit_int32_t);
+
+#define PROTO                          1
+#  include "jit_x86-cpu.c"
+#  include "jit_x86-sse.c"
+#  include "jit_x86-x87.c"
+#undef PROTO
+
+/*
+ * Initialization
+ */
+jit_cpu_t              jit_cpu;
+jit_register_t         _rvs[] = {
+#if __X32
+    { rc(gpr) | rc(rg8) | 0,           "%eax" },
+    { rc(gpr) | rc(rg8) | 1,           "%ecx" },
+    { rc(gpr) | rc(rg8) | 2,           "%edx" },
+    { rc(sav) | rc(rg8) | rc(gpr) | 3, "%ebx" },
+    { rc(sav) | rc(gpr) | 6,           "%esi" },
+    { rc(sav) | rc(gpr) | 7,           "%edi" },
+    { rc(sav) | 4,                     "%esp" },
+    { rc(sav) | 5,                     "%ebp" },
+    { rc(xpr) | rc(fpr) | 0,           "%xmm0" },
+    { rc(xpr) | rc(fpr) | 1,           "%xmm1" },
+    { rc(xpr) | rc(fpr) | 2,           "%xmm2" },
+    { rc(xpr) | rc(fpr) | 3,           "%xmm3" },
+    { rc(xpr) | rc(fpr) | 4,           "%xmm4" },
+    { rc(xpr) | rc(fpr) | 5,           "%xmm5" },
+    { rc(xpr) | rc(fpr) | 6,           "%xmm6" },
+    { rc(xpr) | rc(fpr) | 7,           "%xmm7" },
+    { rc(fpr) | 0,                     "st(0)" },
+    { rc(fpr) | 1,                     "st(1)" },
+    { rc(fpr) | 2,                     "st(2)" },
+    { rc(fpr) | 3,                     "st(3)" },
+    { rc(fpr) | 4,                     "st(4)" },
+    { rc(fpr) | 5,                     "st(5)" },
+    { rc(fpr) | 6,                     "st(6)" },
+    { rc(fpr) | 7,                     "st(7)" },
+#else
+#  if __CYGWIN__ || _WIN32
+    { rc(gpr) | rc(rg8) | 0,           "%rax" },
+    { rc(gpr) | rc(rg8) | rc(rg8) | 10,        "%r10" },
+    { rc(gpr) | rc(rg8) | rc(rg8) | 11,        "%r11" },
+    { rc(sav) | rc(rg8) | rc(gpr) | 3, "%rbx" },
+    { rc(sav) | rc(gpr) | 7,           "%rdi" },
+    { rc(sav) | rc(gpr) | 6,           "%rsi" },
+    { rc(sav) | rc(gpr) | 12,          "%r12" },
+    { rc(sav) | rc(gpr) | 13,          "%r13" },
+    { rc(sav) | rc(gpr) | 14,          "%r14" },
+    { rc(sav) | rc(gpr) | 15,          "%r15" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 9, "%r9" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 8, "%r8" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 2, "%rdx" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 1, "%rcx" },
+    { rc(sav) | 4,                     "%rsp" },
+    { rc(sav) | 5,                     "%rbp" },
+    { rc(xpr) | rc(fpr) | 4,           "%xmm4" },
+    { rc(xpr) | rc(fpr) | 5,           "%xmm5" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 6, "%xmm6" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 7, "%xmm7" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 8, "%xmm8" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 9, "%xmm9" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 10,        "%xmm10" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 11,        "%xmm11" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 12,        "%xmm12" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 13,        "%xmm13" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 14,        "%xmm14" },
+    { rc(sav) | rc(xpr) | rc(fpr) | 15,        "%xmm15" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 3, "%xmm3" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 2, "%xmm2" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 1, "%xmm1" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 0, "%xmm0" },
+#else
+    /* %rax is a pseudo flag argument for varargs functions */
+    { rc(arg) | rc(gpr) | rc(rg8) | 0, "%rax" },
+    { rc(gpr) | rc(rg8) | 10,          "%r10" },
+    { rc(gpr) | rc(rg8) | 11,          "%r11" },
+    { rc(sav) | rc(rg8) | rc(gpr) | 3, "%rbx" },
+    { rc(sav) | rc(rg8) | rc(gpr) | 13,        "%r13" },
+    { rc(sav) | rc(rg8) | rc(gpr) | 14,        "%r14" },
+    { rc(sav) | rc(rg8) | rc(gpr) | 15,        "%r15" },
+    { rc(sav) | rc(gpr) | rc(rg8) | 12,        "%r12" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 9, "%r9" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 8, "%r8" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 1, "%rcx" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 2, "%rdx" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 6, "%rsi" },
+    { rc(arg) | rc(rg8) | rc(gpr) | 7, "%rdi" },
+    { rc(sav) | 4,                     "%rsp" },
+    { rc(sav) | 5,                     "%rbp" },
+    { rc(xpr) | rc(fpr) | 8,           "%xmm8" },
+    { rc(xpr) | rc(fpr) | 9,           "%xmm9" },
+    { rc(xpr) | rc(fpr) | 10,          "%xmm10" },
+    { rc(xpr) | rc(fpr) | 11,          "%xmm11" },
+    { rc(xpr) | rc(fpr) | 12,          "%xmm12" },
+    { rc(xpr) | rc(fpr) | 13,          "%xmm13" },
+    { rc(xpr) | rc(fpr) | 14,          "%xmm14" },
+    { rc(xpr) | rc(fpr) | 15,          "%xmm15" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 7, "%xmm7" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 6, "%xmm6" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 5, "%xmm5" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 4, "%xmm4" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 3, "%xmm3" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 2, "%xmm2" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 1, "%xmm1" },
+    { rc(xpr) | rc(arg) | rc(fpr) | 0, "%xmm0" },
+#  endif
+    { rc(fpr) | 0,                     "st(0)" },
+    { rc(fpr) | 1,                     "st(1)" },
+    { rc(fpr) | 2,                     "st(2)" },
+    { rc(fpr) | 3,                     "st(3)" },
+    { rc(fpr) | 4,                     "st(4)" },
+    { rc(fpr) | 5,                     "st(5)" },
+    { rc(fpr) | 6,                     "st(6)" },
+    { rc(fpr) | 7,                     "st(7)" },
+#endif
+    { _NOREG,                          "<none>" },
+};
+
+/*
+ * Implementation
+ */
+void
+jit_get_cpu(void)
+{
+    union {
+       struct {
+           jit_uint32_t sse3           : 1;
+           jit_uint32_t pclmulqdq      : 1;
+           jit_uint32_t dtes64         : 1;    /* amd reserved */
+           jit_uint32_t monitor        : 1;
+           jit_uint32_t ds_cpl         : 1;    /* amd reserved */
+           jit_uint32_t vmx            : 1;    /* amd reserved */
+           jit_uint32_t smx            : 1;    /* amd reserved */
+           jit_uint32_t est            : 1;    /* amd reserved */
+           jit_uint32_t tm2            : 1;    /* amd reserved */
+           jit_uint32_t ssse3          : 1;
+           jit_uint32_t cntx_id        : 1;    /* amd reserved */
+           jit_uint32_t __reserved0    : 1;
+           jit_uint32_t fma            : 1;
+           jit_uint32_t cmpxchg16b     : 1;
+           jit_uint32_t xtpr           : 1;    /* amd reserved */
+           jit_uint32_t pdcm           : 1;    /* amd reserved */
+           jit_uint32_t __reserved1    : 1;
+           jit_uint32_t pcid           : 1;    /* amd reserved */
+           jit_uint32_t dca            : 1;    /* amd reserved */
+           jit_uint32_t sse4_1         : 1;
+           jit_uint32_t sse4_2         : 1;
+           jit_uint32_t x2apic         : 1;    /* amd reserved */
+           jit_uint32_t movbe          : 1;    /* amd reserved */
+           jit_uint32_t popcnt         : 1;
+           jit_uint32_t tsc            : 1;    /* amd reserved */
+           jit_uint32_t aes            : 1;
+           jit_uint32_t xsave          : 1;
+           jit_uint32_t osxsave        : 1;
+           jit_uint32_t avx            : 1;
+           jit_uint32_t __reserved2    : 1;    /* amd F16C */
+           jit_uint32_t __reserved3    : 1;
+           jit_uint32_t __alwayszero   : 1;    /* amd RAZ */
+       } bits;
+       jit_uword_t     cpuid;
+    } ecx;
+    union {
+       struct {
+           jit_uint32_t fpu            : 1;
+           jit_uint32_t vme            : 1;
+           jit_uint32_t de             : 1;
+           jit_uint32_t pse            : 1;
+           jit_uint32_t tsc            : 1;
+           jit_uint32_t msr            : 1;
+           jit_uint32_t pae            : 1;
+           jit_uint32_t mce            : 1;
+           jit_uint32_t cmpxchg8b      : 1;
+           jit_uint32_t apic           : 1;
+           jit_uint32_t __reserved0    : 1;
+           jit_uint32_t sep            : 1;
+           jit_uint32_t mtrr           : 1;
+           jit_uint32_t pge            : 1;
+           jit_uint32_t mca            : 1;
+           jit_uint32_t cmov           : 1;
+           jit_uint32_t pat            : 1;
+           jit_uint32_t pse36          : 1;
+           jit_uint32_t psn            : 1;    /* amd reserved */
+           jit_uint32_t clfsh          : 1;
+           jit_uint32_t __reserved1    : 1;
+           jit_uint32_t ds             : 1;    /* amd reserved */
+           jit_uint32_t acpi           : 1;    /* amd reserved */
+           jit_uint32_t mmx            : 1;
+           jit_uint32_t fxsr           : 1;
+           jit_uint32_t sse            : 1;
+           jit_uint32_t sse2           : 1;
+           jit_uint32_t ss             : 1;    /* amd reserved */
+           jit_uint32_t htt            : 1;
+           jit_uint32_t tm             : 1;    /* amd reserved */
+           jit_uint32_t __reserved2    : 1;
+           jit_uint32_t pbe            : 1;    /* amd reserved */
+       } bits;
+       jit_uword_t     cpuid;
+    } edx;
+#if __X32
+    int                        ac, flags;
+#endif
+    jit_uword_t                eax, ebx;
+
+#if __X32
+    /* adapted from glibc __sysconf */
+    __asm__ volatile ("pushfl;\n\t"
+                     "popl %0;\n\t"
+                     "movl $0x240000, %1;\n\t"
+                     "xorl %0, %1;\n\t"
+                     "pushl %1;\n\t"
+                     "popfl;\n\t"
+                     "pushfl;\n\t"
+                     "popl %1;\n\t"
+                     "xorl %0, %1;\n\t"
+                     "pushl %0;\n\t"
+                     "popfl"
+                     : "=r" (flags), "=r" (ac));
+
+    /* i386 or i486 without cpuid */
+    if ((ac & (1 << 21)) == 0)
+       /* probably without x87 as well */
+       return;
+#endif
+
+    /* query %eax = 1 function */
+#if __X32 || __X64_32
+    __asm__ volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
+#else
+    __asm__ volatile ("xchgq %%rbx, %1; cpuid; xchgq %%rbx, %1"
+#endif
+                     : "=a" (eax), "=r" (ebx),
+                     "=c" (ecx.cpuid), "=d" (edx.cpuid)
+                     : "0" (1));
+
+    jit_cpu.fpu                = edx.bits.fpu;
+    jit_cpu.cmpxchg8b  = edx.bits.cmpxchg8b;
+    jit_cpu.cmov       = edx.bits.cmov;
+    jit_cpu.mmx                = edx.bits.mmx;
+    jit_cpu.sse                = edx.bits.sse;
+    jit_cpu.sse2       = edx.bits.sse2;
+    jit_cpu.sse3       = ecx.bits.sse3;
+    jit_cpu.pclmulqdq  = ecx.bits.pclmulqdq;
+    jit_cpu.ssse3      = ecx.bits.ssse3;
+    jit_cpu.fma                = ecx.bits.fma;
+    jit_cpu.cmpxchg16b = ecx.bits.cmpxchg16b;
+    jit_cpu.sse4_1     = ecx.bits.sse4_1;
+    jit_cpu.sse4_2     = ecx.bits.sse4_2;
+    jit_cpu.movbe      = ecx.bits.movbe;
+    jit_cpu.popcnt     = ecx.bits.popcnt;
+    jit_cpu.aes                = ecx.bits.aes;
+    jit_cpu.avx                = ecx.bits.avx;
+
+    /* query %eax = 0x80000001 function */
+#if __X64
+#  if __X64_32
+    __asm__ volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
+#  else
+    __asm__ volatile ("xchgq %%rbx, %1; cpuid; xchgq %%rbx, %1"
+#  endif
+                     : "=a" (eax), "=r" (ebx),
+                     "=c" (ecx.cpuid), "=d" (edx.cpuid)
+                     : "0" (0x80000001));
+    jit_cpu.lahf       = ecx.cpuid & 1;
+#endif
+}
+
+void
+_jit_init(jit_state_t *_jit)
+{
+#if __X32
+    jit_int32_t                regno;
+    static jit_bool_t  first = 1;
+#endif
+
+    _jitc->reglen = jit_size(_rvs) - 1;
+#if __X32
+    if (first) {
+       if (!jit_cpu.sse2) {
+           for (regno = _jitc->reglen; regno >= 0; regno--) {
+               if (_rvs[regno].spec & jit_class_xpr)
+                   _rvs[regno].spec = 0;
+           }
+       }
+       first = 0;
+    }
+#endif
+}
+
+void
+_jit_prolog(jit_state_t *_jit)
+{
+    jit_int32_t                offset;
+
+    if (_jitc->function)
+       jit_epilog();
+    assert(jit_regset_cmp_ui(&_jitc->regarg, 0) == 0);
+    jit_regset_set_ui(&_jitc->regsav, 0);
+    offset = _jitc->functions.offset;
+    if (offset >= _jitc->functions.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->functions.ptr,
+                   _jitc->functions.length * sizeof(jit_function_t),
+                   (_jitc->functions.length + 16) * sizeof(jit_function_t));
+       _jitc->functions.length += 16;
+    }
+    _jitc->function = _jitc->functions.ptr + _jitc->functions.offset++;
+    _jitc->function->self.size = stack_framesize;
+    _jitc->function->self.argi = _jitc->function->self.argf =
+       _jitc->function->self.aoff = _jitc->function->self.alen = 0;
+    /* sse/x87 conversion */
+    _jitc->function->self.aoff = CVT_OFFSET;
+    _jitc->function->self.call = jit_call_default;
+    jit_alloc((jit_pointer_t *)&_jitc->function->regoff,
+             _jitc->reglen * sizeof(jit_int32_t));
+
+    /* _no_link here does not mean the jit_link() call can be removed
+     * by rewriting as:
+     * _jitc->function->prolog = jit_new_node(jit_code_prolog);
+     */
+    _jitc->function->prolog = jit_new_node_no_link(jit_code_prolog);
+    jit_link(_jitc->function->prolog);
+    _jitc->function->prolog->w.w = offset;
+    _jitc->function->epilog = jit_new_node_no_link(jit_code_epilog);
+    /* u:      label value
+     * v:      offset in blocks vector
+     * w:      offset in functions vector
+     */
+    _jitc->function->epilog->w.w = offset;
+
+    jit_regset_new(&_jitc->function->regset);
+}
+
+jit_int32_t
+_jit_allocai(jit_state_t *_jit, jit_int32_t length)
+{
+    assert(_jitc->function);
+    switch (length) {
+       case 0: case 1:                                         break;
+       case 2:         _jitc->function->self.aoff &= -2;       break;
+       case 3: case 4: _jitc->function->self.aoff &= -4;       break;
+       default:        _jitc->function->self.aoff &= -8;       break;
+    }
+    _jitc->function->self.aoff -= length;
+
+    /* jit_allocai() may be called from jit_x86-cpu.c, and force a function
+     * generation restart on some conditions: div/rem and qmul/qdiv, due
+     * to registers constraints.
+     * The check is to prevent an assertion of a jit_xyz() being called
+     * during code generation, and attempting to add a node to the tail
+     * of the current IR generation. */
+    if (!_jitc->realize) {
+       jit_inc_synth_ww(allocai, _jitc->function->self.aoff, length);
+       jit_dec_synth();
+    }
+
+    return (_jitc->function->self.aoff);
+}
+
+void
+_jit_allocar(jit_state_t *_jit, jit_int32_t u, jit_int32_t v)
+{
+    jit_int32_t                 reg;
+    assert(_jitc->function);
+    jit_inc_synth_ww(allocar, u, v);
+    if (!_jitc->function->allocar) {
+       _jitc->function->aoffoff = jit_allocai(sizeof(jit_int32_t));
+       _jitc->function->allocar = 1;
+    }
+    reg = jit_get_reg(jit_class_gpr);
+    jit_negr(reg, v);
+    jit_andi(reg, reg, -16);
+    jit_ldxi_i(u, JIT_FP, _jitc->function->aoffoff);
+    jit_addr(u, u, reg);
+    jit_addr(JIT_SP, JIT_SP, reg);
+    jit_stxi_i(_jitc->function->aoffoff, JIT_FP, u);
+    jit_unget_reg(reg);
+    jit_dec_synth();
+}
+
+void
+_jit_ret(jit_state_t *_jit)
+{
+    jit_node_t         *instr;
+    assert(_jitc->function);
+    jit_inc_synth(ret);
+    /* jump to epilog */
+    instr = jit_jmpi();
+    jit_patch_at(instr, _jitc->function->epilog);
+    jit_dec_synth();
+}
+
+void
+_jit_retr(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr, u);
+    /* movr(%ret, %ret) would be optimized out */
+    if (JIT_RET != u)
+       jit_movr(JIT_RET, u);
+    /* explicitly tell it is live */
+    jit_live(JIT_RET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti(jit_state_t *_jit, jit_word_t u)
+{
+    jit_inc_synth_w(reti, u);
+    jit_movi(JIT_RET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_f, u);
+    if (JIT_FRET != u)
+       jit_movr_f(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_inc_synth_f(reti_f, u);
+    jit_movi_f(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_retr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(retr_d, u);
+    if (JIT_FRET != u)
+       jit_movr_d(JIT_FRET, u);
+    else
+       jit_live(JIT_FRET);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_reti_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_inc_synth_d(reti_d, u);
+    jit_movi_d(JIT_FRET, u);
+    jit_ret();
+    jit_dec_synth();
+}
+
+void
+_jit_epilog(jit_state_t *_jit)
+{
+    assert(_jitc->function);
+    assert(_jitc->function->epilog->next == NULL);
+    jit_link(_jitc->function->epilog);
+    _jitc->function = NULL;
+}
+
+jit_bool_t
+_jit_arg_register_p(jit_state_t *_jit, jit_node_t *u)
+{
+    if (u->code == jit_code_arg)
+       return (jit_arg_reg_p(u->u.w));
+    assert(u->code == jit_code_arg_f || u->code == jit_code_arg_d);
+    return (jit_arg_f_reg_p(u->u.w));
+}
+
+void
+_jit_ellipsis(jit_state_t *_jit)
+{
+    jit_inc_synth(ellipsis);
+    if (_jitc->prepare) {
+       jit_link_prepare();
+       /* Remember that a varargs function call is being constructed. */
+       assert(!(_jitc->function->call.call & jit_call_varargs));
+       _jitc->function->call.call |= jit_call_varargs;
+    }
+    else {
+       jit_link_prolog();
+       /* Remember the current function is varargs. */
+       assert(!(_jitc->function->self.call & jit_call_varargs));
+       _jitc->function->self.call |= jit_call_varargs;
+
+#if __X64 && !(__CYGWIN__ || _WIN32)
+       /* Allocate va_list like object in the stack.
+        * If applicable, with enough space to save all argument
+        * registers, and use fixed offsets for them. */
+       _jitc->function->vaoff = jit_allocai(sizeof(jit_va_list_t));
+
+       /* Initialize gp offset in save area. */
+       if (jit_arg_reg_p(_jitc->function->self.argi))
+           _jitc->function->vagp = _jitc->function->self.argi * 8;
+       else
+           _jitc->function->vagp = va_gp_max_offset;
+
+       /* Initialize fp offset in save area. */
+       if (jit_arg_f_reg_p(_jitc->function->self.argf))
+           _jitc->function->vafp = _jitc->function->self.argf * 16 +
+                                   va_gp_max_offset;
+       else
+           _jitc->function->vafp = va_fp_max_offset;
+#endif
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_va_push(jit_state_t *_jit, jit_int32_t u)
+{
+    jit_inc_synth_w(va_push, u);
+    jit_pushargr(u);
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_arg(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    assert(!(_jitc->function->self.call & jit_call_varargs));
+#if __X64
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi++;
+#  if __CYGWIN__ || _WIN32
+       _jitc->function->self.size += sizeof(jit_word_t);
+#  endif
+    }
+    else
+#endif
+    {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += REAL_WORDSIZE;
+    }
+    node = jit_new_node_ww(jit_code_arg, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_f(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    assert(!(_jitc->function->self.call & jit_call_varargs));
+#if __X64
+#  if __CYGWIN__ || _WIN32
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi++;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+#  else
+    if (jit_arg_f_reg_p(_jitc->function->self.argf))
+       offset = _jitc->function->self.argf++;
+#  endif
+    else
+#endif
+    {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += REAL_WORDSIZE;
+    }
+    node = jit_new_node_ww(jit_code_arg_f, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+jit_node_t *
+_jit_arg_d(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_int32_t                 offset;
+    assert(_jitc->function);
+    assert(!(_jitc->function->self.call & jit_call_varargs));
+#if __X64
+#  if __CYGWIN__ || _WIN32
+    if (jit_arg_reg_p(_jitc->function->self.argi)) {
+       offset = _jitc->function->self.argi++;
+       _jitc->function->self.size += sizeof(jit_word_t);
+    }
+#  else
+    if (jit_arg_f_reg_p(_jitc->function->self.argf))
+       offset = _jitc->function->self.argf++;
+#  endif
+    else
+#endif
+    {
+       offset = _jitc->function->self.size;
+       _jitc->function->self.size += sizeof(jit_float64_t);
+    }
+    node = jit_new_node_ww(jit_code_arg_d, offset,
+                          ++_jitc->function->self.argn);
+    jit_link_prolog();
+    return (node);
+}
+
+void
+_jit_getarg_c(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_c, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_c(u, JIT_RA0 - v->u.w);
+    else
+#endif
+       jit_ldxi_c(u, _RBP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_uc(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_uc, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_uc(u, JIT_RA0 - v->u.w);
+    else
+#endif
+       jit_ldxi_uc(u, _RBP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_s(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_s, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_s(u, JIT_RA0 - v->u.w);
+    else
+#endif
+       jit_ldxi_s(u, _RBP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_us(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_us, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_us(u, JIT_RA0 - v->u.w);
+    else
+#endif
+       jit_ldxi_us(u, _RBP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_i(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_i, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w)) {
+#  if __X64_32
+       jit_movr(u, JIT_RA0 - v->u.w);
+#  else
+       jit_extr_i(u, JIT_RA0 - v->u.w);
+#  endif
+     }
+    else
+#endif
+       jit_ldxi_i(u, _RBP, v->u.w);
+    jit_dec_synth();
+}
+
+#if __X64 && !__X64_32
+void
+_jit_getarg_ui(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_ui, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_extr_ui(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_ui(u, _RBP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_l(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(getarg_l, u, v);
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(u, JIT_RA0 - v->u.w);
+    else
+       jit_ldxi_l(u, _RBP, v->u.w);
+    jit_dec_synth();
+}
+#endif
+
+void
+_jit_putargr(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargr, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr(JIT_RA0 - v->u.w, u);
+    else
+#endif
+       jit_stxi(v->u.w, _RBP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi(jit_state_t *_jit, jit_word_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg);
+    jit_inc_synth_wp(putargi, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi(JIT_RA0 - v->u.w, u);
+    else
+#endif
+    {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(v->u.w, _RBP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(getarg_f, u, v);
+#if __X64
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_f(u, _XMM0 - v->u.w);
+    else
+#endif
+       jit_ldxi_f(u, _RBP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_f(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_wp(putargr_f, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_f(_XMM0 - v->u.w, u);
+    else
+#endif
+       jit_stxi_f(v->u.w, _RBP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_f(jit_state_t *_jit, jit_float32_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_f);
+    jit_inc_synth_fp(putargi_f, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi_f(_XMM0 - v->u.w, u);
+    else
+#endif
+    {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(v->u.w, _RBP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_getarg_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(getarg_d, u, v);
+#if __X64
+    if (jit_arg_f_reg_p(v->u.w))
+       jit_movr_d(u, _XMM0 - v->u.w);
+    else
+#endif
+       jit_ldxi_d(u, _RBP, v->u.w);
+    jit_dec_synth();
+}
+
+void
+_jit_putargr_d(jit_state_t *_jit, jit_int32_t u, jit_node_t *v)
+{
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_wp(putargr_d, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_movr_d(_XMM0 - v->u.w, u);
+    else
+#endif
+       jit_stxi_d(v->u.w, _RBP, u);
+    jit_dec_synth();
+}
+
+void
+_jit_putargi_d(jit_state_t *_jit, jit_float64_t u, jit_node_t *v)
+{
+    jit_int32_t                regno;
+    assert(v->code == jit_code_arg_d);
+    jit_inc_synth_dp(putargi_d, u, v);
+#if __X64
+    if (jit_arg_reg_p(v->u.w))
+       jit_movi_d(_XMM0 - v->u.w, u);
+    else
+#endif
+    {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(v->u.w, _RBP, regno);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr, u);
+    jit_link_prepare();
+#if __X64
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr(JIT_RA0 - _jitc->function->call.argi, u);
+       ++_jitc->function->call.argi;
+#  if __CYGWIN__ || _WIN32
+       if (_jitc->function->call.call & jit_call_varargs)
+           jit_stxi(_jitc->function->call.size, _RSP, u);
+       _jitc->function->call.size += sizeof(jit_word_t);
+#  endif
+    }
+    else
+#endif
+    {
+       jit_stxi(_jitc->function->call.size, _RSP, u);
+       _jitc->function->call.size += REAL_WORDSIZE;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi(jit_state_t *_jit, jit_word_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargi, u);
+    jit_link_prepare();
+#if __X64
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi(JIT_RA0 - _jitc->function->call.argi, u);
+#  if __CYGWIN__ || _WIN32
+       if (_jitc->function->call.call & jit_call_varargs)
+           jit_stxi(_jitc->function->call.size, _RSP,
+                    JIT_RA0 - _jitc->function->call.argi);
+       _jitc->function->call.size += sizeof(jit_word_t);
+#  endif
+       ++_jitc->function->call.argi;
+    }
+    else
+#endif
+    {
+       regno = jit_get_reg(jit_class_gpr);
+       jit_movi(regno, u);
+       jit_stxi(_jitc->function->call.size, _RSP, regno);
+       _jitc->function->call.size += REAL_WORDSIZE;
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_f(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_f, u);
+    jit_link_prepare();
+#if __X64
+#  if __CYGWIN__ || _WIN32
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr_f(_XMM0 - _jitc->function->call.argi, u);
+       if (_jitc->function->call.call & jit_call_varargs) {
+           jit_stxi_f(_jitc->function->call.size, _RSP,
+                      _XMM0 - _jitc->function->call.argi);
+           jit_ldxi_i(JIT_RA0 - _jitc->function->call.argi, _RSP,
+                      _jitc->function->call.size);
+       }
+       ++_jitc->function->call.argi;
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+#  else
+    if (jit_arg_f_reg_p(_jitc->function->self.argf)) {
+       jit_movr_f(_XMM0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+#  endif
+    else
+#endif
+    {
+       jit_stxi_f(_jitc->function->call.size, _RSP, u);
+       _jitc->function->call.size += REAL_WORDSIZE;
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_f(jit_state_t *_jit, jit_float32_t u)
+{
+    jit_int32_t                regno;
+    assert(_jitc->function);
+    jit_inc_synth_f(pushargi_f, u);
+    jit_link_prepare();
+#if __X64
+#  if __CYGWIN__ || _WIN32
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi_f(_XMM0 - _jitc->function->call.argi, u);
+       if (_jitc->function->call.call & jit_call_varargs) {
+           jit_stxi_f(_jitc->function->call.size, _RSP,
+                      _XMM0 - _jitc->function->call.argi);
+           jit_ldxi_i(JIT_RA0 - _jitc->function->call.argi, _RSP,
+                      _jitc->function->call.size);
+       }
+       ++_jitc->function->call.argi;
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+#  else
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movi_f(_XMM0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+#  endif
+    else
+#endif
+    {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_f(regno, u);
+       jit_stxi_f(_jitc->function->call.size, _RSP, regno);
+       _jitc->function->call.size += REAL_WORDSIZE;
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargr_d(jit_state_t *_jit, jit_int32_t u)
+{
+    assert(_jitc->function);
+    jit_inc_synth_w(pushargr_d, u);
+    jit_link_prepare();
+#if __X64
+#  if __CYGWIN__ || _WIN32
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movr_d(_XMM0 - _jitc->function->call.argi, u);
+       if (_jitc->function->call.call & jit_call_varargs) {
+           jit_stxi_d(_jitc->function->call.size, _RSP,
+                      _XMM0 - _jitc->function->call.argi);
+           jit_ldxi_l(JIT_RA0 - _jitc->function->call.argi, _RSP,
+                      _jitc->function->call.size);
+       }
+       ++_jitc->function->call.argi;
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+#  else
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movr_d(_XMM0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+#  endif
+    else
+#endif
+    {
+       jit_stxi_d(_jitc->function->call.size, _RSP, u);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+    }
+    jit_dec_synth();
+}
+
+void
+_jit_pushargi_d(jit_state_t *_jit, jit_float64_t u)
+{
+    jit_int32_t                 regno;
+    assert(_jitc->function);
+    jit_inc_synth_d(pushargi_d, u);
+    jit_link_prepare();
+#if __X64
+#  if __CYGWIN__ || _WIN32
+    if (jit_arg_reg_p(_jitc->function->call.argi)) {
+       jit_movi_d(_XMM0 - _jitc->function->call.argi, u);
+       if (_jitc->function->call.call & jit_call_varargs) {
+           jit_stxi_d(_jitc->function->call.size, _RSP,
+                      _XMM0 - _jitc->function->call.argi);
+           jit_ldxi_l(JIT_RA0 - _jitc->function->call.argi, _RSP,
+                      _jitc->function->call.size);
+       }
+       ++_jitc->function->call.argi;
+       _jitc->function->call.size += sizeof(jit_word_t);
+    }
+#  else
+    if (jit_arg_f_reg_p(_jitc->function->call.argf)) {
+       jit_movi_d(_XMM0 - _jitc->function->call.argf, u);
+       ++_jitc->function->call.argf;
+    }
+#  endif
+    else
+#endif
+    {
+       regno = jit_get_reg(jit_class_fpr);
+       jit_movi_d(regno, u);
+       jit_stxi_d(_jitc->function->call.size, _RSP, regno);
+       _jitc->function->call.size += sizeof(jit_float64_t);
+       jit_unget_reg(regno);
+    }
+    jit_dec_synth();
+}
+
+jit_bool_t
+_jit_regarg_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+#if __X64
+    jit_int32_t                spec;
+
+    spec = jit_class(_rvs[regno].spec);
+    if (spec & jit_class_arg) {
+       if (spec & jit_class_gpr) {
+           regno = JIT_RA0 - regno;
+           if (regno >= 0 && regno < node->v.w)
+               return (1);
+       }
+       else if (spec & jit_class_fpr) {
+           regno = _XMM0 - regno;
+           if (regno >= 0 && regno < node->w.w)
+               return (1);
+       }
+    }
+#endif
+    return (0);
+}
+
+void
+_jit_finishr(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_int32_t                 reg;
+    jit_node_t         *call;
+    assert(_jitc->function);
+    reg = r0;
+    jit_inc_synth_w(finishr, r0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+#if __X64
+#  if !(__CYGWIN__ || _WIN32)
+    if (_jitc->function->call.call & jit_call_varargs) {
+       if (jit_regno(reg) == _RAX) {
+           reg = jit_get_reg(jit_class_gpr);
+           jit_movr(reg, _RAX);
+       }
+       if (_jitc->function->call.argf)
+           jit_movi(_RAX, _jitc->function->call.argf);
+       else
+           jit_movi(_RAX, 0);
+       if (reg != r0)
+           jit_unget_reg(reg);
+    }
+#  endif
+#endif
+    call = jit_callr(reg);
+    call->v.w = _jitc->function->call.argi;
+    call->w.w = _jitc->function->call.argf;
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+}
+
+jit_node_t *
+_jit_finishi(jit_state_t *_jit, jit_pointer_t i0)
+{
+#if __X64
+    jit_int32_t                reg;
+#endif
+    jit_node_t         *node;
+    assert(_jitc->function);
+    jit_inc_synth_w(finishi, (jit_word_t)i0);
+    if (_jitc->function->self.alen < _jitc->function->call.size)
+       _jitc->function->self.alen = _jitc->function->call.size;
+#if __X64
+    /* FIXME preventing %rax allocation is good enough, but for consistency
+     * it should automatically detect %rax is dead, in case it has run out
+     * registers, and not save/restore it, what would be wrong if using the
+     * the return value, otherwise, just a needless noop */
+    /* >> prevent %rax from being allocated as the function pointer */
+    jit_regset_setbit(&_jitc->regarg, _RAX);
+    reg = jit_get_reg(jit_class_gpr);
+    node = jit_movi(reg, (jit_word_t)i0);
+    jit_finishr(reg);
+    jit_unget_reg(reg);
+    /* << prevent %rax from being allocated as the function pointer */
+    jit_regset_clrbit(&_jitc->regarg, _RAX);
+#else
+    node = jit_calli(i0);
+    node->v.w = _jitc->function->call.argi;
+    node->w.w = _jitc->function->call.argf;
+#endif
+    _jitc->function->call.argi = _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = 0;
+    jit_dec_synth();
+    return (node);
+}
+
+void
+_jit_retval_c(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_c, r0);
+    jit_extr_c(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_uc(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_uc, r0);
+    jit_extr_uc(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_s(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_s, r0);
+    jit_extr_s(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_us(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_us, r0);
+    jit_extr_us(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_i(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_i, r0);
+#if __X32 || __X64_32
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+#else
+    jit_extr_i(r0, JIT_RET);
+#endif
+    jit_dec_synth();
+}
+
+#if __X64 && !__X64_32
+void
+_jit_retval_ui(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_ui, r0);
+    jit_extr_ui(r0, JIT_RET);
+    jit_dec_synth();
+}
+
+void
+_jit_retval_l(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_l, r0);
+    if (r0 != JIT_RET)
+       jit_movr(r0, JIT_RET);
+    jit_dec_synth();
+}
+#endif
+
+void
+_jit_retval_f(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_f, r0);
+#if __X64
+    if (r0 != JIT_FRET)
+       jit_movr_f(r0, JIT_FRET);
+#endif
+    jit_dec_synth();
+}
+
+void
+_jit_retval_d(jit_state_t *_jit, jit_int32_t r0)
+{
+    jit_inc_synth_w(retval_d, r0);
+#if __X64
+    if (r0 != JIT_FRET)
+       jit_movr_d(r0, JIT_FRET);
+#endif
+    jit_dec_synth();
+}
+
+jit_pointer_t
+_emit_code(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *temp;
+    jit_word_t          word;
+    jit_int32_t                 value;
+    jit_int32_t                 offset;
+    struct {
+       jit_node_t      *node;
+       jit_word_t       word;
+#if DEVEL_DISASSEMBLER
+       jit_word_t       prevw;
+#endif
+       jit_int32_t      patch_offset;
+    } undo;
+#if DEVEL_DISASSEMBLER
+    jit_word_t          prevw;
+#endif
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+
+    undo.word = 0;
+    undo.node = NULL;
+    undo.patch_offset = 0;
+#define case_rr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w), rn(node->v.w));            \
+               break
+#define case_rw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), node->v.w);                \
+               break
+#define case_rf(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               if (jit_x87_reg_p(node->v.w))                           \
+                   x87_##name##r##type(rn(node->u.w), rn(node->v.w));  \
+               else                                                    \
+                   sse_##name##r##type(rn(node->u.w), rn(node->v.w));  \
+               break
+#define case_fr(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               if (jit_x87_reg_p(node->u.w))                           \
+                   x87_##name##r##type(rn(node->u.w), rn(node->v.w));  \
+               else                                                    \
+                   sse_##name##r##type(rn(node->u.w), rn(node->v.w));  \
+               break
+#define case_fw(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               if (jit_x87_reg_p(node->u.w))                           \
+                   x87_##name##i##type(rn(node->u.w), node->v.w);      \
+               else                                                    \
+                   sse_##name##i##type(rn(node->u.w), node->v.w);      \
+               break
+#define case_wr(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w));                \
+               break
+#define case_wf(name, type)                                            \
+           case jit_code_##name##i##type:                              \
+               if (jit_x87_reg_p(node->v.w))                           \
+                   x87_##name##i##type(node->u.w, rn(node->v.w));      \
+               else                                                    \
+                   sse_##name##i##type(node->u.w, rn(node->v.w));      \
+               break
+#define case_ff(name, type)                                            \
+           case jit_code_##name##r##type:                              \
+               if (jit_x87_reg_p(node->u.w) &&                         \
+                   jit_x87_reg_p(node->v.w))                           \
+                   x87_##name##r##type(rn(node->u.w), rn(node->v.w));  \
+               else                                                    \
+                   sse_##name##r##type(rn(node->u.w), rn(node->v.w));  \
+               break;
+#define case_rrr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.w),                            \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_rrrr(name, type)                                          \
+           case jit_code_##name##r##type:                              \
+               name##r##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), rn(node->w.w));            \
+               break
+#define case_frr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               if (jit_x87_reg_p(node->u.w))                           \
+                   x87_##name##r##type(rn(node->u.w),                  \
+                                       rn(node->v.w), rn(node->w.w));  \
+               else                                                    \
+                   sse_##name##r##type(rn(node->u.w),                  \
+                                       rn(node->v.w), rn(node->w.w));  \
+               break
+#define case_rrf(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               if (jit_x87_reg_p(node->w.w))                           \
+                   x87_##name##r##type(rn(node->u.w),                  \
+                                       rn(node->v.w), rn(node->w.w));  \
+               else                                                    \
+                   sse_##name##r##type(rn(node->u.w),                  \
+                                       rn(node->v.w), rn(node->w.w));  \
+               break
+#define case_rrw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.w), rn(node->v.w), node->w.w); \
+               break
+#define case_rrrw(name, type)                                          \
+           case jit_code_##name##i##type:                              \
+               name##i##type(rn(node->u.q.l), rn(node->u.q.h),         \
+                             rn(node->v.w), node->w.w);                \
+               break
+#define case_frw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               if (jit_x87_reg_p(node->u.w))                           \
+                   x87_##name##i##type(rn(node->u.w),                  \
+                                       rn(node->v.w), node->w.w);      \
+               else                                                    \
+                   sse_##name##i##type(rn(node->u.w),                  \
+                                       rn(node->v.w), node->w.w);      \
+               break
+#define case_wrr(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               name##i##type(node->u.w, rn(node->v.w), rn(node->w.w)); \
+               break
+#define case_wrf(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               if (jit_x87_reg_p(node->w.w))                           \
+                   x87_##name##i##type(node->u.w,                      \
+                                       rn(node->v.w), rn(node->w.w));  \
+               else                                                    \
+                   sse_##name##i##type(node->u.w,                      \
+                                       rn(node->v.w), rn(node->w.w));  \
+               break
+#define case_brr(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##r##type(temp->u.w, rn(node->v.w),             \
+                                 rn(node->w.w));                       \
+               else {                                                  \
+                   word = name##r##type(_jit->pc.w,                    \
+                                        rn(node->v.w), rn(node->w.w)); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_brw(name, type)                                           \
+           case jit_code_##name##i##type:                              \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch)                        \
+                   name##i##type(temp->u.w,                            \
+                                 rn(node->v.w), node->w.w);            \
+               else {                                                  \
+                   word = name##i##type(_jit->pc.w,                    \
+                                        rn(node->v.w), node->w.w);     \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_rff(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               if (jit_x87_reg_p(node->v.w) &&                         \
+                   jit_x87_reg_p(node->w.w))                           \
+                   x87_##name##r##type(rn(node->u.w), rn(node->v.w),   \
+                                       rn(node->w.w));                 \
+               else                                                    \
+                   sse_##name##r##type(rn(node->u.w), rn(node->v.w),   \
+                                       rn(node->w.w));                 \
+               break;
+#define case_rfw(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               assert(node->flag & jit_flag_data);                     \
+               if (jit_x87_reg_p(node->v.w))                           \
+                   x87_##name##i##type(rn(node->u.w), rn(node->v.w),   \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               else                                                    \
+                   sse_##name##i##type(rn(node->u.w), rn(node->v.w),   \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               break
+#define case_fff(name, type)                                           \
+           case jit_code_##name##r##type:                              \
+               if (jit_x87_reg_p(node->u.w) &&                         \
+                   jit_x87_reg_p(node->v.w) &&                         \
+                   jit_x87_reg_p(node->w.w))                           \
+                   x87_##name##r##type(rn(node->u.w),                  \
+                                       rn(node->v.w), rn(node->w.w));  \
+               else                                                    \
+                   sse_##name##r##type(rn(node->u.w),                  \
+                                       rn(node->v.w), rn(node->w.w));  \
+               break
+#define case_ffw(name, type, size)                                     \
+           case jit_code_##name##i##type:                              \
+               assert(node->flag & jit_flag_data);                     \
+               if (jit_x87_reg_p(node->u.w) &&                         \
+                   jit_x87_reg_p(node->v.w))                           \
+                   x87_##name##i##type(rn(node->u.w), rn(node->v.w),   \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               else                                                    \
+                   sse_##name##i##type(rn(node->u.w), rn(node->v.w),   \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               break
+#define case_bff(name, type)                                           \
+           case jit_code_b##name##r##type:                             \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch) {                      \
+                   if (jit_x87_reg_p(node->v.w) &&                     \
+                       jit_x87_reg_p(node->w.w))                       \
+                       x87_b##name##r##type(temp->u.w,                 \
+                               rn(node->v.w), rn(node->w.w));          \
+                   else                                                \
+                       sse_b##name##r##type(temp->u.w,                 \
+                               rn(node->v.w), rn(node->w.w));          \
+               }                                                       \
+               else {                                                  \
+                   if (jit_x87_reg_p(node->v.w) &&                     \
+                       jit_x87_reg_p(node->w.w))                       \
+                       word = x87_b##name##r##type(_jit->pc.w,         \
+                               rn(node->v.w), rn(node->w.w));          \
+                   else                                                \
+                       word = sse_b##name##r##type(_jit->pc.w,         \
+                               rn(node->v.w), rn(node->w.w));          \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#define case_bfw(name, type, size)                                     \
+           case jit_code_b##name##i##type:                             \
+               temp = node->u.n;                                       \
+               assert(temp->code == jit_code_label ||                  \
+                      temp->code == jit_code_epilog);                  \
+               if (temp->flag & jit_flag_patch) {                      \
+                   if (jit_x87_reg_p(node->v.w))                       \
+                       x87_b##name##i##type(temp->u.w,                 \
+                               rn(node->v.w),                          \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+                   else                                                \
+                       sse_b##name##i##type(temp->u.w,                 \
+                               rn(node->v.w),                          \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+               }                                                       \
+               else {                                                  \
+                   if (jit_x87_reg_p(node->v.w))                       \
+                       word = x87_b##name##i##type(_jit->pc.w,         \
+                               rn(node->v.w),                          \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+                   else                                                \
+                       word = sse_b##name##i##type(_jit->pc.w,         \
+                               rn(node->v.w),                          \
+                               (jit_float##size##_t *)node->w.n->u.w); \
+                   patch(word, node);                                  \
+               }                                                       \
+               break
+#if DEVEL_DISASSEMBLER
+    prevw = _jit->pc.w;
+#endif
+    for (node = _jitc->head; node; node = node->next) {
+       if (_jit->pc.uc >= _jitc->code.end)
+           return (NULL);
+
+#if DEVEL_DISASSEMBLER
+       node->offset = (jit_uword_t)_jit->pc.w - (jit_uword_t)prevw;
+       prevw = _jit->pc.w;
+#endif
+       value = jit_classify(node->code);
+       jit_regarg_set(node, value);
+       switch (node->code) {
+           case jit_code_align:
+               assert(!(node->u.w & (node->u.w - 1)) &&
+                      node->u.w <= sizeof(jit_word_t));
+               if ((word = _jit->pc.w & (node->u.w - 1)))
+                   nop(node->u.w - word);
+               break;
+           case jit_code_note:         case jit_code_name:
+               node->u.w = _jit->pc.w;
+               break;
+           case jit_code_label:
+               if ((node->link || (node->flag & jit_flag_use)) &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               break;
+               case_rrr(add,);
+               case_rrw(add,);
+               case_rrr(addx,);
+               case_rrw(addx,);
+               case_rrr(addc,);
+               case_rrw(addc,);
+               case_rrr(sub,);
+               case_rrw(sub,);
+               case_rrr(subx,);
+               case_rrw(subx,);
+               case_rrr(subc,);
+               case_rrw(subc,);
+               case_rrw(rsb,);
+               case_rrr(mul,);
+               case_rrw(mul,);
+               case_rrrr(qmul,);
+               case_rrrw(qmul,);
+               case_rrrr(qmul, _u);
+               case_rrrw(qmul, _u);
+               case_rrr(div,);
+               case_rrw(div,);
+               case_rrr(div, _u);
+               case_rrw(div, _u);
+               case_rrrr(qdiv,);
+               case_rrrw(qdiv,);
+               case_rrrr(qdiv, _u);
+               case_rrrw(qdiv, _u);
+               case_rrr(rem,);
+               case_rrw(rem,);
+               case_rrr(rem, _u);
+               case_rrw(rem, _u);
+               case_rrr(and,);
+               case_rrw(and,);
+               case_rrr(or,);
+               case_rrw(or,);
+               case_rrr(xor,);
+               case_rrw(xor,);
+               case_rrr(lsh,);
+               case_rrw(lsh,);
+               case_rrr(rsh,);
+               case_rrw(rsh,);
+               case_rrr(rsh, _u);
+               case_rrw(rsh, _u);
+               case_rr(neg,);
+               case_rr(com,);
+               case_rrr(lt,);
+               case_rrw(lt,);
+               case_rrr(lt, _u);
+               case_rrw(lt, _u);
+               case_rrr(le,);
+               case_rrw(le,);
+               case_rrr(le, _u);
+               case_rrw(le, _u);
+               case_rrr(eq,);
+               case_rrw(eq,);
+               case_rrr(ge,);
+               case_rrw(ge,);
+               case_rrr(ge, _u);
+               case_rrw(ge, _u);
+               case_rrr(gt,);
+               case_rrw(gt,);
+               case_rrr(gt, _u);
+               case_rrw(gt, _u);
+               case_rrr(ne,);
+               case_rrw(ne,);
+               case_rr(mov,);
+           case jit_code_movi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->v.n;
+                   if (temp->code == jit_code_data ||
+                       (temp->code == jit_code_label &&
+                        (temp->flag & jit_flag_patch)))
+                       movi(rn(node->u.w), temp->u.w);
+                   else {
+                       assert(temp->code == jit_code_label ||
+                              temp->code == jit_code_epilog);
+                       word = movi_p(rn(node->u.w), node->v.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   movi(rn(node->u.w), node->v.w);
+               break;
+               case_rr(hton, _us);
+               case_rr(hton, _ui);
+#if __X64 && !__X64_32
+               case_rr(hton, _ul);
+#endif
+               case_rr(ext, _c);
+               case_rr(ext, _uc);
+               case_rr(ext, _s);
+               case_rr(ext, _us);
+#if __X64 && !__X64_32
+               case_rr(ext, _i);
+               case_rr(ext, _ui);
+#endif
+               case_rf(trunc, _f_i);
+               case_rf(trunc, _d_i);
+#if __X64
+               case_rf(trunc, _f_l);
+               case_rf(trunc, _d_l);
+#endif
+               case_rr(ld, _c);
+               case_rw(ld, _c);
+               case_rr(ld, _uc);
+               case_rw(ld, _uc);
+               case_rr(ld, _s);
+               case_rw(ld, _s);
+               case_rr(ld, _us);
+               case_rw(ld, _us);
+               case_rr(ld, _i);
+               case_rw(ld, _i);
+#if __X64 && !__X64_32
+               case_rr(ld, _ui);
+               case_rw(ld, _ui);
+               case_rr(ld, _l);
+               case_rw(ld, _l);
+#endif
+               case_rrr(ldx, _c);
+               case_rrw(ldx, _c);
+               case_rrr(ldx, _uc);
+               case_rrw(ldx, _uc);
+               case_rrr(ldx, _s);
+               case_rrw(ldx, _s);
+               case_rrr(ldx, _us);
+               case_rrw(ldx, _us);
+               case_rrr(ldx, _i);
+               case_rrw(ldx, _i);
+#if __X64 && !__X64_32
+               case_rrr(ldx, _ui);
+               case_rrw(ldx, _ui);
+               case_rrr(ldx, _l);
+               case_rrw(ldx, _l);
+#endif
+               case_rr(st, _c);
+               case_wr(st, _c);
+               case_rr(st, _s);
+               case_wr(st, _s);
+               case_rr(st, _i);
+               case_wr(st, _i);
+#if __X64 && !__X64_32
+               case_rr(st, _l);
+               case_wr(st, _l);
+#endif
+               case_rrr(stx, _c);
+               case_wrr(stx, _c);
+               case_rrr(stx, _s);
+               case_wrr(stx, _s);
+               case_rrr(stx, _i);
+               case_wrr(stx, _i);
+#if __X64 && !__X64_32
+               case_rrr(stx, _l);
+               case_wrr(stx, _l);
+#endif
+               case_brr(blt,);
+               case_brw(blt,);
+               case_brr(blt, _u);
+               case_brw(blt, _u);
+               case_brr(ble,);
+               case_brw(ble,);
+               case_brr(ble, _u);
+               case_brw(ble, _u);
+               case_brr(beq,);
+               case_brw(beq,);
+               case_brr(bge,);
+               case_brw(bge,);
+               case_brr(bge, _u);
+               case_brw(bge, _u);
+               case_brr(bgt,);
+               case_brw(bgt,);
+               case_brr(bgt, _u);
+               case_brw(bgt, _u);
+               case_brr(bne,);
+               case_brw(bne,);
+               case_brr(bms,);
+               case_brw(bms,);
+               case_brr(bmc,);
+               case_brw(bmc,);
+               case_brr(boadd,);
+               case_brw(boadd,);
+               case_brr(boadd, _u);
+               case_brw(boadd, _u);
+               case_brr(bxadd,);
+               case_brw(bxadd,);
+               case_brr(bxadd, _u);
+               case_brw(bxadd, _u);
+               case_brr(bosub,);
+               case_brw(bosub,);
+               case_brr(bosub, _u);
+               case_brw(bosub, _u);
+               case_brr(bxsub,);
+               case_brw(bxsub,);
+               case_brr(bxsub, _u);
+               case_brw(bxsub, _u);
+               case_fff(add, _f);
+               case_ffw(add, _f, 32);
+               case_fff(sub, _f);
+               case_ffw(sub, _f, 32);
+               case_ffw(rsb, _f, 32);
+               case_fff(mul, _f);
+               case_ffw(mul, _f, 32);
+               case_fff(div, _f);
+               case_ffw(div, _f, 32);
+               case_ff(abs, _f);
+               case_ff(neg, _f);
+               case_ff(sqrt, _f);
+               case_fr(ext, _f);
+               case_fr(ext, _d_f);
+               case_rff(lt, _f);
+               case_rfw(lt, _f, 32);
+               case_rff(le, _f);
+               case_rfw(le, _f, 32);
+               case_rff(eq, _f);
+               case_rfw(eq, _f, 32);
+               case_rff(ge, _f);
+               case_rfw(ge, _f, 32);
+               case_rff(gt, _f);
+               case_rfw(gt, _f, 32);
+               case_rff(ne, _f);
+               case_rfw(ne, _f, 32);
+               case_rff(unlt, _f);
+               case_rfw(unlt, _f, 32);
+               case_rff(unle, _f);
+               case_rfw(unle, _f, 32);
+               case_rff(uneq, _f);
+               case_rfw(uneq, _f, 32);
+               case_rff(unge, _f);
+               case_rfw(unge, _f, 32);
+               case_rff(ungt, _f);
+               case_rfw(ungt, _f, 32);
+               case_rff(ltgt, _f);
+               case_rfw(ltgt, _f, 32);
+               case_rff(ord, _f);
+               case_rfw(ord, _f, 32);
+               case_rff(unord, _f);
+               case_rfw(unord, _f, 32);
+           case jit_code_movr_f:
+               if (jit_x87_reg_p(node->u.w)) {
+                   if (jit_x87_reg_p(node->v.w))
+                       x87_movr_f(rn(node->u.w), rn(node->v.w));
+                   else
+                       x87_from_sse_f(rn(node->u.w), rn(node->v.w));
+               }
+               else {
+                   if (jit_sse_reg_p(node->v.w))
+                       sse_movr_f(rn(node->u.w), rn(node->v.w));
+                   else
+                       sse_from_x87_f(rn(node->u.w), rn(node->v.w));
+               }
+               break;
+           case jit_code_movi_f:
+               assert(node->flag & jit_flag_data);
+               if (jit_x87_reg_p(node->u.w))
+                   x87_movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               else
+                   sse_movi_f(rn(node->u.w), (jit_float32_t *)node->v.n->u.w);
+               break;
+               case_fr(ld, _f);
+               case_fw(ld, _f);
+               case_frr(ldx, _f);
+               case_frw(ldx, _f);
+               case_rf(st, _f);
+               case_wf(st, _f);
+               case_rrf(stx, _f);
+               case_wrf(stx, _f);
+               case_bff(lt, _f);
+               case_bfw(lt, _f, 32);
+               case_bff(le, _f);
+               case_bfw(le, _f, 32);
+               case_bff(eq, _f);
+               case_bfw(eq, _f, 32);
+               case_bff(ge, _f);
+               case_bfw(ge, _f, 32);
+               case_bff(gt, _f);
+               case_bfw(gt, _f, 32);
+               case_bff(ne, _f);
+               case_bfw(ne, _f, 32);
+               case_bff(unlt, _f);
+               case_bfw(unlt, _f, 32);
+               case_bff(unle, _f);
+               case_bfw(unle, _f, 32);
+               case_bff(uneq, _f);
+               case_bfw(uneq, _f, 32);
+               case_bff(unge, _f);
+               case_bfw(unge, _f, 32);
+               case_bff(ungt, _f);
+               case_bfw(ungt, _f, 32);
+               case_bff(ltgt, _f);
+               case_bfw(ltgt, _f, 32);
+               case_bff(ord, _f);
+               case_bfw(ord, _f, 32);
+               case_bff(unord, _f);
+               case_bfw(unord, _f, 32);
+               case_fff(add, _d);
+               case_ffw(add, _d, 64);
+               case_fff(sub, _d);
+               case_ffw(sub, _d, 64);
+               case_ffw(rsb, _d, 64);
+               case_fff(mul, _d);
+               case_ffw(mul, _d, 64);
+               case_fff(div, _d);
+               case_ffw(div, _d, 64);
+               case_ff(abs, _d);
+               case_ff(neg, _d);
+               case_ff(sqrt, _d);
+               case_fr(ext, _d);
+               case_fr(ext, _f_d);
+               case_rff(lt, _d);
+               case_rfw(lt, _d, 64);
+               case_rff(le, _d);
+               case_rfw(le, _d, 64);
+               case_rff(eq, _d);
+               case_rfw(eq, _d, 64);
+               case_rff(ge, _d);
+               case_rfw(ge, _d, 64);
+               case_rff(gt, _d);
+               case_rfw(gt, _d, 64);
+               case_rff(ne, _d);
+               case_rfw(ne, _d, 64);
+               case_rff(unlt, _d);
+               case_rfw(unlt, _d, 64);
+               case_rff(unle, _d);
+               case_rfw(unle, _d, 64);
+               case_rff(uneq, _d);
+               case_rfw(uneq, _d, 64);
+               case_rff(unge, _d);
+               case_rfw(unge, _d, 64);
+               case_rff(ungt, _d);
+               case_rfw(ungt, _d, 64);
+               case_rff(ltgt, _d);
+               case_rfw(ltgt, _d, 64);
+               case_rff(ord, _d);
+               case_rfw(ord, _d, 64);
+               case_rff(unord, _d);
+               case_rfw(unord, _d, 64);
+           case jit_code_movr_d:
+               if (jit_x87_reg_p(node->u.w)) {
+                   if (jit_x87_reg_p(node->v.w))
+                       x87_movr_d(rn(node->u.w), rn(node->v.w));
+                   else
+                       x87_from_sse_d(rn(node->u.w), rn(node->v.w));
+               }
+               else {
+                   if (jit_sse_reg_p(node->v.w))
+                       sse_movr_d(rn(node->u.w), rn(node->v.w));
+                   else
+                       sse_from_x87_d(rn(node->u.w), rn(node->v.w));
+               }
+               break;
+           case jit_code_movi_d:
+               assert(node->flag & jit_flag_data);
+               if (jit_x87_reg_p(node->u.w))
+                   x87_movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               else
+                   sse_movi_d(rn(node->u.w), (jit_float64_t *)node->v.n->u.w);
+               break;
+               case_fr(ld, _d);
+               case_fw(ld, _d);
+               case_frr(ldx, _d);
+               case_frw(ldx, _d);
+               case_rf(st, _d);
+               case_wf(st, _d);
+               case_rrf(stx, _d);
+               case_wrf(stx, _d);
+               case_bff(lt, _d);
+               case_bfw(lt, _d, 64);
+               case_bff(le, _d);
+               case_bfw(le, _d, 64);
+               case_bff(eq, _d);
+               case_bfw(eq, _d, 64);
+               case_bff(ge, _d);
+               case_bfw(ge, _d, 64);
+               case_bff(gt, _d);
+               case_bfw(gt, _d, 64);
+               case_bff(ne, _d);
+               case_bfw(ne, _d, 64);
+               case_bff(unlt, _d);
+               case_bfw(unlt, _d, 64);
+               case_bff(unle, _d);
+               case_bfw(unle, _d, 64);
+               case_bff(uneq, _d);
+               case_bfw(uneq, _d, 64);
+               case_bff(unge, _d);
+               case_bfw(unge, _d, 64);
+               case_bff(ungt, _d);
+               case_bfw(ungt, _d, 64);
+               case_bff(ltgt, _d);
+               case_bfw(ltgt, _d, 64);
+               case_bff(ord, _d);
+               case_bfw(ord, _d, 64);
+               case_bff(unord, _d);
+               case_bfw(unord, _d, 64);
+           case jit_code_jmpr:
+               jmpr(rn(node->u.w));
+               break;
+           case jit_code_jmpi:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   if (temp->flag & jit_flag_patch)
+                       jmpi(temp->u.w);
+                   else {
+                       word = jmpi(_jit->pc.w);
+                       patch(word, node);
+                   }
+               }
+               else
+                   jmpi(node->u.w);
+               break;
+           case jit_code_callr:
+               callr(rn(node->u.w));
+               break;
+           case jit_code_calli:
+               if (node->flag & jit_flag_node) {
+                   temp = node->u.n;
+                   assert(temp->code == jit_code_label ||
+                          temp->code == jit_code_epilog);
+                   word = calli(temp->u.w);
+                   if (!(temp->flag & jit_flag_patch))
+                       patch(word, node);
+               }
+               else
+                   calli(node->u.w);
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               undo.node = node;
+               undo.word = _jit->pc.w;
+#if DEVEL_DISASSEMBLER
+               undo.prevw = prevw;
+#endif
+               undo.patch_offset = _jitc->patches.offset;
+           restart_function:
+               _jitc->again = 0;
+               prolog(node);
+               break;
+           case jit_code_epilog:
+               assert(_jitc->function == _jitc->functions.ptr + node->w.w);
+               if (_jitc->again) {
+                   for (temp = undo.node->next;
+                        temp != node; temp = temp->next) {
+                       if (temp->code == jit_code_label ||
+                           temp->code == jit_code_epilog)
+                           temp->flag &= ~jit_flag_patch;
+                   }
+                   temp->flag &= ~jit_flag_patch;
+                   node = undo.node;
+                   _jit->pc.w = undo.word;
+#if DEVEL_DISASSEMBLER
+                   prevw = undo.prevw;
+#endif
+                   _jitc->patches.offset = undo.patch_offset;
+                   goto restart_function;
+               }
+               if (node->link &&
+                   (word = _jit->pc.w & (sizeof(jit_word_t) - 1)))
+                   nop(sizeof(jit_word_t) - word);
+               /* remember label is defined */
+               node->flag |= jit_flag_patch;
+               node->u.w = _jit->pc.w;
+               epilog(node);
+               _jitc->function = NULL;
+               break;
+           case jit_code_va_start:
+               vastart(rn(node->u.w));
+               break;
+           case jit_code_va_arg:
+               vaarg(rn(node->u.w), rn(node->v.w));
+               break;
+           case jit_code_va_arg_d:
+               vaarg_d(rn(node->u.w), rn(node->v.w), jit_x87_reg_p(node->u.w));
+               break;
+           case jit_code_live:                 case jit_code_ellipsis:
+           case jit_code_va_push:
+           case jit_code_allocai:              case jit_code_allocar:
+           case jit_code_arg:
+           case jit_code_arg_f:                case jit_code_arg_d:
+           case jit_code_va_end:
+           case jit_code_ret:
+           case jit_code_retr:                 case jit_code_reti:
+           case jit_code_retr_f:               case jit_code_reti_f:
+           case jit_code_retr_d:               case jit_code_reti_d:
+           case jit_code_getarg_c:             case jit_code_getarg_uc:
+           case jit_code_getarg_s:             case jit_code_getarg_us:
+           case jit_code_getarg_i:
+#if __X64 && !__X64_32
+           case jit_code_getarg_ui:            case jit_code_getarg_l:
+#endif
+           case jit_code_getarg_f:             case jit_code_getarg_d:
+           case jit_code_putargr:              case jit_code_putargi:
+           case jit_code_putargr_f:            case jit_code_putargi_f:
+           case jit_code_putargr_d:            case jit_code_putargi_d:
+           case jit_code_pushargr:             case jit_code_pushargi:
+           case jit_code_pushargr_f:           case jit_code_pushargi_f:
+           case jit_code_pushargr_d:           case jit_code_pushargi_d:
+           case jit_code_retval_c:             case jit_code_retval_uc:
+           case jit_code_retval_s:             case jit_code_retval_us:
+           case jit_code_retval_i:
+#if __X64 && !__X32
+           case jit_code_retval_ui:            case jit_code_retval_l:
+#endif
+           case jit_code_prepare:
+           case jit_code_finishr:              case jit_code_finishi:
+               break;
+           case jit_code_retval_f:
+#if __X32
+               if (jit_sse_reg_p(node->u.w)) {
+                   fstpr(_ST1_REGNO);
+                   sse_from_x87_f(rn(node->u.w), _ST0_REGNO);
+               }
+               else
+                   fstpr(rn(node->u.w) + 1);
+#endif
+               break;
+           case jit_code_retval_d:
+#if __X32
+               if (jit_sse_reg_p(node->u.w)) {
+                   fstpr(_ST1_REGNO);
+                   sse_from_x87_d(rn(node->u.w), _ST0_REGNO);
+               }
+               else
+                   fstpr(rn(node->u.w) + 1);
+#endif
+               break;
+           default:
+               abort();
+       }
+       jit_regarg_clr(node, value);
+       assert(_jitc->regarg == 0 && _jitc->synth == 0);
+       /* update register live state */
+       jit_reglive(node);
+    }
+#undef case_bfw
+#undef case_bff
+#undef case_ffw
+#undef case_rfw
+#undef case_rff
+#undef case_brw
+#undef case_brr
+#undef case_wrf
+#undef case_wrr
+#undef case_frw
+#undef case_rrf
+#undef case_rrw
+#undef case_frr
+#undef case_rrr
+#undef case_wf
+#undef case_fw
+#undef case_fr
+#undef case_rr
+
+    for (offset = 0; offset < _jitc->patches.offset; offset++) {
+       node = _jitc->patches.ptr[offset].node;
+       word = node->code == jit_code_movi ? node->v.n->u.w : node->u.n->u.w;
+       patch_at(node, _jitc->patches.ptr[offset].inst, word);
+    }
+
+    jit_flush(_jit->code.ptr, _jit->pc.uc);
+
+    return (_jit->code.ptr);
+}
+
+#define CODE                           1
+#  include "jit_x86-cpu.c"
+#  include "jit_x86-sse.c"
+#  include "jit_x86-x87.c"
+#undef CODE
+
+void
+jit_flush(void *fptr, void *tptr)
+{
+}
+
+void
+_emit_ldxi(jit_state_t *_jit, jit_gpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    ldxi(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_gpr_t r1)
+{
+    stxi(i0, rn(r0), rn(r1));
+}
+
+void
+_emit_ldxi_d(jit_state_t *_jit, jit_fpr_t r0, jit_gpr_t r1, jit_word_t i0)
+{
+    if (jit_x87_reg_p(r0))
+       x87_ldxi_d(rn(r0), rn(r1), i0);
+    else
+       sse_ldxi_d(rn(r0), rn(r1), i0);
+}
+
+void
+_emit_stxi_d(jit_state_t *_jit, jit_word_t i0, jit_gpr_t r0, jit_fpr_t r1)
+{
+    if (jit_x87_reg_p(r1))
+       x87_stxi_d(i0, rn(r0), rn(r1));
+    else
+       sse_stxi_d(i0, rn(r0), rn(r1));
+}
+
+static void
+_patch(jit_state_t *_jit, jit_word_t instr, jit_node_t *node)
+{
+    jit_int32_t                flag;
+
+    assert(node->flag & jit_flag_node);
+    if (node->code == jit_code_movi)
+       flag = node->v.n->flag;
+    else
+       flag = node->u.n->flag;
+    assert(!(flag & jit_flag_patch));
+    if (_jitc->patches.offset >= _jitc->patches.length) {
+       jit_realloc((jit_pointer_t *)&_jitc->patches.ptr,
+                   _jitc->patches.length * sizeof(jit_patch_t),
+                   (_jitc->patches.length + 1024) * sizeof(jit_patch_t));
+       _jitc->patches.length += 1024;
+    }
+    _jitc->patches.ptr[_jitc->patches.offset].inst = instr;
+    _jitc->patches.ptr[_jitc->patches.offset].node = node;
+    ++_jitc->patches.offset;
+}
+
+static void
+_sse_from_x87_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    x87_stxi_f(CVT_OFFSET, _RBP_REGNO, r1);
+    sse_ldxi_f(r0, _RBP_REGNO, CVT_OFFSET);
+}
+
+static void
+_sse_from_x87_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    x87_stxi_d(CVT_OFFSET, _RBP_REGNO, r1);
+    sse_ldxi_d(r0, _RBP_REGNO, CVT_OFFSET);
+}
+
+static void
+_x87_from_sse_f(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    sse_stxi_f(CVT_OFFSET, _RBP_REGNO, r1);
+    x87_ldxi_f(r0, _RBP_REGNO, CVT_OFFSET);
+}
+
+static void
+_x87_from_sse_d(jit_state_t *_jit, jit_int32_t r0, jit_int32_t r1)
+{
+    sse_stxi_d(CVT_OFFSET, _RBP_REGNO, r1);
+    x87_ldxi_d(r0, _RBP_REGNO, CVT_OFFSET);
+}
diff --git a/deps/lightning/lib/lightning.c b/deps/lightning/lib/lightning.c
new file mode 100644 (file)
index 0000000..507abb6
--- /dev/null
@@ -0,0 +1,3517 @@
+/*
+ * Copyright (C) 2012-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+#ifdef _WIN32
+#  include <mman.h>
+#else
+#  include <sys/mman.h>
+#endif
+#if defined(__sgi)
+#  include <fcntl.h>
+#endif
+
+#ifndef MAP_ANON
+#  define MAP_ANON                     MAP_ANONYMOUS
+#  ifndef MAP_ANONYMOUS
+#    define MAP_ANONYMOUS              0
+#  endif
+#endif
+
+#define jit_regload_reload             0       /* convert to reload */
+#define jit_regload_delete             1       /* just remove node */
+#define jit_regload_isdead             2       /* delete and unset live bit */
+
+/*
+ * Prototypes
+ */
+static jit_word_t hash_data(const void*, jit_word_t);
+
+#define new_pool()                     _new_pool(_jit)
+static void _new_pool(jit_state_t*);
+
+#define new_node(u)                    _new_node(_jit, u)
+static jit_node_t *_new_node(jit_state_t*, jit_code_t);
+
+#define link_node(u)                   _link_node(_jit, u)
+static inline jit_node_t *_link_node(jit_state_t*, jit_node_t*);
+
+#define del_node(u, v)                 _del_node(_jit, u, v)
+static inline void _del_node(jit_state_t*, jit_node_t*, jit_node_t*);
+
+#define free_node(u)                   _free_node(_jit, u)
+static inline void _free_node(jit_state_t*, jit_node_t*);
+
+#define del_label(u, v)                        _del_label(_jit, u, v)
+static void _del_label(jit_state_t*, jit_node_t*, jit_node_t*);
+
+#define jit_dataset()                  _jit_dataset(_jit)
+static void
+_jit_dataset(jit_state_t *_jit);
+
+#define jit_setup(block)               _jit_setup(_jit, block)
+static void
+_jit_setup(jit_state_t *_jit, jit_block_t *block);
+
+#define jit_follow(block, todo)                _jit_follow(_jit, block, todo)
+static void
+_jit_follow(jit_state_t *_jit, jit_block_t *block, jit_bool_t *todo);
+
+#define jit_update(node, live, mask)   _jit_update(_jit, node, live, mask)
+static void
+_jit_update(jit_state_t *_jit, jit_node_t *node,
+           jit_regset_t *live, jit_regset_t *mask);
+
+#define thread_jumps()                 _thread_jumps(_jit)
+static void
+_thread_jumps(jit_state_t *_jit);
+
+#define sequential_labels()            _sequential_labels(_jit)
+static void
+_sequential_labels(jit_state_t *_jit);
+
+#define split_branches()               _split_branches(_jit)
+static void
+_split_branches(jit_state_t *_jit);
+
+#define shortcut_jump(prev, node)      _shortcut_jump(_jit, prev, node)
+static jit_bool_t
+_shortcut_jump(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node);
+
+#define redundant_jump(prev, node)     _redundant_jump(_jit, prev, node)
+static jit_bool_t
+_redundant_jump(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node);
+
+static jit_code_t
+reverse_jump_code(jit_code_t code);
+
+#define reverse_jump(prev, node)       _reverse_jump(_jit, prev, node)
+static jit_bool_t
+_reverse_jump(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node);
+
+#define redundant_store(node, jump)    _redundant_store(_jit, node, jump)
+static void
+_redundant_store(jit_state_t *_jit, jit_node_t *node, jit_bool_t jump);
+
+#define simplify_movr(p, n, k, s)      _simplify_movr(_jit, p, n, k, s)
+static jit_bool_t
+_simplify_movr(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node,
+              jit_int32_t kind, jit_int32_t size);
+
+#define simplify_movi(p, n, k, s)      _simplify_movi(_jit, p, n, k, s)
+static jit_bool_t
+_simplify_movi(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node,
+              jit_int32_t kind, jit_int32_t size);
+
+#define simplify_ldxi(prev, node)      _simplify_ldxi(_jit, prev, node)
+static jit_bool_t
+_simplify_ldxi(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node);
+
+#define simplify_stxi(prev, node)      _simplify_stxi(_jit, prev, node)
+static jit_bool_t
+_simplify_stxi(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node);
+
+#define simplify_spill(node, regno)    _simplify_spill(_jit, node, regno)
+static void
+_simplify_spill(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno);
+
+#define simplify()                     _simplify(_jit)
+static void
+_simplify(jit_state_t *_jit);
+
+#define jit_reg_undef                  -1
+#define jit_reg_static                  0
+#define jit_reg_change                  1
+#define register_change_p(n, l, r)     _register_change_p(_jit, n, l, r)
+static jit_int32_t
+_register_change_p(jit_state_t *_jit, jit_node_t *node, jit_node_t *link,
+                  jit_int32_t regno);
+
+#define spill_reglive_p(node, regno)   _spill_reglive_p(_jit, node, regno)
+static jit_bool_t
+_spill_reglive_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno);
+
+#define patch_registers()              _patch_registers(_jit)
+static void
+_patch_registers(jit_state_t *_jit);
+
+#define patch_register(n,l,r,p)                _patch_register(_jit,n,l,r,p)
+static void
+_patch_register(jit_state_t *jit, jit_node_t *node, jit_node_t *link,
+               jit_int32_t regno, jit_int32_t patch);
+
+/*
+ * Initialization
+ */
+#if !defined(__sgi)
+#define  mmap_fd                       -1
+#endif
+
+/*
+ * Implementation
+ */
+void
+init_jit(const char *progname)
+{
+    jit_get_cpu();
+    jit_init_debug(progname);
+    jit_init_size();
+}
+
+void
+finish_jit(void)
+{
+    jit_finish_debug();
+    jit_finish_size();
+}
+
+jit_int32_t
+_jit_get_reg(jit_state_t *_jit, jit_int32_t regspec)
+{
+    jit_int32_t                spec;
+    jit_int32_t                regno;
+
+    spec = regspec & ~(jit_class_chk|jit_class_nospill);
+    if (spec & jit_class_named) {
+       regno = jit_regno(spec);
+       if (jit_regset_tstbit(&_jitc->regsav, regno))
+           /* fail if register is spilled */
+           goto fail;
+       if (jit_regset_tstbit(&_jitc->regarg, regno))
+           /* fail if register is an argument to current instruction */
+           goto fail;
+       if (jit_regset_tstbit(&_jitc->reglive, regno)) {
+           if (regspec & jit_class_nospill)
+               /* fail if register is live and should not spill/reload */
+               goto fail;
+           goto spill;
+       }
+       jit_regset_setbit(&_jitc->regarg, regno);
+       return (regno);
+    }
+    else
+       assert(jit_class(spec) != 0);
+
+    if (_jitc->emit) {
+       /* search for a free register matching spec */
+       for (regno = 0; regno < _jitc->reglen; regno++) {
+           if ((jit_class(_rvs[regno].spec) & spec) == spec &&
+               !jit_regset_tstbit(&_jitc->regarg, regno) &&
+               !jit_regset_tstbit(&_jitc->reglive, regno))
+               goto regarg;
+       }
+
+       /* search for a register matching spec that is not an argument
+        * for the current instruction */
+       for (regno = 0; regno < _jitc->reglen; regno++) {
+           if ((jit_class(_rvs[regno].spec) & spec) == spec &&
+               !jit_regset_tstbit(&_jitc->regsav, regno) &&
+               !jit_regset_tstbit(&_jitc->regarg, regno) &&
+               !(regspec & jit_class_nospill)) {
+           spill:
+               assert(_jitc->function != NULL);
+               if (spec & jit_class_gpr) {
+                   if (!_jitc->function->regoff[regno]) {
+                       _jitc->function->regoff[regno] =
+                           jit_allocai(sizeof(jit_word_t));
+                       _jitc->again = 1;
+                   }
+#if DEBUG
+                   /* emit_stxi must not need temporary registers */
+                   assert(!_jitc->getreg);
+                   _jitc->getreg = 1;
+#endif
+                   emit_stxi(_jitc->function->regoff[regno], JIT_FP, regno);
+#if DEBUG
+                   _jitc->getreg = 0;
+#endif
+               }
+               else {
+                   if (!_jitc->function->regoff[regno]) {
+                       _jitc->function->regoff[regno] =
+                           jit_allocai(sizeof(jit_float64_t));
+                       _jitc->again = 1;
+                   }
+#if DEBUG
+                   /* emit_stxi must not need temporary registers */
+                   assert(!_jitc->getreg);
+                   _jitc->getreg = 1;
+#endif
+                   emit_stxi_d(_jitc->function->regoff[regno], JIT_FP, regno);
+#if DEBUG
+                   _jitc->getreg = 0;
+#endif
+               }
+               jit_regset_setbit(&_jitc->regsav, regno);
+           regarg:
+               jit_regset_setbit(&_jitc->regarg, regno);
+               if (jit_class(_rvs[regno].spec) & jit_class_sav) {
+                   /* if will modify callee save registers without a
+                    * function prolog, better patch this assertion */
+                   assert(_jitc->function != NULL);
+                   if (!jit_regset_tstbit(&_jitc->function->regset, regno)) {
+                       jit_regset_setbit(&_jitc->function->regset, regno);
+                       _jitc->again = 1;
+                   }
+               }
+               return (regno);
+           }
+       }
+    }
+    else {
+       /* nospill hint only valid during emit" */
+       assert(!(regspec & jit_class_nospill));
+       for (regno = 0; regno < _jitc->reglen; regno++) {
+           if ((jit_class(_rvs[regno].spec) & spec) == spec &&
+               !jit_regset_tstbit(&_jitc->regsav, regno) &&
+               !jit_regset_tstbit(&_jitc->regarg, regno)) {
+               jit_regset_setbit(&_jitc->regarg, regno);
+               jit_regset_setbit(&_jitc->regsav, regno);
+               jit_save(regno);
+               return (jit_regno_patch|regno);
+           }
+       }
+    }
+
+    /* Out of hardware registers */
+fail:
+    assert(regspec & jit_class_chk);
+    return (JIT_NOREG);
+}
+
+void
+_jit_unget_reg(jit_state_t *_jit, jit_int32_t regno)
+{
+    regno = jit_regno(regno);
+    if (jit_regset_tstbit(&_jitc->regsav, regno)) {
+       if (_jitc->emit) {
+#if DEBUG
+           /* emit_ldxi must not need a temporary register */
+           assert(!_jitc->getreg);
+           _jitc->getreg = 1;
+#endif
+           if (jit_class(_rvs[regno].spec) & jit_class_gpr)
+               emit_ldxi(regno, JIT_FP, _jitc->function->regoff[regno]);
+           else
+               emit_ldxi_d(regno, JIT_FP, _jitc->function->regoff[regno]);
+#if DEBUG
+           /* emit_ldxi must not need a temporary register */
+           _jitc->getreg = 0;
+#endif
+       }
+       else
+           jit_load(regno);
+       jit_regset_clrbit(&_jitc->regsav, regno);
+    }
+#if defined(jit_carry)
+    assert((regno == jit_carry /*&& _NOREG != jit_carry*/) ||
+          jit_regset_tstbit(&_jitc->regarg, regno) != 0);
+#else
+    assert(jit_regset_tstbit(&_jitc->regarg, regno) != 0);
+#endif
+    jit_regset_clrbit(&_jitc->regarg, regno);
+}
+
+jit_bool_t
+_jit_callee_save_p(jit_state_t *_jit, jit_int32_t regno)
+{
+    assert(regno >= 0 && regno < JIT_NOREG);
+    return (!!(_rvs[regno].spec & jit_class_sav));
+}
+
+extern jit_bool_t
+_jit_pointer_p(jit_state_t *_jit, jit_pointer_t address)
+{
+    return ((jit_uint8_t *)address >= _jit->code.ptr &&
+           (jit_word_t)address < _jit->pc.w);
+}
+
+#if __ia64__
+void
+jit_regset_com(jit_regset_t *u, jit_regset_t *v)
+{
+    u->rl = ~v->rl;            u->rh = ~v->rh;
+    u->fl = ~v->fl;            u->fh = ~v->fh;
+}
+
+void
+jit_regset_and(jit_regset_t *u, jit_regset_t *v, jit_regset_t *w)
+{
+    u->rl = v->rl & w->rl;     u->rh = v->rh & w->rh;
+    u->fl = v->fl & w->fl;     u->fh = v->fh & w->fh;
+}
+
+void
+jit_regset_ior(jit_regset_t *u, jit_regset_t *v, jit_regset_t *w)
+{
+    u->rl = v->rl | w->rl;     u->rh = v->rh | w->rh;
+    u->fl = v->fl | w->fl;     u->fh = v->fh | w->fh;
+}
+
+void
+jit_regset_xor(jit_regset_t *u, jit_regset_t *v, jit_regset_t *w)
+{
+    u->rl = v->rl ^ w->rl;     u->rh = v->rh ^ w->rh;
+    u->fl = v->fl ^ w->fl;     u->fh = v->fh ^ w->fh;
+}
+
+void
+jit_regset_set(jit_regset_t *u, jit_regset_t *v)
+{
+    u->rl = v->rl;             u->rh = v->rh;
+    u->fl = v->fl;             u->fh = v->fh;
+}
+
+void
+jit_regset_set_mask(jit_regset_t *u, jit_int32_t v)
+{
+    jit_bool_t         w = !!(v & (v - 1));
+
+    assert(v >= 0 && v <= 256);
+    if (v == 0)
+       u->rl = u->rh = u->fl = u->fh = -1LL;
+    else if (v <= 64) {
+       u->rl = w ? (1LL << v) - 1 : -1LL;
+       u->rh = u->fl = u->fh = 0;
+    }
+    else if (v <= 128) {
+       u->rl = -1LL;
+       u->rh = w ? (1LL << (v - 64)) - 1 : -1LL;
+       u->fl = u->fh = 0;
+    }
+    else if (v <= 192) {
+       u->rl = u->rh = -1LL;
+       u->fl = w ? (1LL << (v - 128)) - 1 : -1LL;
+       u->fh = 0;
+    }
+    else {
+       u->rl = u->rh = u->fl = -1LL;
+       u->fh = w ? (1LL << (v - 128)) - 1 : -1LL;
+    }
+}
+
+jit_bool_t
+jit_regset_cmp_ui(jit_regset_t *u, jit_word_t v)
+{
+    return !((u->rl == v && u->rh == 0 && u->fl == 0 && u->fh == 0));
+}
+
+void
+jit_regset_set_ui(jit_regset_t *u, jit_word_t v)
+{
+    u->rl = v;
+    u->rh = u->fl = u->fh = 0;
+}
+
+jit_bool_t
+jit_regset_set_p(jit_regset_t *u)
+{
+    return (u->rl || u->rh || u->fl || u->fh);
+}
+
+void
+jit_regset_clrbit(jit_regset_t *set, jit_int32_t bit)
+{
+    assert(bit >= 0 && bit <= 255);
+    if (bit < 64)
+       set->rl &= ~(1LL << bit);
+    else if (bit < 128)
+       set->rh &= ~(1LL << (bit - 64));
+    else if (bit < 192)
+       set->fl &= ~(1LL << (bit - 128));
+    else
+       set->fh &= ~(1LL << (bit - 192));
+}
+
+void
+jit_regset_setbit(jit_regset_t *set, jit_int32_t bit)
+{
+    assert(bit >= 0 && bit <= 255);
+    if (bit < 64)
+       set->rl |= 1LL << bit;
+    else if (bit < 128)
+       set->rh |= 1LL << (bit - 64);
+    else if (bit < 192)
+       set->fl |= 1LL << (bit - 128);
+    else
+       set->fh |= 1LL << (bit - 192);
+}
+
+jit_bool_t
+jit_regset_tstbit(jit_regset_t *set, jit_int32_t bit)
+{
+    assert(bit >= 0 && bit <= 255);
+    if (bit < 64)
+       return (!!(set->rl & (1LL << bit)));
+    else if (bit < 128)
+       return (!!(set->rh & (1LL << (bit - 64))));
+    else if (bit < 192)
+       return (!!(set->fl & (1LL << (bit - 128))));
+    return (!!(set->fh & (1LL << (bit - 192))));
+}
+
+unsigned long
+jit_regset_scan1(jit_regset_t *set, jit_int32_t offset)
+{
+    assert(offset >= 0 && offset <= 255);
+    for (; offset < 64; offset++) {
+       if (set->rl & (1LL << offset))
+           return (offset);
+    }
+    for (; offset < 128; offset++) {
+       if (set->rh & (1LL << (offset - 64)))
+           return (offset);
+    }
+    for (; offset < 192; offset++) {
+       if (set->fl & (1LL << (offset - 128)))
+           return (offset);
+    }
+    for (; offset < 256; offset++) {
+       if (set->fh & (1LL << (offset - 192)))
+           return (offset);
+    }
+    return (ULONG_MAX);
+}
+
+#elif __sparc__ && __WORDSIZE == 64
+void
+jit_regset_com(jit_regset_t *u, jit_regset_t *v)
+{
+    u->rl = ~v->rl;            u->rh = ~v->rh;
+}
+
+void
+jit_regset_and(jit_regset_t *u, jit_regset_t *v, jit_regset_t *w)
+{
+    u->rl = v->rl & w->rl;     u->rh = v->rh & w->rh;
+}
+
+void
+jit_regset_ior(jit_regset_t *u, jit_regset_t *v, jit_regset_t *w)
+{
+    u->rl = v->rl | w->rl;     u->rh = v->rh | w->rh;
+}
+
+void
+jit_regset_xor(jit_regset_t *u, jit_regset_t *v, jit_regset_t *w)
+{
+    u->rl = v->rl ^ w->rl;     u->rh = v->rh ^ w->rh;
+}
+
+void
+jit_regset_set(jit_regset_t *u, jit_regset_t *v)
+{
+    u->rl = v->rl;             u->rh = v->rh;
+}
+
+void
+jit_regset_set_mask(jit_regset_t *u, jit_int32_t v)
+{
+    jit_bool_t         w = !!(v & (v - 1));
+
+    assert(v >= 0 && v <= 128);
+    if (v == 0)
+       u->rl = u->rh = -1LL;
+    else if (v <= 64) {
+       u->rl = w ? (1LL << v) - 1 : -1LL;
+       u->rh = 0;
+    }
+    else {
+       u->rl = -1LL;
+       u->rh = w ? (1LL << (v - 64)) - 1 : -1LL;
+    }
+}
+
+jit_bool_t
+jit_regset_cmp_ui(jit_regset_t *u, jit_word_t v)
+{
+    return !((u->rl == v && u->rh == 0));
+}
+
+void
+jit_regset_set_ui(jit_regset_t *u, jit_word_t v)
+{
+    u->rl = v;
+    u->rh = 0;
+}
+
+jit_bool_t
+jit_regset_set_p(jit_regset_t *u)
+{
+    return (u->rl || u->rh);
+}
+
+void
+jit_regset_clrbit(jit_regset_t *set, jit_int32_t bit)
+{
+    assert(bit >= 0 && bit <= 128);
+    if (bit < 64)
+       set->rl &= ~(1LL << bit);
+    else
+       set->rh &= ~(1LL << (bit - 64));
+}
+
+void
+jit_regset_setbit(jit_regset_t *set, jit_int32_t bit)
+{
+    assert(bit >= 0 && bit <= 127);
+    if (bit < 64)
+       set->rl |= 1LL << bit;
+    else
+       set->rh |= 1LL << (bit - 64);
+}
+
+jit_bool_t
+jit_regset_tstbit(jit_regset_t *set, jit_int32_t bit)
+{
+    assert(bit >= 0 && bit <= 127);
+    if (bit < 64)
+       return (!!(set->rl & (1LL << bit)));
+    else
+       return (!!(set->rh & (1LL << (bit - 64))));
+}
+
+unsigned long
+jit_regset_scan1(jit_regset_t *set, jit_int32_t offset)
+{
+    assert(offset >= 0 && offset <= 127);
+    for (; offset < 64; offset++) {
+       if (set->rl & (1LL << offset))
+           return (offset);
+    }
+    for (; offset < 128; offset++) {
+       if (set->rh & (1LL << (offset - 64)))
+           return (offset);
+    }
+    return (ULONG_MAX);
+}
+
+#else
+unsigned long
+jit_regset_scan1(jit_regset_t *set, jit_int32_t offset)
+{
+    jit_regset_t       mask;
+    assert(offset >= 0 && offset <= 63);
+    if ((mask = *set >> offset)) {
+       for (;;) {
+           if (mask & 1)
+               return (offset);
+           mask >>= 1;
+           ++offset;
+       }
+    }
+    return (ULONG_MAX);
+}
+#endif
+
+void
+_jit_save(jit_state_t *_jit, jit_int32_t reg)
+{
+    reg = jit_regno(reg);
+    assert(!_jitc->realize);
+    _jitc->spill[reg] = jit_new_node_w(jit_code_save, reg);
+}
+
+void
+_jit_load(jit_state_t *_jit, jit_int32_t reg)
+{
+    jit_node_t         *node;
+
+    reg = jit_regno(reg);
+    assert(!_jitc->realize);
+    assert(_jitc->spill[reg] != NULL);
+    node = jit_new_node_w(jit_code_load, reg);
+    /* create a path to flag the save/load is not required */
+    node->link = _jitc->spill[reg];
+    node->link->link = node;
+    _jitc->spill[reg] = NULL;
+}
+
+static jit_word_t
+hash_data(const void *data, jit_word_t length)
+{
+    const jit_uint8_t          *ptr;
+    jit_word_t          i, key;
+    for (i = key = 0, ptr = data; i < length; i++)
+       key = (key << (key & 1)) ^ ptr[i];
+    return (key);
+}
+
+jit_pointer_t
+_jit_address(jit_state_t *_jit, jit_node_t *node)
+{
+    assert(_jitc->done);
+    assert(node != NULL &&
+          /* If a node type that is documented to be a fixed marker */
+          (node->code == jit_code_note || node->code == jit_code_name ||
+           /* If another special fixed marker, returned by jit_indirect() */
+           (node->code == jit_code_label && (node->flag & jit_flag_use) != 0)));
+    return ((jit_pointer_t)node->u.w);
+}
+
+jit_node_t *
+_jit_data(jit_state_t *_jit, const void *data,
+         jit_word_t length, jit_int32_t align)
+{
+    jit_word_t          key;
+    jit_node_t         *node;
+
+    assert(!_jitc->realize);
+
+    /* Ensure there is space even if asking for a duplicate */
+    if (((_jitc->data.offset + 7) & -8) + length > _jit->data.length) {
+       jit_word_t       size;
+
+       size = (_jit->data.length + length + 4096) & - 4095;
+       assert(size >= _jit->data.length);
+       if (_jitc->data.ptr == NULL)
+           jit_alloc((jit_pointer_t *)&_jitc->data.ptr, size);
+       else
+           jit_realloc((jit_pointer_t *)&_jitc->data.ptr,
+                       _jit->data.length, size);
+       _jit->data.length = size;
+    }
+    if (_jitc->data.table == NULL)
+       jit_alloc((jit_pointer_t *)&_jitc->data.table,
+                 (_jitc->data.size = 16) * sizeof(jit_node_t*));
+
+    key = hash_data(data, length) & (_jitc->data.size - 1);
+    node = _jitc->data.table[key];
+    for (; node; node = node->next) {
+       if (node->v.w == length &&
+           memcmp(_jitc->data.ptr + node->u.w, data, length) == 0)
+           break;
+    }
+
+    if (!node) {
+       node = jit_new_node_no_link(jit_code_data);
+       if (!align)
+           align = length;
+       switch (align) {
+           case 0:     case 1:
+               break;
+           case 2:
+               _jitc->data.offset = (_jitc->data.offset + 1) & -2;
+               break;
+           case 3:     case 4:
+               _jitc->data.offset = (_jitc->data.offset + 3) & -4;
+               break;
+           default:
+               _jitc->data.offset = (_jitc->data.offset + 7) & -8;
+               break;
+       }
+       node->u.w = _jitc->data.offset;
+       node->v.w = length;
+       jit_memcpy(_jitc->data.ptr + _jitc->data.offset, data, length);
+       _jitc->data.offset += length;
+
+       node->next = _jitc->data.table[key];
+       _jitc->data.table[key] = node;
+       ++_jitc->data.count;
+
+       /* Rehash if more than 75% used table */
+       if (_jitc->data.count >
+           (_jitc->data.size >> 1) + (_jitc->data.size >> 2) &&
+           (_jitc->data.size << 1) > _jitc->data.size) {
+           jit_word_t    i;
+           jit_node_t  **hash;
+           jit_node_t   *next;
+           jit_node_t   *temp;
+
+           jit_alloc((jit_pointer_t *)&hash,
+                     (_jitc->data.size << 1) * sizeof(jit_node_t*));
+           for (i = 0; i < _jitc->data.size; i++) {
+               temp = _jitc->data.table[i];
+               for (; temp; temp = next) {
+                   next = temp->next;
+                   key = hash_data(_jitc->data.ptr + temp->u.w, temp->v.w) &
+                         ((_jitc->data.size << 1) - 1);
+                   temp->next = hash[key];
+                   hash[key] = temp;
+               }
+           }
+           jit_free((jit_pointer_t *)&_jitc->data.table);
+           _jitc->data.table = hash;
+           _jitc->data.size <<= 1;
+       }
+    }
+
+    return (node);
+}
+
+static void
+_new_pool(jit_state_t *_jit)
+{
+    jit_node_t         *list;
+    jit_int32_t                 offset;
+
+    if (_jitc->pool.offset >= _jitc->pool.length) {
+       jit_int32_t      length;
+
+       length = _jitc->pool.length + 16;
+       jit_realloc((jit_pointer_t *)&_jitc->pool.ptr,
+                   _jitc->pool.length * sizeof(jit_node_t *),
+                   length * sizeof(jit_node_t *));
+       _jitc->pool.length = length;
+    }
+    jit_alloc((jit_pointer_t *)(_jitc->pool.ptr + _jitc->pool.offset),
+             sizeof(jit_node_t) * 1024);
+    list = _jitc->pool.ptr[_jitc->pool.offset];
+    for (offset = 1; offset < 1024; offset++, list++)
+       list->next = list + 1;
+    list->next = _jitc->list;
+    _jitc->list = _jitc->pool.ptr[_jitc->pool.offset];
+    ++_jitc->pool.offset;
+}
+
+static jit_node_t *
+_new_node(jit_state_t *_jit, jit_code_t code)
+{
+    jit_node_t         *node;
+
+    if (_jitc->list == NULL)
+       new_pool();
+    node = _jitc->list;
+    _jitc->list = node->next;
+    if (_jitc->synth)
+       node->flag |= jit_flag_synth;
+    node->next = NULL;
+    node->code = code;
+
+    return (node);
+}
+
+static inline jit_node_t *
+_link_node(jit_state_t *_jit, jit_node_t *node)
+{
+    if (_jitc->tail)
+       _jitc->tail->next = node;
+    else
+       _jitc->head = node;
+    return (_jitc->tail = node);
+}
+
+static inline void
+_del_node(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node)
+{
+    if (prev == node) {
+       assert(prev == _jitc->head);
+       _jitc->head = node->next;
+    }
+    else
+       prev->next = node->next;
+    memset(node, 0, sizeof(jit_node_t));
+    node->next = _jitc->list;
+    _jitc->list = node;
+}
+
+static inline void
+_free_node(jit_state_t *_jit, jit_node_t *node)
+{
+    memset(node, 0, sizeof(jit_node_t));
+    node->next = _jitc->list;
+    _jitc->list = node;
+}
+
+static void
+_del_label(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node)
+{
+    jit_block_t                *block;
+
+    /* only allow call to del_label on linked labels */
+    block = _jitc->blocks.ptr + node->v.w;
+    assert(block->label == node);
+
+    /* del_label() should only be called when optimizing.
+     * This will leave an empty block index */
+    jit_regset_del(&block->reglive);
+    jit_regset_del(&block->regmask);
+    block->label = NULL;
+
+    /* redundant, should be already true */
+    assert(node->link == NULL);
+    del_node(prev, node);
+}
+
+jit_state_t *
+jit_new_state(void)
+{
+    jit_state_t                *_jit;
+
+    jit_alloc((jit_pointer_t *)&_jit, sizeof(jit_state_t));
+    jit_alloc((jit_pointer_t *)&_jitc, sizeof(jit_compiler_t));
+    jit_regset_new(&_jitc->regarg);
+    jit_regset_new(&_jitc->regsav);
+    jit_regset_new(&_jitc->reglive);
+    jit_regset_new(&_jitc->regmask);
+
+    jit_init();
+
+    jit_alloc((jit_pointer_t *)&_jitc->spill,
+             _jitc->reglen * sizeof(jit_node_t*));
+    jit_alloc((jit_pointer_t *)&_jitc->gen,
+             _jitc->reglen * sizeof(jit_int32_t));
+    jit_alloc((jit_pointer_t *)&_jitc->values,
+             _jitc->reglen * sizeof(jit_value_t));
+
+    jit_alloc((jit_pointer_t *)&_jitc->patches.ptr,
+             (_jitc->patches.length = 1024) * sizeof(jit_patch_t));
+    jit_alloc((jit_pointer_t *)&_jitc->functions.ptr,
+             (_jitc->functions.length = 16) * sizeof(jit_function_t));
+    jit_alloc((jit_pointer_t *)&_jitc->pool.ptr,
+             (_jitc->pool.length = 16) * sizeof(jit_node_t*));
+    jit_alloc((jit_pointer_t *)&_jitc->blocks.ptr,
+             (_jitc->blocks.length = 16) * sizeof(jit_block_t));
+#if __arm__ && DISASSEMBLER
+    jit_alloc((jit_pointer_t *)&_jitc->data_info.ptr,
+             (_jitc->data_info.length = 1024) * sizeof(jit_data_info_t));
+#endif
+
+    /* allocate at most one extra note in case jit_name() is
+     * never called, or called after adding at least one note */
+    _jit->note.length = 1;
+    _jitc->note.size = sizeof(jit_note_t);
+
+    return (_jit);
+}
+
+void
+_jit_clear_state(jit_state_t *_jit)
+{
+#if DEVEL_DISASSEMBLER
+#  define jit_really_clear_state()     _jit_really_clear_state(_jit)
+}
+
+void _jit_really_clear_state(jit_state_t *_jit)
+{
+#endif
+    jit_word_t          offset;
+    jit_function_t     *function;
+
+    /* release memory not required at jit execution time and set
+     * pointers to NULL to explicitly know they are released */
+    _jitc->head = _jitc->tail = NULL;
+
+    jit_free((jit_pointer_t *)&_jitc->data.table);
+    _jitc->data.size = _jitc->data.count = 0;
+
+    jit_free((jit_pointer_t *)&_jitc->spill);
+    jit_free((jit_pointer_t *)&_jitc->gen);
+    jit_free((jit_pointer_t *)&_jitc->values);
+
+    jit_free((jit_pointer_t *)&_jitc->blocks.ptr);
+
+    jit_free((jit_pointer_t *)&_jitc->patches.ptr);
+    _jitc->patches.offset = _jitc->patches.length = 0;
+
+    for (offset = 0; offset < _jitc->functions.offset; offset++) {
+       function = _jitc->functions.ptr + offset;
+       jit_free((jit_pointer_t *)&function->regoff);
+    }
+    jit_free((jit_pointer_t *)&_jitc->functions.ptr);
+    _jitc->functions.offset = _jitc->functions.length = 0;
+    _jitc->function = NULL;
+
+    for (offset = 0; offset < _jitc->pool.offset; offset++)
+       jit_free((jit_pointer_t *)(_jitc->pool.ptr + offset));
+    jit_free((jit_pointer_t *)&_jitc->pool.ptr);
+    _jitc->pool.offset = _jitc->pool.length = 0;
+    _jitc->list = NULL;
+
+    _jitc->note.head = _jitc->note.tail =
+       _jitc->note.name = _jitc->note.note = NULL;
+    _jitc->note.base = NULL;
+
+#if __arm__ && DISASSEMBLER
+    jit_free((jit_pointer_t *)&_jitc->data_info.ptr);
+#endif
+
+#if (__powerpc__ && _CALL_AIXDESC) || __ia64__
+    jit_free((jit_pointer_t *)&_jitc->prolog.ptr);
+#endif
+
+#if __ia64__
+    jit_regset_del(&_jitc->regs);
+#endif
+
+    jit_free((jit_pointer_t *)&_jitc);
+}
+
+void
+_jit_destroy_state(jit_state_t *_jit)
+{
+#if DEVEL_DISASSEMBLER
+    jit_really_clear_state();
+#endif
+    if (!_jit->user_code)
+       munmap(_jit->code.ptr, _jit->code.length);
+    if (!_jit->user_data)
+       munmap(_jit->data.ptr, _jit->data.length);
+    jit_free((jit_pointer_t *)&_jit);
+}
+
+void
+_jit_synth_inc(jit_state_t *_jit)
+{
+    assert(_jitc->synth < 8);
+    ++_jitc->synth;
+}
+
+jit_node_t *
+_jit_new_node(jit_state_t *_jit, jit_code_t code)
+{
+    assert(!_jitc->realize);
+    return (link_node(new_node(code)));
+}
+
+jit_node_t *
+_jit_new_node_no_link(jit_state_t *_jit, jit_code_t code)
+{
+    assert(!_jitc->realize);
+    return (new_node(code));
+}
+
+void
+_jit_link_node(jit_state_t *_jit, jit_node_t *node)
+{
+    assert(!_jitc->realize);
+    link_node(node);
+}
+
+void
+_jit_synth_dec(jit_state_t *_jit)
+{
+    assert(_jitc->synth > 0);
+    --_jitc->synth;
+}
+
+jit_node_t *
+_jit_new_node_w(jit_state_t *_jit, jit_code_t code,
+               jit_word_t u)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.w = u;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_f(jit_state_t *_jit, jit_code_t code,
+               jit_float32_t u)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.f = u;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_d(jit_state_t *_jit, jit_code_t code,
+               jit_float64_t u)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.d = u;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_p(jit_state_t *_jit, jit_code_t code,
+               jit_pointer_t u)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.p = u;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_ww(jit_state_t *_jit, jit_code_t code,
+                jit_word_t u, jit_word_t v)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.w = u;
+    node->v.w = v;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_wp(jit_state_t *_jit, jit_code_t code,
+                jit_word_t u, jit_pointer_t v)
+{
+    return (jit_new_node_ww(code, u, (jit_word_t)v));
+}
+
+jit_node_t *
+_jit_new_node_fp(jit_state_t *_jit, jit_code_t code,
+                jit_float32_t u, jit_pointer_t v)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.f = u;
+    node->v.w = (jit_word_t)v;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_dp(jit_state_t *_jit, jit_code_t code,
+                jit_float64_t u, jit_pointer_t v)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.d = u;
+    node->v.w = (jit_word_t)v;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_pw(jit_state_t *_jit, jit_code_t code,
+                jit_pointer_t u, jit_word_t v)
+{
+    return (jit_new_node_ww(code, (jit_word_t)u, v));
+}
+
+jit_node_t *
+_jit_new_node_wf(jit_state_t *_jit, jit_code_t code,
+                jit_word_t u, jit_float32_t v)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.w = u;
+    node->v.f = v;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_wd(jit_state_t *_jit, jit_code_t code,
+                jit_word_t u, jit_float64_t v)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.w = u;
+    node->v.d = v;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_www(jit_state_t *_jit, jit_code_t code,
+                 jit_word_t u, jit_word_t v, jit_word_t w)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.w = u;
+    node->v.w = v;
+    node->w.w = w;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_qww(jit_state_t *_jit, jit_code_t code,
+                 jit_int32_t l, jit_int32_t h,
+                 jit_word_t v, jit_word_t w)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    assert(l != h);
+    node->u.q.l = l;
+    node->u.q.h = h;
+    node->v.w = v;
+    node->w.w = w;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_wwf(jit_state_t *_jit, jit_code_t code,
+                 jit_word_t u, jit_word_t v, jit_float32_t w)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.w = u;
+    node->v.w = v;
+    node->w.f = w;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_wwd(jit_state_t *_jit, jit_code_t code,
+                 jit_word_t u, jit_word_t v, jit_float64_t w)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.w = u;
+    node->v.w = v;
+    node->w.d = w;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_pww(jit_state_t *_jit, jit_code_t code,
+                 jit_pointer_t u, jit_word_t v, jit_word_t w)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.p = u;
+    node->v.w = v;
+    node->w.w = w;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_pwf(jit_state_t *_jit, jit_code_t code,
+                 jit_pointer_t u, jit_word_t v, jit_float32_t w)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.p = u;
+    node->v.w = v;
+    node->w.f = w;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_new_node_pwd(jit_state_t *_jit, jit_code_t code,
+                 jit_pointer_t u, jit_word_t v, jit_float64_t w)
+{
+    jit_node_t         *node = new_node(code);
+    assert(!_jitc->realize);
+    node->u.p = u;
+    node->v.w = v;
+    node->w.d = w;
+    return (link_node(node));
+}
+
+jit_node_t *
+_jit_label(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+
+    if (!(node = _jitc->tail) || node->code != jit_code_label) {
+       node = jit_forward();
+       jit_link(node);
+    }
+
+    return (node);
+}
+
+jit_node_t *
+_jit_forward(jit_state_t *_jit)
+{
+    return (jit_new_node_no_link(jit_code_label));
+}
+
+jit_node_t *
+_jit_indirect(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+
+    node = jit_label();
+    node->flag |= jit_flag_use;
+
+    return (node);
+}
+
+void
+_jit_link(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_block_t                *block;
+
+    assert((node->code == jit_code_label ||
+           node->code == jit_code_prolog ||
+           node->code == jit_code_epilog) && !node->next);
+    jit_link_node(node);
+    if (_jitc->blocks.offset >= _jitc->blocks.length) {
+       jit_word_t        length;
+
+       length = _jitc->blocks.length + 16;
+       jit_realloc((jit_pointer_t *)&_jitc->blocks.ptr,
+                   _jitc->blocks.length * sizeof(jit_block_t),
+                   length * sizeof(jit_block_t));
+       _jitc->blocks.length = length;
+    }
+    block = _jitc->blocks.ptr + _jitc->blocks.offset;
+    block->label = node;
+    node->v.w = _jitc->blocks.offset;
+    jit_regset_new(&block->reglive);
+    jit_regset_new(&block->regmask);
+    ++_jitc->blocks.offset;
+}
+
+jit_bool_t
+_jit_forward_p(jit_state_t *_jit, jit_node_t *node)
+{
+    return (node->code == jit_code_label && !node->next && node != _jitc->tail);
+}
+
+jit_bool_t
+_jit_indirect_p(jit_state_t *_jit, jit_node_t *node)
+{
+    return (node->code == jit_code_label && !!(node->flag & jit_flag_use));
+}
+
+jit_bool_t
+_jit_target_p(jit_state_t *_jit, jit_node_t *node)
+{
+    return (node->code == jit_code_label && !!node->link);
+}
+
+void
+_jit_prepare(jit_state_t *_jit)
+{
+    assert(_jitc->function != NULL);
+    _jitc->function->call.call = jit_call_default;
+    _jitc->function->call.argi =
+       _jitc->function->call.argf =
+       _jitc->function->call.size = 0;
+    _jitc->prepare = jit_new_node(jit_code_prepare);
+}
+
+void
+_jit_patch(jit_state_t* _jit, jit_node_t *instr)
+{
+    jit_node_t         *label;
+
+    if (!(label = _jitc->tail) || label->code != jit_code_label)
+       label = jit_label();
+    jit_patch_at(instr, label);
+}
+
+jit_int32_t
+_jit_classify(jit_state_t *_jit, jit_code_t code)
+{
+    jit_int32_t                mask;
+
+    switch (code) {
+       case jit_code_data:     case jit_code_save:     case jit_code_load:
+       case jit_code_name:     case jit_code_label:    case jit_code_note:
+       case jit_code_prolog:   case jit_code_ellipsis: case jit_code_va_push:
+       case jit_code_epilog:   case jit_code_ret:      case jit_code_prepare:
+           mask = 0;
+           break;
+       case jit_code_live:     case jit_code_va_end:
+       case jit_code_retr:     case jit_code_retr_f:   case jit_code_retr_d:
+       case jit_code_pushargr: case jit_code_pushargr_f:
+       case jit_code_pushargr_d:
+       case jit_code_finishr:  /* synthesized will set jit_cc_a0_jmp */
+           mask = jit_cc_a0_reg;
+           break;
+       case jit_code_align:    case jit_code_reti:     case jit_code_pushargi:
+       case jit_code_finishi:  /* synthesized will set jit_cc_a0_jmp */
+           mask = jit_cc_a0_int;
+           break;
+       case jit_code_reti_f:   case jit_code_pushargi_f:
+           mask = jit_cc_a0_flt;
+           break;
+       case jit_code_reti_d:   case jit_code_pushargi_d:
+           mask = jit_cc_a0_dbl;
+           break;
+       case jit_code_allocai:
+           mask = jit_cc_a0_int|jit_cc_a1_int;
+           break;
+       case jit_code_arg:      case jit_code_arg_f:    case jit_code_arg_d:
+           mask = jit_cc_a0_int|jit_cc_a0_arg;
+           break;
+       case jit_code_calli:    case jit_code_jmpi:
+           mask = jit_cc_a0_jmp;
+           break;
+       case jit_code_callr:    case jit_code_jmpr:
+           mask = jit_cc_a0_reg|jit_cc_a0_jmp;
+           break;
+       case jit_code_retval_c: case jit_code_retval_uc:
+       case jit_code_retval_s: case jit_code_retval_us:
+       case jit_code_retval_i: case jit_code_retval_ui:
+       case jit_code_retval_l:
+       case jit_code_retval_f: case jit_code_retval_d:
+       case jit_code_va_start:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg;
+           break;
+       case jit_code_getarg_c: case jit_code_getarg_uc:
+       case jit_code_getarg_s: case jit_code_getarg_us:
+       case jit_code_getarg_i: case jit_code_getarg_ui:
+       case jit_code_getarg_l:
+       case jit_code_getarg_f: case jit_code_getarg_d:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_arg;
+           break;
+       case jit_code_putargr:  case jit_code_putargr_f:
+       case jit_code_putargr_d:
+           mask = jit_cc_a0_reg|jit_cc_a1_arg;
+           break;
+       case jit_code_putargi:
+           mask = jit_cc_a0_int|jit_cc_a1_arg;
+           break;
+       case jit_code_putargi_f:
+           mask = jit_cc_a0_flt|jit_cc_a1_arg;
+           break;
+       case jit_code_putargi_d:
+           mask = jit_cc_a0_dbl|jit_cc_a1_arg;
+           break;
+       case jit_code_movi:     case jit_code_ldi_c:    case jit_code_ldi_uc:
+       case jit_code_ldi_s:    case jit_code_ldi_us:   case jit_code_ldi_i:
+       case jit_code_ldi_ui:   case jit_code_ldi_l:    case jit_code_ldi_f:
+       case jit_code_ldi_d:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_int;
+           break;
+       case jit_code_movi_f:   case jit_code_movi_f_w:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_flt;
+           break;
+       case jit_code_movi_d:   case jit_code_movi_d_w:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_dbl;
+           break;
+       case jit_code_movi_d_ww:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_reg|jit_cc_a1_chg|
+                  jit_cc_a2_dbl;
+           break;
+       case jit_code_negr:     case jit_code_comr:     case jit_code_movr:
+       case jit_code_extr_c:   case jit_code_extr_uc:  case jit_code_extr_s:
+       case jit_code_extr_us:  case jit_code_extr_i:   case jit_code_extr_ui:
+       case jit_code_truncr_f_i:                       case jit_code_truncr_f_l:
+       case jit_code_truncr_d_i:                       case jit_code_truncr_d_l:
+       case jit_code_htonr_us: case jit_code_htonr_ui: case jit_code_htonr_ul:
+       case jit_code_ldr_c:    case jit_code_ldr_uc:
+       case jit_code_ldr_s:    case jit_code_ldr_us:   case jit_code_ldr_i:
+       case jit_code_ldr_ui:   case jit_code_ldr_l:    case jit_code_negr_f:
+       case jit_code_absr_f:   case jit_code_sqrtr_f:  case jit_code_movr_f:
+       case jit_code_extr_f:   case jit_code_extr_d_f: case jit_code_ldr_f:
+       case jit_code_negr_d:   case jit_code_absr_d:   case jit_code_sqrtr_d:
+       case jit_code_movr_d:   case jit_code_extr_d:   case jit_code_extr_f_d:
+       case jit_code_ldr_d:
+       case jit_code_movr_w_f: case jit_code_movr_f_w:
+       case jit_code_movr_w_d: case jit_code_movr_d_w:
+       case jit_code_va_arg:   case jit_code_va_arg_d:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_reg;
+           break;
+       case jit_code_movr_d_ww:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_reg|jit_cc_a1_chg|
+                  jit_cc_a2_reg;
+           break;
+       case jit_code_addi:     case jit_code_addxi:    case jit_code_addci:
+       case jit_code_subi:     case jit_code_subxi:    case jit_code_subci:
+       case jit_code_rsbi:
+       case jit_code_muli:     case jit_code_divi:     case jit_code_divi_u:
+       case jit_code_remi:     case jit_code_remi_u:   case jit_code_andi:
+       case jit_code_ori:      case jit_code_xori:     case jit_code_lshi:
+       case jit_code_rshi:     case jit_code_rshi_u:   case jit_code_lti:
+       case jit_code_lti_u:    case jit_code_lei:      case jit_code_lei_u:
+       case jit_code_eqi:      case jit_code_gei:      case jit_code_gei_u:
+       case jit_code_gti:      case jit_code_gti_u:    case jit_code_nei:
+       case jit_code_ldxi_c:   case jit_code_ldxi_uc:  case jit_code_ldxi_s:
+       case jit_code_ldxi_us:  case jit_code_ldxi_i:   case jit_code_ldxi_ui:
+       case jit_code_ldxi_l:   case jit_code_ldxi_f:   case jit_code_ldxi_d:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_reg|jit_cc_a2_int;
+           break;
+       case jit_code_qmuli:    case jit_code_qmuli_u:
+       case jit_code_qdivi:    case jit_code_qdivi_u:
+           mask = jit_cc_a0_reg|jit_cc_a0_rlh|jit_cc_a0_chg|
+                  jit_cc_a1_reg|jit_cc_a2_int;
+           break;
+       case jit_code_addi_f:   case jit_code_subi_f:   case jit_code_rsbi_f:
+       case jit_code_muli_f:   case jit_code_divi_f:   case jit_code_lti_f:
+       case jit_code_lei_f:    case jit_code_eqi_f:    case jit_code_gei_f:
+       case jit_code_gti_f:    case jit_code_nei_f:    case jit_code_unlti_f:
+       case jit_code_unlei_f:  case jit_code_uneqi_f:  case jit_code_ungei_f:
+       case jit_code_ungti_f:  case jit_code_ltgti_f:  case jit_code_ordi_f:
+       case jit_code_unordi_f:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_reg|jit_cc_a2_flt;
+           break;
+       case jit_code_addi_d:   case jit_code_subi_d:   case jit_code_rsbi_d:
+       case jit_code_muli_d:   case jit_code_divi_d:   case jit_code_lti_d:
+       case jit_code_lei_d:    case jit_code_eqi_d:    case jit_code_gei_d:
+       case jit_code_gti_d:    case jit_code_nei_d:    case jit_code_unlti_d:
+       case jit_code_unlei_d:  case jit_code_uneqi_d:  case jit_code_ungei_d:
+       case jit_code_ungti_d:  case jit_code_ltgti_d:  case jit_code_ordi_d:
+       case jit_code_unordi_d:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_reg|jit_cc_a2_dbl;
+           break;
+       case jit_code_addr:     case jit_code_addxr:    case jit_code_addcr:
+       case jit_code_subr:     case jit_code_subxr:    case jit_code_subcr:
+       case jit_code_mulr:     case jit_code_divr:     case jit_code_divr_u:
+       case jit_code_remr:     case jit_code_remr_u:   case jit_code_andr:
+       case jit_code_orr:      case jit_code_xorr:     case jit_code_lshr:
+       case jit_code_rshr:     case jit_code_rshr_u:   case jit_code_ltr:
+       case jit_code_ltr_u:    case jit_code_ler:      case jit_code_ler_u:
+       case jit_code_eqr:      case jit_code_ger:      case jit_code_ger_u:
+       case jit_code_gtr:      case jit_code_gtr_u:    case jit_code_ner:
+       case jit_code_ldxr_c:   case jit_code_ldxr_uc:  case jit_code_ldxr_s:
+       case jit_code_ldxr_us:  case jit_code_ldxr_i:   case jit_code_ldxr_ui:
+       case jit_code_ldxr_l:   case jit_code_addr_f:   case jit_code_subr_f:
+       case jit_code_mulr_f:   case jit_code_divr_f:   case jit_code_ltr_f:
+       case jit_code_ler_f:    case jit_code_eqr_f:    case jit_code_ger_f:
+       case jit_code_gtr_f:    case jit_code_ner_f:    case jit_code_unltr_f:
+       case jit_code_unler_f:  case jit_code_uneqr_f:  case jit_code_unger_f:
+       case jit_code_ungtr_f:  case jit_code_ltgtr_f:  case jit_code_ordr_f:
+       case jit_code_unordr_f: case jit_code_ldxr_f:   case jit_code_addr_d:
+       case jit_code_subr_d:   case jit_code_mulr_d:   case jit_code_divr_d:
+       case jit_code_ltr_d:    case jit_code_ler_d:    case jit_code_eqr_d:
+       case jit_code_ger_d:    case jit_code_gtr_d:    case jit_code_ner_d:
+       case jit_code_unltr_d:  case jit_code_unler_d:  case jit_code_uneqr_d:
+       case jit_code_unger_d:  case jit_code_ungtr_d:  case jit_code_ltgtr_d:
+       case jit_code_ordr_d:   case jit_code_unordr_d: case jit_code_ldxr_d:
+       case jit_code_movr_ww_d:
+           mask = jit_cc_a0_reg|jit_cc_a0_chg|jit_cc_a1_reg|jit_cc_a2_reg;
+           break;
+       case jit_code_qmulr:    case jit_code_qmulr_u:
+       case jit_code_qdivr:    case jit_code_qdivr_u:
+           mask = jit_cc_a0_reg|jit_cc_a0_rlh|jit_cc_a0_chg|
+                  jit_cc_a1_reg|jit_cc_a2_reg;
+           break;
+       case jit_code_sti_c:    case jit_code_sti_s:    case jit_code_sti_i:
+       case jit_code_sti_l:    case jit_code_sti_f:    case jit_code_sti_d:
+           mask = jit_cc_a0_int|jit_cc_a1_reg;
+           break;
+       case jit_code_blti:     case jit_code_blti_u:   case jit_code_blei:
+       case jit_code_blei_u:   case jit_code_beqi:     case jit_code_bgei:
+       case jit_code_bgei_u:   case jit_code_bgti:     case jit_code_bgti_u:
+       case jit_code_bnei:     case jit_code_bmsi:     case jit_code_bmci:
+           mask = jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a2_int;
+           break;
+       case jit_code_blti_f:   case jit_code_blei_f:   case jit_code_beqi_f:
+       case jit_code_bgei_f:   case jit_code_bgti_f:   case jit_code_bnei_f:
+       case jit_code_bunlti_f: case jit_code_bunlei_f: case jit_code_buneqi_f:
+       case jit_code_bungei_f: case jit_code_bungti_f: case jit_code_bltgti_f:
+       case jit_code_bordi_f:  case jit_code_bunordi_f:
+           mask = jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a2_flt;
+           break;
+       case jit_code_blti_d:   case jit_code_blei_d:   case jit_code_beqi_d:
+       case jit_code_bgei_d:   case jit_code_bgti_d:   case jit_code_bnei_d:
+       case jit_code_bunlti_d: case jit_code_bunlei_d: case jit_code_buneqi_d:
+       case jit_code_bungei_d: case jit_code_bungti_d: case jit_code_bltgti_d:
+       case jit_code_bordi_d:  case jit_code_bunordi_d:
+           mask = jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a2_dbl;
+           break;
+       case jit_code_allocar:  /* synthesized instructions make it
+                                * equivalent to jit_cc_a0_chg */
+       case jit_code_str_c:    case jit_code_str_s:    case jit_code_str_i:
+       case jit_code_str_l:    case jit_code_str_f:    case jit_code_str_d:
+           mask = jit_cc_a0_reg|jit_cc_a1_reg;
+           break;
+       case jit_code_stxi_c:   case jit_code_stxi_s:   case jit_code_stxi_i:
+       case jit_code_stxi_l:   case jit_code_stxi_f:   case jit_code_stxi_d:
+           mask = jit_cc_a0_int|jit_cc_a1_reg|jit_cc_a2_reg;
+           break;
+       case jit_code_bltr:     case jit_code_bltr_u:   case jit_code_bler:
+       case jit_code_bler_u:   case jit_code_beqr:     case jit_code_bger:
+       case jit_code_bger_u:   case jit_code_bgtr:     case jit_code_bgtr_u:
+       case jit_code_bner:     case jit_code_bmsr:     case jit_code_bmcr:
+       case jit_code_bltr_f:   case jit_code_bler_f:   case jit_code_beqr_f:
+       case jit_code_bger_f:   case jit_code_bgtr_f:   case jit_code_bner_f:
+       case jit_code_bunltr_f: case jit_code_bunler_f: case jit_code_buneqr_f:
+       case jit_code_bunger_f: case jit_code_bungtr_f: case jit_code_bltgtr_f:
+       case jit_code_bordr_f:  case jit_code_bunordr_f:case jit_code_bltr_d:
+       case jit_code_bler_d:   case jit_code_beqr_d:   case jit_code_bger_d:
+       case jit_code_bgtr_d:   case jit_code_bner_d:   case jit_code_bunltr_d:
+       case jit_code_bunler_d: case jit_code_buneqr_d: case jit_code_bunger_d:
+       case jit_code_bungtr_d: case jit_code_bltgtr_d: case jit_code_bordr_d:
+       case jit_code_bunordr_d:
+           mask = jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a2_reg;
+           break;
+       case jit_code_boaddi:   case jit_code_boaddi_u: case jit_code_bxaddi:
+       case jit_code_bxaddi_u: case jit_code_bosubi:   case jit_code_bosubi_u:
+       case jit_code_bxsubi:   case jit_code_bxsubi_u:
+           mask = jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a1_chg|jit_cc_a2_int;
+           break;
+       case jit_code_stxr_c:   case jit_code_stxr_s:   case jit_code_stxr_i:
+       case jit_code_stxr_l:   case jit_code_stxr_f:   case jit_code_stxr_d:
+           mask = jit_cc_a0_reg|jit_cc_a1_reg|jit_cc_a2_reg;
+           break;
+       case jit_code_boaddr:   case jit_code_boaddr_u: case jit_code_bxaddr:
+       case jit_code_bxaddr_u: case jit_code_bosubr:   case jit_code_bosubr_u:
+       case jit_code_bxsubr:   case jit_code_bxsubr_u:
+           mask = jit_cc_a0_jmp|jit_cc_a1_reg|jit_cc_a1_chg|jit_cc_a2_reg;
+           break;
+       default:
+           abort();
+    }
+
+    return (mask);
+}
+
+void
+_jit_patch_abs(jit_state_t *_jit, jit_node_t *instr, jit_pointer_t address)
+{
+    jit_int32_t                mask;
+
+    switch (instr->code) {
+       case jit_code_movi:     case jit_code_ldi_c:    case jit_code_ldi_uc:
+       case jit_code_ldi_s:    case jit_code_ldi_us:   case jit_code_ldi_i:
+       case jit_code_ldi_ui:   case jit_code_ldi_l:    case jit_code_ldi_f:
+       case jit_code_ldi_d:
+           instr->v.p = address;
+           break;
+       case jit_code_sti_c:    case jit_code_sti_s:    case jit_code_sti_i:
+       case jit_code_sti_l:    case jit_code_sti_f:    case jit_code_sti_d:
+           instr->u.p = address;
+           break;
+       default:
+           mask = jit_classify(instr->code);
+           assert((mask & (jit_cc_a0_reg|jit_cc_a0_jmp)) == jit_cc_a0_jmp);
+           instr->u.p = address;
+    }
+}
+
+void
+_jit_patch_at(jit_state_t *_jit, jit_node_t *instr, jit_node_t *label)
+{
+    jit_int32_t                mask;
+
+    assert(!(instr->flag & jit_flag_node));
+    instr->flag |= jit_flag_node;
+    switch (instr->code) {
+       case jit_code_movi:
+           assert(label->code == jit_code_label ||
+                  label->code == jit_code_data);
+           instr->v.n = label;
+           if (label->code == jit_code_data)
+               instr->flag |= jit_flag_data;
+           break;
+       case jit_code_jmpi:
+           assert(label->code == jit_code_label ||
+                  label->code == jit_code_epilog);
+           instr->u.n = label;
+           break;
+       default:
+           mask = jit_classify(instr->code);
+           assert((mask & (jit_cc_a0_reg|jit_cc_a0_jmp)) == jit_cc_a0_jmp);
+           assert(label->code == jit_code_label);
+           instr->u.n = label;
+           break;
+    }
+    /* link field is used as list of nodes associated with a given label */
+    instr->link = label->link;
+    label->link = instr;
+}
+
+void
+_jit_optimize(jit_state_t *_jit)
+{
+    jit_bool_t          jump;
+    jit_bool_t          todo;
+    jit_int32_t                 mask;
+    jit_node_t         *node;
+    jit_block_t                *block;
+    jit_word_t          offset;
+
+    _jitc->function = NULL;
+
+    thread_jumps();
+    sequential_labels();
+    split_branches();
+
+    /* create initial mapping of live register values
+     * at the start of a basic block */
+    for (offset = 0; offset < _jitc->blocks.offset; offset++) {
+       block = _jitc->blocks.ptr + offset;
+       if (!block->label)
+           continue;
+       if (block->label->code != jit_code_epilog)
+           jit_setup(block);
+    }
+
+    /* set live state of registers not referenced in a block, but
+     * referenced in a jump target or normal flow */
+    do {
+       todo = 0;
+       for (offset = 0; offset < _jitc->blocks.offset; offset++) {
+           block = _jitc->blocks.ptr + offset;
+           if (!block->label)
+               continue;
+           if (block->label->code != jit_code_epilog)
+               jit_follow(block, &todo);
+       }
+    } while (todo);
+
+    patch_registers();
+    simplify();
+
+    /* figure out labels that are only reached with a jump
+     * and is required to do a simple redundant_store removal
+     * on jit_beqi below */
+    jump = 1;
+    for (node = _jitc->head; node; node = node->next) {
+       switch (node->code) {
+           case jit_code_label:
+               if (!jump)
+                   node->flag |= jit_flag_head;
+               break;
+           case jit_code_jmpi:         case jit_code_jmpr:
+           case jit_code_epilog:
+               jump = 1;
+               break;
+           case jit_code_data:         case jit_code_note:
+               break;
+           default:
+               jump = 0;
+               break;
+       }
+    }
+
+    for (node = _jitc->head; node; node = node->next) {
+       mask = jit_classify(node->code);
+       if (mask & jit_cc_a0_reg)
+           node->u.w &= ~jit_regno_patch;
+       if (mask & jit_cc_a1_reg)
+           node->v.w &= ~jit_regno_patch;
+       if (mask & jit_cc_a2_reg)
+           node->w.w &= ~jit_regno_patch;
+       switch (node->code) {
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               break;
+           case jit_code_epilog:
+               _jitc->function = NULL;
+               break;
+           case jit_code_beqi:
+               redundant_store(node, 1);
+               break;
+           case jit_code_bnei:
+               redundant_store(node, 0);
+               break;
+           default:
+#if JIT_HASH_CONSTS
+               if (mask & jit_cc_a0_flt) {
+                   node->u.p = jit_data(&node->u.f, sizeof(jit_float32_t), 4);
+                   node->flag |= jit_flag_node | jit_flag_data;
+               }
+               else if (mask & jit_cc_a0_dbl) {
+                   node->u.p = jit_data(&node->u.d, sizeof(jit_float64_t), 8);
+                   node->flag |= jit_flag_node | jit_flag_data;
+               }
+               else if (mask & jit_cc_a1_flt) {
+                   node->v.p = jit_data(&node->v.f, sizeof(jit_float32_t), 4);
+                   node->flag |= jit_flag_node | jit_flag_data;
+               }
+               else if (mask & jit_cc_a1_dbl) {
+                   node->v.p = jit_data(&node->v.d, sizeof(jit_float64_t), 8);
+                   node->flag |= jit_flag_node | jit_flag_data;
+               }
+               else if (mask & jit_cc_a2_flt) {
+                   node->w.p = jit_data(&node->w.f, sizeof(jit_float32_t), 4);
+                   node->flag |= jit_flag_node | jit_flag_data;
+               }
+               else if (mask & jit_cc_a2_dbl) {
+                   node->w.p = jit_data(&node->w.d, sizeof(jit_float64_t), 8);
+                   node->flag |= jit_flag_node | jit_flag_data;
+               }
+#endif
+               if (_jitc->function) {
+                   if ((mask & (jit_cc_a0_reg|jit_cc_a0_chg)) ==
+                       (jit_cc_a0_reg|jit_cc_a0_chg)) {
+                       if (mask & jit_cc_a0_rlh) {
+                           jit_regset_setbit(&_jitc->function->regset,
+                                             jit_regno(node->u.q.l));
+                           jit_regset_setbit(&_jitc->function->regset,
+                                             jit_regno(node->u.q.h));
+                       }
+                       else
+                           jit_regset_setbit(&_jitc->function->regset,
+                                             jit_regno(node->u.w));
+                   }
+                   if ((mask & (jit_cc_a1_reg|jit_cc_a1_chg)) ==
+                       (jit_cc_a1_reg|jit_cc_a1_chg))
+                       jit_regset_setbit(&_jitc->function->regset,
+                                         jit_regno(node->v.w));
+                   if ((mask & (jit_cc_a2_reg|jit_cc_a2_chg)) ==
+                       (jit_cc_a2_reg|jit_cc_a2_chg))
+                       jit_regset_setbit(&_jitc->function->regset,
+                                         jit_regno(node->w.w));
+               }
+               break;
+       }
+    }
+}
+
+void
+_jit_reglive(jit_state_t *_jit, jit_node_t *node)
+{
+    jit_int32_t                 spec;
+    jit_int32_t                 value;
+    jit_block_t                *block;
+
+    switch (node->code) {
+       case jit_code_label:    case jit_code_prolog:   case jit_code_epilog:
+           block = _jitc->blocks.ptr + node->v.w;
+           jit_regset_set(&_jitc->reglive, &block->reglive);
+           break;
+       case jit_code_callr:
+           value = jit_regno(node->u.w);
+           if (!(node->u.w & jit_regno_patch)) {
+               jit_regset_setbit(&_jitc->reglive, value);
+           }
+       case jit_code_calli:
+           for (value = 0; value < _jitc->reglen; value++) {
+               spec = jit_class(_rvs[value].spec);
+               if ((spec & jit_class_arg) && jit_regarg_p(node, value))
+                   jit_regset_setbit(&_jitc->reglive, value);
+               else if (!(spec & jit_class_sav))
+                   jit_regset_clrbit(&_jitc->reglive, value);
+           }
+           break;
+       default:
+           value = jit_classify(node->code);
+           if (value & jit_cc_a0_reg) {
+               if (value & jit_cc_a0_rlh) {
+                   if (!(node->u.q.l & jit_regno_patch)) {
+                       if (value & jit_cc_a0_chg) {
+                           jit_regset_clrbit(&_jitc->reglive, node->u.q.l);
+                           jit_regset_setbit(&_jitc->regmask, node->u.q.l);
+                       }
+                       else
+                           jit_regset_setbit(&_jitc->reglive, node->u.q.l);
+                   }
+                   if (!(node->u.q.h & jit_regno_patch)) {
+                       if (value & jit_cc_a0_chg) {
+                           jit_regset_clrbit(&_jitc->reglive, node->u.q.h);
+                           jit_regset_setbit(&_jitc->regmask, node->u.q.h);
+                       }
+                       else
+                           jit_regset_setbit(&_jitc->reglive, node->u.q.h);
+                   }
+               }
+               else {
+                   if (!(node->u.w & jit_regno_patch)) {
+                       if (value & jit_cc_a0_chg) {
+                           jit_regset_clrbit(&_jitc->reglive, node->u.w);
+                           jit_regset_setbit(&_jitc->regmask, node->u.w);
+                       }
+                       else
+                           jit_regset_setbit(&_jitc->reglive, node->u.w);
+                   }
+               }
+           }
+           if ((value & jit_cc_a1_reg) && !(node->v.w & jit_regno_patch)) {
+               if (value & jit_cc_a1_chg) {
+                   jit_regset_clrbit(&_jitc->reglive, node->v.w);
+                   jit_regset_setbit(&_jitc->regmask, node->v.w);
+               }
+               else
+                   jit_regset_setbit(&_jitc->reglive, node->v.w);
+           }
+           if ((value & jit_cc_a2_reg) && !(node->w.w & jit_regno_patch)) {
+               if (value & jit_cc_a2_chg) {
+                   jit_regset_clrbit(&_jitc->reglive, node->w.w);
+                   jit_regset_setbit(&_jitc->regmask, node->w.w);
+               }
+               else
+                   jit_regset_setbit(&_jitc->reglive, node->w.w);
+           }
+           if (jit_regset_set_p(&_jitc->regmask)) {
+               jit_update(node->next, &_jitc->reglive, &_jitc->regmask);
+               if (jit_regset_set_p(&_jitc->regmask)) {
+                   /* any unresolved live state is considered as live */
+                   jit_regset_ior(&_jitc->reglive,
+                                  &_jitc->reglive, &_jitc->regmask);
+                   jit_regset_set_ui(&_jitc->regmask, 0);
+               }
+           }
+           break;
+    }
+}
+
+void
+_jit_regarg_set(jit_state_t *_jit, jit_node_t *node, jit_int32_t value)
+{
+#if GET_JIT_SIZE
+    jit_size_prepare();
+#endif
+    if (value & jit_cc_a0_reg) {
+       if (value & jit_cc_a0_rlh) {
+           jit_regset_setbit(&_jitc->regarg, jit_regno(node->u.q.l));
+           jit_regset_setbit(&_jitc->regarg, jit_regno(node->u.q.h));
+       }
+       else
+           jit_regset_setbit(&_jitc->regarg, jit_regno(node->u.w));
+    }
+    if (value & jit_cc_a1_reg)
+       jit_regset_setbit(&_jitc->regarg, jit_regno(node->v.w));
+    if (value & jit_cc_a2_reg)
+       jit_regset_setbit(&_jitc->regarg, jit_regno(node->w.w));
+}
+
+void
+_jit_regarg_clr(jit_state_t *_jit, jit_node_t *node, jit_int32_t value)
+{
+#if GET_JIT_SIZE
+    jit_size_collect(node);
+#endif
+    if (value & jit_cc_a0_reg) {
+       if (value & jit_cc_a0_rlh) {
+           jit_regset_clrbit(&_jitc->regarg, jit_regno(node->u.q.l));
+           jit_regset_clrbit(&_jitc->regarg, jit_regno(node->u.q.h));
+       }
+       else
+           jit_regset_clrbit(&_jitc->regarg, jit_regno(node->u.w));
+    }
+    if (value & jit_cc_a1_reg)
+       jit_regset_clrbit(&_jitc->regarg, jit_regno(node->v.w));
+    if (value & jit_cc_a2_reg)
+       jit_regset_clrbit(&_jitc->regarg, jit_regno(node->w.w));
+}
+
+void
+_jit_realize(jit_state_t *_jit)
+{
+    assert(!_jitc->realize);
+    if (_jitc->function)
+       jit_epilog();
+    jit_optimize();
+    _jitc->realize = 1;
+
+    /* ensure it is aligned */
+    _jitc->data.offset = (_jitc->data.offset + 7) & -8;
+
+#if GET_JIT_SIZE
+    /* Heuristic to guess code buffer size */
+    _jitc->mult = 4;
+    _jit->code.length = _jitc->pool.length * 1024 * _jitc->mult;
+#else
+    _jit->code.length = jit_get_size();
+#endif
+}
+
+void
+_jit_dataset(jit_state_t *_jit)
+{
+    jit_uint8_t                *ptr;
+    jit_node_t         *node;
+    jit_word_t          offset;
+#if defined(__sgi)
+    int                         mmap_fd;
+#endif
+
+    assert(!_jitc->dataset);
+    if (!_jit->user_data) {
+
+       /* create read only data buffer */
+       _jit->data.length = (_jitc->data.offset +
+                            /* reserve space for annotations */
+                            _jitc->note.size + 4095) & -4096;
+#if defined(__sgi)
+       mmap_fd = open("/dev/zero", O_RDWR);
+#endif
+       _jit->data.ptr = mmap(NULL, _jit->data.length,
+                             PROT_READ | PROT_WRITE,
+                             MAP_PRIVATE | MAP_ANON, mmap_fd, 0);
+       assert(_jit->data.ptr != MAP_FAILED);
+#if defined(__sgi)
+       close(mmap_fd);
+#endif
+    }
+
+    if (!_jitc->no_data)
+       jit_memcpy(_jit->data.ptr, _jitc->data.ptr, _jitc->data.offset);
+
+    if (_jitc->no_note) {
+       /* Space for one note is always allocated, so revert it here
+        * if after jit_new_state was called, it is also requested to
+        * not generate annotation information */
+       _jit->note.length = 0;
+       _jitc->note.size = 0;
+    }
+    else {
+       _jitc->note.base = _jit->data.ptr;
+       if (!_jitc->no_data)
+           _jitc->note.base += _jitc->data.offset;
+       memset(_jitc->note.base, 0, _jitc->note.size);
+    }
+
+    if (_jit->user_data)
+       /* Need the temporary hashed data until jit_emit is finished */
+       ptr = _jitc->no_data ? _jitc->data.ptr : _jit->data.ptr;
+    else {
+       ptr = _jit->data.ptr;
+       /* Temporary hashed data no longer required */
+       jit_free((jit_pointer_t *)&_jitc->data.ptr);
+    }
+
+    for (offset = 0; offset < _jitc->data.size; offset++) {
+       for (node = _jitc->data.table[offset]; node; node = node->next) {
+           node->flag |= jit_flag_patch;
+           node->u.w = (jit_word_t)(ptr + node->u.w);
+       }
+    }
+
+    _jitc->dataset = 1;
+}
+
+jit_pointer_t
+_jit_get_code(jit_state_t *_jit, jit_word_t *length)
+{
+    assert(_jitc->realize);
+    if (length) {
+       if (_jitc->done)
+           /* If code already generated, return exact size of code */
+           *length = _jit->pc.uc - _jit->code.ptr;
+       else
+           /* Else return current size of the code buffer */
+           *length = _jit->code.length;
+    }
+
+    return (_jit->code.ptr);
+}
+
+void
+_jit_set_code(jit_state_t *_jit, jit_pointer_t ptr, jit_word_t length)
+{
+    assert(_jitc->realize);
+    _jit->code.ptr = ptr;
+    _jit->code.length = length;
+    _jit->user_code = 1;
+}
+
+jit_pointer_t
+_jit_get_data(jit_state_t *_jit, jit_word_t *data_size, jit_word_t *note_size)
+{
+    assert(_jitc->realize);
+    if (data_size)
+       *data_size = _jitc->data.offset;
+    if (note_size)
+       *note_size = _jitc->note.size;
+    return (_jit->data.ptr);
+}
+
+void
+_jit_set_data(jit_state_t *_jit, jit_pointer_t ptr,
+             jit_word_t length, jit_word_t flags)
+{
+    assert(_jitc->realize);
+    if (flags & JIT_DISABLE_DATA)
+       _jitc->no_data = 1;
+    else
+       assert(length >= _jitc->data.offset);
+    if (flags & JIT_DISABLE_NOTE)
+       _jitc->no_note = 1;
+    else {
+       if (flags & JIT_DISABLE_DATA)
+           assert(length >= _jitc->note.size);
+       else
+           assert(length >= _jitc->data.offset + _jitc->note.size);
+    }
+    _jit->data.ptr = ptr;
+    _jit->data.length = length;
+    _jit->user_data = 1;
+}
+
+jit_pointer_t
+_jit_emit(jit_state_t *_jit)
+{
+    jit_pointer_t       code;
+    jit_node_t         *node;
+    size_t              length;
+    int                         result;
+#if defined(__sgi)
+    int                         mmap_fd;
+#endif
+
+    if (!_jitc->realize)
+       jit_realize();
+
+    if (!_jitc->dataset)
+       jit_dataset();
+
+    _jitc->emit = 1;
+
+    if (!_jit->user_code) {
+#if defined(__sgi)
+       mmap_fd = open("/dev/zero", O_RDWR);
+#endif
+       _jit->code.ptr = mmap(NULL, _jit->code.length,
+                             PROT_EXEC | PROT_READ | PROT_WRITE,
+                             MAP_PRIVATE | MAP_ANON, mmap_fd, 0);
+       assert(_jit->code.ptr != MAP_FAILED);
+    }
+    _jitc->code.end = _jit->code.ptr + _jit->code.length -
+       jit_get_max_instr();
+    _jit->pc.uc = _jit->code.ptr;
+
+    for (;;) {
+       if ((code = emit_code()) == NULL) {
+           _jitc->patches.offset = 0;
+           for (node = _jitc->head; node; node = node->next) {
+               if (node->link &&
+                   (node->code == jit_code_label ||
+                    node->code == jit_code_epilog))
+                   node->flag &= ~jit_flag_patch;
+           }
+           if (_jit->user_code)
+               goto fail;
+#if GET_JIT_SIZE
+           ++_jitc->mult;
+           length = _jitc->pool.length * 1024 * _jitc->mult;
+#else
+           /* Should only happen on very special cases */
+           length = _jit->code.length + 4096;
+#endif
+
+#if !HAVE_MREMAP
+           munmap(_jit->code.ptr, _jit->code.length);
+#endif
+
+#if HAVE_MREMAP
+#  if __NetBSD__
+           _jit->code.ptr = mremap(_jit->code.ptr, _jit->code.length,
+                                   _jit->code.ptr, length, 0);
+#  else
+           _jit->code.ptr = mremap(_jit->code.ptr, _jit->code.length,
+                                   length, MREMAP_MAYMOVE, NULL);
+#  endif
+#else
+           _jit->code.ptr = mmap(NULL, length,
+                                 PROT_EXEC | PROT_READ | PROT_WRITE,
+                                 MAP_PRIVATE | MAP_ANON, mmap_fd, 0);
+#endif
+
+           assert(_jit->code.ptr != MAP_FAILED);
+           _jit->code.length = length;
+           _jitc->code.end = _jit->code.ptr + _jit->code.length -
+               jit_get_max_instr();
+           _jit->pc.uc = _jit->code.ptr;
+       }
+       else
+           break;
+    }
+
+#if defined(__sgi)
+    if (!_jit->user_code)
+       close(mmap_fd);
+#endif
+
+    _jitc->done = 1;
+    if (!_jitc->no_note)
+       jit_annotate();
+
+    if (_jit->user_data)
+       jit_free((jit_pointer_t *)&_jitc->data.ptr);
+    else {
+       result = mprotect(_jit->data.ptr, _jit->data.length, PROT_READ);
+       assert(result == 0);
+    }
+    if (!_jit->user_code) {
+       result = mprotect(_jit->code.ptr, _jit->code.length,
+                         PROT_READ | PROT_EXEC);
+       assert(result == 0);
+    }
+
+    return (_jit->code.ptr);
+fail:
+    return (NULL);
+}
+
+void
+_jit_frame(jit_state_t *_jit, jit_int32_t frame)
+{
+    jit_trampoline(frame, 1);
+}
+
+void
+_jit_tramp(jit_state_t *_jit, jit_int32_t frame)
+{
+    jit_trampoline(frame, 0);
+}
+
+void
+_jit_trampoline(jit_state_t *_jit, jit_int32_t frame, jit_bool_t prolog)
+{
+    jit_int32_t                regno;
+
+    /* Must be called after prolog, actually, just to simplify
+     * tests and know there is a current function and that
+     * _jitc->function->self.aoff is at the before any alloca value */
+    assert(_jitc->tail && _jitc->tail->code == jit_code_prolog);
+
+    /* + 24 for 3 possible spilled temporaries (that could be a double) */
+    frame += 24;
+#if defined(__hppa__)
+    frame += _jitc->function->self.aoff;
+#else
+    frame -= _jitc->function->self.aoff;
+#endif
+    _jitc->function->frame = frame;
+    if (prolog)
+       _jitc->function->define_frame = 1;
+    else
+       _jitc->function->assume_frame = 1;
+    for (regno = 0; regno < _jitc->reglen; regno++)
+       if (jit_class(_rvs[regno].spec) & jit_class_sav)
+           jit_regset_setbit(&_jitc->function->regset, regno);
+}
+
+/*   Compute initial reglive and regmask set values of a basic block.
+ * reglive is the set of known live registers
+ * regmask is the set of registers not referenced in the block
+ *   Registers in regmask might be live.
+ */
+static void
+_jit_setup(jit_state_t *_jit, jit_block_t *block)
+{
+    jit_node_t         *node;
+    jit_bool_t          live;
+    unsigned long       value;
+
+    jit_regset_set_mask(&block->regmask, _jitc->reglen);
+    for (value = 0; value < _jitc->reglen; ++value)
+       if (!(jit_class(_rvs[value].spec) & (jit_class_gpr|jit_class_fpr)))
+           jit_regset_clrbit(&block->regmask, value);
+
+    for (node = block->label->next; node; node = node->next) {
+       switch (node->code) {
+           case jit_code_label:        case jit_code_prolog:
+           case jit_code_epilog:
+               return;
+           default:
+               /* Check argument registers in reverse order to properly
+                * handle registers that are both, argument and result */
+               value = jit_classify(node->code);
+               if ((value & jit_cc_a2_reg) &&
+                   !(node->w.w & jit_regno_patch) &&
+                   jit_regset_tstbit(&block->regmask, node->w.w)) {
+                   live = !(value & jit_cc_a2_chg);
+                   jit_regset_clrbit(&block->regmask, node->w.w);
+                   if (live)
+                       jit_regset_setbit(&block->reglive, node->w.w);
+               }
+               if ((value & jit_cc_a1_reg) &&
+                   !(node->v.w & jit_regno_patch) &&
+                   jit_regset_tstbit(&block->regmask, node->v.w)) {
+                   live = !(value & jit_cc_a1_chg);
+                   jit_regset_clrbit(&block->regmask, node->v.w);
+                   if (live)
+                       jit_regset_setbit(&block->reglive, node->v.w);
+               }
+               if (value & jit_cc_a0_reg) {
+                   live = !(value & jit_cc_a0_chg);
+                   if (value & jit_cc_a0_rlh) {
+                       if (!(node->u.q.l & jit_regno_patch) &&
+                           jit_regset_tstbit(&block->regmask, node->u.q.l)) {
+                           jit_regset_clrbit(&block->regmask, node->u.q.l);
+                           if (live)
+                               jit_regset_setbit(&block->reglive, node->u.q.l);
+                       }
+                       if (!(node->u.q.h & jit_regno_patch) &&
+                           jit_regset_tstbit(&block->regmask, node->u.q.h)) {
+                           jit_regset_clrbit(&block->regmask, node->u.q.h);
+                           if (live)
+                               jit_regset_setbit(&block->reglive, node->u.q.h);
+                       }
+                   }
+                   else {
+                       if (!(node->u.w & jit_regno_patch) &&
+                           jit_regset_tstbit(&block->regmask, node->u.w)) {
+                           jit_regset_clrbit(&block->regmask, node->u.w);
+                           if (live)
+                               jit_regset_setbit(&block->reglive, node->u.w);
+                       }
+                   }
+               }
+               break;
+       }
+    }
+}
+
+/*  Update regmask and reglive of blocks at entry point of branch targets
+ * or normal flow that have a live register not used in this block.
+ */
+static void
+_jit_follow(jit_state_t *_jit, jit_block_t *block, jit_bool_t *todo)
+{
+    jit_node_t         *node;
+    jit_block_t                *next;
+    jit_int32_t                 spec;
+    jit_int32_t                 regno;
+    unsigned long       value;
+    jit_node_t         *label;
+    jit_regset_t        reglive;
+    jit_regset_t        regmask;
+    jit_regset_t        regtemp;
+
+    jit_regset_set(&reglive, &block->reglive);
+    jit_regset_set(&regmask, &block->regmask);
+    for (node = block->label->next; node; node = node->next) {
+       switch (node->code) {
+           case jit_code_label:
+               /*  Do not consider jmpi and jmpr cannot jump to the
+                * next instruction. */
+               next = _jitc->blocks.ptr + node->v.w;
+               /*  Set of live registers in next block that are at unknown
+                * state in this block. */
+               jit_regset_and(&regtemp, &regmask, &next->reglive);
+               if (jit_regset_set_p(&regtemp)) {
+                   /*  Add live state of next block to current block. */
+                   jit_regset_ior(&block->reglive, &block->reglive, &regtemp);
+                   /*  Remove from unknown state bitmask. */
+                   jit_regset_com(&regtemp, &regtemp);
+                   jit_regset_and(&block->regmask, &block->regmask, &regtemp);
+                   *todo = 1;
+               }
+           case jit_code_prolog:
+           case jit_code_epilog:
+               return;
+           case jit_code_callr:
+               value = jit_regno(node->u.w);
+               if (!(node->u.w & jit_regno_patch)) {
+                   if (jit_regset_tstbit(&regmask, value)) {
+                       jit_regset_clrbit(&regmask, value);
+                       jit_regset_setbit(&reglive, value);
+                   }
+               }
+           case jit_code_calli:
+               for (value = 0; value < _jitc->reglen; ++value) {
+                   value = jit_regset_scan1(&regmask, value);
+                   if (value >= _jitc->reglen)
+                       break;
+                   spec = jit_class(_rvs[value].spec);
+                   if (!(spec & jit_class_sav))
+                       jit_regset_clrbit(&regmask, value);
+                   if ((spec & jit_class_arg) && jit_regarg_p(node, value))
+                       jit_regset_setbit(&reglive, value);
+               }
+               break;
+           default:
+               value = jit_classify(node->code);
+               if (value & jit_cc_a2_reg) {
+                   if (!(node->w.w & jit_regno_patch)) {
+                       if (jit_regset_tstbit(&regmask, node->w.w)) {
+                           jit_regset_clrbit(&regmask, node->w.w);
+                           if (!(value & jit_cc_a2_chg))
+                               jit_regset_setbit(&reglive, node->w.w);
+                       }
+                   }
+               }
+               if (value & jit_cc_a1_reg) {
+                   if (!(node->v.w & jit_regno_patch)) {
+                       if (jit_regset_tstbit(&regmask, node->v.w)) {
+                           jit_regset_clrbit(&regmask, node->v.w);
+                           if (!(value & jit_cc_a1_chg))
+                               jit_regset_setbit(&reglive, node->v.w);
+                       }
+                   }
+               }
+               if (value & jit_cc_a0_reg) {
+                   if (value & jit_cc_a0_rlh) {
+                       if (!(node->u.q.l & jit_regno_patch)) {
+                           if (jit_regset_tstbit(&regmask, node->u.q.l)) {
+                               jit_regset_clrbit(&regmask, node->u.q.l);
+                               if (!(value & jit_cc_a0_chg))
+                                   jit_regset_setbit(&reglive, node->u.q.l);
+                           }
+                       }
+                       if (!(node->u.q.h & jit_regno_patch)) {
+                           if (jit_regset_tstbit(&regmask, node->u.q.h)) {
+                               jit_regset_clrbit(&regmask, node->u.q.h);
+                               if (!(value & jit_cc_a0_chg))
+                                   jit_regset_setbit(&reglive, node->u.q.h);
+                           }
+                       }
+                   }
+                   else {
+                       if (!(node->u.w & jit_regno_patch)) {
+                           if (jit_regset_tstbit(&regmask, node->u.w)) {
+                               jit_regset_clrbit(&regmask, node->u.w);
+                               if (!(value & jit_cc_a0_chg))
+                                   jit_regset_setbit(&reglive, node->u.w);
+                           }
+                       }
+                   }
+               }
+               if (value & jit_cc_a0_jmp) {
+                   if (node->flag & jit_flag_node) {
+                       label = node->u.n;
+                       /*  Do not consider jmpi and jmpr cannot jump to the
+                        * next instruction. */
+                       next = _jitc->blocks.ptr + label->v.w;
+                       jit_regset_and(&regtemp, &regmask, &next->reglive);
+                       if (jit_regset_set_p(&regtemp)) {
+                           /* Add live state. */
+                           jit_regset_ior(&block->reglive,
+                                          &block->reglive, &regtemp);
+                           /*  Remove from unknown state bitmask. */
+                           jit_regset_com(&regtemp, &regtemp);
+                           jit_regset_and(&block->regmask,
+                                          &block->regmask, &regtemp);
+                           *todo = 1;
+                       }
+                   }
+                   else {
+                       /*   Jump to unknown location.
+                        *   This is a pitfall of the implementation.
+                        *   Only jmpi to not a jit code should reach here,
+                        * or a jmpr of a computed address.
+                        *   Because the implementation needs jit_class_nospill
+                        * registers, must treat jmpr as a function call. This
+                        * means that only JIT_Vn registers can be trusted on
+                        * arrival of jmpr.
+                        */
+                       for (regno = 0; regno < _jitc->reglen; regno++) {
+                           spec = jit_class(_rvs[regno].spec);
+                           if (jit_regset_tstbit(&regmask, regno) &&
+                               (spec & (jit_class_gpr|jit_class_fpr)) &&
+                               !(spec & jit_class_sav))
+                               jit_regset_clrbit(&regmask, regno);
+                       }
+                       /*   Assume non callee save registers are live due
+                        * to jump to unknown location. */
+                       /* Treat all callee save as live. */
+                       jit_regset_ior(&reglive, &reglive, &regmask);
+                       /* Treat anything else as dead. */
+                       jit_regset_set_ui(&regmask, 0);
+                   }
+               }
+               break;
+       }
+    }
+}
+
+/*  Follow code generation up to finding a label or end of code.
+ *  When finding a label, update the set of live registers.
+ *  On branches, update based on taken branch or normal flow.
+ */
+static void
+_jit_update(jit_state_t *_jit, jit_node_t *node,
+           jit_regset_t *live, jit_regset_t *mask)
+{
+    jit_int32_t                 spec;
+    jit_int32_t                 regno;
+    unsigned long       value;
+    jit_block_t                *block;
+    jit_node_t         *label;
+    jit_regset_t        regtemp;
+
+    for (; node; node = node->next) {
+       if (jit_regset_set_p(mask) == 0)
+           break;
+       switch (node->code) {
+           case jit_code_label:
+               block = _jitc->blocks.ptr + node->v.w;
+               jit_regset_and(&regtemp, mask, &block->reglive);
+               if (jit_regset_set_p(&regtemp)) {
+                   /* Add live state. */
+                   jit_regset_ior(live, live, &regtemp);
+                   /*  Remove from unknown state bitmask. */
+                   jit_regset_com(&regtemp, &regtemp);
+                   jit_regset_and(mask, mask, &regtemp);
+               }
+               return;
+           case jit_code_prolog:
+               jit_regset_set_ui(mask, 0);
+               return;
+           case jit_code_epilog:
+               jit_regset_set_ui(mask, 0);
+               return;
+           case jit_code_callr:
+               value = jit_regno(node->u.w);
+               if (!(node->u.w & jit_regno_patch)) {
+                   if (jit_regset_tstbit(mask, value)) {
+                       jit_regset_clrbit(mask, value);
+                       jit_regset_setbit(live, value);
+                   }
+               }
+           case jit_code_calli:
+               for (value = 0; value < _jitc->reglen; ++value) {
+                   value = jit_regset_scan1(mask, value);
+                   if (value >= _jitc->reglen)
+                       break;
+                   spec = jit_class(_rvs[value].spec);
+                   if (!(spec & jit_class_sav))
+                       jit_regset_clrbit(mask, value);
+                   if ((spec & jit_class_arg) && jit_regarg_p(node, value))
+                       jit_regset_setbit(live, value);
+               }
+               break;
+           default:
+               value = jit_classify(node->code);
+               if (value & jit_cc_a2_reg) {
+                   if (!(node->w.w & jit_regno_patch)) {
+                       if (jit_regset_tstbit(mask, node->w.w)) {
+                           jit_regset_clrbit(mask, node->w.w);
+                           if (!(value & jit_cc_a2_chg))
+                               jit_regset_setbit(live, node->w.w);
+                       }
+                   }
+               }
+               if (value & jit_cc_a1_reg) {
+                   if (!(node->v.w & jit_regno_patch)) {
+                       if (jit_regset_tstbit(mask, node->v.w)) {
+                           jit_regset_clrbit(mask, node->v.w);
+                           if (!(value & jit_cc_a1_chg))
+                               jit_regset_setbit(live, node->v.w);
+                       }
+                   }
+               }
+               if (value & jit_cc_a0_reg) {
+                   if (value & jit_cc_a0_rlh) {
+                       if (!(node->u.q.l & jit_regno_patch)) {
+                           if (jit_regset_tstbit(mask, node->u.q.l)) {
+                               jit_regset_clrbit(mask, node->u.q.l);
+                               if (!(value & jit_cc_a0_chg))
+                                   jit_regset_setbit(live, node->u.q.l);
+                           }
+                       }
+                       if (!(node->u.q.h & jit_regno_patch)) {
+                           if (jit_regset_tstbit(mask, node->u.q.h)) {
+                               jit_regset_clrbit(mask, node->u.q.h);
+                               if (!(value & jit_cc_a0_chg))
+                                   jit_regset_setbit(live, node->u.q.h);
+                           }
+                       }
+                   }
+                   else {
+                       if (!(node->u.w & jit_regno_patch)) {
+                           if (jit_regset_tstbit(mask, node->u.w)) {
+                               jit_regset_clrbit(mask, node->u.w);
+                               if (!(value & jit_cc_a0_chg))
+                                   jit_regset_setbit(live, node->u.w);
+                           }
+                       }
+                   }
+               }
+               if (value & jit_cc_a0_jmp) {
+                   if (node->flag & jit_flag_node) {
+                       label = node->u.n;
+                       /*  Do not consider jmpi and jmpr cannot jump to the
+                        * next instruction. */
+                       block = _jitc->blocks.ptr + label->v.w;
+                       jit_regset_and(&regtemp, mask, &block->reglive);
+                       if (jit_regset_set_p(&regtemp)) {
+                           /* Add live state. */
+                           jit_regset_ior(live, live, &regtemp);
+                           /*  Remove from unknown state bitmask. */
+                           jit_regset_com(&regtemp, &regtemp);
+                           jit_regset_and(mask, mask, &regtemp);
+                       }
+                   }
+                   else {
+                       /*   Jump to unknown location.
+                        *   This is a pitfall of the implementation.
+                        *   Only jmpi to not a jit code should reach here,
+                        * or a jmpr of a computed address.
+                        *   Because the implementation needs jit_class_nospill
+                        * registers, must treat jmpr as a function call. This
+                        * means that only JIT_Vn registers can be trusted on
+                        * arrival of jmpr.
+                        */
+                       for (regno = 0; regno < _jitc->reglen; regno++) {
+                           spec = jit_class(_rvs[regno].spec);
+                           if (jit_regset_tstbit(mask, regno) &&
+                               (spec & (jit_class_gpr|jit_class_fpr)) &&
+                               !(spec & jit_class_sav))
+                               jit_regset_clrbit(mask, regno);
+                       }
+                       /*   Assume non callee save registers are live due
+                        * to jump to unknown location. */
+                       /* Treat all callee save as live. */
+                       jit_regset_ior(live, live, mask);
+                       /* Treat anything else as dead. */
+                       jit_regset_set_ui(mask, 0);
+                   }
+               }
+               break;
+       }
+    }
+}
+
+static void
+_thread_jumps(jit_state_t *_jit)
+{
+    jit_node_t         *prev;
+    jit_node_t         *node;
+    jit_node_t         *next;
+    jit_int32_t                 mask;
+
+    for (prev = node = _jitc->head; node;) {
+       next = node->next;
+       switch (node->code) {
+           case jit_code_jmpi:
+               if (redundant_jump(prev, node)) {
+                   node = prev;
+                   continue;
+               }
+               if (shortcut_jump(prev, node))
+                   continue;
+               break;
+           case jit_code_jmpr:
+           case jit_code_callr:        case jit_code_calli:
+               /* non optimizable jump like code */
+               break;
+           default:
+               mask = jit_classify(node->code);
+               if (mask & jit_cc_a0_jmp) {
+                   if (reverse_jump(prev, node) ||
+                       shortcut_jump(prev, node))
+                       continue;
+               }
+               break;
+       }
+       prev = node;
+       node = next;
+    }
+}
+
+static void
+_sequential_labels(jit_state_t *_jit)
+{
+    jit_node_t         *jump;
+    jit_node_t         *link;
+    jit_node_t         *prev;
+    jit_node_t         *next;
+    jit_node_t         *node;
+
+    for (prev = node = _jitc->head; node; node = next) {
+       next = node->next;
+       if (node->code == jit_code_label) {
+           if (!node->flag) {
+               if (!node->link) {
+                   del_label(prev, node);
+                   continue;
+               }
+               if (prev != node && prev->code == jit_code_label) {
+                   if ((jump = node->link)) {
+                       for (; jump; jump = link) {
+                           link = jump->link;
+                           jump->u.n = prev;
+                           jump->link = prev->link;
+                           prev->link = jump;
+                       }
+                       node->link = NULL;
+                   }
+                   del_label(prev, node);
+                   continue;
+               }
+           }
+           if (next && next->code == jit_code_label && !next->flag) {
+               if ((jump = next->link)) {
+                   for (; jump; jump = link) {
+                       link = jump->link;
+                       jump->u.n = node;
+                       jump->link = node->link;
+                       node->link = jump;
+                   }
+                   next->link = NULL;
+               }
+               del_label(node, next);
+               next = node->next;
+               continue;
+           }
+       }
+       prev = node;
+    }
+}
+
+static void
+_split_branches(jit_state_t *_jit)
+{
+    jit_node_t         *node;
+    jit_node_t         *next;
+    jit_node_t         *label;
+    jit_block_t                *block;
+
+    for (node = _jitc->head; node; node = next) {
+       if ((next = node->next)) {
+           if (next->code == jit_code_label ||
+               next->code == jit_code_prolog ||
+               next->code == jit_code_epilog)
+               continue;
+           /* split block on branches */
+           if (jit_classify(node->code) & jit_cc_a0_jmp) {
+               label = new_node(jit_code_label);
+               label->next = next;
+               node->next = label;
+               if (_jitc->blocks.offset >= _jitc->blocks.length) {
+                   jit_word_t    length;
+
+                   length = _jitc->blocks.length + 16;
+                   jit_realloc((jit_pointer_t *)&_jitc->blocks.ptr,
+                               _jitc->blocks.length * sizeof(jit_block_t),
+                               length * sizeof(jit_block_t));
+                   _jitc->blocks.length = length;
+               }
+               block = _jitc->blocks.ptr + _jitc->blocks.offset;
+               block->label = label;
+               label->v.w = _jitc->blocks.offset;
+               jit_regset_new(&block->reglive);
+               jit_regset_new(&block->regmask);
+               ++_jitc->blocks.offset;
+           }
+       }
+    }
+}
+
+static jit_bool_t
+_shortcut_jump(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node)
+{
+    jit_bool_t          cond;
+    jit_node_t         *jump;
+    jit_node_t         *next;
+    jit_node_t         *temp;
+
+    if (!(node->flag & jit_flag_node))
+       return (0);
+    assert(node->code != jit_code_jmpr);
+    cond = node->code != jit_code_jmpi;
+    jump = node->u.n;
+    for (next = jump->next; next; next = next->next) {
+       switch (next->code) {
+           case jit_code_jmpi:
+               if (!(next->flag & jit_flag_node))
+                   return (0);
+               if (jump->link == node)
+                   jump->link = node->link;
+               else {
+                   for (temp = jump->link;
+                        temp->link != node;
+                        temp = temp->link)
+                       assert(temp != NULL);
+                   temp->link = node->link;
+               }
+               jump = next->u.n;
+               node->u.n = jump;
+               node->link = jump->link;
+               jump->link = node;
+               return (1);
+           case jit_code_jmpr:
+               if (cond)
+                   return (0);
+               node->code = jit_code_jmpr;
+               node->u.w = next->u.w;
+               node->link = NULL;
+               node->flag &= ~jit_flag_node;
+               return (1);
+           case jit_code_note:         case jit_code_label:
+               break;
+           default:
+               return (0);
+       }
+    }
+    return (0);
+}
+
+static jit_bool_t
+_redundant_jump(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node)
+{
+    jit_node_t         *local_prev;
+    jit_node_t         *local_next;
+
+    if (!(node->flag & jit_flag_node))
+       return (0);
+    for (local_prev = node, local_next = node->next;
+        local_next;
+        local_prev = local_next, local_next = local_next->next) {
+
+       switch (local_next->code) {
+           case jit_code_label:        case jit_code_epilog:
+               if (node->u.n == local_next) {
+                   if (local_next->link == node)
+                       local_next->link = node->link;
+                   else {
+                       for (local_prev = local_next->link;
+                            local_prev->link != node;
+                            local_prev = local_prev->link)
+                           assert(local_prev != NULL);
+                       local_prev->link = node->link;
+                   }
+                   del_node(prev, node);
+                   return (1);
+               }
+               break;
+           case jit_code_name:         case jit_code_note:
+           case jit_code_align:
+               break;
+           default:
+               return (0);
+       }
+    }
+    return (0);
+}
+
+static jit_code_t
+reverse_jump_code(jit_code_t code)
+{
+    switch (code) {
+       case jit_code_bltr:     return (jit_code_bger);
+       case jit_code_blti:     return (jit_code_bgei);
+       case jit_code_bltr_u:   return (jit_code_bger_u);
+       case jit_code_blti_u:   return (jit_code_bgei_u);
+       case jit_code_bler:     return (jit_code_bgtr);
+       case jit_code_blei:     return (jit_code_bgti);
+       case jit_code_bler_u:   return (jit_code_bgtr_u);
+       case jit_code_blei_u:   return (jit_code_bgti_u);
+       case jit_code_beqr:     return (jit_code_bner);
+       case jit_code_beqi:     return (jit_code_bnei);
+       case jit_code_bger:     return (jit_code_bltr);
+       case jit_code_bgei:     return (jit_code_blti);
+       case jit_code_bger_u:   return (jit_code_bltr_u);
+       case jit_code_bgei_u:   return (jit_code_blti_u);
+       case jit_code_bgtr:     return (jit_code_bler);
+       case jit_code_bgti:     return (jit_code_blei);
+       case jit_code_bgtr_u:   return (jit_code_bler_u);
+       case jit_code_bgti_u:   return (jit_code_blei_u);
+       case jit_code_bner:     return (jit_code_beqr);
+       case jit_code_bnei:     return (jit_code_beqi);
+       case jit_code_bmsr:     return (jit_code_bmcr);
+       case jit_code_bmsi:     return (jit_code_bmci);
+       case jit_code_bmcr:     return (jit_code_bmsr);
+       case jit_code_bmci:     return (jit_code_bmsi);
+       case jit_code_bltr_f:   return (jit_code_bunger_f);
+       case jit_code_blti_f:   return (jit_code_bungei_f);
+       case jit_code_bler_f:   return (jit_code_bungtr_f);
+       case jit_code_blei_f:   return (jit_code_bungti_f);
+
+       case jit_code_beqr_f:   return (jit_code_bner_f);
+       case jit_code_beqi_f:   return (jit_code_bnei_f);
+
+       case jit_code_bger_f:   return (jit_code_bunltr_f);
+       case jit_code_bgei_f:   return (jit_code_bunlti_f);
+       case jit_code_bgtr_f:   return (jit_code_bunler_f);
+       case jit_code_bgti_f:   return (jit_code_bunlei_f);
+
+       case jit_code_bner_f:   return (jit_code_beqr_f);
+       case jit_code_bnei_f:   return (jit_code_beqr_f);
+
+       case jit_code_bunltr_f: return (jit_code_bger_f);
+       case jit_code_bunlti_f: return (jit_code_bgei_f);
+       case jit_code_bunler_f: return (jit_code_bgtr_f);
+       case jit_code_bunlei_f: return (jit_code_bgti_f);
+
+       case jit_code_buneqr_f: return (jit_code_bltgtr_f);
+       case jit_code_buneqi_f: return (jit_code_bltgti_f);
+
+       case jit_code_bunger_f: return (jit_code_bltr_f);
+       case jit_code_bungei_f: return (jit_code_blti_f);
+       case jit_code_bungtr_f: return (jit_code_bler_f);
+       case jit_code_bungti_f: return (jit_code_blei_f);
+
+       case jit_code_bltgtr_f: return (jit_code_buneqr_f);
+       case jit_code_bltgti_f: return (jit_code_buneqi_f);
+
+       case jit_code_bordr_f:  return (jit_code_bunordr_f);
+       case jit_code_bordi_f:  return (jit_code_bunordi_f);
+       case jit_code_bunordr_f:return (jit_code_bordr_f);
+       case jit_code_bunordi_f:return (jit_code_bordi_f);
+       case jit_code_bltr_d:   return (jit_code_bunger_d);
+       case jit_code_blti_d:   return (jit_code_bungei_d);
+       case jit_code_bler_d:   return (jit_code_bungtr_d);
+       case jit_code_blei_d:   return (jit_code_bungti_d);
+
+       case jit_code_beqr_d:   return (jit_code_bner_d);
+       case jit_code_beqi_d:   return (jit_code_bnei_d);
+
+       case jit_code_bger_d:   return (jit_code_bunltr_d);
+       case jit_code_bgei_d:   return (jit_code_bunlti_d);
+       case jit_code_bgtr_d:   return (jit_code_bunler_d);
+       case jit_code_bgti_d:   return (jit_code_bunlei_d);
+
+       case jit_code_bner_d:   return (jit_code_beqr_d);
+       case jit_code_bnei_d:   return (jit_code_beqi_d);
+
+       case jit_code_bunltr_d: return (jit_code_bger_d);
+       case jit_code_bunlti_d: return (jit_code_bgei_d);
+       case jit_code_bunler_d: return (jit_code_bgtr_d);
+       case jit_code_bunlei_d: return (jit_code_bgti_d);
+
+       case jit_code_buneqr_d: return (jit_code_bltgtr_d);
+       case jit_code_buneqi_d: return (jit_code_bltgti_d);
+
+       case jit_code_bunger_d: return (jit_code_bltr_d);
+       case jit_code_bungei_d: return (jit_code_blti_d);
+       case jit_code_bungtr_d: return (jit_code_bler_d);
+       case jit_code_bungti_d: return (jit_code_blei_d);
+
+       case jit_code_bltgtr_d: return (jit_code_buneqr_d);
+       case jit_code_bltgti_d: return (jit_code_buneqi_d);
+
+       case jit_code_bordr_d:  return (jit_code_bunordr_d);
+       case jit_code_bordi_d:  return (jit_code_bunordi_d);
+       case jit_code_bunordr_d:return (jit_code_bordr_d);
+       case jit_code_bunordi_d:return (jit_code_bordi_d);
+       case jit_code_boaddr:   return (jit_code_bxaddr);
+       case jit_code_boaddi:   return (jit_code_bxaddi);
+       case jit_code_boaddr_u: return (jit_code_bxaddr_u);
+       case jit_code_boaddi_u: return (jit_code_bxaddi_u);
+       case jit_code_bxaddr:   return (jit_code_boaddr);
+       case jit_code_bxaddi:   return (jit_code_boaddi);
+       case jit_code_bxaddr_u: return (jit_code_boaddr_u);
+       case jit_code_bxaddi_u: return (jit_code_boaddi_u);
+       case jit_code_bosubr:   return (jit_code_bxsubr);
+       case jit_code_bosubi:   return (jit_code_bxsubi);
+       case jit_code_bosubr_u: return (jit_code_bxsubr_u);
+       case jit_code_bosubi_u: return (jit_code_bxsubi_u);
+       case jit_code_bxsubr:   return (jit_code_bosubr);
+       case jit_code_bxsubi:   return (jit_code_bosubi);
+       case jit_code_bxsubr_u: return (jit_code_bosubr_u);
+       case jit_code_bxsubi_u: return (jit_code_bosubi_u);
+       default:                abort();        /* invalid jump code */
+    }
+}
+
+/*
+ * change common pattern:
+ *     <cond_jump L0> <jump L1> <label L0>
+ * into
+ *     <reverse_cond_jump L1>
+ */
+static jit_bool_t
+_reverse_jump(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node)
+{
+    jit_node_t         *local_prev;
+    jit_node_t         *local_next;
+    jit_node_t         *local_jump;
+
+    if (!(node->flag & jit_flag_node))
+       return (0);
+    /* =><cond_jump L0> <jump L1> <label L0> */
+    local_next = node->next;
+    if (local_next->code != jit_code_jmpi ||
+       !(local_next->flag & jit_flag_node))
+       return (0);
+    /* <cond_jump L0> =><jump L1> <label L0> */
+
+    local_jump = local_next->u.n;
+    for (local_prev = local_next, local_next = local_next->next;
+        local_next;
+        local_prev = local_next, local_next = local_next->next) {
+       switch (local_next->code) {
+           case jit_code_label:        case jit_code_epilog:
+               if (node->u.n == local_next) {
+                   if (local_next->link == node)
+                       local_next->link = node->link;
+                   else {
+                       for (local_prev = local_next->link;
+                            local_prev->link != node;
+                            local_prev = local_prev->link)
+                           assert(local_prev != NULL);
+                       local_prev->link = node->link;
+                   }
+                   del_node(node, node->next);
+                   node->code = reverse_jump_code(node->code);
+                   node->u.n = local_jump;
+                   node->link = local_jump->link;
+                   local_jump->link = node;
+                   return (1);
+               }
+               break;
+           case jit_code_note:
+               break;
+           default:
+               return (0);
+       }
+    }
+    return (0);
+}
+
+static void
+_redundant_store(jit_state_t *_jit, jit_node_t *node, jit_bool_t jump)
+{
+    jit_node_t         *iter;
+    jit_node_t         *prev;
+    jit_word_t          word;
+    jit_int32_t                 spec;
+    jit_int32_t                 regno;
+
+    if (jump) {
+       prev = node->u.n;
+       if (prev->code == jit_code_epilog)
+           return;
+       assert(prev->code == jit_code_label);
+       if ((prev->flag & jit_flag_head) || node->link || prev->link != node)
+           /* multiple sources */
+           return;
+       /* if there are sequential labels it will return below */
+    }
+    else
+       prev = node;
+    word = node->w.w;
+    regno = jit_regno(node->v.w);
+    for (iter = prev->next; iter; prev = iter, iter = iter->next) {
+       switch (iter->code) {
+           case jit_code_label:        case jit_code_prolog:
+           case jit_code_epilog:
+               return;
+           case jit_code_movi:
+               if (regno == jit_regno(iter->u.w)) {
+                   if (iter->flag || iter->v.w != word)
+                       return;
+                   del_node(prev, iter);
+                   iter = prev;
+               }
+               break;
+           default:
+               spec = jit_classify(iter->code);
+               if (spec & jit_cc_a0_jmp)
+                   return;
+               if ((spec & (jit_cc_a0_reg|jit_cc_a0_chg)) ==
+                   (jit_cc_a0_reg|jit_cc_a0_chg)) {
+                   if (spec & jit_cc_a0_rlh) {
+                       if (regno == jit_regno(iter->u.q.l) ||
+                           regno == jit_regno(iter->u.q.h))
+                           return;
+                   }
+                   else {
+                       if (regno == jit_regno(iter->u.w))
+                           return;
+                   }
+               }
+               if ((spec & (jit_cc_a1_reg|jit_cc_a1_chg)) ==
+                   (jit_cc_a1_reg|jit_cc_a1_chg)) {
+                   if (regno == jit_regno(iter->v.w))
+                       return;
+               }
+               if ((spec & (jit_cc_a2_reg|jit_cc_a2_chg)) ==
+                   (jit_cc_a2_reg|jit_cc_a2_chg)) {
+                   if (regno == jit_regno(iter->w.w))
+                       return;
+               }
+               break;
+       }
+    }
+}
+
+static jit_bool_t
+_simplify_movr(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node,
+              jit_int32_t kind, jit_int32_t size)
+{
+    jit_int32_t                 regno;
+    jit_int32_t                 right;
+    jit_value_t                *value;
+
+    regno = jit_regno(node->u.w);
+    right = jit_regno(node->v.w);
+    value = _jitc->values + regno;
+    if ((value->kind == jit_kind_register &&
+        jit_regno(value->base.q.l) == right &&
+        value->base.q.h == _jitc->gen[right]) ||
+       (value->kind == kind && _jitc->values[right].kind == kind &&
+        memcmp(&value->base.w, &_jitc->values[right].base.w, size) == 0)) {
+       del_node(prev, node);
+       return (1);
+    }
+    if (_jitc->values[right].kind == jit_kind_word)
+       jit_memcpy(value, _jitc->values + right, sizeof(jit_value_t));
+    else {
+       value->kind = jit_kind_register;
+       value->base.q.l = right;
+       value->base.q.h = _jitc->gen[right];
+    }
+    ++_jitc->gen[regno];
+
+    return (0);
+}
+
+static jit_bool_t
+_simplify_movi(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node,
+              jit_int32_t kind, jit_int32_t size)
+{
+    jit_value_t                *value;
+    jit_int32_t                 spec;
+    jit_int32_t                 regno;
+    jit_int32_t                 offset;
+
+    regno = jit_regno(node->u.w);
+    value = _jitc->values + regno;
+    if (node->flag & jit_flag_node) {
+       /* set to undefined if value will be patched */
+       value->kind = 0;
+       ++_jitc->gen[regno];
+       return (0);
+    }
+    if (value->kind == kind) {
+       if (memcmp(&node->v.w, &value->base.w, size) == 0) {
+           del_node(prev, node);
+           return (1);
+       }
+       spec = jit_class(_rvs[regno].spec);
+       if (kind == jit_kind_word)
+           spec &= jit_class_gpr;
+       else
+           spec &= (jit_class_xpr | jit_class_fpr);
+       for (offset = 0; offset < _jitc->reglen; offset++) {
+           if (_jitc->values[offset].kind == kind &&
+               memcmp(&node->v.w, &_jitc->values[offset].base.w, size) == 0 &&
+               (jit_class(_rvs[offset].spec) & spec) == spec) {
+               if (kind == jit_kind_word)
+                   node->code = jit_code_movr;
+               else if (kind == jit_kind_float32)
+                   node->code = jit_code_movr_f;
+               else
+                   node->code = jit_code_movr_d;
+               node->v.w = offset;
+               jit_memcpy(value, _jitc->values + offset, sizeof(jit_value_t));
+               ++_jitc->gen[regno];
+               return (0);
+           }
+       }
+    }
+    value->kind = kind;
+    jit_memcpy(&value->base.w, &node->v.w, size);
+    ++_jitc->gen[regno];
+
+    return (0);
+}
+
+/* simple/safe redundandy test not checking if another register
+ * holds the same value
+ */
+static jit_bool_t
+_simplify_ldxi(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node)
+{
+    jit_value_t                *value;
+    jit_int32_t                 regno;
+    jit_int32_t                 right;
+
+    regno = jit_regno(node->u.w);
+    right = jit_regno(node->v.w);
+    value = _jitc->values + regno;
+    if (regno != right &&
+       value->kind == jit_kind_code && value->code == node->code &&
+       value->base.q.l == right && value->base.q.h == _jitc->gen[right] &&
+       node->w.w == value->disp.w) {
+       del_node(prev, node);
+       return (1);
+    }
+    value->kind = jit_kind_code;
+    value->code = node->code;
+    value->base.q.l = right;
+    value->base.q.h = _jitc->gen[right];
+    value->disp.w = node->w.w;
+    ++_jitc->gen[regno];
+
+    return (0);
+}
+
+static jit_bool_t
+_simplify_stxi(jit_state_t *_jit, jit_node_t *prev, jit_node_t *node)
+{
+    jit_value_t                *value;
+    jit_int32_t                 regno;
+    jit_int32_t                 right;
+    jit_int32_t                 offset;
+
+    regno = jit_regno(node->w.w);
+    right = jit_regno(node->v.w);
+    value = _jitc->values + regno;
+
+    /* check for redundant store after load */
+    if (regno != right &&
+       value->kind == jit_kind_code && value->code == node->code &&
+       value->base.q.l == right && value->base.q.h == _jitc->gen[right] &&
+       node->u.w == value->disp.w) {
+       del_node(prev, node);
+       return (1);
+    }
+
+    /* assume anything can alias, and invalidate tracked values */
+    for (offset = 0; offset < _jitc->reglen; offset++) {
+       if (_jitc->values[offset].kind == jit_kind_code) {
+           _jitc->values[offset].kind = 0;
+           ++_jitc->gen[offset];
+       }
+    }
+
+    /* no multiple information, so, if set to a constant,
+     * prefer to keep that information */
+    if (value->kind == 0) {
+       value->kind = jit_kind_code;
+       switch (node->code) {
+           /* no information about signed/unsigned either */
+           case jit_code_stxi_c:       value->code = jit_code_ldxi_c;  break;
+           case jit_code_stxi_s:       value->code = jit_code_ldxi_s;  break;
+           case jit_code_stxi_i:       value->code = jit_code_ldxi_i;  break;
+           case jit_code_stxi_l:       value->code = jit_code_ldxi_l;  break;
+           case jit_code_stxi_f:       value->code = jit_code_ldxi_f;  break;
+           case jit_code_stxi_d:       value->code = jit_code_ldxi_d;  break;
+           default:                    abort();
+       }
+       value->kind = jit_kind_code;
+       value->base.q.l = right;
+       value->base.q.h = _jitc->gen[right];
+       value->disp.w = node->u.w;
+    }
+
+    return (0);
+}
+
+/* usually there should be only one store in the
+ * jit_get_reg/jit_unget_reg, but properly handle
+ * multiple ones by moving the save node */
+static void
+_simplify_spill(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    jit_node_t         *save;
+    jit_node_t         *temp;
+
+    if ((temp = _jitc->spill[regno]) && (save = temp->next) != node) {
+       temp->next = save->next;
+       save->next = node->next;
+       node->next = save;
+       _jitc->spill[regno] = node;
+    }
+}
+
+/* checks for simple cases where a register is set more than
+ * once to the same value, and is a common pattern of calls
+ * to jit_pushargi and jit_pushargr
+ */
+static void
+_simplify(jit_state_t *_jit)
+{
+    jit_node_t         *prev;
+    jit_node_t         *node;
+    jit_node_t         *next;
+    jit_int32_t                 info;
+    jit_int32_t                 regno;
+
+    for (prev = NULL, node = _jitc->head; node; prev = node, node = next) {
+       next = node->next;
+       switch (node->code) {
+           case jit_code_label:        case jit_code_prolog:
+           case jit_code_callr:        case jit_code_calli:
+           reset:
+               memset(_jitc->gen, 0, sizeof(jit_int32_t) * _jitc->reglen);
+               memset(_jitc->values, 0, sizeof(jit_value_t) * _jitc->reglen);
+               break;
+           case jit_code_save:
+               _jitc->spill[jit_regno(node->u.w)] = prev;
+               break;
+           case jit_code_load:
+               regno = jit_regno(node->u.w);
+               if (register_change_p(node->link->next, node, regno) !=
+                   jit_reg_change) {
+                   /* spill not required due to optimizing common
+                    * redundancy case of calling jit_get_reg/jit_unget_reg
+                    * and then setting the register to the value it is
+                    * already holding */
+                   patch_register(node->link->next, node,
+                                  jit_regno_patch|regno, regno);
+                   del_node(_jitc->spill[regno], node->link);
+                   del_node(prev, node);
+                   node = prev;
+               }
+               _jitc->spill[regno] = NULL;
+               break;
+           case jit_code_movr:
+               regno = jit_regno(node->u.w);
+               if (simplify_movr(prev, node,
+                                 jit_kind_word, sizeof(jit_word_t)))
+                   simplify_spill(node = prev, regno);
+               break;
+           case jit_code_movi:
+               regno = jit_regno(node->u.w);
+               if (simplify_movi(prev, node,
+                                 jit_kind_word, sizeof(jit_word_t)))
+                   simplify_spill(node = prev, regno);
+               break;
+           case jit_code_movr_f:
+               regno = jit_regno(node->u.w);
+               if (simplify_movr(prev, node,
+                                 jit_kind_float32, sizeof(jit_float32_t)))
+                   simplify_spill(node = prev, regno);
+               break;
+           case jit_code_movi_f:
+               regno = jit_regno(node->u.w);
+               if (simplify_movi(prev, node,
+                                 jit_kind_float32, sizeof(jit_float32_t)))
+                   simplify_spill(node = prev, regno);
+               break;
+           case jit_code_movr_d:
+               regno = jit_regno(node->u.w);
+               if (simplify_movr(prev, node,
+                                 jit_kind_float64, sizeof(jit_float64_t)))
+                   simplify_spill(node = prev, regno);
+               break;
+           case jit_code_movi_d:
+               regno = jit_regno(node->u.w);
+               if (simplify_movi(prev, node,
+                                 jit_kind_float64, sizeof(jit_float64_t)))
+                   simplify_spill(node = prev, regno);
+               break;
+           case jit_code_ldxi_c:       case jit_code_ldxi_uc:
+           case jit_code_ldxi_s:       case jit_code_ldxi_us:
+           case jit_code_ldxi_i:       case jit_code_ldxi_ui:
+           case jit_code_ldxi_l:
+           case jit_code_ldxi_f:       case jit_code_ldxi_d:
+               regno = jit_regno(node->u.w);
+               if (simplify_ldxi(prev, node))
+                   simplify_spill(node = prev, regno);
+               break;
+           case jit_code_stxi_c:       case jit_code_stxi_s:
+           case jit_code_stxi_i:       case jit_code_stxi_l:
+           case jit_code_stxi_f:       case jit_code_stxi_d:
+               regno = jit_regno(node->u.w);
+               if (simplify_stxi(prev, node))
+                   simplify_spill(node = prev, regno);
+               break;
+           default:
+               info = jit_classify(node->code);
+               if (info & jit_cc_a0_jmp)
+                   /* labels are not implicitly added when not taking
+                    * a conditional branch */
+                   goto reset;
+               if (info & jit_cc_a0_chg) {
+                   if (info & jit_cc_a0_rlh) {
+                       regno = jit_regno(node->u.q.l);
+                       _jitc->values[regno].kind = 0;
+                       ++_jitc->gen[regno];
+                       regno = jit_regno(node->u.q.h);
+                       _jitc->values[regno].kind = 0;
+                       ++_jitc->gen[regno];
+                   }
+                   else {
+                       regno = jit_regno(node->u.w);
+                       _jitc->values[regno].kind = 0;
+                       ++_jitc->gen[regno];
+                   }
+               }
+               if (info & jit_cc_a1_chg) {
+                   regno = jit_regno(node->v.w);
+                   _jitc->values[regno].kind = 0;
+                   ++_jitc->gen[regno];
+               }
+               if (info & jit_cc_a2_chg) {
+                   regno = jit_regno(node->w.w);
+                   _jitc->values[regno].kind = 0;
+                   ++_jitc->gen[regno];
+               }
+               break;
+       }
+    }
+}
+
+static jit_int32_t
+_register_change_p(jit_state_t *_jit, jit_node_t *node, jit_node_t *link,
+                  jit_int32_t regno)
+{
+    jit_int32_t                value;
+
+    for (; node != link; node = node->next) {
+       switch (node->code) {
+           case jit_code_label:        case jit_code_prolog:
+               /* lack of extra information so cannot say it is undefined */
+               return (jit_reg_change);
+           case jit_code_callr:        case jit_code_calli:
+               if (!(jit_class(_rvs[regno].spec) & jit_class_sav))
+                   return (jit_reg_undef);
+               break;
+           default:
+               value = jit_classify(node->code);
+               /* lack of extra information */
+               if (value & jit_cc_a0_jmp)
+                   return (jit_reg_change);
+               else if ((value & (jit_cc_a0_reg|jit_cc_a0_chg)) ==
+                        (jit_cc_a0_reg|jit_cc_a0_chg) &&
+                        (((value & jit_cc_a0_rlh) &&
+                          (node->u.q.l == regno || node->u.q.h == regno)) ||
+                         (!(value & jit_cc_a0_rlh) &&
+                          node->u.w == regno)))
+                   return (jit_reg_change);
+               else if ((value & jit_cc_a1_reg) && node->v.w == regno &&
+                        (value & jit_cc_a1_chg))
+                   return (jit_reg_change);
+               else if ((value & jit_cc_a2_reg) && node->w.w == regno &&
+                        (value & jit_cc_a2_chg))
+                   return (jit_reg_change);
+       }
+    }
+
+    return (jit_reg_static);
+}
+
+/* most of this could be done at the same time as generating jit, but
+ * avoid complications on different cpu backends and patch spill/loads
+ * here, by simulating jit generation */
+static jit_bool_t
+_spill_reglive_p(jit_state_t *_jit, jit_node_t *node, jit_int32_t regno)
+{
+    if (!jit_regset_tstbit(&_jitc->reglive, regno)) {
+       jit_regset_setbit(&_jitc->regmask, regno);
+       jit_update(node->next, &_jitc->reglive, &_jitc->regmask);
+       if (!jit_regset_tstbit(&_jitc->reglive, regno) &&
+           register_change_p(node->next, node->link, regno) != jit_reg_change)
+           return (0);
+    }
+
+    return (1);
+}
+
+static void
+_patch_registers(jit_state_t *_jit)
+{
+    jit_node_t         *prev;
+    jit_node_t         *node;
+    jit_node_t         *next;
+    jit_int32_t                 info;
+    jit_int32_t                 spec;
+    jit_int32_t                 regno;
+    jit_int32_t                 value;
+
+    _jitc->function = NULL;
+
+    jit_reglive_setup();
+    for (prev = NULL, node = _jitc->head; node; node = next) {
+       next = node->next;
+
+       info = jit_classify(node->code);
+       jit_regarg_set(node, info);
+
+       switch (node->code) {
+           case jit_code_save:
+               regno = jit_regno(node->u.w);
+               if (!spill_reglive_p(node, regno)) {
+                   /* register is not live, just remove spill/reload */
+                   jit_regarg_clr(node, info);
+                   node->link->v.w = jit_regload_delete;
+                   del_node(prev, node);
+                   continue;
+               }
+               else {
+                   /* try to find a free register of the same class */
+                   spec = jit_class(_rvs[regno].spec) & ~jit_class_arg;
+                   for (value = 0; value < _jitc->reglen; value++) {
+                       if (value != regno &&
+                           ((jit_class(_rvs[value].spec) & spec) &
+                            ~jit_class_arg) == spec &&
+                           !jit_regset_tstbit(&_jitc->regarg, value) &&
+                           !spill_reglive_p(node, value))
+                           break;
+                   }
+                   if (value < _jitc->reglen) {
+                       jit_regarg_clr(node, info);
+                       patch_register(node->next, node->link,
+                                      jit_regno_patch|node->u.w,
+                                      jit_regno_patch|value);
+                       /* mark as live just in case there are nested
+                        * register patches, so that next patch will
+                        * not want to use the same register */
+                       jit_regset_setbit(&_jitc->reglive, value);
+                       /* register is not live, just remove spill/reload */
+                       node->link->v.w = jit_regload_isdead;
+                       del_node(prev, node);
+                       continue;
+                   }
+                   else {
+                       /* failed to find a free register */
+                       if (spec & jit_class_gpr) {
+                           if (!_jitc->function->regoff[regno])
+                               _jitc->function->regoff[regno] =
+                                   jit_allocai(sizeof(jit_word_t));
+#if __WORDSIZE == 32
+                           node->code = jit_code_stxi_i;
+#else
+                           node->code = jit_code_stxi_l;
+#endif
+                       }
+                       else {
+                           node->code = jit_code_stxi_d;
+                           if (!_jitc->function->regoff[regno])
+                               _jitc->function->regoff[regno] =
+                                   jit_allocai(sizeof(jit_float64_t));
+                       }
+                       node->u.w = _jitc->function->regoff[regno];
+                       node->v.w = JIT_FP;
+                       node->w.w = regno;
+                       node->link = NULL;
+                   }
+               }
+               break;
+           case jit_code_load:
+               regno = jit_regno(node->u.w);
+               if (node->v.w) {
+                   if (node->v.w == jit_regload_isdead)
+                       jit_regset_clrbit(&_jitc->reglive, regno);
+                   del_node(prev, node);
+                   continue;
+               }
+               spec = jit_class(_rvs[regno].spec);
+               if (spec & jit_class_gpr) {
+#if __WORDSIZE == 32
+                   node->code = jit_code_ldxi_i;
+#else
+                   node->code = jit_code_ldxi_l;
+#endif
+               }
+               else
+                   node->code = jit_code_ldxi_d;
+               node->v.w = regno;
+               node->v.w = JIT_FP;
+               node->w.w = _jitc->function->regoff[regno];
+               node->link = NULL;
+               break;
+           case jit_code_prolog:
+               _jitc->function = _jitc->functions.ptr + node->w.w;
+               break;
+           case jit_code_epilog:
+               _jitc->function = NULL;
+               break;
+           default:
+               break;
+       }
+
+       jit_regarg_clr(node, info);
+       /* update register live state */
+       jit_reglive(node);
+       prev = node;
+    }
+}
+
+static void
+_patch_register(jit_state_t *_jit, jit_node_t *node, jit_node_t *link,
+               jit_int32_t regno, jit_int32_t patch)
+{
+    jit_int32_t                value;
+
+    for (; node != link; node = node->next) {
+       value = jit_classify(node->code);
+       if (value & jit_cc_a0_reg) {
+           if (value & jit_cc_a0_rlh) {
+               if (node->u.q.l == regno)
+                   node->u.q.l = patch;
+               if (node->u.q.h == regno)
+                   node->u.q.h = patch;
+           }
+           else {
+               if (node->u.w == regno)
+                   node->u.w = patch;
+           }
+       }
+       if ((value & jit_cc_a1_reg) && node->v.w == regno)
+           node->v.w = patch;
+       if ((value & jit_cc_a2_reg) && node->w.w == regno)
+           node->w.w = patch;
+    }
+}
+
+#if defined(__i386__) || defined(__x86_64__)
+#  include "jit_x86.c"
+#elif defined(__mips__)
+#  include "jit_mips.c"
+#elif defined(__arm__)
+#  include "jit_arm.c"
+#elif defined(__powerpc__)
+#  include "jit_ppc.c"
+#elif defined(__sparc__)
+#  include "jit_sparc.c"
+#elif defined(__ia64__)
+#  include "jit_ia64.c"
+#elif defined(__hppa__)
+#  include "jit_hppa.c"
+#elif defined(__aarch64__)
+#  include "jit_aarch64.c"
+#elif defined(__s390__) || defined(__s390x__)
+#  include "jit_s390.c"
+#elif defined(__alpha__)
+#  include "jit_alpha.c"
+#elif defined(__riscv)
+#  include "jit_riscv.c"
+#endif
diff --git a/deps/lightning/lightning.pc.in b/deps/lightning/lightning.pc.in
new file mode 100644 (file)
index 0000000..e13f7c0
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: GNU Lightning
+Description: JIT library
+Version: @VERSION@
+Libs: -L${libdir} -llightning
+Cflags: -I${includedir}/
+
+
diff --git a/deps/lightning/m4/.gitkeep b/deps/lightning/m4/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/deps/lightning/size.c b/deps/lightning/size.c
new file mode 100644 (file)
index 0000000..4e93370
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2013-2019  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU lightning.
+ *
+ * GNU lightning is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU lightning is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ * License for more details.
+ *
+ * Authors:
+ *     Paulo Cesar Pereira de Andrade
+ */
+
+#include <lightning.h>
+#include <lightning/jit_private.h>
+#include <stdio.h>
+#include "lib/jit_names.c"
+
+jit_int16_t    _szs[jit_code_last_code];
+
+int
+main(int argc, char *argv[])
+{
+    FILE               *fp;
+    jit_word_t          offset;
+    int                         code, size, max;
+
+    if ((fp = fopen(JIT_SIZE_PATH, "r")) == NULL)
+       exit(-1);
+    while (fscanf(fp, "%d %d\n", &code, &size) == 2) {
+       if (_szs[code] < size)
+           _szs[code] = size;
+    }
+    fclose(fp);
+
+    max = 0;
+    for (offset = 0; offset < jit_code_last_code; offset++)
+       if (max < _szs[offset])
+           max = _szs[offset];
+
+    if ((fp = fopen(JIT_SIZE_PATH, "w")) == NULL)
+       exit(-1);
+
+
+#if __X64 || __X32
+#  if __X64
+    fprintf(fp, "#if __X64\n");
+#    if __X64_32
+    fprintf(fp, "#  if __X64_32\n");
+#    else
+    fprintf(fp, "#  if !__X64_32\n");
+#    endif
+#  else
+    fprintf(fp, "#if __X32\n");
+#  endif
+#else
+    fprintf(fp, "#if __WORDSIZE == %d\n", __WORDSIZE);
+#endif
+#if defined(__arm__)
+#  if defined(__ARM_PCS_VFP)
+    fprintf(fp, "#if defined(__ARM_PCS_VFP)\n");
+#  else
+    fprintf(fp, "#if !defined(__ARM_PCS_VFP)\n");
+#  endif
+#elif defined(__mips__)
+#  if __WORDSIZE == 32
+#    if NEW_ABI
+    fprintf(fp, "#if NEW_ABI\n");
+#    else
+    fprintf(fp, "#if !NEW_ABI\n");
+#    endif
+#  endif
+#elif defined(__powerpc__)
+    fprintf(fp, "#if defined(__powerpc__)\n");
+    fprintf(fp, "#if __BYTE_ORDER == %s\n",
+           __BYTE_ORDER == __BIG_ENDIAN ? "__BIG_ENDIAN" : "__LITTLE_ENDIAN");
+#  if __WORDSIZE == 32
+    fprintf(fp, "#if %s\n",
+#    if !_CALL_SYSV
+          "!"
+#    endif
+          "_CALL_SYSV"
+          );
+#  endif
+#endif
+    fprintf(fp, "#define JIT_INSTR_MAX %d\n", max);
+    for (offset = 0; offset < jit_code_last_code; offset++)
+       fprintf(fp, "    %d,    /* %s */\n", _szs[offset], code_name[offset]);
+#if defined(__arm__)
+    fprintf(fp, "#endif /* __ARM_PCS_VFP */\n");
+#elif defined(__mips__)
+#  if __WORDSIZE == 32
+    fprintf(fp, "#endif /* NEW_ABI */\n");
+#  endif
+#elif defined(__powerpc__)
+    fprintf(fp, "#endif /* "
+#  if !_CALL_SYSV
+           "!"
+#  endif
+           "_CALL_SYSV"
+           " */\n");
+    fprintf(fp, "#endif /* __BYTE_ORDER */\n");
+    fprintf(fp, "#endif /* __powerpc__ */\n");
+#endif
+#if __X64 || __X32
+#  if __X64
+    fprintf(fp, "#  endif /* __X64_32 */\n");
+    fprintf(fp, "#endif /* __X64 */\n");
+#  else
+    fprintf(fp, "#endif /* __X32 */\n");
+#  endif
+#else
+    fprintf(fp, "#endif /* __WORDSIZE */\n");
+#endif
+
+    fclose(fp);
+
+    return (0);
+}
diff --git a/deps/lightrec/.gitignore b/deps/lightrec/.gitignore
new file mode 100644 (file)
index 0000000..bae14b5
--- /dev/null
@@ -0,0 +1,2 @@
+*.o
+*.so*
diff --git a/deps/lightrec/.gitrepo b/deps/lightrec/.gitrepo
new file mode 100644 (file)
index 0000000..4ebb7d2
--- /dev/null
@@ -0,0 +1,12 @@
+; DO NOT EDIT (unless you know what you are doing)
+;
+; This subdirectory is a git "subrepo", and this file is maintained by the
+; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
+;
+[subrepo]
+       remote = https://github.com/pcercuei/lightrec.git
+       branch = master
+       commit = 2cca097e538876d219b8af9663abe0ca74f68bb2
+       parent = 5c00ea32a0eab812299b08acd14c25bf6ba4ca7a
+       method = merge
+       cmdver = 0.4.1
diff --git a/deps/lightrec/CMakeLists.txt b/deps/lightrec/CMakeLists.txt
new file mode 100644 (file)
index 0000000..c58dac5
--- /dev/null
@@ -0,0 +1,119 @@
+cmake_minimum_required(VERSION 3.0)
+project(lightrec LANGUAGES C VERSION 0.3)
+
+set(BUILD_SHARED_LIBS ON CACHE BOOL "Build shared libraries")
+if (NOT BUILD_SHARED_LIBS)
+       add_definitions(-DLIGHTREC_STATIC)
+endif (NOT BUILD_SHARED_LIBS)
+
+if (NOT LOG_LEVEL)
+       set(LOG_LEVEL Info CACHE STRING "Log level" FORCE)
+       set_property(CACHE LOG_LEVEL PROPERTY STRINGS NoLog Error Warning Info Debug)
+endif()
+
+if (NOT CMAKE_BUILD_TYPE)
+       set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING
+               "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel."
+               FORCE)
+       set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS None Debug Release RelWithDebInfo MinSizeRel)
+endif()
+
+string(TOUPPER ${LOG_LEVEL} LIGHTREC_LOG_LEVEL)
+add_definitions(-DLOG_LEVEL=${LIGHTREC_LOG_LEVEL}_L)
+
+if (CMAKE_COMPILER_IS_GNUCC)
+       add_compile_options(-fvisibility=hidden)
+endif()
+
+list(APPEND LIGHTREC_SOURCES
+       blockcache.c
+       disassembler.c
+       emitter.c
+       interpreter.c
+       lightrec.c
+       memmanager.c
+       optimizer.c
+       regcache.c
+)
+list(APPEND LIGHTREC_HEADERS
+       blockcache.h
+       debug.h
+       disassembler.h
+       emitter.h
+       interpreter.h
+       lightrec-private.h
+       lightrec.h
+       memmanager.h
+       optimizer.h
+       recompiler.h
+       regcache.h
+)
+
+option(ENABLE_FIRST_PASS "Run the interpreter as first-pass optimization" ON)
+
+option(ENABLE_THREADED_COMPILER "Enable threaded compiler" ON)
+if (ENABLE_THREADED_COMPILER)
+       list(APPEND LIGHTREC_SOURCES recompiler.c reaper.c)
+
+       if (NOT ENABLE_FIRST_PASS)
+               message(SEND_ERROR "Threaded compiler requires first-pass optimization")
+       endif (NOT ENABLE_FIRST_PASS)
+endif (ENABLE_THREADED_COMPILER)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+add_library(${PROJECT_NAME} ${LIGHTREC_SOURCES} ${LIGHTREC_HEADERS})
+set_target_properties(${PROJECT_NAME} PROPERTIES
+       VERSION ${PROJECT_VERSION}
+       SOVERSION ${PROJECT_VERSION_MAJOR}
+       PUBLIC_HEADER lightrec.h
+       C_STANDARD 11
+       C_STANDARD_REQUIRED ON
+       C_EXTENSIONS OFF
+)
+
+option(ENABLE_TINYMM "Enable optional libtinymm dependency" OFF)
+if (ENABLE_TINYMM)
+       find_library(TINYMM_LIBRARIES tinymm REQUIRED)
+       find_path(TINYMM_INCLUDE_DIR tinymm.h REQUIRED)
+
+       include_directories(${TINYMM_INCLUDE_DIR})
+       target_link_libraries(${PROJECT_NAME} PRIVATE ${TINYMM_LIBRARIES})
+endif (ENABLE_TINYMM)
+
+if (ENABLE_THREADED_COMPILER)
+       find_library(PTHREAD_LIBRARIES pthread REQUIRED)
+       find_path(PTHREAD_INCLUDE_DIR pthread.h REQUIRED)
+
+       include_directories(${PTHREAD_INCLUDE_DIR})
+       target_link_libraries(${PROJECT_NAME} PRIVATE ${PTHREAD_LIBRARIES})
+endif (ENABLE_THREADED_COMPILER)
+
+find_library(LIBLIGHTNING lightning REQUIRED)
+find_path(LIBLIGHTNING_INCLUDE_DIR lightning.h REQUIRED)
+
+include_directories(${LIBLIGHTNING_INCLUDE_DIR})
+target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBLIGHTNING})
+
+if (LOG_LEVEL STREQUAL Debug)
+       find_library(LIBOPCODES NAMES opcodes-multiarch opcodes)
+       find_path(LIBOPCODES_INCLUDE_DIR dis-asm.h)
+
+       if (NOT LIBOPCODES OR NOT LIBOPCODES_INCLUDE_DIR)
+               message(SEND_ERROR "Debug log level requires libopcodes (from binutils) to be installed.")
+       endif ()
+
+       set(ENABLE_DISASSEMBLER ON)
+       include_directories(${LIBOPCODES_INCLUDE_DIR})
+       target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBOPCODES})
+endif()
+
+configure_file(config.h.cmakein config.h @ONLY)
+
+include(GNUInstallDirs)
+install(TARGETS ${PROJECT_NAME}
+       ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+       LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+       RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+       PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+)
diff --git a/deps/lightrec/COPYING b/deps/lightrec/COPYING
new file mode 100644 (file)
index 0000000..161a3d1
--- /dev/null
@@ -0,0 +1,482 @@
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL.  It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it.  You can use it for
+your libraries, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library.  If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+\f
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software.  To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+  Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs.  This
+license, the GNU Library General Public License, applies to certain
+designated libraries.  This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+  The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it.  Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program.  However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+  Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries.  We
+concluded that weaker conditions might promote sharing better.
+
+  However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves.  This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them.  (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.)  The hope is that this
+will lead to faster development of free libraries.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+  Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+\f
+                 GNU LIBRARY GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License").  Each licensee is
+addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    c) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    d) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+     Appendix: How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+    MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/deps/lightrec/README.md b/deps/lightrec/README.md
new file mode 100644 (file)
index 0000000..40ecc8f
--- /dev/null
@@ -0,0 +1,53 @@
+
+# Lightrec
+
+Lightrec is a MIPS-to-everything dynamic recompiler for
+PlayStation emulators, using
+[GNU Lightning](https://www.gnu.org/software/lightning/)
+as the code emitter.
+
+As such, in theory it should be able to run on every CPU that Lightning
+can generate code for; including, but not limited to, __x86__, __x86_64__,
+__ARM__, __Aarch64__, __MIPS__, __PowerPC__ and __Risc-V__.
+
+## Features
+
+* __High-level optimizations__.  The MIPS code is first pre-compiled into
+a form of Intermediate Representation (IR).
+Basically, just a single-linked list of structures representing the
+instructions. On that list, several optimization steps are performed:
+instructions are modified, reordered, tagged; new meta-instructions
+can be added, for instance to tell the code generator that a certain
+register won't be used anymore.
+
+* __Lazy compilation__.
+If Lightrec detects a block of code that would be very hard to
+compile properly (e.g. a branch with a branch in its delay slot),
+the block is marked as not compilable, and will always be emulated
+with the built-in interpreter. This allows to keep the code emitter
+simple and easy to understand.
+
+* __Run-time profiling__.
+The generated code will gather run-time information about the I/O access
+(whether they hit RAM, or hardware registers).
+The code generator will then use this information to generate direct
+read/writes to the emulated memories, instead of jumping to C for
+every call.
+
+* __Threaded compilation__.
+When entering a loading zone, where a lot of code has to be compiled,
+we don't want the compilation process to slow down the pace of emulation.
+To avoid that, the code compiler optionally runs on a thread, and the
+main loop will emulate the blocks that have not been compiled yet with
+the interpreter. This helps to drastically reduce the stutter that
+typically happens when a lot of new code is run.
+
+## Emulators
+
+Lightrec has been ported to the following emulators:
+
+* [__PCSX-ReArmed__ (my own fork)](https://github.com/pcercuei/pcsx_rearmed)
+
+* [__pcsx4all__ (my own fork)](https://github.com/pcercuei/pcsx4all)
+
+* [__Beetle__ (libretro)](https://github.com/libretro/beetle-psx-libretro/)
\ No newline at end of file
diff --git a/deps/lightrec/blockcache.c b/deps/lightrec/blockcache.c
new file mode 100644 (file)
index 0000000..4263431
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2015-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "blockcache.h"
+#include "debug.h"
+#include "lightrec-private.h"
+#include "memmanager.h"
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+/* Must be power of two */
+#define LUT_SIZE 0x4000
+
+struct blockcache {
+       struct lightrec_state *state;
+       struct block * lut[LUT_SIZE];
+};
+
+struct block * lightrec_find_block(struct blockcache *cache, u32 pc)
+{
+       struct block *block;
+
+       pc = kunseg(pc);
+
+       for (block = cache->lut[(pc >> 2) & (LUT_SIZE - 1)];
+            block; block = block->next)
+               if (kunseg(block->pc) == pc)
+                       return block;
+
+       return NULL;
+}
+
+void remove_from_code_lut(struct blockcache *cache, struct block *block)
+{
+       struct lightrec_state *state = block->state;
+       const struct opcode *op;
+       u32 offset = lut_offset(block->pc);
+
+       /* Use state->get_next_block in the code LUT, which basically
+        * calls back get_next_block_func(), until the compiler
+        * overrides this. This is required, as a NULL value in the code
+        * LUT means an outdated block. */
+       state->code_lut[offset] = state->get_next_block;
+
+       for (op = block->opcode_list; op; op = op->next)
+               if (op->c.i.op == OP_META_SYNC)
+                       state->code_lut[offset + op->offset] = NULL;
+
+}
+
+void lightrec_register_block(struct blockcache *cache, struct block *block)
+{
+       u32 pc = kunseg(block->pc);
+       struct block *old;
+
+       old = cache->lut[(pc >> 2) & (LUT_SIZE - 1)];
+       if (old)
+               block->next = old;
+
+       cache->lut[(pc >> 2) & (LUT_SIZE - 1)] = block;
+
+       remove_from_code_lut(cache, block);
+}
+
+void lightrec_unregister_block(struct blockcache *cache, struct block *block)
+{
+       u32 pc = kunseg(block->pc);
+       struct block *old = cache->lut[(pc >> 2) & (LUT_SIZE - 1)];
+
+       if (old == block) {
+               cache->lut[(pc >> 2) & (LUT_SIZE - 1)] = old->next;
+               return;
+       }
+
+       for (; old; old = old->next) {
+               if (old->next == block) {
+                       old->next = block->next;
+                       return;
+               }
+       }
+
+       pr_err("Block at PC 0x%x is not in cache\n", block->pc);
+}
+
+void lightrec_free_block_cache(struct blockcache *cache)
+{
+       struct block *block, *next;
+       unsigned int i;
+
+       for (i = 0; i < LUT_SIZE; i++) {
+               for (block = cache->lut[i]; block; block = next) {
+                       next = block->next;
+                       lightrec_free_block(block);
+               }
+       }
+
+       lightrec_free(cache->state, MEM_FOR_LIGHTREC, sizeof(*cache), cache);
+}
+
+struct blockcache * lightrec_blockcache_init(struct lightrec_state *state)
+{
+       struct blockcache *cache;
+
+       cache = lightrec_calloc(state, MEM_FOR_LIGHTREC, sizeof(*cache));
+       if (!cache)
+               return NULL;
+
+       cache->state = state;
+
+       return cache;
+}
+
+u32 lightrec_calculate_block_hash(const struct block *block)
+{
+       const struct lightrec_mem_map *map = block->map;
+       u32 pc, hash = 0xffffffff;
+       const u32 *code;
+       unsigned int i;
+
+       pc = kunseg(block->pc) - map->pc;
+
+       while (map->mirror_of)
+               map = map->mirror_of;
+
+       code = map->address + pc;
+
+       /* Jenkins one-at-a-time hash algorithm */
+       for (i = 0; i < block->nb_ops; i++) {
+               hash += *code++;
+               hash += (hash << 10);
+               hash ^= (hash >> 6);
+       }
+
+       hash += (hash << 3);
+       hash ^= (hash >> 11);
+       hash += (hash << 15);
+
+       return hash;
+}
+
+bool lightrec_block_is_outdated(struct block *block)
+{
+       void **lut_entry = &block->state->code_lut[lut_offset(block->pc)];
+       bool outdated;
+
+       if (*lut_entry)
+               return false;
+
+       outdated = block->hash != lightrec_calculate_block_hash(block);
+       if (likely(!outdated)) {
+               /* The block was marked as outdated, but the content is still
+                * the same */
+               if (block->function)
+                       *lut_entry = block->function;
+               else
+                       *lut_entry = block->state->get_next_block;
+       }
+
+       return outdated;
+}
diff --git a/deps/lightrec/blockcache.h b/deps/lightrec/blockcache.h
new file mode 100644 (file)
index 0000000..ff63651
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __BLOCKCACHE_H__
+#define __BLOCKCACHE_H__
+
+#include "lightrec.h"
+
+struct blockcache;
+
+struct block * lightrec_find_block(struct blockcache *cache, u32 pc);
+void lightrec_register_block(struct blockcache *cache, struct block *block);
+void lightrec_unregister_block(struct blockcache *cache, struct block *block);
+
+struct blockcache * lightrec_blockcache_init(struct lightrec_state *state);
+void lightrec_free_block_cache(struct blockcache *cache);
+
+u32 lightrec_calculate_block_hash(const struct block *block);
+_Bool lightrec_block_is_outdated(struct block *block);
+
+#endif /* __BLOCKCACHE_H__ */
diff --git a/deps/lightrec/config.h b/deps/lightrec/config.h
new file mode 100644 (file)
index 0000000..b72ae10
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __LIGHTREC_CONFIG_H__
+#define __LIGHTREC_CONFIG_H__
+
+#define ENABLE_THREADED_COMPILER 1
+#define ENABLE_FIRST_PASS 1
+#define ENABLE_DISASSEMBLER 0
+#define ENABLE_TINYMM 0
+
+#endif /* __LIGHTREC_CONFIG_H__ */
diff --git a/deps/lightrec/config.h.cmakein b/deps/lightrec/config.h.cmakein
new file mode 100644 (file)
index 0000000..1eac007
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __LIGHTREC_CONFIG_H__
+#define __LIGHTREC_CONFIG_H__
+
+#cmakedefine01 ENABLE_THREADED_COMPILER
+#cmakedefine01 ENABLE_FIRST_PASS
+#cmakedefine01 ENABLE_DISASSEMBLER
+#cmakedefine01 ENABLE_TINYMM
+
+#endif /* __LIGHTREC_CONFIG_H__ */
+
diff --git a/deps/lightrec/debug.h b/deps/lightrec/debug.h
new file mode 100644 (file)
index 0000000..4facc22
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define NOLOG_L 0
+#define ERROR_L 1
+#define WARNING_L 2
+#define INFO_L 3
+#define DEBUG_L 4
+
+#ifndef LOG_LEVEL
+#define LOG_LEVEL INFO_L
+#endif
+
+// -------------
+
+#ifndef COLOR_DEBUG
+#define COLOR_DEBUG   "\e[0;32m"
+#endif
+#ifndef COLOR_WARNING
+#define COLOR_WARNING "\e[01;35m"
+#endif
+#ifndef COLOR_ERROR
+#define COLOR_ERROR   "\e[01;31m"
+#endif
+
+#define COLOR_END "\e[0m"
+
+#if (LOG_LEVEL >= DEBUG_L)
+# ifdef COLOR_DEBUG
+#  define pr_debug(str, ...) do {                                      \
+       if (isatty(STDOUT_FILENO))                                      \
+               fprintf(stdout, COLOR_DEBUG "DEBUG: " str COLOR_END,    \
+                       ##__VA_ARGS__);                                 \
+       else                                                            \
+               fprintf(stdout, "DEBUG: " str, ##__VA_ARGS__);          \
+       } while (0)
+# else
+#  define pr_debug(...) \
+    fprintf(stdout, "DEBUG: " __VA_ARGS__)
+# endif
+#else
+#define pr_debug(...)
+#endif
+
+#if (LOG_LEVEL >= INFO_L)
+# ifdef COLOR_INFO
+#  define pr_info(str, ...) \
+    fprintf(stdout, COLOR_INFO str COLOR_END, ##__VA_ARGS__)
+# else
+#  define pr_info(...) \
+    fprintf(stdout, __VA_ARGS__)
+# endif
+#else
+#define pr_info(...)
+#endif
+
+#if (LOG_LEVEL >= WARNING_L)
+# ifdef COLOR_WARNING
+#  define pr_warn(str, ...) do {                                       \
+       if (isatty(STDERR_FILENO))                                      \
+               fprintf(stderr, COLOR_WARNING "WARNING: " str COLOR_END,\
+                       ##__VA_ARGS__);                                 \
+       else                                                            \
+               fprintf(stderr, "WARNING: " str, ##__VA_ARGS__);        \
+       } while (0)
+# else
+#  define pr_warn(...) \
+    fprintf(stderr, "WARNING: " __VA_ARGS__)
+# endif
+#else
+#define pr_warn(...)
+#endif
+
+#if (LOG_LEVEL >= ERROR_L)
+# ifdef COLOR_ERROR
+#  define pr_err(str, ...) do {                                                \
+       if (isatty(STDERR_FILENO))                                      \
+               fprintf(stderr, COLOR_ERROR "ERROR: " str COLOR_END,    \
+                       ##__VA_ARGS__);                                 \
+       else                                                            \
+               fprintf(stderr, "ERROR: " str, ##__VA_ARGS__);          \
+       } while (0)
+# else
+#  define pr_err(...) \
+    fprintf(stderr, "ERROR: " __VA_ARGS__)
+# endif
+#else
+#define pr_err(...)
+#endif
+
+#endif
diff --git a/deps/lightrec/disassembler.c b/deps/lightrec/disassembler.c
new file mode 100644 (file)
index 0000000..06fcec9
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "config.h"
+
+#if ENABLE_DISASSEMBLER
+#include <dis-asm.h>
+#endif
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "debug.h"
+#include "disassembler.h"
+#include "lightrec-private.h"
+#include "memmanager.h"
+
+static bool is_unconditional_jump(const struct opcode *op)
+{
+       switch (op->i.op) {
+       case OP_SPECIAL:
+               return op->r.op == OP_SPECIAL_JR || op->r.op == OP_SPECIAL_JALR;
+       case OP_J:
+       case OP_JAL:
+               return true;
+       case OP_BEQ:
+       case OP_BLEZ:
+               return op->i.rs == op->i.rt;
+       case OP_REGIMM:
+               return (op->r.rt == OP_REGIMM_BGEZ ||
+                       op->r.rt == OP_REGIMM_BGEZAL) && op->i.rs == 0;
+       default:
+               return false;
+       }
+}
+
+static bool is_syscall(const struct opcode *op)
+{
+       return (op->i.op == OP_SPECIAL && (op->r.op == OP_SPECIAL_SYSCALL ||
+                                          op->r.op == OP_SPECIAL_BREAK)) ||
+               (op->i.op == OP_CP0 && (op->r.rs == OP_CP0_MTC0 ||
+                                       op->r.rs == OP_CP0_CTC0) &&
+                (op->r.rd == 12 || op->r.rd == 13));
+}
+
+void lightrec_free_opcode_list(struct lightrec_state *state, struct opcode *list)
+{
+       struct opcode *next;
+
+       while (list) {
+               next = list->next;
+               lightrec_free(state, MEM_FOR_IR, sizeof(*list), list);
+               list = next;
+       }
+}
+
+struct opcode * lightrec_disassemble(struct lightrec_state *state,
+                                    const u32 *src, unsigned int *len)
+{
+       struct opcode *head = NULL;
+       bool stop_next = false;
+       struct opcode *curr, *last;
+       unsigned int i;
+
+       for (i = 0, last = NULL; ; i++, last = curr) {
+               curr = lightrec_calloc(state, MEM_FOR_IR, sizeof(*curr));
+               if (!curr) {
+                       pr_err("Unable to allocate memory\n");
+                       lightrec_free_opcode_list(state, head);
+                       return NULL;
+               }
+
+               if (!last)
+                       head = curr;
+               else
+                       last->next = curr;
+
+               /* TODO: Take care of endianness */
+               curr->opcode = LE32TOH(*src++);
+               curr->offset = i;
+
+               /* NOTE: The block disassembly ends after the opcode that
+                * follows an unconditional jump (delay slot) */
+               if (stop_next || is_syscall(curr))
+                       break;
+               else if (is_unconditional_jump(curr))
+                       stop_next = true;
+       }
+
+       if (len)
+               *len = (i + 1) * sizeof(u32);
+
+       return head;
+}
+
+unsigned int lightrec_cycles_of_opcode(union code code)
+{
+       switch (code.i.op) {
+       case OP_META_REG_UNLOAD:
+       case OP_META_SYNC:
+               return 0;
+       default:
+               return 2;
+       }
+}
+
+#if ENABLE_DISASSEMBLER
+void lightrec_print_disassembly(const struct block *block,
+                               const u32 *code, unsigned int length)
+{
+       struct disassemble_info info;
+       unsigned int i;
+
+       memset(&info, 0, sizeof(info));
+       init_disassemble_info(&info, stdout, (fprintf_ftype) fprintf);
+
+       info.buffer = (bfd_byte *) code;
+       info.buffer_vma = (bfd_vma)(uintptr_t) code;
+       info.buffer_length = length;
+       info.flavour = bfd_target_unknown_flavour;
+       info.arch = bfd_arch_mips;
+       info.mach = bfd_mach_mips3000;
+       disassemble_init_for_target(&info);
+
+       for (i = 0; i < length; i += 4) {
+               void print_insn_little_mips(bfd_vma, struct disassemble_info *);
+               putc('\t', stdout);
+               print_insn_little_mips((bfd_vma)(uintptr_t) code++, &info);
+               putc('\n', stdout);
+       }
+}
+#endif
diff --git a/deps/lightrec/disassembler.h b/deps/lightrec/disassembler.h
new file mode 100644 (file)
index 0000000..249d094
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __DISASSEMBLER_H__
+#define __DISASSEMBLER_H__
+
+#include "debug.h"
+#include "lightrec.h"
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+#define LIGHTREC_DIRECT_IO     (1 << 0)
+#define LIGHTREC_NO_INVALIDATE (1 << 1)
+#define LIGHTREC_NO_DS         (1 << 2)
+#define LIGHTREC_SMC           (1 << 3)
+#define LIGHTREC_EMULATE_BRANCH        (1 << 4)
+#define LIGHTREC_LOCAL_BRANCH  (1 << 5)
+#define LIGHTREC_HW_IO         (1 << 6)
+#define LIGHTREC_MULT32                (1 << 7)
+
+struct block;
+
+enum standard_opcodes {
+       OP_SPECIAL              = 0x00,
+       OP_REGIMM               = 0x01,
+       OP_J                    = 0x02,
+       OP_JAL                  = 0x03,
+       OP_BEQ                  = 0x04,
+       OP_BNE                  = 0x05,
+       OP_BLEZ                 = 0x06,
+       OP_BGTZ                 = 0x07,
+       OP_ADDI                 = 0x08,
+       OP_ADDIU                = 0x09,
+       OP_SLTI                 = 0x0a,
+       OP_SLTIU                = 0x0b,
+       OP_ANDI                 = 0x0c,
+       OP_ORI                  = 0x0d,
+       OP_XORI                 = 0x0e,
+       OP_LUI                  = 0x0f,
+       OP_CP0                  = 0x10,
+       OP_CP2                  = 0x12,
+       OP_LB                   = 0x20,
+       OP_LH                   = 0x21,
+       OP_LWL                  = 0x22,
+       OP_LW                   = 0x23,
+       OP_LBU                  = 0x24,
+       OP_LHU                  = 0x25,
+       OP_LWR                  = 0x26,
+       OP_SB                   = 0x28,
+       OP_SH                   = 0x29,
+       OP_SWL                  = 0x2a,
+       OP_SW                   = 0x2b,
+       OP_SWR                  = 0x2e,
+       OP_LWC2                 = 0x32,
+       OP_SWC2                 = 0x3a,
+
+       OP_META_REG_UNLOAD      = 0x11,
+
+       OP_META_BEQZ            = 0x14,
+       OP_META_BNEZ            = 0x15,
+
+       OP_META_MOV             = 0x16,
+       OP_META_SYNC            = 0x17,
+};
+
+enum special_opcodes {
+       OP_SPECIAL_SLL          = 0x00,
+       OP_SPECIAL_SRL          = 0x02,
+       OP_SPECIAL_SRA          = 0x03,
+       OP_SPECIAL_SLLV         = 0x04,
+       OP_SPECIAL_SRLV         = 0x06,
+       OP_SPECIAL_SRAV         = 0x07,
+       OP_SPECIAL_JR           = 0x08,
+       OP_SPECIAL_JALR         = 0x09,
+       OP_SPECIAL_SYSCALL      = 0x0c,
+       OP_SPECIAL_BREAK        = 0x0d,
+       OP_SPECIAL_MFHI         = 0x10,
+       OP_SPECIAL_MTHI         = 0x11,
+       OP_SPECIAL_MFLO         = 0x12,
+       OP_SPECIAL_MTLO         = 0x13,
+       OP_SPECIAL_MULT         = 0x18,
+       OP_SPECIAL_MULTU        = 0x19,
+       OP_SPECIAL_DIV          = 0x1a,
+       OP_SPECIAL_DIVU         = 0x1b,
+       OP_SPECIAL_ADD          = 0x20,
+       OP_SPECIAL_ADDU         = 0x21,
+       OP_SPECIAL_SUB          = 0x22,
+       OP_SPECIAL_SUBU         = 0x23,
+       OP_SPECIAL_AND          = 0x24,
+       OP_SPECIAL_OR           = 0x25,
+       OP_SPECIAL_XOR          = 0x26,
+       OP_SPECIAL_NOR          = 0x27,
+       OP_SPECIAL_SLT          = 0x2a,
+       OP_SPECIAL_SLTU         = 0x2b,
+};
+
+enum regimm_opcodes {
+       OP_REGIMM_BLTZ          = 0x00,
+       OP_REGIMM_BGEZ          = 0x01,
+       OP_REGIMM_BLTZAL        = 0x10,
+       OP_REGIMM_BGEZAL        = 0x11,
+};
+
+enum cp0_opcodes {
+       OP_CP0_MFC0             = 0x00,
+       OP_CP0_CFC0             = 0x02,
+       OP_CP0_MTC0             = 0x04,
+       OP_CP0_CTC0             = 0x06,
+       OP_CP0_RFE              = 0x10,
+};
+
+enum cp2_opcodes {
+       OP_CP2_BASIC            = 0x00,
+};
+
+enum cp2_basic_opcodes {
+       OP_CP2_BASIC_MFC2       = 0x00,
+       OP_CP2_BASIC_CFC2       = 0x02,
+       OP_CP2_BASIC_MTC2       = 0x04,
+       OP_CP2_BASIC_CTC2       = 0x06,
+};
+
+struct opcode_r {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+       u32 zero :6;
+       u32 rs   :5;
+       u32 rt   :5;
+       u32 rd   :5;
+       u32 imm  :5;
+       u32 op   :6;
+#else
+       u32 op   :6;
+       u32 imm  :5;
+       u32 rd   :5;
+       u32 rt   :5;
+       u32 rs   :5;
+       u32 zero :6;
+#endif
+} __packed;
+
+struct opcode_i {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+       u32 op  :6;
+       u32 rs  :5;
+       u32 rt  :5;
+       u32 imm :16;
+#else
+       u32 imm :16;
+       u32 rt  :5;
+       u32 rs  :5;
+       u32 op  :6;
+#endif
+} __packed;
+
+struct opcode_j {
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+       u32 op  :6;
+       u32 imm :26;
+#else
+       u32 imm :26;
+       u32 op  :6;
+#endif
+} __packed;
+
+union code {
+       /* Keep in sync with struct opcode */
+       u32 opcode;
+       struct opcode_r r;
+       struct opcode_i i;
+       struct opcode_j j;
+};
+
+struct opcode {
+       /* Keep this union at the first position */
+       union {
+               union code c;
+
+               /* Keep in sync with union code */
+               u32 opcode;
+               struct opcode_r r;
+               struct opcode_i i;
+               struct opcode_j j;
+       };
+       u16 flags;
+       u16 offset;
+       struct opcode *next;
+};
+
+struct opcode * lightrec_disassemble(struct lightrec_state *state,
+                                    const u32 *src, unsigned int *len);
+void lightrec_free_opcode_list(struct lightrec_state *state,
+                              struct opcode *list);
+
+unsigned int lightrec_cycles_of_opcode(union code code);
+
+void lightrec_print_disassembly(const struct block *block,
+                               const u32 *code, unsigned int length);
+
+#endif /* __DISASSEMBLER_H__ */
diff --git a/deps/lightrec/emitter.c b/deps/lightrec/emitter.c
new file mode 100644 (file)
index 0000000..0cf75c3
--- /dev/null
@@ -0,0 +1,1578 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "blockcache.h"
+#include "debug.h"
+#include "disassembler.h"
+#include "emitter.h"
+#include "optimizer.h"
+#include "regcache.h"
+
+#include <lightning.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+typedef void (*lightrec_rec_func_t)(const struct block *,
+                                   const struct opcode *, u32);
+
+/* Forward declarations */
+static void rec_SPECIAL(const struct block *block,
+                      const struct opcode *op, u32 pc);
+static void rec_REGIMM(const struct block *block,
+                     const struct opcode *op, u32 pc);
+static void rec_CP0(const struct block *block, const struct opcode *op, u32 pc);
+static void rec_CP2(const struct block *block, const struct opcode *op, u32 pc);
+
+
+static void unknown_opcode(const struct block *block,
+                          const struct opcode *op, u32 pc)
+{
+       pr_warn("Unknown opcode: 0x%08x at PC 0x%08x\n", op->opcode, pc);
+}
+
+static void lightrec_emit_end_of_block(const struct block *block,
+                                      const struct opcode *op, u32 pc,
+                                      s8 reg_new_pc, u32 imm, u8 ra_reg,
+                                      u32 link, bool update_cycles)
+{
+       struct lightrec_state *state = block->state;
+       struct regcache *reg_cache = state->reg_cache;
+       u32 cycles = state->cycles;
+       jit_state_t *_jit = block->_jit;
+
+       jit_note(__FILE__, __LINE__);
+
+       if (link) {
+               /* Update the $ra register */
+               u8 link_reg = lightrec_alloc_reg_out(reg_cache, _jit, ra_reg);
+               jit_movi(link_reg, link);
+               lightrec_free_reg(reg_cache, link_reg);
+       }
+
+       if (reg_new_pc < 0) {
+               reg_new_pc = lightrec_alloc_reg(reg_cache, _jit, JIT_V0);
+               lightrec_lock_reg(reg_cache, _jit, reg_new_pc);
+
+               jit_movi(reg_new_pc, imm);
+       }
+
+       if (has_delay_slot(op->c) &&
+           !(op->flags & (LIGHTREC_NO_DS | LIGHTREC_LOCAL_BRANCH))) {
+               cycles += lightrec_cycles_of_opcode(op->next->c);
+
+               /* Recompile the delay slot */
+               if (op->next->c.opcode)
+                       lightrec_rec_opcode(block, op->next, pc + 4);
+       }
+
+       /* Store back remaining registers */
+       lightrec_storeback_regs(reg_cache, _jit);
+
+       jit_movr(JIT_V0, reg_new_pc);
+
+       if (cycles && update_cycles) {
+               jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, cycles);
+               pr_debug("EOB: %u cycles\n", cycles);
+       }
+
+       if (op->next && ((op->flags & LIGHTREC_NO_DS) || op->next->next))
+               state->branches[state->nb_branches++] = jit_jmpi();
+}
+
+void lightrec_emit_eob(const struct block *block,
+                      const struct opcode *op, u32 pc)
+{
+       struct lightrec_state *state = block->state;
+       struct regcache *reg_cache = state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+
+       lightrec_storeback_regs(reg_cache, _jit);
+
+       jit_movi(JIT_V0, pc);
+       jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE,
+                state->cycles - lightrec_cycles_of_opcode(op->c));
+
+       state->branches[state->nb_branches++] = jit_jmpi();
+}
+
+static void rec_special_JR(const struct block *block,
+                          const struct opcode *op, u32 pc)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rs = lightrec_request_reg_in(reg_cache, _jit, op->r.rs, JIT_V0);
+
+       _jit_name(block->_jit, __func__);
+       lightrec_lock_reg(reg_cache, _jit, rs);
+       lightrec_emit_end_of_block(block, op, pc, rs, 0, 31, 0, true);
+}
+
+static void rec_special_JALR(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rs = lightrec_request_reg_in(reg_cache, _jit, op->r.rs, JIT_V0);
+
+       _jit_name(block->_jit, __func__);
+       lightrec_lock_reg(reg_cache, _jit, rs);
+       lightrec_emit_end_of_block(block, op, pc, rs, 0, op->r.rd, pc + 8, true);
+}
+
+static void rec_J(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       lightrec_emit_end_of_block(block, op, pc, -1,
+                                  (pc & 0xf0000000) | (op->j.imm << 2), 31, 0, true);
+}
+
+static void rec_JAL(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       lightrec_emit_end_of_block(block, op, pc, -1,
+                                  (pc & 0xf0000000) | (op->j.imm << 2),
+                                  31, pc + 8, true);
+}
+
+static void rec_b(const struct block *block, const struct opcode *op, u32 pc,
+                 jit_code_t code, u32 link, bool unconditional, bool bz)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       struct native_register *regs_backup;
+       jit_state_t *_jit = block->_jit;
+       struct lightrec_branch *branch;
+       jit_node_t *addr;
+       u8 link_reg;
+       u32 offset, cycles = block->state->cycles;
+       bool is_forward = (s16)op->i.imm >= -1;
+
+       jit_note(__FILE__, __LINE__);
+
+       if (!(op->flags & LIGHTREC_NO_DS))
+               cycles += lightrec_cycles_of_opcode(op->next->c);
+
+       block->state->cycles = 0;
+
+       if (cycles)
+               jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, cycles);
+
+       if (!unconditional) {
+               u8 rs = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->i.rs),
+                  rt = bz ? 0 : lightrec_alloc_reg_in_ext(reg_cache,
+                                                          _jit, op->i.rt);
+
+               /* Generate the branch opcode */
+               addr = jit_new_node_pww(code, NULL, rs, rt);
+
+               lightrec_free_regs(reg_cache);
+               regs_backup = lightrec_regcache_enter_branch(reg_cache);
+       }
+
+       if (op->flags & LIGHTREC_LOCAL_BRANCH) {
+               if (op->next && !(op->flags & LIGHTREC_NO_DS)) {
+                       /* Recompile the delay slot */
+                       if (op->next->opcode)
+                               lightrec_rec_opcode(block, op->next, pc + 4);
+               }
+
+               if (link) {
+                       /* Update the $ra register */
+                       link_reg = lightrec_alloc_reg_out(reg_cache, _jit, 31);
+                       jit_movi(link_reg, link);
+                       lightrec_free_reg(reg_cache, link_reg);
+               }
+
+               /* Store back remaining registers */
+               lightrec_storeback_regs(reg_cache, _jit);
+
+               offset = op->offset + 1 + (s16)op->i.imm;
+               pr_debug("Adding local branch to offset 0x%x\n", offset << 2);
+               branch = &block->state->local_branches[
+                       block->state->nb_local_branches++];
+
+               branch->target = offset;
+               if (is_forward)
+                       branch->branch = jit_jmpi();
+               else
+                       branch->branch = jit_bgti(LIGHTREC_REG_CYCLE, 0);
+       }
+
+       if (!(op->flags & LIGHTREC_LOCAL_BRANCH) || !is_forward) {
+               lightrec_emit_end_of_block(block, op, pc, -1,
+                                          pc + 4 + ((s16)op->i.imm << 2),
+                                          31, link, false);
+       }
+
+       if (!unconditional) {
+               jit_patch(addr);
+               lightrec_regcache_leave_branch(reg_cache, regs_backup);
+
+               if (bz && link) {
+                       /* Update the $ra register */
+                       link_reg = lightrec_alloc_reg_out_ext(reg_cache,
+                                                             _jit, 31);
+                       jit_movi(link_reg, (s32)link);
+                       lightrec_free_reg(reg_cache, link_reg);
+               }
+
+               if (!(op->flags & LIGHTREC_NO_DS) && op->next->opcode)
+                       lightrec_rec_opcode(block, op->next, pc + 4);
+       }
+}
+
+static void rec_BNE(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_beqr, 0, false, false);
+}
+
+static void rec_BEQ(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_bner, 0,
+                       op->i.rs == op->i.rt, false);
+}
+
+static void rec_BLEZ(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_bgti, 0, op->i.rs == 0, true);
+}
+
+static void rec_BGTZ(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_blei, 0, false, true);
+}
+
+static void rec_regimm_BLTZ(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_bgei, 0, false, true);
+}
+
+static void rec_regimm_BLTZAL(const struct block *block,
+                             const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_bgei, pc + 8, false, true);
+}
+
+static void rec_regimm_BGEZ(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_blti, 0, !op->i.rs, true);
+}
+
+static void rec_regimm_BGEZAL(const struct block *block,
+                             const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_blti, pc + 8, !op->i.rs, true);
+}
+
+static void rec_alu_imm(const struct block *block, const struct opcode *op,
+                       jit_code_t code, bool sign_extend)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rs, rt;
+
+       jit_note(__FILE__, __LINE__);
+       rs = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->i.rs);
+       rt = lightrec_alloc_reg_out_ext(reg_cache, _jit, op->i.rt);
+
+       if (sign_extend)
+               jit_new_node_www(code, rt, rs, (s32)(s16) op->i.imm);
+       else
+               jit_new_node_www(code, rt, rs, (u32)(u16) op->i.imm);
+
+       lightrec_free_reg(reg_cache, rs);
+       lightrec_free_reg(reg_cache, rt);
+}
+
+static void rec_alu_special(const struct block *block, const struct opcode *op,
+                           jit_code_t code, bool out_ext)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rd, rt, rs;
+
+       jit_note(__FILE__, __LINE__);
+       rs = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->r.rs);
+       rt = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->r.rt);
+
+       if (out_ext)
+          rd = lightrec_alloc_reg_out_ext(reg_cache, _jit, op->r.rd);
+       else
+          rd = lightrec_alloc_reg_out(reg_cache, _jit, op->r.rd);
+
+       jit_new_node_www(code, rd, rs, rt);
+
+       lightrec_free_reg(reg_cache, rs);
+       lightrec_free_reg(reg_cache, rt);
+       lightrec_free_reg(reg_cache, rd);
+}
+
+static void rec_alu_shiftv(const struct block *block,
+                          const struct opcode *op, jit_code_t code)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rd, rt, rs, temp;
+
+       jit_note(__FILE__, __LINE__);
+       rs = lightrec_alloc_reg_in(reg_cache, _jit, op->r.rs);
+       temp = lightrec_alloc_reg_temp(reg_cache, _jit);
+
+       if (code == jit_code_rshr) {
+               rt = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->r.rt);
+               rd = lightrec_alloc_reg_out_ext(reg_cache, _jit, op->r.rd);
+       } else {
+               rt = lightrec_alloc_reg_in(reg_cache, _jit, op->r.rt);
+               rd = lightrec_alloc_reg_out(reg_cache, _jit, op->r.rd);
+       }
+
+       jit_andi(temp, rs, 0x1f);
+
+#if __WORDSIZE == 64
+       if (code == jit_code_rshr_u) {
+               jit_extr_ui(rd, rt);
+               jit_new_node_www(code, rd, rd, temp);
+       }
+#endif
+
+       if (__WORDSIZE == 32 || code != jit_code_rshr_u)
+               jit_new_node_www(code, rd, rt, temp);
+
+       lightrec_free_reg(reg_cache, rs);
+       lightrec_free_reg(reg_cache, temp);
+       lightrec_free_reg(reg_cache, rt);
+       lightrec_free_reg(reg_cache, rd);
+}
+
+static void rec_ADDIU(const struct block *block,
+                     const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_imm(block, op, jit_code_addi, true);
+}
+
+static void rec_ADDI(const struct block *block, const struct opcode *op, u32 pc)
+{
+       /* TODO: Handle the exception? */
+       _jit_name(block->_jit, __func__);
+       rec_alu_imm(block, op, jit_code_addi, true);
+}
+
+static void rec_SLTIU(const struct block *block,
+                     const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_imm(block, op, jit_code_lti_u, true);
+}
+
+static void rec_SLTI(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_imm(block, op, jit_code_lti, true);
+}
+
+static void rec_ANDI(const struct block *block, const struct opcode *op, u32 pc)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rs, rt;
+
+       _jit_name(block->_jit, __func__);
+       jit_note(__FILE__, __LINE__);
+       rs = lightrec_alloc_reg_in(reg_cache, _jit, op->i.rs);
+       rt = lightrec_alloc_reg_out_ext(reg_cache, _jit, op->i.rt);
+
+       /* PSX code uses ANDI 0xff / ANDI 0xffff a lot, which are basically
+        * casts to uint8_t / uint16_t. */
+       if (op->i.imm == 0xff)
+               jit_extr_uc(rt, rs);
+       else if (op->i.imm == 0xffff)
+               jit_extr_us(rt, rs);
+       else
+               jit_andi(rt, rs, (u32)(u16) op->i.imm);
+
+       lightrec_free_reg(reg_cache, rs);
+       lightrec_free_reg(reg_cache, rt);
+}
+
+static void rec_ORI(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_imm(block, op, jit_code_ori, false);
+}
+
+static void rec_XORI(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_imm(block, op, jit_code_xori, false);
+}
+
+static void rec_LUI(const struct block *block, const struct opcode *op, u32 pc)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rt;
+
+       jit_name(__func__);
+       jit_note(__FILE__, __LINE__);
+       rt = lightrec_alloc_reg_out_ext(reg_cache, _jit, op->i.rt);
+
+       jit_movi(rt, (s32)(op->i.imm << 16));
+
+       lightrec_free_reg(reg_cache, rt);
+}
+
+static void rec_special_ADDU(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_special(block, op, jit_code_addr, false);
+}
+
+static void rec_special_ADD(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       /* TODO: Handle the exception? */
+       _jit_name(block->_jit, __func__);
+       rec_alu_special(block, op, jit_code_addr, false);
+}
+
+static void rec_special_SUBU(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_special(block, op, jit_code_subr, false);
+}
+
+static void rec_special_SUB(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       /* TODO: Handle the exception? */
+       _jit_name(block->_jit, __func__);
+       rec_alu_special(block, op, jit_code_subr, false);
+}
+
+static void rec_special_AND(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_special(block, op, jit_code_andr, false);
+}
+
+static void rec_special_OR(const struct block *block,
+                          const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_special(block, op, jit_code_orr, false);
+}
+
+static void rec_special_XOR(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_special(block, op, jit_code_xorr, false);
+}
+
+static void rec_special_NOR(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rd;
+
+       jit_name(__func__);
+       rec_alu_special(block, op, jit_code_orr, false);
+       rd = lightrec_alloc_reg_out(reg_cache, _jit, op->r.rd);
+
+       jit_comr(rd, rd);
+
+       lightrec_free_reg(reg_cache, rd);
+}
+
+static void rec_special_SLTU(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_special(block, op, jit_code_ltr_u, true);
+}
+
+static void rec_special_SLT(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_special(block, op, jit_code_ltr, true);
+}
+
+static void rec_special_SLLV(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_shiftv(block, op, jit_code_lshr);
+}
+
+static void rec_special_SRLV(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_shiftv(block, op, jit_code_rshr_u);
+}
+
+static void rec_special_SRAV(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_shiftv(block, op, jit_code_rshr);
+}
+
+static void rec_alu_shift(const struct block *block,
+                         const struct opcode *op, jit_code_t code)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rd, rt;
+
+       jit_note(__FILE__, __LINE__);
+
+       if (code == jit_code_rshi) {
+               rt = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->r.rt);
+               rd = lightrec_alloc_reg_out_ext(reg_cache, _jit, op->r.rd);
+       } else {
+               rt = lightrec_alloc_reg_in(reg_cache, _jit, op->r.rt);
+               rd = lightrec_alloc_reg_out(reg_cache, _jit, op->r.rd);
+       }
+
+#if __WORDSIZE == 64
+       if (code == jit_code_rshi_u) {
+               jit_extr_ui(rd, rt);
+               jit_new_node_www(code, rd, rd, op->r.imm);
+       }
+#endif
+       if (__WORDSIZE == 32 || code != jit_code_rshi_u)
+               jit_new_node_www(code, rd, rt, op->r.imm);
+
+       lightrec_free_reg(reg_cache, rt);
+       lightrec_free_reg(reg_cache, rd);
+}
+
+static void rec_special_SLL(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_shift(block, op, jit_code_lshi);
+}
+
+static void rec_special_SRL(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_shift(block, op, jit_code_rshi_u);
+}
+
+static void rec_special_SRA(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_shift(block, op, jit_code_rshi);
+}
+
+static void rec_alu_mult(const struct block *block,
+                        const struct opcode *op, bool is_signed)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 lo, hi, rs, rt;
+
+       jit_note(__FILE__, __LINE__);
+
+       lo = lightrec_alloc_reg_out(reg_cache, _jit, REG_LO);
+       if (!(op->flags & LIGHTREC_MULT32))
+               hi = lightrec_alloc_reg_out_ext(reg_cache, _jit, REG_HI);
+       else if (__WORDSIZE == 64)
+               hi = lightrec_alloc_reg_temp(reg_cache, _jit);
+
+       if (__WORDSIZE == 32 || !is_signed) {
+               rs = lightrec_alloc_reg_in(reg_cache, _jit, op->r.rs);
+               rt = lightrec_alloc_reg_in(reg_cache, _jit, op->r.rt);
+       } else {
+               rs = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->r.rs);
+               rt = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->r.rt);
+       }
+
+#if __WORDSIZE == 32
+       /* On 32-bit systems, do a 32*32->64 bit operation, or a 32*32->32 bit
+        * operation if the MULT was detected a 32-bit only. */
+       if (!(op->flags & LIGHTREC_MULT32)) {
+               if (is_signed)
+                       jit_qmulr(lo, hi, rs, rt);
+               else
+                       jit_qmulr_u(lo, hi, rs, rt);
+       } else {
+               jit_mulr(lo, rs, rt);
+       }
+#else
+       /* On 64-bit systems, do a 64*64->64 bit operation.
+        * The input registers must be 32 bits, so we first sign-extend (if
+        * mult) or clear (if multu) the input registers. */
+       if (is_signed) {
+               jit_mulr(lo, rs, rt);
+       } else {
+               jit_extr_ui(lo, rt);
+               jit_extr_ui(hi, rs);
+               jit_mulr(lo, hi, lo);
+       }
+
+       /* The 64-bit output value is in $lo, store the upper 32 bits in $hi */
+       if (!(op->flags & LIGHTREC_MULT32))
+               jit_rshi(hi, lo, 32);
+#endif
+
+       lightrec_free_reg(reg_cache, rs);
+       lightrec_free_reg(reg_cache, rt);
+       lightrec_free_reg(reg_cache, lo);
+       if (__WORDSIZE == 64 || !(op->flags & LIGHTREC_MULT32))
+               lightrec_free_reg(reg_cache, hi);
+}
+
+static void rec_alu_div(const struct block *block,
+                       const struct opcode *op, bool is_signed)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       jit_node_t *branch, *to_end;
+       u8 lo, hi, rs, rt;
+
+       jit_note(__FILE__, __LINE__);
+       lo = lightrec_alloc_reg_out(reg_cache, _jit, REG_LO);
+       hi = lightrec_alloc_reg_out(reg_cache, _jit, REG_HI);
+
+       if (__WORDSIZE == 32 || !is_signed) {
+               rs = lightrec_alloc_reg_in(reg_cache, _jit, op->r.rs);
+               rt = lightrec_alloc_reg_in(reg_cache, _jit, op->r.rt);
+       } else {
+               rs = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->r.rs);
+               rt = lightrec_alloc_reg_in_ext(reg_cache, _jit, op->r.rt);
+       }
+
+       /* Jump to special handler if dividing by zero  */
+       branch = jit_beqi(rt, 0);
+
+#if __WORDSIZE == 32
+       if (is_signed)
+               jit_qdivr(lo, hi, rs, rt);
+       else
+               jit_qdivr_u(lo, hi, rs, rt);
+#else
+       /* On 64-bit systems, the input registers must be 32 bits, so we first sign-extend
+        * (if div) or clear (if divu) the input registers. */
+       if (is_signed) {
+               jit_qdivr(lo, hi, rs, rt);
+       } else {
+               jit_extr_ui(lo, rt);
+               jit_extr_ui(hi, rs);
+               jit_qdivr_u(lo, hi, hi, lo);
+       }
+#endif
+
+       /* Jump above the div-by-zero handler */
+       to_end = jit_jmpi();
+
+       jit_patch(branch);
+
+       if (is_signed) {
+               jit_lti(lo, rs, 0);
+               jit_lshi(lo, lo, 1);
+               jit_subi(lo, lo, 1);
+       } else {
+               jit_movi(lo, 0xffffffff);
+       }
+
+       jit_movr(hi, rs);
+
+       jit_patch(to_end);
+
+       lightrec_free_reg(reg_cache, rs);
+       lightrec_free_reg(reg_cache, rt);
+       lightrec_free_reg(reg_cache, lo);
+       lightrec_free_reg(reg_cache, hi);
+}
+
+static void rec_special_MULT(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_mult(block, op, true);
+}
+
+static void rec_special_MULTU(const struct block *block,
+                             const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_mult(block, op, false);
+}
+
+static void rec_special_DIV(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_div(block, op, true);
+}
+
+static void rec_special_DIVU(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_div(block, op, false);
+}
+
+static void rec_alu_mv_lo_hi(const struct block *block, u8 dst, u8 src)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+
+       jit_note(__FILE__, __LINE__);
+       src = lightrec_alloc_reg_in(reg_cache, _jit, src);
+       dst = lightrec_alloc_reg_out_ext(reg_cache, _jit, dst);
+
+#if __WORDSIZE == 32
+       jit_movr(dst, src);
+#else
+       jit_extr_i(dst, src);
+#endif
+
+       lightrec_free_reg(reg_cache, src);
+       lightrec_free_reg(reg_cache, dst);
+}
+
+static void rec_special_MFHI(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_mv_lo_hi(block, op->r.rd, REG_HI);
+}
+
+static void rec_special_MTHI(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_mv_lo_hi(block, REG_HI, op->r.rs);
+}
+
+static void rec_special_MFLO(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_mv_lo_hi(block, op->r.rd, REG_LO);
+}
+
+static void rec_special_MTLO(const struct block *block,
+                            const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_alu_mv_lo_hi(block, REG_LO, op->r.rs);
+}
+
+static void rec_io(const struct block *block, const struct opcode *op,
+                  bool load_rt, bool read_rt)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       bool is_tagged = op->flags & (LIGHTREC_HW_IO | LIGHTREC_DIRECT_IO);
+       u32 offset;
+       u8 tmp, tmp2, tmp3;
+
+       jit_note(__FILE__, __LINE__);
+
+       tmp = lightrec_alloc_reg(reg_cache, _jit, JIT_R0);
+
+       if (is_tagged) {
+               offset = offsetof(struct lightrec_state, rw_func);
+       } else {
+               tmp3 = lightrec_alloc_reg(reg_cache, _jit, JIT_R1);
+               offset = offsetof(struct lightrec_state, rw_generic_func);
+       }
+
+       tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
+       jit_ldxi(tmp2, LIGHTREC_REG_STATE, offset);
+
+       lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rs, false);
+
+       if (read_rt && likely(op->i.rt))
+               lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rt, true);
+       else if (load_rt)
+               lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rt, false);
+
+       if (is_tagged) {
+               jit_movi(tmp, op->opcode);
+       } else {
+               jit_movi(tmp, (uintptr_t)op);
+               jit_movi(tmp3, (uintptr_t)block);
+       }
+
+       jit_callr(tmp2);
+
+       lightrec_free_reg(reg_cache, tmp);
+       lightrec_free_reg(reg_cache, tmp2);
+       if (!is_tagged)
+               lightrec_free_reg(reg_cache, tmp3);
+       lightrec_regcache_mark_live(reg_cache, _jit);
+}
+
+static void rec_store_direct_no_invalidate(const struct block *block,
+                                          const struct opcode *op,
+                                          jit_code_t code)
+{
+       struct lightrec_state *state = block->state;
+       struct regcache *reg_cache = state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       jit_node_t *to_not_ram, *to_end;
+       u8 tmp, tmp2, rs, rt;
+       s16 imm;
+
+       jit_note(__FILE__, __LINE__);
+       rs = lightrec_alloc_reg_in(reg_cache, _jit, op->i.rs);
+       tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
+       tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
+
+       /* Convert to KUNSEG and avoid RAM mirrors */
+       if (state->mirrors_mapped) {
+               imm = (s16)op->i.imm;
+               jit_andi(tmp, rs, 0x1f800000 | (4 * RAM_SIZE - 1));
+       } else if (op->i.imm) {
+               imm = 0;
+               jit_addi(tmp, rs, (s16)op->i.imm);
+               jit_andi(tmp, tmp, 0x1f800000 | (RAM_SIZE - 1));
+       } else {
+               imm = 0;
+               jit_andi(tmp, rs, 0x1f800000 | (RAM_SIZE - 1));
+       }
+
+       lightrec_free_reg(reg_cache, rs);
+
+       if (state->offset_ram != state->offset_scratch) {
+               to_not_ram = jit_bmsi(tmp, BIT(28));
+
+               jit_movi(tmp2, state->offset_ram);
+
+               to_end = jit_jmpi();
+               jit_patch(to_not_ram);
+
+               jit_movi(tmp2, state->offset_scratch);
+               jit_patch(to_end);
+       } else if (state->offset_ram) {
+               jit_movi(tmp2, state->offset_ram);
+       }
+
+       if (state->offset_ram || state->offset_scratch)
+               jit_addr(tmp, tmp, tmp2);
+
+       lightrec_free_reg(reg_cache, tmp2);
+
+       rt = lightrec_alloc_reg_in(reg_cache, _jit, op->i.rt);
+       jit_new_node_www(code, imm, tmp, rt);
+
+       lightrec_free_reg(reg_cache, rt);
+       lightrec_free_reg(reg_cache, tmp);
+}
+
+static void rec_store_direct(const struct block *block, const struct opcode *op,
+                            jit_code_t code)
+{
+       struct lightrec_state *state = block->state;
+       struct regcache *reg_cache = state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       jit_node_t *to_not_ram, *to_end = 0;
+       u8 tmp, tmp2, tmp3, rs, rt;
+
+       jit_note(__FILE__, __LINE__);
+
+       rs = lightrec_alloc_reg_in(reg_cache, _jit, op->i.rs);
+       tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
+       tmp3 = lightrec_alloc_reg_in(reg_cache, _jit, 0);
+
+       /* Convert to KUNSEG and avoid RAM mirrors */
+       if (op->i.imm) {
+               jit_addi(tmp2, rs, (s16)op->i.imm);
+               jit_andi(tmp2, tmp2, 0x1f800000 | (RAM_SIZE - 1));
+       } else {
+               jit_andi(tmp2, rs, 0x1f800000 | (RAM_SIZE - 1));
+       }
+
+       lightrec_free_reg(reg_cache, rs);
+       tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
+
+       to_not_ram = jit_bgti(tmp2, RAM_SIZE);
+
+       /* Compute the offset to the code LUT */
+       jit_andi(tmp, tmp2, (RAM_SIZE - 1) & ~3);
+#if __WORDSIZE == 64
+       jit_lshi(tmp, tmp, 1);
+#endif
+       jit_addr(tmp, LIGHTREC_REG_STATE, tmp);
+
+       /* Write NULL to the code LUT to invalidate any block that's there */
+       jit_stxi(offsetof(struct lightrec_state, code_lut), tmp, tmp3);
+
+       if (state->offset_ram != state->offset_scratch) {
+               jit_movi(tmp, state->offset_ram);
+
+               to_end = jit_jmpi();
+       }
+
+       jit_patch(to_not_ram);
+
+       if (state->offset_ram || state->offset_scratch)
+               jit_movi(tmp, state->offset_scratch);
+
+       if (state->offset_ram != state->offset_scratch)
+               jit_patch(to_end);
+
+       if (state->offset_ram || state->offset_scratch)
+               jit_addr(tmp2, tmp2, tmp);
+
+       lightrec_free_reg(reg_cache, tmp);
+       lightrec_free_reg(reg_cache, tmp3);
+
+       rt = lightrec_alloc_reg_in(reg_cache, _jit, op->i.rt);
+       jit_new_node_www(code, 0, tmp2, rt);
+
+       lightrec_free_reg(reg_cache, rt);
+       lightrec_free_reg(reg_cache, tmp2);
+}
+
+static void rec_store(const struct block *block, const struct opcode *op,
+                    jit_code_t code)
+{
+       if (op->flags & LIGHTREC_NO_INVALIDATE) {
+               rec_store_direct_no_invalidate(block, op, code);
+       } else if (op->flags & LIGHTREC_DIRECT_IO) {
+               if (block->state->invalidate_from_dma_only)
+                       rec_store_direct_no_invalidate(block, op, code);
+               else
+                       rec_store_direct(block, op, code);
+       } else {
+               rec_io(block, op, true, false);
+       }
+}
+
+static void rec_SB(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_store(block, op, jit_code_stxi_c);
+}
+
+static void rec_SH(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_store(block, op, jit_code_stxi_s);
+}
+
+static void rec_SW(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_store(block, op, jit_code_stxi_i);
+}
+
+static void rec_SWL(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_io(block, op, true, false);
+}
+
+static void rec_SWR(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_io(block, op, true, false);
+}
+
+static void rec_SWC2(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_io(block, op, false, false);
+}
+
+static void rec_load_direct(const struct block *block, const struct opcode *op,
+                           jit_code_t code)
+{
+       struct lightrec_state *state = block->state;
+       struct regcache *reg_cache = state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       jit_node_t *to_not_ram, *to_not_bios = 0, *to_end, *to_end2;
+       u8 tmp, rs, rt, addr_reg;
+       s16 imm;
+
+       if (!op->i.rt)
+               return;
+
+       jit_note(__FILE__, __LINE__);
+       rs = lightrec_alloc_reg_in(reg_cache, _jit, op->i.rs);
+       rt = lightrec_alloc_reg_out_ext(reg_cache, _jit, op->i.rt);
+
+       if ((state->offset_ram == state->offset_bios &&
+           state->offset_ram == state->offset_scratch &&
+           state->mirrors_mapped) || !op->i.imm) {
+               addr_reg = rs;
+               imm = (s16)op->i.imm;
+       } else {
+               jit_addi(rt, rs, (s16)op->i.imm);
+               addr_reg = rt;
+               imm = 0;
+
+               if (op->i.rs != op->i.rt)
+                       lightrec_free_reg(reg_cache, rs);
+       }
+
+       tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
+
+       if (state->offset_ram == state->offset_bios &&
+           state->offset_ram == state->offset_scratch) {
+               if (!state->mirrors_mapped) {
+                       jit_andi(tmp, addr_reg, BIT(28));
+                       jit_rshi_u(tmp, tmp, 28 - 22);
+                       jit_ori(tmp, tmp, 0x1f800000 | (RAM_SIZE - 1));
+                       jit_andr(rt, addr_reg, tmp);
+               } else {
+                       jit_andi(rt, addr_reg, 0x1fffffff);
+               }
+
+               if (state->offset_ram)
+                       jit_movi(tmp, state->offset_ram);
+       } else {
+               to_not_ram = jit_bmsi(addr_reg, BIT(28));
+
+               /* Convert to KUNSEG and avoid RAM mirrors */
+               jit_andi(rt, addr_reg, RAM_SIZE - 1);
+
+               if (state->offset_ram)
+                       jit_movi(tmp, state->offset_ram);
+
+               to_end = jit_jmpi();
+
+               jit_patch(to_not_ram);
+
+               if (state->offset_bios != state->offset_scratch)
+                       to_not_bios = jit_bmci(addr_reg, BIT(22));
+
+               /* Convert to KUNSEG */
+               jit_andi(rt, addr_reg, 0x1fc00000 | (BIOS_SIZE - 1));
+
+               jit_movi(tmp, state->offset_bios);
+
+               if (state->offset_bios != state->offset_scratch) {
+                       to_end2 = jit_jmpi();
+
+                       jit_patch(to_not_bios);
+
+                       /* Convert to KUNSEG */
+                       jit_andi(rt, addr_reg, 0x1f800fff);
+
+                       if (state->offset_scratch)
+                               jit_movi(tmp, state->offset_scratch);
+
+                       jit_patch(to_end2);
+               }
+
+               jit_patch(to_end);
+       }
+
+       if (state->offset_ram || state->offset_bios || state->offset_scratch)
+               jit_addr(rt, rt, tmp);
+
+       jit_new_node_www(code, rt, rt, imm);
+
+       lightrec_free_reg(reg_cache, addr_reg);
+       lightrec_free_reg(reg_cache, rt);
+       lightrec_free_reg(reg_cache, tmp);
+}
+
+static void rec_load(const struct block *block, const struct opcode *op,
+                   jit_code_t code)
+{
+       if (op->flags & LIGHTREC_DIRECT_IO)
+               rec_load_direct(block, op, code);
+       else
+               rec_io(block, op, false, true);
+}
+
+static void rec_LB(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_load(block, op, jit_code_ldxi_c);
+}
+
+static void rec_LBU(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_load(block, op, jit_code_ldxi_uc);
+}
+
+static void rec_LH(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_load(block, op, jit_code_ldxi_s);
+}
+
+static void rec_LHU(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_load(block, op, jit_code_ldxi_us);
+}
+
+static void rec_LWL(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_io(block, op, true, true);
+}
+
+static void rec_LWR(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_io(block, op, true, true);
+}
+
+static void rec_LW(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_load(block, op, jit_code_ldxi_i);
+}
+
+static void rec_LWC2(const struct block *block, const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_io(block, op, false, false);
+}
+
+static void rec_break_syscall(const struct block *block,
+                             const struct opcode *op, u32 pc, bool is_break)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u32 offset;
+       u8 tmp;
+
+       jit_note(__FILE__, __LINE__);
+
+       if (is_break)
+               offset = offsetof(struct lightrec_state, break_func);
+       else
+               offset = offsetof(struct lightrec_state, syscall_func);
+
+       tmp = lightrec_alloc_reg_temp(reg_cache, _jit);
+       jit_ldxi(tmp, LIGHTREC_REG_STATE, offset);
+       jit_callr(tmp);
+       lightrec_free_reg(reg_cache, tmp);
+
+       lightrec_regcache_mark_live(reg_cache, _jit);
+
+       /* TODO: the return address should be "pc - 4" if we're a delay slot */
+       lightrec_emit_end_of_block(block, op, pc, -1, pc, 31, 0, true);
+}
+
+static void rec_special_SYSCALL(const struct block *block,
+                               const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_break_syscall(block, op, pc, false);
+}
+
+static void rec_special_BREAK(const struct block *block,
+                             const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_break_syscall(block, op, pc, true);
+}
+
+static void rec_mfc(const struct block *block, const struct opcode *op)
+{
+       u8 tmp, tmp2;
+       struct lightrec_state *state = block->state;
+       struct regcache *reg_cache = state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+
+       jit_note(__FILE__, __LINE__);
+
+       tmp = lightrec_alloc_reg(reg_cache, _jit, JIT_R0);
+       tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
+
+       jit_ldxi(tmp2, LIGHTREC_REG_STATE,
+                offsetof(struct lightrec_state, mfc_func));
+
+       lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rt, true);
+
+       jit_movi(tmp, op->opcode);
+       jit_callr(tmp2);
+       lightrec_free_reg(reg_cache, tmp);
+       lightrec_free_reg(reg_cache, tmp2);
+
+       lightrec_regcache_mark_live(reg_cache, _jit);
+}
+
+static void rec_mtc(const struct block *block, const struct opcode *op, u32 pc)
+{
+       struct lightrec_state *state = block->state;
+       struct regcache *reg_cache = state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 tmp, tmp2;
+
+       jit_note(__FILE__, __LINE__);
+
+       tmp = lightrec_alloc_reg(reg_cache, _jit, JIT_R0);
+       tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
+       jit_ldxi(tmp2, LIGHTREC_REG_STATE,
+                offsetof(struct lightrec_state, mtc_func));
+
+       lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rs, false);
+       lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rt, false);
+
+       jit_movi(tmp, op->opcode);
+       jit_callr(tmp2);
+       lightrec_free_reg(reg_cache, tmp);
+       lightrec_free_reg(reg_cache, tmp2);
+
+       lightrec_regcache_mark_live(reg_cache, _jit);
+
+       if (op->i.op == OP_CP0 && !(op->flags & LIGHTREC_NO_DS) &&
+           (op->r.rd == 12 || op->r.rd == 13))
+               lightrec_emit_end_of_block(block, op, pc, -1, pc + 4, 0, 0, true);
+}
+
+static void rec_cp0_MFC0(const struct block *block,
+                        const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_mfc(block, op);
+}
+
+static void rec_cp0_CFC0(const struct block *block,
+                        const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_mfc(block, op);
+}
+
+static void rec_cp0_MTC0(const struct block *block,
+                        const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_mtc(block, op, pc);
+}
+
+static void rec_cp0_CTC0(const struct block *block,
+                        const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_mtc(block, op, pc);
+}
+
+static void rec_cp2_basic_MFC2(const struct block *block,
+                              const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_mfc(block, op);
+}
+
+static void rec_cp2_basic_CFC2(const struct block *block,
+                              const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_mfc(block, op);
+}
+
+static void rec_cp2_basic_MTC2(const struct block *block,
+                              const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_mtc(block, op, pc);
+}
+
+static void rec_cp2_basic_CTC2(const struct block *block,
+                              const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_mtc(block, op, pc);
+}
+
+static void rec_cp0_RFE(const struct block *block,
+                       const struct opcode *op, u32 pc)
+{
+       struct lightrec_state *state = block->state;
+       jit_state_t *_jit = block->_jit;
+       u8 tmp;
+
+       jit_name(__func__);
+       jit_note(__FILE__, __LINE__);
+
+       tmp = lightrec_alloc_reg_temp(state->reg_cache, _jit);
+       jit_ldxi(tmp, LIGHTREC_REG_STATE,
+                offsetof(struct lightrec_state, rfe_func));
+       jit_callr(tmp);
+       lightrec_free_reg(state->reg_cache, tmp);
+
+       lightrec_regcache_mark_live(state->reg_cache, _jit);
+}
+
+static void rec_CP(const struct block *block, const struct opcode *op, u32 pc)
+{
+       struct regcache *reg_cache = block->state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 tmp, tmp2;
+
+       jit_name(__func__);
+       jit_note(__FILE__, __LINE__);
+
+       tmp = lightrec_alloc_reg(reg_cache, _jit, JIT_R0);
+       tmp2 = lightrec_alloc_reg_temp(reg_cache, _jit);
+
+       jit_ldxi(tmp2, LIGHTREC_REG_STATE,
+                offsetof(struct lightrec_state, cp_func));
+
+       jit_movi(tmp, op->opcode);
+       jit_callr(tmp2);
+       lightrec_free_reg(reg_cache, tmp);
+       lightrec_free_reg(reg_cache, tmp2);
+
+       lightrec_regcache_mark_live(reg_cache, _jit);
+}
+
+static void rec_meta_unload(const struct block *block,
+                           const struct opcode *op, u32 pc)
+{
+       struct lightrec_state *state = block->state;
+       struct regcache *reg_cache = state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+
+       jit_name(__func__);
+       jit_note(__FILE__, __LINE__);
+
+       pr_debug("Unloading reg %s\n", lightrec_reg_name(op->i.rs));
+       lightrec_clean_reg_if_loaded(reg_cache, _jit, op->i.rs, true);
+}
+
+static void rec_meta_BEQZ(const struct block *block,
+                         const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_bnei, 0, false, true);
+}
+
+static void rec_meta_BNEZ(const struct block *block,
+                         const struct opcode *op, u32 pc)
+{
+       _jit_name(block->_jit, __func__);
+       rec_b(block, op, pc, jit_code_beqi, 0, false, true);
+}
+
+static void rec_meta_MOV(const struct block *block,
+                        const struct opcode *op, u32 pc)
+{
+       struct lightrec_state *state = block->state;
+       struct regcache *reg_cache = state->reg_cache;
+       jit_state_t *_jit = block->_jit;
+       u8 rs, rd;
+
+       _jit_name(block->_jit, __func__);
+       jit_note(__FILE__, __LINE__);
+       rs = op->r.rs ? lightrec_alloc_reg_in(reg_cache, _jit, op->r.rs) : 0;
+       rd = lightrec_alloc_reg_out_ext(reg_cache, _jit, op->r.rd);
+
+       if (op->r.rs == 0) {
+               jit_movi(rd, 0);
+       } else {
+#if __WORDSIZE == 32
+               jit_movr(rd, rs);
+#else
+               jit_extr_i(rd, rs);
+#endif
+       }
+
+       lightrec_free_reg(state->reg_cache, rs);
+       lightrec_free_reg(state->reg_cache, rd);
+}
+
+static void rec_meta_sync(const struct block *block,
+                         const struct opcode *op, u32 pc)
+{
+       struct lightrec_state *state = block->state;
+       struct lightrec_branch_target *target;
+       jit_state_t *_jit = block->_jit;
+
+       jit_name(__func__);
+       jit_note(__FILE__, __LINE__);
+
+       jit_subi(LIGHTREC_REG_CYCLE, LIGHTREC_REG_CYCLE, state->cycles);
+       state->cycles = 0;
+
+       lightrec_storeback_regs(state->reg_cache, _jit);
+       lightrec_regcache_reset(state->reg_cache);
+
+       pr_debug("Adding branch target at offset 0x%x\n",
+                op->offset << 2);
+       target = &state->targets[state->nb_targets++];
+       target->offset = op->offset;
+       target->label = jit_indirect();
+}
+
+static const lightrec_rec_func_t rec_standard[64] = {
+       [OP_SPECIAL]            = rec_SPECIAL,
+       [OP_REGIMM]             = rec_REGIMM,
+       [OP_J]                  = rec_J,
+       [OP_JAL]                = rec_JAL,
+       [OP_BEQ]                = rec_BEQ,
+       [OP_BNE]                = rec_BNE,
+       [OP_BLEZ]               = rec_BLEZ,
+       [OP_BGTZ]               = rec_BGTZ,
+       [OP_ADDI]               = rec_ADDI,
+       [OP_ADDIU]              = rec_ADDIU,
+       [OP_SLTI]               = rec_SLTI,
+       [OP_SLTIU]              = rec_SLTIU,
+       [OP_ANDI]               = rec_ANDI,
+       [OP_ORI]                = rec_ORI,
+       [OP_XORI]               = rec_XORI,
+       [OP_LUI]                = rec_LUI,
+       [OP_CP0]                = rec_CP0,
+       [OP_CP2]                = rec_CP2,
+       [OP_LB]                 = rec_LB,
+       [OP_LH]                 = rec_LH,
+       [OP_LWL]                = rec_LWL,
+       [OP_LW]                 = rec_LW,
+       [OP_LBU]                = rec_LBU,
+       [OP_LHU]                = rec_LHU,
+       [OP_LWR]                = rec_LWR,
+       [OP_SB]                 = rec_SB,
+       [OP_SH]                 = rec_SH,
+       [OP_SWL]                = rec_SWL,
+       [OP_SW]                 = rec_SW,
+       [OP_SWR]                = rec_SWR,
+       [OP_LWC2]               = rec_LWC2,
+       [OP_SWC2]               = rec_SWC2,
+
+       [OP_META_REG_UNLOAD]    = rec_meta_unload,
+       [OP_META_BEQZ]          = rec_meta_BEQZ,
+       [OP_META_BNEZ]          = rec_meta_BNEZ,
+       [OP_META_MOV]           = rec_meta_MOV,
+       [OP_META_SYNC]          = rec_meta_sync,
+};
+
+static const lightrec_rec_func_t rec_special[64] = {
+       [OP_SPECIAL_SLL]        = rec_special_SLL,
+       [OP_SPECIAL_SRL]        = rec_special_SRL,
+       [OP_SPECIAL_SRA]        = rec_special_SRA,
+       [OP_SPECIAL_SLLV]       = rec_special_SLLV,
+       [OP_SPECIAL_SRLV]       = rec_special_SRLV,
+       [OP_SPECIAL_SRAV]       = rec_special_SRAV,
+       [OP_SPECIAL_JR]         = rec_special_JR,
+       [OP_SPECIAL_JALR]       = rec_special_JALR,
+       [OP_SPECIAL_SYSCALL]    = rec_special_SYSCALL,
+       [OP_SPECIAL_BREAK]      = rec_special_BREAK,
+       [OP_SPECIAL_MFHI]       = rec_special_MFHI,
+       [OP_SPECIAL_MTHI]       = rec_special_MTHI,
+       [OP_SPECIAL_MFLO]       = rec_special_MFLO,
+       [OP_SPECIAL_MTLO]       = rec_special_MTLO,
+       [OP_SPECIAL_MULT]       = rec_special_MULT,
+       [OP_SPECIAL_MULTU]      = rec_special_MULTU,
+       [OP_SPECIAL_DIV]        = rec_special_DIV,
+       [OP_SPECIAL_DIVU]       = rec_special_DIVU,
+       [OP_SPECIAL_ADD]        = rec_special_ADD,
+       [OP_SPECIAL_ADDU]       = rec_special_ADDU,
+       [OP_SPECIAL_SUB]        = rec_special_SUB,
+       [OP_SPECIAL_SUBU]       = rec_special_SUBU,
+       [OP_SPECIAL_AND]        = rec_special_AND,
+       [OP_SPECIAL_OR]         = rec_special_OR,
+       [OP_SPECIAL_XOR]        = rec_special_XOR,
+       [OP_SPECIAL_NOR]        = rec_special_NOR,
+       [OP_SPECIAL_SLT]        = rec_special_SLT,
+       [OP_SPECIAL_SLTU]       = rec_special_SLTU,
+};
+
+static const lightrec_rec_func_t rec_regimm[64] = {
+       [OP_REGIMM_BLTZ]        = rec_regimm_BLTZ,
+       [OP_REGIMM_BGEZ]        = rec_regimm_BGEZ,
+       [OP_REGIMM_BLTZAL]      = rec_regimm_BLTZAL,
+       [OP_REGIMM_BGEZAL]      = rec_regimm_BGEZAL,
+};
+
+static const lightrec_rec_func_t rec_cp0[64] = {
+       [OP_CP0_MFC0]           = rec_cp0_MFC0,
+       [OP_CP0_CFC0]           = rec_cp0_CFC0,
+       [OP_CP0_MTC0]           = rec_cp0_MTC0,
+       [OP_CP0_CTC0]           = rec_cp0_CTC0,
+       [OP_CP0_RFE]            = rec_cp0_RFE,
+};
+
+static const lightrec_rec_func_t rec_cp2_basic[64] = {
+       [OP_CP2_BASIC_MFC2]     = rec_cp2_basic_MFC2,
+       [OP_CP2_BASIC_CFC2]     = rec_cp2_basic_CFC2,
+       [OP_CP2_BASIC_MTC2]     = rec_cp2_basic_MTC2,
+       [OP_CP2_BASIC_CTC2]     = rec_cp2_basic_CTC2,
+};
+
+static void rec_SPECIAL(const struct block *block,
+                       const struct opcode *op, u32 pc)
+{
+       lightrec_rec_func_t f = rec_special[op->r.op];
+       if (likely(f))
+               (*f)(block, op, pc);
+       else
+               unknown_opcode(block, op, pc);
+}
+
+static void rec_REGIMM(const struct block *block,
+                      const struct opcode *op, u32 pc)
+{
+       lightrec_rec_func_t f = rec_regimm[op->r.rt];
+       if (likely(f))
+               (*f)(block, op, pc);
+       else
+               unknown_opcode(block, op, pc);
+}
+
+static void rec_CP0(const struct block *block, const struct opcode *op, u32 pc)
+{
+       lightrec_rec_func_t f = rec_cp0[op->r.rs];
+       if (likely(f))
+               (*f)(block, op, pc);
+       else
+               rec_CP(block, op, pc);
+}
+
+static void rec_CP2(const struct block *block, const struct opcode *op, u32 pc)
+{
+       if (op->r.op == OP_CP2_BASIC) {
+               lightrec_rec_func_t f = rec_cp2_basic[op->r.rs];
+               if (likely(f)) {
+                       (*f)(block, op, pc);
+                       return;
+               }
+       }
+
+       rec_CP(block, op, pc);
+}
+
+void lightrec_rec_opcode(const struct block *block,
+                        const struct opcode *op, u32 pc)
+{
+       lightrec_rec_func_t f = rec_standard[op->i.op];
+       if (likely(f))
+               (*f)(block, op, pc);
+       else
+               unknown_opcode(block, op, pc);
+}
diff --git a/deps/lightrec/emitter.h b/deps/lightrec/emitter.h
new file mode 100644 (file)
index 0000000..ec3fc78
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __EMITTER_H__
+#define __EMITTER_H__
+
+#include "lightrec.h"
+
+struct block;
+struct opcode;
+
+void lightrec_rec_opcode(const struct block *block,
+                        const struct opcode *op, u32 pc);
+void lightrec_emit_eob(const struct block *block,
+                      const struct opcode *op, u32 pc);
+
+#endif /* __EMITTER_H__ */
diff --git a/deps/lightrec/interpreter.c b/deps/lightrec/interpreter.c
new file mode 100644 (file)
index 0000000..ff609a4
--- /dev/null
@@ -0,0 +1,1138 @@
+/*
+ * Copyright (C) 2019-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "disassembler.h"
+#include "interpreter.h"
+#include "lightrec-private.h"
+#include "optimizer.h"
+#include "regcache.h"
+
+#include <stdbool.h>
+
+struct interpreter;
+
+static u32 int_CP0(struct interpreter *inter);
+static u32 int_CP2(struct interpreter *inter);
+static u32 int_SPECIAL(struct interpreter *inter);
+static u32 int_REGIMM(struct interpreter *inter);
+static u32 int_branch(struct interpreter *inter, u32 pc,
+                     union code code, bool branch);
+
+typedef u32 (*lightrec_int_func_t)(struct interpreter *inter);
+
+static const lightrec_int_func_t int_standard[64];
+
+struct interpreter {
+       struct lightrec_state *state;
+       struct block *block;
+       struct opcode *op;
+       u32 cycles;
+       bool delay_slot;
+};
+
+static inline u32 execute(lightrec_int_func_t func, struct interpreter *inter)
+{
+       return (*func)(inter);
+}
+
+static inline u32 jump_skip(struct interpreter *inter)
+{
+       inter->op = inter->op->next;
+
+       return execute(int_standard[inter->op->i.op], inter);
+}
+
+static inline u32 jump_next(struct interpreter *inter)
+{
+       inter->cycles += lightrec_cycles_of_opcode(inter->op->c);
+
+       if (unlikely(inter->delay_slot))
+               return 0;
+
+       return jump_skip(inter);
+}
+
+static inline u32 jump_after_branch(struct interpreter *inter)
+{
+       inter->cycles += lightrec_cycles_of_opcode(inter->op->c);
+
+       if (unlikely(inter->delay_slot))
+               return 0;
+
+       inter->op = inter->op->next;
+
+       return jump_skip(inter);
+}
+
+static void update_cycles_before_branch(struct interpreter *inter)
+{
+       u32 cycles;
+
+       if (!inter->delay_slot) {
+               cycles = lightrec_cycles_of_opcode(inter->op->c);
+
+               if (has_delay_slot(inter->op->c) &&
+                   !(inter->op->flags & LIGHTREC_NO_DS))
+                       cycles += lightrec_cycles_of_opcode(inter->op->next->c);
+
+               inter->cycles += cycles;
+               inter->state->current_cycle += inter->cycles;
+               inter->cycles = -cycles;
+       }
+}
+
+static bool is_branch_taken(const u32 *reg_cache, union code op)
+{
+       switch (op.i.op) {
+       case OP_SPECIAL:
+               return op.r.op == OP_SPECIAL_JR || op.r.op == OP_SPECIAL_JALR;
+       case OP_J:
+       case OP_JAL:
+               return true;
+       case OP_BEQ:
+       case OP_META_BEQZ:
+               return reg_cache[op.r.rs] == reg_cache[op.r.rt];
+       case OP_BNE:
+       case OP_META_BNEZ:
+               return reg_cache[op.r.rs] != reg_cache[op.r.rt];
+       case OP_REGIMM:
+               switch (op.r.rt) {
+               case OP_REGIMM_BLTZ:
+               case OP_REGIMM_BLTZAL:
+                       return (s32)reg_cache[op.r.rs] < 0;
+               case OP_REGIMM_BGEZ:
+               case OP_REGIMM_BGEZAL:
+                       return (s32)reg_cache[op.r.rs] >= 0;
+               }
+       default:
+               break;
+       }
+
+       return false;
+}
+
+static u32 int_delay_slot(struct interpreter *inter, u32 pc, bool branch)
+{
+       struct lightrec_state *state = inter->state;
+       u32 *reg_cache = state->native_reg_cache;
+       struct opcode new_op, *op = inter->op->next;
+       union code op_next;
+       struct interpreter inter2 = {
+               .state = state,
+               .cycles = inter->cycles,
+               .delay_slot = true,
+               .block = NULL,
+       };
+       bool run_first_op = false, dummy_ld = false, save_rs = false,
+            load_in_ds, branch_in_ds = false, branch_at_addr = false,
+            branch_taken;
+       u32 old_rs, new_rs, new_rt;
+       u32 next_pc, ds_next_pc;
+       u32 cause, epc;
+
+       if (op->i.op == OP_CP0 && op->r.rs == OP_CP0_RFE) {
+               /* When an IRQ happens, the PSX exception handlers (when done)
+                * will jump back to the instruction that was executed right
+                * before the IRQ, unless it was a GTE opcode; in that case, it
+                * jumps to the instruction right after.
+                * Since we will never handle the IRQ right after a GTE opcode,
+                * but on branch boundaries, we need to adjust the return
+                * address so that the GTE opcode is effectively executed.
+                */
+               cause = (*state->ops.cop0_ops.cfc)(state, op->c.opcode, 13);
+               epc = (*state->ops.cop0_ops.cfc)(state, op->c.opcode, 14);
+
+               if (!(cause & 0x7c) && epc == pc - 4)
+                       pc -= 4;
+       }
+
+       if (inter->delay_slot) {
+               /* The branch opcode was in a delay slot of another branch
+                * opcode. Just return the target address of the second
+                * branch. */
+               return pc;
+       }
+
+       /* An opcode located in the delay slot performing a delayed read
+        * requires special handling; we will always resort to using the
+        * interpreter in that case.
+        * Same goes for when we have a branch in a delay slot of another
+        * branch. */
+       load_in_ds = load_in_delay_slot(op->c);
+       branch_in_ds = has_delay_slot(op->c);
+
+       if (branch) {
+               if (load_in_ds || branch_in_ds)
+                       op_next = lightrec_read_opcode(state, pc);
+
+               if (load_in_ds) {
+                       /* Verify that the next block actually reads the
+                        * destination register of the delay slot opcode. */
+                       run_first_op = opcode_reads_register(op_next, op->r.rt);
+               }
+
+               if (branch_in_ds) {
+                       run_first_op = true;
+                       next_pc = pc + 4;
+               }
+
+               if (load_in_ds && run_first_op) {
+                       next_pc = pc + 4;
+
+                       /* If the first opcode of the next block writes the
+                        * regiser used as the address for the load, we need to
+                        * reset to the old value after it has been executed,
+                        * then restore the new value after the delay slot
+                        * opcode has been executed. */
+                       save_rs = opcode_reads_register(op->c, op->r.rs) &&
+                               opcode_writes_register(op_next, op->r.rs);
+                       if (save_rs)
+                               old_rs = reg_cache[op->r.rs];
+
+                       /* If both the first opcode of the next block and the
+                        * delay slot opcode write to the same register, the
+                        * value written by the delay slot opcode is
+                        * discarded. */
+                       dummy_ld = opcode_writes_register(op_next, op->r.rt);
+               }
+
+               if (!run_first_op) {
+                       next_pc = pc;
+               } else if (has_delay_slot(op_next)) {
+                       /* The first opcode of the next block is a branch, so we
+                        * cannot execute it here, because of the load delay.
+                        * Just check whether or not the branch would be taken,
+                        * and save that info into the interpreter struct. */
+                       branch_at_addr = true;
+                       branch_taken = is_branch_taken(reg_cache, op_next);
+                       pr_debug("Target of impossible branch is a branch, "
+                                "%staken.\n", branch_taken ? "" : "not ");
+                       inter->cycles += lightrec_cycles_of_opcode(op_next);
+                       old_rs = reg_cache[op_next.r.rs];
+               } else {
+                       new_op.c = op_next;
+                       new_op.flags = 0;
+                       new_op.offset = 0;
+                       new_op.next = NULL;
+                       inter2.op = &new_op;
+
+                       /* Execute the first opcode of the next block */
+                       (*int_standard[inter2.op->i.op])(&inter2);
+
+                       if (save_rs) {
+                               new_rs = reg_cache[op->r.rs];
+                               reg_cache[op->r.rs] = old_rs;
+                       }
+
+                       inter->cycles += lightrec_cycles_of_opcode(op_next);
+               }
+       } else {
+               next_pc = inter->block->pc
+                       + (inter->op->offset + 2) * sizeof(u32);
+       }
+
+       inter2.block = inter->block;
+       inter2.op = op;
+       inter2.cycles = inter->cycles;
+
+       if (dummy_ld)
+               new_rt = reg_cache[op->r.rt];
+
+       /* Execute delay slot opcode */
+       ds_next_pc = (*int_standard[inter2.op->i.op])(&inter2);
+
+       if (branch_at_addr) {
+               if (op_next.i.op == OP_SPECIAL)
+                       /* TODO: Handle JALR setting $ra */
+                       ds_next_pc = old_rs;
+               else if (op_next.i.op == OP_J || op_next.i.op == OP_JAL)
+                       /* TODO: Handle JAL setting $ra */
+                       ds_next_pc = (pc & 0xf0000000) | (op_next.j.imm << 2);
+               else
+                       ds_next_pc = pc + 4 + ((s16)op_next.i.imm << 2);
+       }
+
+       if (branch_at_addr && !branch_taken) {
+               /* If the branch at the target of the branch opcode is not
+                * taken, we jump to its delay slot */
+               next_pc = pc + sizeof(u32);
+       } else if (branch_at_addr || (!branch && branch_in_ds)) {
+               next_pc = ds_next_pc;
+       }
+
+       if (save_rs)
+               reg_cache[op->r.rs] = new_rs;
+       if (dummy_ld)
+               reg_cache[op->r.rt] = new_rt;
+
+       inter->cycles += lightrec_cycles_of_opcode(op->c);
+
+       if (branch_at_addr && branch_taken) {
+               /* If the branch at the target of the branch opcode is taken,
+                * we execute its delay slot here, and jump to its target
+                * address. */
+               op_next = lightrec_read_opcode(state, pc + 4);
+
+               new_op.c = op_next;
+               new_op.flags = 0;
+               new_op.offset = sizeof(u32);
+               new_op.next = NULL;
+               inter2.op = &new_op;
+               inter2.block = NULL;
+
+               inter->cycles += lightrec_cycles_of_opcode(op_next);
+
+               pr_debug("Running delay slot of branch at target of impossible "
+                        "branch\n");
+               (*int_standard[inter2.op->i.op])(&inter2);
+       }
+
+       return next_pc;
+}
+
+static u32 int_unimplemented(struct interpreter *inter)
+{
+       pr_warn("Unimplemented opcode 0x%08x\n", inter->op->opcode);
+
+       return jump_next(inter);
+}
+
+static u32 int_jump(struct interpreter *inter, bool link)
+{
+       struct lightrec_state *state = inter->state;
+       u32 old_pc = inter->block->pc + inter->op->offset * sizeof(u32);
+       u32 pc = (old_pc & 0xf0000000) | (inter->op->j.imm << 2);
+
+       if (link)
+               state->native_reg_cache[31] = old_pc + 8;
+
+       if (inter->op->flags & LIGHTREC_NO_DS)
+               return pc;
+
+       return int_delay_slot(inter, pc, true);
+}
+
+static u32 int_J(struct interpreter *inter)
+{
+       return int_jump(inter, false);
+}
+
+static u32 int_JAL(struct interpreter *inter)
+{
+       return int_jump(inter, true);
+}
+
+static u32 int_jumpr(struct interpreter *inter, u8 link_reg)
+{
+       struct lightrec_state *state = inter->state;
+       u32 old_pc, next_pc = state->native_reg_cache[inter->op->r.rs];
+
+       if (link_reg) {
+               old_pc = inter->block->pc + inter->op->offset * sizeof(u32);
+               state->native_reg_cache[link_reg] = old_pc + 8;
+       }
+
+       if (inter->op->flags & LIGHTREC_NO_DS)
+               return next_pc;
+
+       return int_delay_slot(inter, next_pc, true);
+}
+
+static u32 int_special_JR(struct interpreter *inter)
+{
+       return int_jumpr(inter, 0);
+}
+
+static u32 int_special_JALR(struct interpreter *inter)
+{
+       return int_jumpr(inter, inter->op->r.rd);
+}
+
+static u32 int_do_branch(struct interpreter *inter, u32 old_pc, u32 next_pc)
+{
+       if (!inter->delay_slot &&
+           (inter->op->flags & LIGHTREC_LOCAL_BRANCH) &&
+           (s16)inter->op->c.i.imm >= 0) {
+               next_pc = old_pc + ((1 + (s16)inter->op->c.i.imm) << 2);
+               next_pc = lightrec_emulate_block(inter->block, next_pc);
+       }
+
+       return next_pc;
+}
+
+static u32 int_branch(struct interpreter *inter, u32 pc,
+                     union code code, bool branch)
+{
+       u32 next_pc = pc + 4 + ((s16)code.i.imm << 2);
+
+       update_cycles_before_branch(inter);
+
+       if (inter->op->flags & LIGHTREC_NO_DS) {
+               if (branch)
+                       return int_do_branch(inter, pc, next_pc);
+               else
+                       return jump_next(inter);
+       }
+
+       if (!inter->delay_slot)
+               next_pc = int_delay_slot(inter, next_pc, branch);
+
+       if (branch)
+               return int_do_branch(inter, pc, next_pc);
+
+       if (inter->op->flags & LIGHTREC_EMULATE_BRANCH)
+               return pc + 8;
+       else
+               return jump_after_branch(inter);
+}
+
+static u32 int_beq(struct interpreter *inter, bool bne)
+{
+       u32 rs, rt, old_pc = inter->block->pc + inter->op->offset * sizeof(u32);
+
+       rs = inter->state->native_reg_cache[inter->op->i.rs];
+       rt = inter->state->native_reg_cache[inter->op->i.rt];
+
+       return int_branch(inter, old_pc, inter->op->c, (rs == rt) ^ bne);
+}
+
+static u32 int_BEQ(struct interpreter *inter)
+{
+       return int_beq(inter, false);
+}
+
+static u32 int_BNE(struct interpreter *inter)
+{
+       return int_beq(inter, true);
+}
+
+static u32 int_bgez(struct interpreter *inter, bool link, bool lt, bool regimm)
+{
+       u32 old_pc = inter->block->pc + inter->op->offset * sizeof(u32);
+       s32 rs;
+
+       if (link)
+               inter->state->native_reg_cache[31] = old_pc + 8;
+
+       rs = (s32)inter->state->native_reg_cache[inter->op->i.rs];
+
+       return int_branch(inter, old_pc, inter->op->c,
+                         ((regimm && !rs) || rs > 0) ^ lt);
+}
+
+static u32 int_regimm_BLTZ(struct interpreter *inter)
+{
+       return int_bgez(inter, false, true, true);
+}
+
+static u32 int_regimm_BGEZ(struct interpreter *inter)
+{
+       return int_bgez(inter, false, false, true);
+}
+
+static u32 int_regimm_BLTZAL(struct interpreter *inter)
+{
+       return int_bgez(inter, true, true, true);
+}
+
+static u32 int_regimm_BGEZAL(struct interpreter *inter)
+{
+       return int_bgez(inter, true, false, true);
+}
+
+static u32 int_BLEZ(struct interpreter *inter)
+{
+       return int_bgez(inter, false, true, false);
+}
+
+static u32 int_BGTZ(struct interpreter *inter)
+{
+       return int_bgez(inter, false, false, false);
+}
+
+static u32 int_cfc(struct interpreter *inter)
+{
+       struct lightrec_state *state = inter->state;
+       const struct opcode *op = inter->op;
+       u32 val;
+
+       val = lightrec_mfc(state, op->c);
+
+       if (likely(op->r.rt))
+               state->native_reg_cache[op->r.rt] = val;
+
+       return jump_next(inter);
+}
+
+static u32 int_ctc(struct interpreter *inter)
+{
+       struct lightrec_state *state = inter->state;
+       const struct opcode *op = inter->op;
+
+       lightrec_mtc(state, op->c, state->native_reg_cache[op->r.rt]);
+
+       /* If we have a MTC0 or CTC0 to CP0 register 12 (Status) or 13 (Cause),
+        * return early so that the emulator will be able to check software
+        * interrupt status. */
+       if (!(inter->op->flags & LIGHTREC_NO_DS) &&
+           op->i.op == OP_CP0 && (op->r.rd == 12 || op->r.rd == 13))
+               return inter->block->pc + (op->offset + 1) * sizeof(u32);
+       else
+               return jump_next(inter);
+}
+
+static u32 int_cp0_RFE(struct interpreter *inter)
+{
+       struct lightrec_state *state = inter->state;
+       u32 status;
+
+       /* Read CP0 Status register (r12) */
+       status = state->ops.cop0_ops.mfc(state, inter->op->c.opcode, 12);
+
+       /* Switch the bits */
+       status = ((status & 0x3c) >> 2) | (status & ~0xf);
+
+       /* Write it back */
+       state->ops.cop0_ops.ctc(state, inter->op->c.opcode, 12, status);
+
+       return jump_next(inter);
+}
+
+static u32 int_CP(struct interpreter *inter)
+{
+       struct lightrec_state *state = inter->state;
+       const struct lightrec_cop_ops *ops;
+       const struct opcode *op = inter->op;
+
+       if ((op->j.imm >> 25) & 1)
+               ops = &state->ops.cop2_ops;
+       else
+               ops = &state->ops.cop0_ops;
+
+       (*ops->op)(state, (op->j.imm) & ~(1 << 25));
+
+       return jump_next(inter);
+}
+
+static u32 int_ADDI(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_i *op = &inter->op->i;
+
+       if (likely(op->rt))
+               reg_cache[op->rt] = reg_cache[op->rs] + (s32)(s16)op->imm;
+
+       return jump_next(inter);
+}
+
+static u32 int_SLTI(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_i *op = &inter->op->i;
+
+       if (likely(op->rt))
+               reg_cache[op->rt] = (s32)reg_cache[op->rs] < (s32)(s16)op->imm;
+
+       return jump_next(inter);
+}
+
+static u32 int_SLTIU(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_i *op = &inter->op->i;
+
+       if (likely(op->rt))
+               reg_cache[op->rt] = reg_cache[op->rs] < (u32)(s32)(s16)op->imm;
+
+       return jump_next(inter);
+}
+
+static u32 int_ANDI(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_i *op = &inter->op->i;
+
+       if (likely(op->rt))
+               reg_cache[op->rt] = reg_cache[op->rs] & op->imm;
+
+       return jump_next(inter);
+}
+
+static u32 int_ORI(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_i *op = &inter->op->i;
+
+       if (likely(op->rt))
+               reg_cache[op->rt] = reg_cache[op->rs] | op->imm;
+
+       return jump_next(inter);
+}
+
+static u32 int_XORI(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_i *op = &inter->op->i;
+
+       if (likely(op->rt))
+               reg_cache[op->rt] = reg_cache[op->rs] ^ op->imm;
+
+       return jump_next(inter);
+}
+
+static u32 int_LUI(struct interpreter *inter)
+{
+       struct opcode_i *op = &inter->op->i;
+
+       inter->state->native_reg_cache[op->rt] = op->imm << 16;
+
+       return jump_next(inter);
+}
+
+static u32 int_io(struct interpreter *inter, bool is_load)
+{
+       struct opcode_i *op = &inter->op->i;
+       u32 *reg_cache = inter->state->native_reg_cache;
+       u32 val;
+
+       val = lightrec_rw(inter->state, inter->op->c,
+                         reg_cache[op->rs], reg_cache[op->rt],
+                         &inter->op->flags);
+
+       if (is_load && op->rt)
+               reg_cache[op->rt] = val;
+
+       return jump_next(inter);
+}
+
+static u32 int_load(struct interpreter *inter)
+{
+       return int_io(inter, true);
+}
+
+static u32 int_store(struct interpreter *inter)
+{
+       u32 next_pc;
+
+       if (likely(!(inter->op->flags & LIGHTREC_SMC)))
+               return int_io(inter, false);
+
+       lightrec_rw(inter->state, inter->op->c,
+                   inter->state->native_reg_cache[inter->op->i.rs],
+                   inter->state->native_reg_cache[inter->op->i.rt],
+                   &inter->op->flags);
+
+       next_pc = inter->block->pc + (inter->op->offset + 1) * 4;
+
+       /* Invalidate next PC, to force the rest of the block to be rebuilt */
+       lightrec_invalidate(inter->state, next_pc, 4);
+
+       return next_pc;
+}
+
+static u32 int_LWC2(struct interpreter *inter)
+{
+       return int_io(inter, false);
+}
+
+static u32 int_special_SLL(struct interpreter *inter)
+{
+       struct opcode *op = inter->op;
+       u32 rt;
+
+       if (op->opcode) { /* Handle NOPs */
+               rt = inter->state->native_reg_cache[op->r.rt];
+               inter->state->native_reg_cache[op->r.rd] = rt << op->r.imm;
+       }
+
+       return jump_next(inter);
+}
+
+static u32 int_special_SRL(struct interpreter *inter)
+{
+       struct opcode *op = inter->op;
+       u32 rt = inter->state->native_reg_cache[op->r.rt];
+
+       inter->state->native_reg_cache[op->r.rd] = rt >> op->r.imm;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_SRA(struct interpreter *inter)
+{
+       struct opcode *op = inter->op;
+       s32 rt = inter->state->native_reg_cache[op->r.rt];
+
+       inter->state->native_reg_cache[op->r.rd] = rt >> op->r.imm;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_SLLV(struct interpreter *inter)
+{
+       struct opcode *op = inter->op;
+       u32 rs = inter->state->native_reg_cache[op->r.rs];
+       u32 rt = inter->state->native_reg_cache[op->r.rt];
+
+       inter->state->native_reg_cache[op->r.rd] = rt << (rs & 0x1f);
+
+       return jump_next(inter);
+}
+
+static u32 int_special_SRLV(struct interpreter *inter)
+{
+       struct opcode *op = inter->op;
+       u32 rs = inter->state->native_reg_cache[op->r.rs];
+       u32 rt = inter->state->native_reg_cache[op->r.rt];
+
+       inter->state->native_reg_cache[op->r.rd] = rt >> (rs & 0x1f);
+
+       return jump_next(inter);
+}
+
+static u32 int_special_SRAV(struct interpreter *inter)
+{
+       struct opcode *op = inter->op;
+       u32 rs = inter->state->native_reg_cache[op->r.rs];
+       s32 rt = inter->state->native_reg_cache[op->r.rt];
+
+       inter->state->native_reg_cache[op->r.rd] = rt >> (rs & 0x1f);
+
+       return jump_next(inter);
+}
+
+static u32 int_syscall_break(struct interpreter *inter)
+{
+
+       if (inter->op->r.op == OP_SPECIAL_BREAK)
+               inter->state->exit_flags |= LIGHTREC_EXIT_BREAK;
+       else
+               inter->state->exit_flags |= LIGHTREC_EXIT_SYSCALL;
+
+       return inter->block->pc + inter->op->offset * sizeof(u32);
+}
+
+static u32 int_special_MFHI(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = reg_cache[REG_HI];
+
+       return jump_next(inter);
+}
+
+static u32 int_special_MTHI(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+
+       reg_cache[REG_HI] = reg_cache[inter->op->r.rs];
+
+       return jump_next(inter);
+}
+
+static u32 int_special_MFLO(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = reg_cache[REG_LO];
+
+       return jump_next(inter);
+}
+
+static u32 int_special_MTLO(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+
+       reg_cache[REG_LO] = reg_cache[inter->op->r.rs];
+
+       return jump_next(inter);
+}
+
+static u32 int_special_MULT(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       s32 rs = reg_cache[inter->op->r.rs];
+       s32 rt = reg_cache[inter->op->r.rt];
+       u64 res = (s64)rs * (s64)rt;
+
+       if (!(inter->op->flags & LIGHTREC_MULT32))
+               reg_cache[REG_HI] = res >> 32;
+       reg_cache[REG_LO] = res;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_MULTU(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       u32 rs = reg_cache[inter->op->r.rs];
+       u32 rt = reg_cache[inter->op->r.rt];
+       u64 res = (u64)rs * (u64)rt;
+
+       if (!(inter->op->flags & LIGHTREC_MULT32))
+               reg_cache[REG_HI] = res >> 32;
+       reg_cache[REG_LO] = res;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_DIV(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       s32 rs = reg_cache[inter->op->r.rs];
+       s32 rt = reg_cache[inter->op->r.rt];
+       u32 lo, hi;
+
+       if (rt == 0) {
+               hi = rs;
+               lo = (rs < 0) * 2 - 1;
+       } else if ((rs == 0x80000000) && (rt == 0xFFFFFFFF)) {
+               lo = rs;
+               hi = 0;
+       } else {
+               lo = rs / rt;
+               hi = rs % rt;
+       }
+
+       reg_cache[REG_HI] = hi;
+       reg_cache[REG_LO] = lo;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_DIVU(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       u32 rs = reg_cache[inter->op->r.rs];
+       u32 rt = reg_cache[inter->op->r.rt];
+       u32 lo, hi;
+
+       if (rt == 0) {
+               hi = rs;
+               lo = (u32)-1;
+       } else {
+               lo = rs / rt;
+               hi = rs % rt;
+       }
+
+       reg_cache[REG_HI] = hi;
+       reg_cache[REG_LO] = lo;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_ADD(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+       s32 rs = reg_cache[op->rs];
+       s32 rt = reg_cache[op->rt];
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = rs + rt;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_SUB(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+       u32 rs = reg_cache[op->rs];
+       u32 rt = reg_cache[op->rt];
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = rs - rt;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_AND(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+       u32 rs = reg_cache[op->rs];
+       u32 rt = reg_cache[op->rt];
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = rs & rt;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_OR(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+       u32 rs = reg_cache[op->rs];
+       u32 rt = reg_cache[op->rt];
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = rs | rt;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_XOR(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+       u32 rs = reg_cache[op->rs];
+       u32 rt = reg_cache[op->rt];
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = rs ^ rt;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_NOR(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+       u32 rs = reg_cache[op->rs];
+       u32 rt = reg_cache[op->rt];
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = ~(rs | rt);
+
+       return jump_next(inter);
+}
+
+static u32 int_special_SLT(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+       s32 rs = reg_cache[op->rs];
+       s32 rt = reg_cache[op->rt];
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = rs < rt;
+
+       return jump_next(inter);
+}
+
+static u32 int_special_SLTU(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+       u32 rs = reg_cache[op->rs];
+       u32 rt = reg_cache[op->rt];
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = rs < rt;
+
+       return jump_next(inter);
+}
+
+static u32 int_META_SKIP(struct interpreter *inter)
+{
+       return jump_skip(inter);
+}
+
+static u32 int_META_MOV(struct interpreter *inter)
+{
+       u32 *reg_cache = inter->state->native_reg_cache;
+       struct opcode_r *op = &inter->op->r;
+
+       if (likely(op->rd))
+               reg_cache[op->rd] = reg_cache[op->rs];
+
+       return jump_next(inter);
+}
+
+static u32 int_META_SYNC(struct interpreter *inter)
+{
+       inter->state->current_cycle += inter->cycles;
+       inter->cycles = 0;
+
+       return jump_skip(inter);
+}
+
+static const lightrec_int_func_t int_standard[64] = {
+       [OP_SPECIAL]            = int_SPECIAL,
+       [OP_REGIMM]             = int_REGIMM,
+       [OP_J]                  = int_J,
+       [OP_JAL]                = int_JAL,
+       [OP_BEQ]                = int_BEQ,
+       [OP_BNE]                = int_BNE,
+       [OP_BLEZ]               = int_BLEZ,
+       [OP_BGTZ]               = int_BGTZ,
+       [OP_ADDI]               = int_ADDI,
+       [OP_ADDIU]              = int_ADDI,
+       [OP_SLTI]               = int_SLTI,
+       [OP_SLTIU]              = int_SLTIU,
+       [OP_ANDI]               = int_ANDI,
+       [OP_ORI]                = int_ORI,
+       [OP_XORI]               = int_XORI,
+       [OP_LUI]                = int_LUI,
+       [OP_CP0]                = int_CP0,
+       [OP_CP2]                = int_CP2,
+       [OP_LB]                 = int_load,
+       [OP_LH]                 = int_load,
+       [OP_LWL]                = int_load,
+       [OP_LW]                 = int_load,
+       [OP_LBU]                = int_load,
+       [OP_LHU]                = int_load,
+       [OP_LWR]                = int_load,
+       [OP_SB]                 = int_store,
+       [OP_SH]                 = int_store,
+       [OP_SWL]                = int_store,
+       [OP_SW]                 = int_store,
+       [OP_SWR]                = int_store,
+       [OP_LWC2]               = int_LWC2,
+       [OP_SWC2]               = int_store,
+
+       [OP_META_REG_UNLOAD]    = int_META_SKIP,
+       [OP_META_BEQZ]          = int_BEQ,
+       [OP_META_BNEZ]          = int_BNE,
+       [OP_META_MOV]           = int_META_MOV,
+       [OP_META_SYNC]          = int_META_SYNC,
+};
+
+static const lightrec_int_func_t int_special[64] = {
+       [OP_SPECIAL_SLL]        = int_special_SLL,
+       [OP_SPECIAL_SRL]        = int_special_SRL,
+       [OP_SPECIAL_SRA]        = int_special_SRA,
+       [OP_SPECIAL_SLLV]       = int_special_SLLV,
+       [OP_SPECIAL_SRLV]       = int_special_SRLV,
+       [OP_SPECIAL_SRAV]       = int_special_SRAV,
+       [OP_SPECIAL_JR]         = int_special_JR,
+       [OP_SPECIAL_JALR]       = int_special_JALR,
+       [OP_SPECIAL_SYSCALL]    = int_syscall_break,
+       [OP_SPECIAL_BREAK]      = int_syscall_break,
+       [OP_SPECIAL_MFHI]       = int_special_MFHI,
+       [OP_SPECIAL_MTHI]       = int_special_MTHI,
+       [OP_SPECIAL_MFLO]       = int_special_MFLO,
+       [OP_SPECIAL_MTLO]       = int_special_MTLO,
+       [OP_SPECIAL_MULT]       = int_special_MULT,
+       [OP_SPECIAL_MULTU]      = int_special_MULTU,
+       [OP_SPECIAL_DIV]        = int_special_DIV,
+       [OP_SPECIAL_DIVU]       = int_special_DIVU,
+       [OP_SPECIAL_ADD]        = int_special_ADD,
+       [OP_SPECIAL_ADDU]       = int_special_ADD,
+       [OP_SPECIAL_SUB]        = int_special_SUB,
+       [OP_SPECIAL_SUBU]       = int_special_SUB,
+       [OP_SPECIAL_AND]        = int_special_AND,
+       [OP_SPECIAL_OR]         = int_special_OR,
+       [OP_SPECIAL_XOR]        = int_special_XOR,
+       [OP_SPECIAL_NOR]        = int_special_NOR,
+       [OP_SPECIAL_SLT]        = int_special_SLT,
+       [OP_SPECIAL_SLTU]       = int_special_SLTU,
+};
+
+static const lightrec_int_func_t int_regimm[64] = {
+       [OP_REGIMM_BLTZ]        = int_regimm_BLTZ,
+       [OP_REGIMM_BGEZ]        = int_regimm_BGEZ,
+       [OP_REGIMM_BLTZAL]      = int_regimm_BLTZAL,
+       [OP_REGIMM_BGEZAL]      = int_regimm_BGEZAL,
+};
+
+static const lightrec_int_func_t int_cp0[64] = {
+       [OP_CP0_MFC0]           = int_cfc,
+       [OP_CP0_CFC0]           = int_cfc,
+       [OP_CP0_MTC0]           = int_ctc,
+       [OP_CP0_CTC0]           = int_ctc,
+       [OP_CP0_RFE]            = int_cp0_RFE,
+};
+
+static const lightrec_int_func_t int_cp2_basic[64] = {
+       [OP_CP2_BASIC_MFC2]     = int_cfc,
+       [OP_CP2_BASIC_CFC2]     = int_cfc,
+       [OP_CP2_BASIC_MTC2]     = int_ctc,
+       [OP_CP2_BASIC_CTC2]     = int_ctc,
+};
+
+static u32 int_SPECIAL(struct interpreter *inter)
+{
+       lightrec_int_func_t f = int_special[inter->op->r.op];
+       if (likely(f))
+               return execute(f, inter);
+       else
+               return int_unimplemented(inter);
+}
+
+static u32 int_REGIMM(struct interpreter *inter)
+{
+       lightrec_int_func_t f = int_regimm[inter->op->r.rt];
+       if (likely(f))
+               return execute(f, inter);
+       else
+               return int_unimplemented(inter);
+}
+
+static u32 int_CP0(struct interpreter *inter)
+{
+       lightrec_int_func_t f = int_cp0[inter->op->r.rs];
+       if (likely(f))
+               return execute(f, inter);
+       else
+               return int_CP(inter);
+}
+
+static u32 int_CP2(struct interpreter *inter)
+{
+       if (inter->op->r.op == OP_CP2_BASIC) {
+               lightrec_int_func_t f = int_cp2_basic[inter->op->r.rs];
+               if (likely(f))
+                       return execute(f, inter);
+       }
+
+       return int_CP(inter);
+}
+
+static u32 lightrec_int_op(struct interpreter *inter)
+{
+       return execute(int_standard[inter->op->i.op], inter);
+}
+
+static u32 lightrec_emulate_block_list(struct block *block, struct opcode *op)
+{
+       struct interpreter inter;
+       u32 pc;
+
+       inter.block = block;
+       inter.state = block->state;
+       inter.op = op;
+       inter.cycles = 0;
+       inter.delay_slot = false;
+
+       pc = lightrec_int_op(&inter);
+
+       /* Add the cycles of the last branch */
+       inter.cycles += lightrec_cycles_of_opcode(inter.op->c);
+
+       block->state->current_cycle += inter.cycles;
+
+       return pc;
+}
+
+u32 lightrec_emulate_block(struct block *block, u32 pc)
+{
+       u32 offset = (kunseg(pc) - kunseg(block->pc)) >> 2;
+       struct opcode *op;
+
+       for (op = block->opcode_list;
+            op && (op->offset < offset); op = op->next);
+       if (op)
+               return lightrec_emulate_block_list(block, op);
+
+       pr_err("PC 0x%x is outside block at PC 0x%x\n", pc, block->pc);
+
+       return 0;
+}
diff --git a/deps/lightrec/interpreter.h b/deps/lightrec/interpreter.h
new file mode 100644 (file)
index 0000000..2113779
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2019-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __LIGHTREC_INTERPRETER_H__
+#define __LIGHTREC_INTERPRETER_H__
+
+#include "lightrec.h"
+
+struct block;
+
+u32 lightrec_emulate_block(struct block *block, u32 pc);
+
+#endif /* __LIGHTREC_INTERPRETER_H__ */
diff --git a/deps/lightrec/lightrec-private.h b/deps/lightrec/lightrec-private.h
new file mode 100644 (file)
index 0000000..6304515
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2016-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __LIGHTREC_PRIVATE_H__
+#define __LIGHTREC_PRIVATE_H__
+
+#include "config.h"
+#include "disassembler.h"
+#include "lightrec.h"
+
+#if ENABLE_THREADED_COMPILER
+#include <stdatomic.h>
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
+#define BIT(x) (1 << (x))
+
+#ifdef __GNUC__
+#      define likely(x)       __builtin_expect(!!(x),1)
+#      define unlikely(x)     __builtin_expect(!!(x),0)
+#else
+#      define likely(x)       (x)
+#      define unlikely(x)     (x)
+#endif
+
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#      define LE32TOH(x)       __builtin_bswap32(x)
+#      define HTOLE32(x)       __builtin_bswap32(x)
+#      define LE16TOH(x)       __builtin_bswap16(x)
+#      define HTOLE16(x)       __builtin_bswap16(x)
+#else
+#      define LE32TOH(x)       (x)
+#      define HTOLE32(x)       (x)
+#      define LE16TOH(x)       (x)
+#      define HTOLE16(x)       (x)
+#endif
+
+/* Flags for (struct block *)->flags */
+#define BLOCK_NEVER_COMPILE    BIT(0)
+#define BLOCK_SHOULD_RECOMPILE BIT(1)
+#define BLOCK_FULLY_TAGGED     BIT(2)
+#define BLOCK_IS_DEAD          BIT(3)
+
+#define RAM_SIZE       0x200000
+#define BIOS_SIZE      0x80000
+
+#define CODE_LUT_SIZE  ((RAM_SIZE + BIOS_SIZE) >> 2)
+
+/* Definition of jit_state_t (avoids inclusion of <lightning.h>) */
+struct jit_node;
+struct jit_state;
+typedef struct jit_state jit_state_t;
+
+struct blockcache;
+struct recompiler;
+struct regcache;
+struct opcode;
+struct tinymm;
+struct reaper;
+
+struct block {
+       jit_state_t *_jit;
+       struct lightrec_state *state;
+       struct opcode *opcode_list;
+       void (*function)(void);
+       u32 pc;
+       u32 hash;
+#if ENABLE_THREADED_COMPILER
+       atomic_flag op_list_freed;
+#endif
+       unsigned int code_size;
+       u16 flags;
+       u16 nb_ops;
+       const struct lightrec_mem_map *map;
+       struct block *next;
+};
+
+struct lightrec_branch {
+       struct jit_node *branch;
+       u32 target;
+};
+
+struct lightrec_branch_target {
+       struct jit_node *label;
+       u32 offset;
+};
+
+struct lightrec_state {
+       u32 native_reg_cache[34];
+       u32 next_pc;
+       u32 current_cycle;
+       u32 target_cycle;
+       u32 exit_flags;
+       struct block *dispatcher, *rw_wrapper, *rw_generic_wrapper,
+                    *mfc_wrapper, *mtc_wrapper, *rfe_wrapper, *cp_wrapper,
+                    *syscall_wrapper, *break_wrapper;
+       void *rw_func, *rw_generic_func, *mfc_func, *mtc_func, *rfe_func,
+            *cp_func, *syscall_func, *break_func;
+       struct jit_node *branches[512];
+       struct lightrec_branch local_branches[512];
+       struct lightrec_branch_target targets[512];
+       unsigned int nb_branches;
+       unsigned int nb_local_branches;
+       unsigned int nb_targets;
+       struct tinymm *tinymm;
+       struct blockcache *block_cache;
+       struct regcache *reg_cache;
+       struct recompiler *rec;
+       struct reaper *reaper;
+       void (*eob_wrapper_func)(void);
+       void (*get_next_block)(void);
+       struct lightrec_ops ops;
+       unsigned int nb_precompile;
+       unsigned int cycles;
+       unsigned int nb_maps;
+       const struct lightrec_mem_map *maps;
+       uintptr_t offset_ram, offset_bios, offset_scratch;
+       _Bool mirrors_mapped;
+       _Bool invalidate_from_dma_only;
+       void *code_lut[];
+};
+
+u32 lightrec_rw(struct lightrec_state *state, union code op,
+               u32 addr, u32 data, u16 *flags);
+
+void lightrec_free_block(struct block *block);
+
+void remove_from_code_lut(struct blockcache *cache, struct block *block);
+
+static inline u32 kunseg(u32 addr)
+{
+       if (unlikely(addr >= 0xa0000000))
+               return addr - 0xa0000000;
+       else
+               return addr &~ 0x80000000;
+}
+
+static inline u32 lut_offset(u32 pc)
+{
+       if (pc & BIT(28))
+               return ((pc & (BIOS_SIZE - 1)) + RAM_SIZE) >> 2; // BIOS
+       else
+               return (pc & (RAM_SIZE - 1)) >> 2; // RAM
+}
+
+void lightrec_mtc(struct lightrec_state *state, union code op, u32 data);
+u32 lightrec_mfc(struct lightrec_state *state, union code op);
+
+union code lightrec_read_opcode(struct lightrec_state *state, u32 pc);
+
+struct block * lightrec_get_block(struct lightrec_state *state, u32 pc);
+int lightrec_compile_block(struct block *block);
+
+#endif /* __LIGHTREC_PRIVATE_H__ */
diff --git a/deps/lightrec/lightrec.c b/deps/lightrec/lightrec.c
new file mode 100644 (file)
index 0000000..7fdf74a
--- /dev/null
@@ -0,0 +1,1430 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "blockcache.h"
+#include "config.h"
+#include "debug.h"
+#include "disassembler.h"
+#include "emitter.h"
+#include "interpreter.h"
+#include "lightrec.h"
+#include "memmanager.h"
+#include "reaper.h"
+#include "recompiler.h"
+#include "regcache.h"
+#include "optimizer.h"
+
+#include <errno.h>
+#include <lightning.h>
+#include <limits.h>
+#if ENABLE_THREADED_COMPILER
+#include <stdatomic.h>
+#endif
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#if ENABLE_TINYMM
+#include <tinymm.h>
+#endif
+
+#define GENMASK(h, l) \
+       (((uintptr_t)-1 << (l)) & ((uintptr_t)-1 >> (__WORDSIZE - 1 - (h))))
+
+static struct block * lightrec_precompile_block(struct lightrec_state *state,
+                                               u32 pc);
+
+static void lightrec_default_sb(struct lightrec_state *state, u32 opcode,
+                               void *host, u32 addr, u8 data)
+{
+       *(u8 *)host = data;
+
+       if (!state->invalidate_from_dma_only)
+               lightrec_invalidate(state, addr, 1);
+}
+
+static void lightrec_default_sh(struct lightrec_state *state, u32 opcode,
+                               void *host, u32 addr, u16 data)
+{
+       *(u16 *)host = HTOLE16(data);
+
+       if (!state->invalidate_from_dma_only)
+               lightrec_invalidate(state, addr, 2);
+}
+
+static void lightrec_default_sw(struct lightrec_state *state, u32 opcode,
+                               void *host, u32 addr, u32 data)
+{
+       *(u32 *)host = HTOLE32(data);
+
+       if (!state->invalidate_from_dma_only)
+               lightrec_invalidate(state, addr, 4);
+}
+
+static u8 lightrec_default_lb(struct lightrec_state *state,
+                             u32 opcode, void *host, u32 addr)
+{
+       return *(u8 *)host;
+}
+
+static u16 lightrec_default_lh(struct lightrec_state *state,
+                              u32 opcode, void *host, u32 addr)
+{
+       return LE16TOH(*(u16 *)host);
+}
+
+static u32 lightrec_default_lw(struct lightrec_state *state,
+                              u32 opcode, void *host, u32 addr)
+{
+       return LE32TOH(*(u32 *)host);
+}
+
+static const struct lightrec_mem_map_ops lightrec_default_ops = {
+       .sb = lightrec_default_sb,
+       .sh = lightrec_default_sh,
+       .sw = lightrec_default_sw,
+       .lb = lightrec_default_lb,
+       .lh = lightrec_default_lh,
+       .lw = lightrec_default_lw,
+};
+
+static void __segfault_cb(struct lightrec_state *state, u32 addr)
+{
+       lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT);
+       pr_err("Segmentation fault in recompiled code: invalid "
+              "load/store at address 0x%08x\n", addr);
+}
+
+static void lightrec_swl(struct lightrec_state *state,
+                        const struct lightrec_mem_map_ops *ops,
+                        u32 opcode, void *host, u32 addr, u32 data)
+{
+       unsigned int shift = addr & 0x3;
+       unsigned int mask = GENMASK(31, (shift + 1) * 8);
+       u32 old_data;
+
+       /* Align to 32 bits */
+       addr &= ~3;
+       host = (void *)((uintptr_t)host & ~3);
+
+       old_data = ops->lw(state, opcode, host, addr);
+
+       data = (data >> ((3 - shift) * 8)) | (old_data & mask);
+
+       ops->sw(state, opcode, host, addr, data);
+}
+
+static void lightrec_swr(struct lightrec_state *state,
+                        const struct lightrec_mem_map_ops *ops,
+                        u32 opcode, void *host, u32 addr, u32 data)
+{
+       unsigned int shift = addr & 0x3;
+       unsigned int mask = (1 << (shift * 8)) - 1;
+       u32 old_data;
+
+       /* Align to 32 bits */
+       addr &= ~3;
+       host = (void *)((uintptr_t)host & ~3);
+
+       old_data = ops->lw(state, opcode, host, addr);
+
+       data = (data << (shift * 8)) | (old_data & mask);
+
+       ops->sw(state, opcode, host, addr, data);
+}
+
+static void lightrec_swc2(struct lightrec_state *state, union code op,
+                         const struct lightrec_mem_map_ops *ops,
+                         void *host, u32 addr)
+{
+       u32 data = state->ops.cop2_ops.mfc(state, op.opcode, op.i.rt);
+
+       ops->sw(state, op.opcode, host, addr, data);
+}
+
+static u32 lightrec_lwl(struct lightrec_state *state,
+                       const struct lightrec_mem_map_ops *ops,
+                       u32 opcode, void *host, u32 addr, u32 data)
+{
+       unsigned int shift = addr & 0x3;
+       unsigned int mask = (1 << (24 - shift * 8)) - 1;
+       u32 old_data;
+
+       /* Align to 32 bits */
+       addr &= ~3;
+       host = (void *)((uintptr_t)host & ~3);
+
+       old_data = ops->lw(state, opcode, host, addr);
+
+       return (data & mask) | (old_data << (24 - shift * 8));
+}
+
+static u32 lightrec_lwr(struct lightrec_state *state,
+                       const struct lightrec_mem_map_ops *ops,
+                       u32 opcode, void *host, u32 addr, u32 data)
+{
+       unsigned int shift = addr & 0x3;
+       unsigned int mask = GENMASK(31, 32 - shift * 8);
+       u32 old_data;
+
+       /* Align to 32 bits */
+       addr &= ~3;
+       host = (void *)((uintptr_t)host & ~3);
+
+       old_data = ops->lw(state, opcode, host, addr);
+
+       return (data & mask) | (old_data >> (shift * 8));
+}
+
+static void lightrec_lwc2(struct lightrec_state *state, union code op,
+                         const struct lightrec_mem_map_ops *ops,
+                         void *host, u32 addr)
+{
+       u32 data = ops->lw(state, op.opcode, host, addr);
+
+       state->ops.cop2_ops.mtc(state, op.opcode, op.i.rt, data);
+}
+
+static void lightrec_invalidate_map(struct lightrec_state *state,
+               const struct lightrec_mem_map *map, u32 addr)
+{
+       if (map == &state->maps[PSX_MAP_KERNEL_USER_RAM])
+               state->code_lut[lut_offset(addr)] = NULL;
+}
+
+static const struct lightrec_mem_map *
+lightrec_get_map(struct lightrec_state *state, u32 kaddr)
+{
+       unsigned int i;
+
+       for (i = 0; i < state->nb_maps; i++) {
+               const struct lightrec_mem_map *map = &state->maps[i];
+
+               if (kaddr >= map->pc && kaddr < map->pc + map->length)
+                       return map;
+       }
+
+       return NULL;
+}
+
+u32 lightrec_rw(struct lightrec_state *state, union code op,
+               u32 addr, u32 data, u16 *flags)
+{
+       const struct lightrec_mem_map *map;
+       const struct lightrec_mem_map_ops *ops;
+       u32 kaddr, pc, opcode = op.opcode;
+       void *host;
+
+       addr += (s16) op.i.imm;
+       kaddr = kunseg(addr);
+
+       map = lightrec_get_map(state, kaddr);
+       if (!map) {
+               __segfault_cb(state, addr);
+               return 0;
+       }
+
+       pc = map->pc;
+
+       while (map->mirror_of)
+               map = map->mirror_of;
+
+       host = (void *)((uintptr_t)map->address + kaddr - pc);
+
+       if (unlikely(map->ops)) {
+               if (flags)
+                       *flags |= LIGHTREC_HW_IO;
+
+               ops = map->ops;
+       } else {
+               if (flags)
+                       *flags |= LIGHTREC_DIRECT_IO;
+
+               ops = &lightrec_default_ops;
+       }
+
+       switch (op.i.op) {
+       case OP_SB:
+               ops->sb(state, opcode, host, addr, (u8) data);
+               return 0;
+       case OP_SH:
+               ops->sh(state, opcode, host, addr, (u16) data);
+               return 0;
+       case OP_SWL:
+               lightrec_swl(state, ops, opcode, host, addr, data);
+               return 0;
+       case OP_SWR:
+               lightrec_swr(state, ops, opcode, host, addr, data);
+               return 0;
+       case OP_SW:
+               ops->sw(state, opcode, host, addr, data);
+               return 0;
+       case OP_SWC2:
+               lightrec_swc2(state, op, ops, host, addr);
+               return 0;
+       case OP_LB:
+               return (s32) (s8) ops->lb(state, opcode, host, addr);
+       case OP_LBU:
+               return ops->lb(state, opcode, host, addr);
+       case OP_LH:
+               return (s32) (s16) ops->lh(state, opcode, host, addr);
+       case OP_LHU:
+               return ops->lh(state, opcode, host, addr);
+       case OP_LWC2:
+               lightrec_lwc2(state, op, ops, host, addr);
+               return 0;
+       case OP_LWL:
+               return lightrec_lwl(state, ops, opcode, host, addr, data);
+       case OP_LWR:
+               return lightrec_lwr(state, ops, opcode, host, addr, data);
+       case OP_LW:
+       default:
+               return ops->lw(state, opcode, host, addr);
+       }
+}
+
+static void lightrec_rw_helper(struct lightrec_state *state,
+                              union code op, u16 *flags)
+{
+       u32 ret = lightrec_rw(state, op,
+                         state->native_reg_cache[op.i.rs],
+                         state->native_reg_cache[op.i.rt], flags);
+
+       switch (op.i.op) {
+       case OP_LB:
+       case OP_LBU:
+       case OP_LH:
+       case OP_LHU:
+       case OP_LWL:
+       case OP_LWR:
+       case OP_LW:
+               if (op.i.rt)
+                       state->native_reg_cache[op.i.rt] = ret;
+       default: /* fall-through */
+               break;
+       }
+}
+
+static void lightrec_rw_cb(struct lightrec_state *state, union code op)
+{
+       lightrec_rw_helper(state, op, NULL);
+}
+
+static void lightrec_rw_generic_cb(struct lightrec_state *state,
+                                  struct opcode *op, struct block *block)
+{
+       bool was_tagged = op->flags & (LIGHTREC_HW_IO | LIGHTREC_DIRECT_IO);
+
+       lightrec_rw_helper(state, op->c, &op->flags);
+
+       if (!was_tagged) {
+               pr_debug("Opcode of block at PC 0x%08x offset 0x%x has been "
+                        "tagged - flag for recompilation\n",
+                        block->pc, op->offset << 2);
+
+               block->flags |= BLOCK_SHOULD_RECOMPILE;
+       }
+}
+
+u32 lightrec_mfc(struct lightrec_state *state, union code op)
+{
+       bool is_cfc = (op.i.op == OP_CP0 && op.r.rs == OP_CP0_CFC0) ||
+                     (op.i.op == OP_CP2 && op.r.rs == OP_CP2_BASIC_CFC2);
+       u32 (*func)(struct lightrec_state *, u32, u8);
+       const struct lightrec_cop_ops *ops;
+
+       if (op.i.op == OP_CP0)
+               ops = &state->ops.cop0_ops;
+       else
+               ops = &state->ops.cop2_ops;
+
+       if (is_cfc)
+               func = ops->cfc;
+       else
+               func = ops->mfc;
+
+       return (*func)(state, op.opcode, op.r.rd);
+}
+
+static void lightrec_mfc_cb(struct lightrec_state *state, union code op)
+{
+       u32 rt = lightrec_mfc(state, op);
+
+       if (op.r.rt)
+               state->native_reg_cache[op.r.rt] = rt;
+}
+
+void lightrec_mtc(struct lightrec_state *state, union code op, u32 data)
+{
+       bool is_ctc = (op.i.op == OP_CP0 && op.r.rs == OP_CP0_CTC0) ||
+                     (op.i.op == OP_CP2 && op.r.rs == OP_CP2_BASIC_CTC2);
+       void (*func)(struct lightrec_state *, u32, u8, u32);
+       const struct lightrec_cop_ops *ops;
+
+       if (op.i.op == OP_CP0)
+               ops = &state->ops.cop0_ops;
+       else
+               ops = &state->ops.cop2_ops;
+
+       if (is_ctc)
+               func = ops->ctc;
+       else
+               func = ops->mtc;
+
+       (*func)(state, op.opcode, op.r.rd, data);
+}
+
+static void lightrec_mtc_cb(struct lightrec_state *state, union code op)
+{
+       lightrec_mtc(state, op, state->native_reg_cache[op.r.rt]);
+}
+
+static void lightrec_rfe_cb(struct lightrec_state *state, union code op)
+{
+       u32 status;
+
+       /* Read CP0 Status register (r12) */
+       status = state->ops.cop0_ops.mfc(state, op.opcode, 12);
+
+       /* Switch the bits */
+       status = ((status & 0x3c) >> 2) | (status & ~0xf);
+
+       /* Write it back */
+       state->ops.cop0_ops.ctc(state, op.opcode, 12, status);
+}
+
+static void lightrec_cp_cb(struct lightrec_state *state, union code op)
+{
+       void (*func)(struct lightrec_state *, u32);
+
+       if ((op.opcode >> 25) & 1)
+               func = state->ops.cop2_ops.op;
+       else
+               func = state->ops.cop0_ops.op;
+
+       (*func)(state, op.opcode);
+}
+
+static void lightrec_syscall_cb(struct lightrec_state *state, union code op)
+{
+       lightrec_set_exit_flags(state, LIGHTREC_EXIT_SYSCALL);
+}
+
+static void lightrec_break_cb(struct lightrec_state *state, union code op)
+{
+       lightrec_set_exit_flags(state, LIGHTREC_EXIT_BREAK);
+}
+
+struct block * lightrec_get_block(struct lightrec_state *state, u32 pc)
+{
+       struct block *block = lightrec_find_block(state->block_cache, pc);
+
+       if (block && lightrec_block_is_outdated(block)) {
+               pr_debug("Block at PC 0x%08x is outdated!\n", block->pc);
+
+               /* Make sure the recompiler isn't processing the block we'll
+                * destroy */
+               if (ENABLE_THREADED_COMPILER)
+                       lightrec_recompiler_remove(state->rec, block);
+
+               lightrec_unregister_block(state->block_cache, block);
+               remove_from_code_lut(state->block_cache, block);
+               lightrec_free_block(block);
+               block = NULL;
+       }
+
+       if (!block) {
+               block = lightrec_precompile_block(state, pc);
+               if (!block) {
+                       pr_err("Unable to recompile block at PC 0x%x\n", pc);
+                       lightrec_set_exit_flags(state, LIGHTREC_EXIT_SEGFAULT);
+                       return NULL;
+               }
+
+               lightrec_register_block(state->block_cache, block);
+       }
+
+       return block;
+}
+
+static void * get_next_block_func(struct lightrec_state *state, u32 pc)
+{
+       struct block *block;
+       bool should_recompile;
+       void *func;
+
+       for (;;) {
+               func = state->code_lut[lut_offset(pc)];
+               if (func && func != state->get_next_block)
+                       return func;
+
+               block = lightrec_get_block(state, pc);
+
+               if (unlikely(!block))
+                       return NULL;
+
+               should_recompile = block->flags & BLOCK_SHOULD_RECOMPILE &&
+                       !(block->flags & BLOCK_IS_DEAD);
+
+               if (unlikely(should_recompile)) {
+                       pr_debug("Block at PC 0x%08x should recompile\n", pc);
+
+                       lightrec_unregister(MEM_FOR_CODE, block->code_size);
+
+                       if (ENABLE_THREADED_COMPILER)
+                               lightrec_recompiler_add(state->rec, block);
+                       else
+                               lightrec_compile_block(block);
+               }
+
+               if (ENABLE_THREADED_COMPILER && likely(!should_recompile))
+                       func = lightrec_recompiler_run_first_pass(block, &pc);
+               else
+                       func = block->function;
+
+               if (likely(func))
+                       return func;
+
+               /* Block wasn't compiled yet - run the interpreter */
+               if (!ENABLE_THREADED_COMPILER &&
+                   ((ENABLE_FIRST_PASS && likely(!should_recompile)) ||
+                    unlikely(block->flags & BLOCK_NEVER_COMPILE)))
+                       pc = lightrec_emulate_block(block, pc);
+
+               if (likely(!(block->flags & BLOCK_NEVER_COMPILE))) {
+                       /* Then compile it using the profiled data */
+                       if (ENABLE_THREADED_COMPILER)
+                               lightrec_recompiler_add(state->rec, block);
+                       else
+                               lightrec_compile_block(block);
+               }
+
+               if (state->exit_flags != LIGHTREC_EXIT_NORMAL ||
+                   state->current_cycle >= state->target_cycle) {
+                       state->next_pc = pc;
+                       return NULL;
+               }
+       }
+}
+
+static s32 c_generic_function_wrapper(struct lightrec_state *state,
+                                     s32 cycles_delta,
+                                     void (*f)(struct lightrec_state *,
+                                               struct opcode *,
+                                               struct block *),
+                                     struct opcode *op, struct block *block)
+{
+       state->current_cycle = state->target_cycle - cycles_delta;
+
+       (*f)(state, op, block);
+
+       return state->target_cycle - state->current_cycle;
+}
+
+static s32 c_function_wrapper(struct lightrec_state *state, s32 cycles_delta,
+                             void (*f)(struct lightrec_state *, union code),
+                             union code op)
+{
+       state->current_cycle = state->target_cycle - cycles_delta;
+
+       (*f)(state, op);
+
+       return state->target_cycle - state->current_cycle;
+}
+
+static struct block * generate_wrapper(struct lightrec_state *state,
+                                      void *f, bool generic)
+{
+       struct block *block;
+       jit_state_t *_jit;
+       unsigned int i;
+       int stack_ptr;
+       jit_word_t code_size;
+       jit_node_t *to_tramp, *to_fn_epilog;
+
+       block = lightrec_malloc(state, MEM_FOR_IR, sizeof(*block));
+       if (!block)
+               goto err_no_mem;
+
+       _jit = jit_new_state();
+       if (!_jit)
+               goto err_free_block;
+
+       jit_name("RW wrapper");
+       jit_note(__FILE__, __LINE__);
+
+       /* Wrapper entry point */
+       jit_prolog();
+
+       stack_ptr = jit_allocai(sizeof(uintptr_t) * NUM_TEMPS);
+
+       for (i = 0; i < NUM_TEMPS; i++)
+               jit_stxi(stack_ptr + i * sizeof(uintptr_t), JIT_FP, JIT_R(i));
+
+       /* Jump to the trampoline */
+       to_tramp = jit_jmpi();
+
+       /* The trampoline will jump back here */
+       to_fn_epilog = jit_label();
+
+       for (i = 0; i < NUM_TEMPS; i++)
+               jit_ldxi(JIT_R(i), JIT_FP, stack_ptr + i * sizeof(uintptr_t));
+
+       jit_ret();
+       jit_epilog();
+
+       /* Trampoline entry point.
+        * The sole purpose of the trampoline is to cheese Lightning not to
+        * save/restore the callee-saved register LIGHTREC_REG_CYCLE, since we
+        * do want to return to the caller with this register modified. */
+       jit_prolog();
+       jit_tramp(256);
+       jit_patch(to_tramp);
+
+       jit_prepare();
+       jit_pushargr(LIGHTREC_REG_STATE);
+       jit_pushargr(LIGHTREC_REG_CYCLE);
+       jit_pushargi((uintptr_t)f);
+       jit_pushargr(JIT_R0);
+       if (generic) {
+               jit_pushargr(JIT_R1);
+               jit_finishi(c_generic_function_wrapper);
+       } else {
+               jit_finishi(c_function_wrapper);
+       }
+
+#if __WORDSIZE == 64
+       jit_retval_i(LIGHTREC_REG_CYCLE);
+#else
+       jit_retval(LIGHTREC_REG_CYCLE);
+#endif
+
+       jit_patch_at(jit_jmpi(), to_fn_epilog);
+       jit_epilog();
+
+       block->state = state;
+       block->_jit = _jit;
+       block->function = jit_emit();
+       block->opcode_list = NULL;
+       block->flags = 0;
+       block->nb_ops = 0;
+
+       jit_get_code(&code_size);
+       lightrec_register(MEM_FOR_CODE, code_size);
+
+       block->code_size = code_size;
+
+       if (ENABLE_DISASSEMBLER) {
+               pr_debug("Wrapper block:\n");
+               jit_disassemble();
+       }
+
+       jit_clear_state();
+       return block;
+
+err_free_block:
+       lightrec_free(state, MEM_FOR_IR, sizeof(*block), block);
+err_no_mem:
+       pr_err("Unable to compile wrapper: Out of memory\n");
+       return NULL;
+}
+
+static struct block * generate_dispatcher(struct lightrec_state *state)
+{
+       struct block *block;
+       jit_state_t *_jit;
+       jit_node_t *to_end, *to_end2, *to_c, *loop, *addr, *addr2;
+       unsigned int i;
+       u32 offset, ram_len;
+       jit_word_t code_size;
+
+       block = lightrec_malloc(state, MEM_FOR_IR, sizeof(*block));
+       if (!block)
+               goto err_no_mem;
+
+       _jit = jit_new_state();
+       if (!_jit)
+               goto err_free_block;
+
+       jit_name("dispatcher");
+       jit_note(__FILE__, __LINE__);
+
+       jit_prolog();
+       jit_frame(256);
+
+       jit_getarg(JIT_R0, jit_arg());
+#if __WORDSIZE == 64
+       jit_getarg_i(LIGHTREC_REG_CYCLE, jit_arg());
+#else
+       jit_getarg(LIGHTREC_REG_CYCLE, jit_arg());
+#endif
+
+       /* Force all callee-saved registers to be pushed on the stack */
+       for (i = 0; i < NUM_REGS; i++)
+               jit_movr(JIT_V(i), JIT_V(i));
+
+       /* Pass lightrec_state structure to blocks, using the last callee-saved
+        * register that Lightning provides */
+       jit_movi(LIGHTREC_REG_STATE, (intptr_t) state);
+
+       loop = jit_label();
+
+       /* Call the block's code */
+       jit_jmpr(JIT_R0);
+
+       /* The block will jump here, with the number of cycles remaining in
+        * LIGHTREC_REG_CYCLE */
+       addr2 = jit_indirect();
+
+       /* Jump to end if state->target_cycle < state->current_cycle */
+       to_end = jit_blei(LIGHTREC_REG_CYCLE, 0);
+
+       /* Convert next PC to KUNSEG and avoid mirrors */
+       ram_len = state->maps[PSX_MAP_KERNEL_USER_RAM].length;
+       jit_andi(JIT_R0, JIT_V0, 0x10000000 | (ram_len - 1));
+       to_c = jit_bgei(JIT_R0, ram_len);
+
+       /* Fast path: code is running from RAM, use the code LUT */
+#if __WORDSIZE == 64
+       jit_lshi(JIT_R0, JIT_R0, 1);
+#endif
+       jit_addr(JIT_R0, JIT_R0, LIGHTREC_REG_STATE);
+       jit_ldxi(JIT_R0, JIT_R0, offsetof(struct lightrec_state, code_lut));
+
+       /* If we get non-NULL, loop */
+       jit_patch_at(jit_bnei(JIT_R0, 0), loop);
+
+       /* Slow path: call C function get_next_block_func() */
+       jit_patch(to_c);
+
+       if (ENABLE_FIRST_PASS) {
+               /* We may call the interpreter - update state->current_cycle */
+               jit_ldxi_i(JIT_R2, LIGHTREC_REG_STATE,
+                          offsetof(struct lightrec_state, target_cycle));
+               jit_subr(JIT_R1, JIT_R2, LIGHTREC_REG_CYCLE);
+               jit_stxi_i(offsetof(struct lightrec_state, current_cycle),
+                          LIGHTREC_REG_STATE, JIT_R1);
+       }
+
+       /* The code LUT will be set to this address when the block at the target
+        * PC has been preprocessed but not yet compiled by the threaded
+        * recompiler */
+       addr = jit_indirect();
+
+       /* Get the next block */
+       jit_prepare();
+       jit_pushargr(LIGHTREC_REG_STATE);
+       jit_pushargr(JIT_V0);
+       jit_finishi(&get_next_block_func);
+       jit_retval(JIT_R0);
+
+       if (ENABLE_FIRST_PASS) {
+               /* The interpreter may have updated state->current_cycle and
+                * state->target_cycle - recalc the delta */
+               jit_ldxi_i(JIT_R1, LIGHTREC_REG_STATE,
+                          offsetof(struct lightrec_state, current_cycle));
+               jit_ldxi_i(JIT_R2, LIGHTREC_REG_STATE,
+                          offsetof(struct lightrec_state, target_cycle));
+               jit_subr(LIGHTREC_REG_CYCLE, JIT_R2, JIT_R1);
+       }
+
+       /* If we get non-NULL, loop */
+       jit_patch_at(jit_bnei(JIT_R0, 0), loop);
+
+       to_end2 = jit_jmpi();
+
+       /* When exiting, the recompiled code will jump to that address */
+       jit_note(__FILE__, __LINE__);
+       jit_patch(to_end);
+
+       /* Store back the next_pc to the lightrec_state structure */
+       offset = offsetof(struct lightrec_state, next_pc);
+       jit_stxi_i(offset, LIGHTREC_REG_STATE, JIT_V0);
+
+       jit_patch(to_end2);
+
+       jit_retr(LIGHTREC_REG_CYCLE);
+       jit_epilog();
+
+       block->state = state;
+       block->_jit = _jit;
+       block->function = jit_emit();
+       block->opcode_list = NULL;
+       block->flags = 0;
+       block->nb_ops = 0;
+
+       jit_get_code(&code_size);
+       lightrec_register(MEM_FOR_CODE, code_size);
+
+       block->code_size = code_size;
+
+       state->eob_wrapper_func = jit_address(addr2);
+       state->get_next_block = jit_address(addr);
+
+       if (ENABLE_DISASSEMBLER) {
+               pr_debug("Dispatcher block:\n");
+               jit_disassemble();
+       }
+
+       /* We're done! */
+       jit_clear_state();
+       return block;
+
+err_free_block:
+       lightrec_free(state, MEM_FOR_IR, sizeof(*block), block);
+err_no_mem:
+       pr_err("Unable to compile dispatcher: Out of memory\n");
+       return NULL;
+}
+
+union code lightrec_read_opcode(struct lightrec_state *state, u32 pc)
+{
+       u32 addr, kunseg_pc = kunseg(pc);
+       const u32 *code;
+       const struct lightrec_mem_map *map = lightrec_get_map(state, kunseg_pc);
+
+       addr = kunseg_pc - map->pc;
+
+       while (map->mirror_of)
+               map = map->mirror_of;
+
+       code = map->address + addr;
+
+       return (union code) *code;
+}
+
+static struct block * lightrec_precompile_block(struct lightrec_state *state,
+                                               u32 pc)
+{
+       struct opcode *list;
+       struct block *block;
+       const u32 *code;
+       u32 addr, kunseg_pc = kunseg(pc);
+       const struct lightrec_mem_map *map = lightrec_get_map(state, kunseg_pc);
+       unsigned int length;
+
+       if (!map)
+               return NULL;
+
+       addr = kunseg_pc - map->pc;
+
+       while (map->mirror_of)
+               map = map->mirror_of;
+
+       code = map->address + addr;
+
+       block = lightrec_malloc(state, MEM_FOR_IR, sizeof(*block));
+       if (!block) {
+               pr_err("Unable to recompile block: Out of memory\n");
+               return NULL;
+       }
+
+       list = lightrec_disassemble(state, code, &length);
+       if (!list) {
+               lightrec_free(state, MEM_FOR_IR, sizeof(*block), block);
+               return NULL;
+       }
+
+       block->pc = pc;
+       block->state = state;
+       block->_jit = NULL;
+       block->function = NULL;
+       block->opcode_list = list;
+       block->map = map;
+       block->next = NULL;
+       block->flags = 0;
+       block->code_size = 0;
+#if ENABLE_THREADED_COMPILER
+       block->op_list_freed = (atomic_flag)ATOMIC_FLAG_INIT;
+#endif
+       block->nb_ops = length / sizeof(u32);
+
+       lightrec_optimize(block);
+
+       length = block->nb_ops * sizeof(u32);
+
+       lightrec_register(MEM_FOR_MIPS_CODE, length);
+
+       if (ENABLE_DISASSEMBLER) {
+               pr_debug("Disassembled block at PC: 0x%x\n", block->pc);
+               lightrec_print_disassembly(block, code, length);
+       }
+
+       pr_debug("Block size: %lu opcodes\n", block->nb_ops);
+
+       /* If the first opcode is an 'impossible' branch, never compile the
+        * block */
+       if (list->flags & LIGHTREC_EMULATE_BRANCH)
+               block->flags |= BLOCK_NEVER_COMPILE;
+
+       block->hash = lightrec_calculate_block_hash(block);
+
+       pr_debug("Recompile count: %u\n", state->nb_precompile++);
+
+       return block;
+}
+
+static bool lightrec_block_is_fully_tagged(struct block *block)
+{
+       struct opcode *op;
+
+       for (op = block->opcode_list; op; op = op->next) {
+               /* Verify that all load/stores of the opcode list
+                * Check all loads/stores of the opcode list and mark the
+                * block as fully compiled if they all have been tagged. */
+               switch (op->c.i.op) {
+               case OP_LB:
+               case OP_LH:
+               case OP_LWL:
+               case OP_LW:
+               case OP_LBU:
+               case OP_LHU:
+               case OP_LWR:
+               case OP_SB:
+               case OP_SH:
+               case OP_SWL:
+               case OP_SW:
+               case OP_SWR:
+               case OP_LWC2:
+               case OP_SWC2:
+                       if (!(op->flags & (LIGHTREC_DIRECT_IO |
+                                          LIGHTREC_HW_IO)))
+                               return false;
+               default: /* fall-through */
+                       continue;
+               }
+       }
+
+       return true;
+}
+
+static void lightrec_reap_block(void *data)
+{
+       struct block *block = data;
+
+       pr_debug("Reap dead block at PC 0x%08x\n", block->pc);
+       lightrec_free_block(block);
+}
+
+static void lightrec_reap_jit(void *data)
+{
+       _jit_destroy_state(data);
+}
+
+int lightrec_compile_block(struct block *block)
+{
+       struct lightrec_state *state = block->state;
+       struct lightrec_branch_target *target;
+       bool op_list_freed = false, fully_tagged = false;
+       struct block *block2;
+       struct opcode *elm;
+       jit_state_t *_jit, *oldjit;
+       jit_node_t *start_of_block;
+       bool skip_next = false;
+       jit_word_t code_size;
+       unsigned int i, j;
+       u32 next_pc, offset;
+
+       fully_tagged = lightrec_block_is_fully_tagged(block);
+       if (fully_tagged)
+               block->flags |= BLOCK_FULLY_TAGGED;
+
+       _jit = jit_new_state();
+       if (!_jit)
+               return -ENOMEM;
+
+       oldjit = block->_jit;
+       block->_jit = _jit;
+
+       lightrec_regcache_reset(state->reg_cache);
+       state->cycles = 0;
+       state->nb_branches = 0;
+       state->nb_local_branches = 0;
+       state->nb_targets = 0;
+
+       jit_prolog();
+       jit_tramp(256);
+
+       start_of_block = jit_label();
+
+       for (elm = block->opcode_list; elm; elm = elm->next) {
+               next_pc = block->pc + elm->offset * sizeof(u32);
+
+               if (skip_next) {
+                       skip_next = false;
+                       continue;
+               }
+
+               state->cycles += lightrec_cycles_of_opcode(elm->c);
+
+               if (elm->flags & LIGHTREC_EMULATE_BRANCH) {
+                       pr_debug("Branch at offset 0x%x will be emulated\n",
+                                elm->offset << 2);
+                       lightrec_emit_eob(block, elm, next_pc);
+                       skip_next = !(elm->flags & LIGHTREC_NO_DS);
+               } else if (elm->opcode) {
+                       lightrec_rec_opcode(block, elm, next_pc);
+                       skip_next = has_delay_slot(elm->c) &&
+                               !(elm->flags & LIGHTREC_NO_DS);
+#if _WIN32
+                       /* FIXME: GNU Lightning on Windows seems to use our
+                        * mapped registers as temporaries. Until the actual bug
+                        * is found and fixed, unconditionally mark our
+                        * registers as live here. */
+                       lightrec_regcache_mark_live(state->reg_cache, _jit);
+#endif
+               }
+       }
+
+       for (i = 0; i < state->nb_branches; i++)
+               jit_patch(state->branches[i]);
+
+       for (i = 0; i < state->nb_local_branches; i++) {
+               struct lightrec_branch *branch = &state->local_branches[i];
+
+               pr_debug("Patch local branch to offset 0x%x\n",
+                        branch->target << 2);
+
+               if (branch->target == 0) {
+                       jit_patch_at(branch->branch, start_of_block);
+                       continue;
+               }
+
+               for (j = 0; j < state->nb_targets; j++) {
+                       if (state->targets[j].offset == branch->target) {
+                               jit_patch_at(branch->branch,
+                                            state->targets[j].label);
+                               break;
+                       }
+               }
+
+               if (j == state->nb_targets)
+                       pr_err("Unable to find branch target\n");
+       }
+
+       jit_ldxi(JIT_R0, LIGHTREC_REG_STATE,
+                offsetof(struct lightrec_state, eob_wrapper_func));
+
+       jit_jmpr(JIT_R0);
+
+       jit_ret();
+       jit_epilog();
+
+       block->function = jit_emit();
+       block->flags &= ~BLOCK_SHOULD_RECOMPILE;
+
+       /* Add compiled function to the LUT */
+       state->code_lut[lut_offset(block->pc)] = block->function;
+
+       /* Fill code LUT with the block's entry points */
+       for (i = 0; i < state->nb_targets; i++) {
+               target = &state->targets[i];
+
+               if (target->offset) {
+                       offset = lut_offset(block->pc) + target->offset;
+                       state->code_lut[offset] = jit_address(target->label);
+               }
+       }
+
+       /* Detect old blocks that have been covered by the new one */
+       for (i = 0; i < state->nb_targets; i++) {
+               target = &state->targets[i];
+
+               if (!target->offset)
+                       continue;
+
+               offset = block->pc + target->offset * sizeof(u32);
+               block2 = lightrec_find_block(state->block_cache, offset);
+               if (block2) {
+                       /* No need to check if block2 is compilable - it must
+                        * be, otherwise block wouldn't be compilable either */
+
+                       block2->flags |= BLOCK_IS_DEAD;
+
+                       pr_debug("Reap block 0x%08x as it's covered by block "
+                                "0x%08x\n", block2->pc, block->pc);
+
+                       lightrec_unregister_block(state->block_cache, block2);
+
+                       if (ENABLE_THREADED_COMPILER) {
+                               lightrec_recompiler_remove(state->rec, block2);
+                               lightrec_reaper_add(state->reaper,
+                                                   lightrec_reap_block,
+                                                   block2);
+                       } else {
+                               lightrec_free_block(block2);
+                       }
+               }
+       }
+
+       jit_get_code(&code_size);
+       lightrec_register(MEM_FOR_CODE, code_size);
+
+       block->code_size = code_size;
+
+       if (ENABLE_DISASSEMBLER) {
+               pr_debug("Compiling block at PC: 0x%x\n", block->pc);
+               jit_disassemble();
+       }
+
+       jit_clear_state();
+
+#if ENABLE_THREADED_COMPILER
+       if (fully_tagged)
+               op_list_freed = atomic_flag_test_and_set(&block->op_list_freed);
+#endif
+       if (fully_tagged && !op_list_freed) {
+               pr_debug("Block PC 0x%08x is fully tagged"
+                        " - free opcode list\n", block->pc);
+               lightrec_free_opcode_list(state, block->opcode_list);
+               block->opcode_list = NULL;
+       }
+
+       if (oldjit) {
+               pr_debug("Block 0x%08x recompiled, reaping old jit context.\n",
+                        block->pc);
+
+               if (ENABLE_THREADED_COMPILER)
+                       lightrec_reaper_add(state->reaper,
+                                           lightrec_reap_jit, oldjit);
+               else
+                       _jit_destroy_state(oldjit);
+       }
+
+       return 0;
+}
+
+u32 lightrec_execute(struct lightrec_state *state, u32 pc, u32 target_cycle)
+{
+       s32 (*func)(void *, s32) = (void *)state->dispatcher->function;
+       void *block_trace;
+       s32 cycles_delta;
+
+       state->exit_flags = LIGHTREC_EXIT_NORMAL;
+
+       /* Handle the cycle counter overflowing */
+       if (unlikely(target_cycle < state->current_cycle))
+               target_cycle = UINT_MAX;
+
+       state->target_cycle = target_cycle;
+
+       block_trace = get_next_block_func(state, pc);
+       if (block_trace) {
+               cycles_delta = state->target_cycle - state->current_cycle;
+
+               cycles_delta = (*func)(block_trace, cycles_delta);
+
+               state->current_cycle = state->target_cycle - cycles_delta;
+       }
+
+       if (ENABLE_THREADED_COMPILER)
+               lightrec_reaper_reap(state->reaper);
+
+       return state->next_pc;
+}
+
+u32 lightrec_execute_one(struct lightrec_state *state, u32 pc)
+{
+       return lightrec_execute(state, pc, state->current_cycle);
+}
+
+u32 lightrec_run_interpreter(struct lightrec_state *state, u32 pc)
+{
+       struct block *block = lightrec_get_block(state, pc);
+       if (!block)
+               return 0;
+
+       state->exit_flags = LIGHTREC_EXIT_NORMAL;
+
+       return lightrec_emulate_block(block, pc);
+}
+
+void lightrec_free_block(struct block *block)
+{
+       lightrec_unregister(MEM_FOR_MIPS_CODE, block->nb_ops * sizeof(u32));
+       if (block->opcode_list)
+               lightrec_free_opcode_list(block->state, block->opcode_list);
+       if (block->_jit)
+               _jit_destroy_state(block->_jit);
+       lightrec_unregister(MEM_FOR_CODE, block->code_size);
+       lightrec_free(block->state, MEM_FOR_IR, sizeof(*block), block);
+}
+
+struct lightrec_state * lightrec_init(char *argv0,
+                                     const struct lightrec_mem_map *map,
+                                     size_t nb,
+                                     const struct lightrec_ops *ops)
+{
+       struct lightrec_state *state;
+
+       /* Sanity-check ops */
+       if (!ops ||
+           !ops->cop0_ops.mfc || !ops->cop0_ops.cfc || !ops->cop0_ops.mtc ||
+           !ops->cop0_ops.ctc || !ops->cop0_ops.op ||
+           !ops->cop2_ops.mfc || !ops->cop2_ops.cfc || !ops->cop2_ops.mtc ||
+           !ops->cop2_ops.ctc || !ops->cop2_ops.op) {
+               pr_err("Missing callbacks in lightrec_ops structure\n");
+               return NULL;
+       }
+
+       init_jit(argv0);
+
+       state = calloc(1, sizeof(*state) +
+                      sizeof(*state->code_lut) * CODE_LUT_SIZE);
+       if (!state)
+               goto err_finish_jit;
+
+       lightrec_register(MEM_FOR_LIGHTREC, sizeof(*state) +
+                         sizeof(*state->code_lut) * CODE_LUT_SIZE);
+
+#if ENABLE_TINYMM
+       state->tinymm = tinymm_init(malloc, free, 4096);
+       if (!state->tinymm)
+               goto err_free_state;
+#endif
+
+       state->block_cache = lightrec_blockcache_init(state);
+       if (!state->block_cache)
+               goto err_free_tinymm;
+
+       state->reg_cache = lightrec_regcache_init(state);
+       if (!state->reg_cache)
+               goto err_free_block_cache;
+
+       if (ENABLE_THREADED_COMPILER) {
+               state->rec = lightrec_recompiler_init(state);
+               if (!state->rec)
+                       goto err_free_reg_cache;
+
+               state->reaper = lightrec_reaper_init(state);
+               if (!state->reaper)
+                       goto err_free_recompiler;
+       }
+
+       state->nb_maps = nb;
+       state->maps = map;
+
+       memcpy(&state->ops, ops, sizeof(*ops));
+
+       state->dispatcher = generate_dispatcher(state);
+       if (!state->dispatcher)
+               goto err_free_reaper;
+
+       state->rw_generic_wrapper = generate_wrapper(state,
+                                                    lightrec_rw_generic_cb,
+                                                    true);
+       if (!state->rw_generic_wrapper)
+               goto err_free_dispatcher;
+
+       state->rw_wrapper = generate_wrapper(state, lightrec_rw_cb, false);
+       if (!state->rw_wrapper)
+               goto err_free_generic_rw_wrapper;
+
+       state->mfc_wrapper = generate_wrapper(state, lightrec_mfc_cb, false);
+       if (!state->mfc_wrapper)
+               goto err_free_rw_wrapper;
+
+       state->mtc_wrapper = generate_wrapper(state, lightrec_mtc_cb, false);
+       if (!state->mtc_wrapper)
+               goto err_free_mfc_wrapper;
+
+       state->rfe_wrapper = generate_wrapper(state, lightrec_rfe_cb, false);
+       if (!state->rfe_wrapper)
+               goto err_free_mtc_wrapper;
+
+       state->cp_wrapper = generate_wrapper(state, lightrec_cp_cb, false);
+       if (!state->cp_wrapper)
+               goto err_free_rfe_wrapper;
+
+       state->syscall_wrapper = generate_wrapper(state, lightrec_syscall_cb,
+                                                 false);
+       if (!state->syscall_wrapper)
+               goto err_free_cp_wrapper;
+
+       state->break_wrapper = generate_wrapper(state, lightrec_break_cb,
+                                               false);
+       if (!state->break_wrapper)
+               goto err_free_syscall_wrapper;
+
+       state->rw_generic_func = state->rw_generic_wrapper->function;
+       state->rw_func = state->rw_wrapper->function;
+       state->mfc_func = state->mfc_wrapper->function;
+       state->mtc_func = state->mtc_wrapper->function;
+       state->rfe_func = state->rfe_wrapper->function;
+       state->cp_func = state->cp_wrapper->function;
+       state->syscall_func = state->syscall_wrapper->function;
+       state->break_func = state->break_wrapper->function;
+
+       map = &state->maps[PSX_MAP_BIOS];
+       state->offset_bios = (uintptr_t)map->address - map->pc;
+
+       map = &state->maps[PSX_MAP_SCRATCH_PAD];
+       state->offset_scratch = (uintptr_t)map->address - map->pc;
+
+       map = &state->maps[PSX_MAP_KERNEL_USER_RAM];
+       state->offset_ram = (uintptr_t)map->address - map->pc;
+
+       if (state->maps[PSX_MAP_MIRROR1].address == map->address + 0x200000 &&
+           state->maps[PSX_MAP_MIRROR2].address == map->address + 0x400000 &&
+           state->maps[PSX_MAP_MIRROR3].address == map->address + 0x600000)
+               state->mirrors_mapped = true;
+
+       return state;
+
+err_free_syscall_wrapper:
+       lightrec_free_block(state->syscall_wrapper);
+err_free_cp_wrapper:
+       lightrec_free_block(state->cp_wrapper);
+err_free_rfe_wrapper:
+       lightrec_free_block(state->rfe_wrapper);
+err_free_mtc_wrapper:
+       lightrec_free_block(state->mtc_wrapper);
+err_free_mfc_wrapper:
+       lightrec_free_block(state->mfc_wrapper);
+err_free_rw_wrapper:
+       lightrec_free_block(state->rw_wrapper);
+err_free_generic_rw_wrapper:
+       lightrec_free_block(state->rw_generic_wrapper);
+err_free_dispatcher:
+       lightrec_free_block(state->dispatcher);
+err_free_reaper:
+       if (ENABLE_THREADED_COMPILER)
+               lightrec_reaper_destroy(state->reaper);
+err_free_recompiler:
+       if (ENABLE_THREADED_COMPILER)
+               lightrec_free_recompiler(state->rec);
+err_free_reg_cache:
+       lightrec_free_regcache(state->reg_cache);
+err_free_block_cache:
+       lightrec_free_block_cache(state->block_cache);
+err_free_tinymm:
+#if ENABLE_TINYMM
+       tinymm_shutdown(state->tinymm);
+err_free_state:
+#endif
+       lightrec_unregister(MEM_FOR_LIGHTREC, sizeof(*state) +
+                           sizeof(*state->code_lut) * CODE_LUT_SIZE);
+       free(state);
+err_finish_jit:
+       finish_jit();
+       return NULL;
+}
+
+void lightrec_destroy(struct lightrec_state *state)
+{
+       if (ENABLE_THREADED_COMPILER) {
+               lightrec_free_recompiler(state->rec);
+               lightrec_reaper_destroy(state->reaper);
+       }
+
+       lightrec_free_regcache(state->reg_cache);
+       lightrec_free_block_cache(state->block_cache);
+       lightrec_free_block(state->dispatcher);
+       lightrec_free_block(state->rw_generic_wrapper);
+       lightrec_free_block(state->rw_wrapper);
+       lightrec_free_block(state->mfc_wrapper);
+       lightrec_free_block(state->mtc_wrapper);
+       lightrec_free_block(state->rfe_wrapper);
+       lightrec_free_block(state->cp_wrapper);
+       lightrec_free_block(state->syscall_wrapper);
+       lightrec_free_block(state->break_wrapper);
+       finish_jit();
+
+#if ENABLE_TINYMM
+       tinymm_shutdown(state->tinymm);
+#endif
+       lightrec_unregister(MEM_FOR_LIGHTREC, sizeof(*state) +
+                           sizeof(*state->code_lut) * CODE_LUT_SIZE);
+       free(state);
+}
+
+void lightrec_invalidate(struct lightrec_state *state, u32 addr, u32 len)
+{
+       u32 kaddr = kunseg(addr & ~0x3);
+       const struct lightrec_mem_map *map = lightrec_get_map(state, kaddr);
+
+       if (map) {
+               while (map->mirror_of)
+                       map = map->mirror_of;
+
+               if (map != &state->maps[PSX_MAP_KERNEL_USER_RAM])
+                       return;
+
+               /* Handle mirrors */
+               kaddr &= (state->maps[PSX_MAP_KERNEL_USER_RAM].length - 1);
+
+               for (; len > 4; len -= 4, kaddr += 4)
+                       lightrec_invalidate_map(state, map, kaddr);
+
+               lightrec_invalidate_map(state, map, kaddr);
+       }
+}
+
+void lightrec_invalidate_all(struct lightrec_state *state)
+{
+       memset(state->code_lut, 0, sizeof(*state->code_lut) * CODE_LUT_SIZE);
+}
+
+void lightrec_set_invalidate_mode(struct lightrec_state *state, bool dma_only)
+{
+       if (state->invalidate_from_dma_only != dma_only)
+               lightrec_invalidate_all(state);
+
+       state->invalidate_from_dma_only = dma_only;
+}
+
+void lightrec_set_exit_flags(struct lightrec_state *state, u32 flags)
+{
+       if (flags != LIGHTREC_EXIT_NORMAL) {
+               state->exit_flags |= flags;
+               state->target_cycle = state->current_cycle;
+       }
+}
+
+u32 lightrec_exit_flags(struct lightrec_state *state)
+{
+       return state->exit_flags;
+}
+
+void lightrec_dump_registers(struct lightrec_state *state, u32 regs[34])
+{
+       memcpy(regs, state->native_reg_cache, sizeof(state->native_reg_cache));
+}
+
+void lightrec_restore_registers(struct lightrec_state *state, u32 regs[34])
+{
+       memcpy(state->native_reg_cache, regs, sizeof(state->native_reg_cache));
+}
+
+u32 lightrec_current_cycle_count(const struct lightrec_state *state)
+{
+       return state->current_cycle;
+}
+
+void lightrec_reset_cycle_count(struct lightrec_state *state, u32 cycles)
+{
+       state->current_cycle = cycles;
+
+       if (state->target_cycle < cycles)
+               state->target_cycle = cycles;
+}
+
+void lightrec_set_target_cycle_count(struct lightrec_state *state, u32 cycles)
+{
+       if (state->exit_flags == LIGHTREC_EXIT_NORMAL) {
+               if (cycles < state->current_cycle)
+                       cycles = state->current_cycle;
+
+               state->target_cycle = cycles;
+       }
+}
diff --git a/deps/lightrec/lightrec.h b/deps/lightrec/lightrec.h
new file mode 100644 (file)
index 0000000..d0793c0
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2016-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __LIGHTREC_H__
+#define __LIGHTREC_H__
+
+#ifdef __cplusplus
+#define _Bool bool
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef _WIN32
+#   ifdef lightrec_EXPORTS
+#      define __api __declspec(dllexport)
+#   elif !defined(LIGHTREC_STATIC)
+#      define __api __declspec(dllimport)
+#   else
+#      define __api
+#   endif
+#elif __GNUC__ >= 4
+#   define __api __attribute__((visibility ("default")))
+#else
+#   define __api
+#endif
+
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t  u8;
+
+typedef int64_t s64;
+typedef int32_t s32;
+typedef int16_t s16;
+typedef int8_t  s8;
+
+struct lightrec_state;
+struct lightrec_mem_map;
+
+/* Exit flags */
+#define LIGHTREC_EXIT_NORMAL   (0)
+#define LIGHTREC_EXIT_SYSCALL  (1 << 0)
+#define LIGHTREC_EXIT_BREAK    (1 << 1)
+#define LIGHTREC_EXIT_CHECK_INTERRUPT  (1 << 2)
+#define LIGHTREC_EXIT_SEGFAULT (1 << 3)
+
+enum psx_map {
+       PSX_MAP_KERNEL_USER_RAM,
+       PSX_MAP_BIOS,
+       PSX_MAP_SCRATCH_PAD,
+       PSX_MAP_PARALLEL_PORT,
+       PSX_MAP_HW_REGISTERS,
+       PSX_MAP_CACHE_CONTROL,
+       PSX_MAP_MIRROR1,
+       PSX_MAP_MIRROR2,
+       PSX_MAP_MIRROR3,
+};
+
+enum mem_type {
+       MEM_FOR_CODE,
+       MEM_FOR_MIPS_CODE,
+       MEM_FOR_IR,
+       MEM_FOR_LIGHTREC,
+       MEM_TYPE_END,
+};
+
+struct lightrec_mem_map_ops {
+       void (*sb)(struct lightrec_state *, u32 opcode,
+                  void *host, u32 addr, u8 data);
+       void (*sh)(struct lightrec_state *, u32 opcode,
+                  void *host, u32 addr, u16 data);
+       void (*sw)(struct lightrec_state *, u32 opcode,
+                  void *host, u32 addr, u32 data);
+       u8 (*lb)(struct lightrec_state *, u32 opcode, void *host, u32 addr);
+       u16 (*lh)(struct lightrec_state *, u32 opcode, void *host, u32 addr);
+       u32 (*lw)(struct lightrec_state *, u32 opcode, void *host, u32 addr);
+};
+
+struct lightrec_mem_map {
+       u32 pc;
+       u32 length;
+       void *address;
+       const struct lightrec_mem_map_ops *ops;
+       const struct lightrec_mem_map *mirror_of;
+};
+
+struct lightrec_cop_ops {
+       u32 (*mfc)(struct lightrec_state *state, u32 op, u8 reg);
+       u32 (*cfc)(struct lightrec_state *state, u32 op, u8 reg);
+       void (*mtc)(struct lightrec_state *state, u32 op, u8 reg, u32 value);
+       void (*ctc)(struct lightrec_state *state, u32 op, u8 reg, u32 value);
+       void (*op)(struct lightrec_state *state, u32 op);
+};
+
+struct lightrec_ops {
+       struct lightrec_cop_ops cop0_ops;
+       struct lightrec_cop_ops cop2_ops;
+};
+
+__api struct lightrec_state *lightrec_init(char *argv0,
+                                          const struct lightrec_mem_map *map,
+                                          size_t nb,
+                                          const struct lightrec_ops *ops);
+
+__api void lightrec_destroy(struct lightrec_state *state);
+
+__api u32 lightrec_execute(struct lightrec_state *state,
+                          u32 pc, u32 target_cycle);
+__api u32 lightrec_execute_one(struct lightrec_state *state, u32 pc);
+__api u32 lightrec_run_interpreter(struct lightrec_state *state, u32 pc);
+
+__api void lightrec_invalidate(struct lightrec_state *state, u32 addr, u32 len);
+__api void lightrec_invalidate_all(struct lightrec_state *state);
+__api void lightrec_set_invalidate_mode(struct lightrec_state *state,
+                                       _Bool dma_only);
+
+__api void lightrec_set_exit_flags(struct lightrec_state *state, u32 flags);
+__api u32 lightrec_exit_flags(struct lightrec_state *state);
+
+__api void lightrec_dump_registers(struct lightrec_state *state, u32 regs[34]);
+__api void lightrec_restore_registers(struct lightrec_state *state,
+                                     u32 regs[34]);
+
+__api u32 lightrec_current_cycle_count(const struct lightrec_state *state);
+__api void lightrec_reset_cycle_count(struct lightrec_state *state, u32 cycles);
+__api void lightrec_set_target_cycle_count(struct lightrec_state *state,
+                                          u32 cycles);
+
+__api unsigned int lightrec_get_mem_usage(enum mem_type type);
+__api unsigned int lightrec_get_total_mem_usage(void);
+__api float lightrec_get_average_ipi(void);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* __LIGHTREC_H__ */
diff --git a/deps/lightrec/memmanager.c b/deps/lightrec/memmanager.c
new file mode 100644 (file)
index 0000000..2e6b99b
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "config.h"
+#include "lightrec-private.h"
+#include "memmanager.h"
+
+#include <stdlib.h>
+#if ENABLE_TINYMM
+#include <tinymm.h>
+#endif
+
+#ifdef ENABLE_THREADED_COMPILER
+#include <stdatomic.h>
+
+static atomic_uint lightrec_bytes[MEM_TYPE_END];
+
+void lightrec_register(enum mem_type type, unsigned int len)
+{
+       atomic_fetch_add(&lightrec_bytes[type], len);
+}
+
+void lightrec_unregister(enum mem_type type, unsigned int len)
+{
+       atomic_fetch_sub(&lightrec_bytes[type], len);
+}
+
+unsigned int lightrec_get_mem_usage(enum mem_type type)
+{
+       return atomic_load(&lightrec_bytes[type]);
+}
+
+#else /* ENABLE_THREADED_COMPILER */
+
+static unsigned int lightrec_bytes[MEM_TYPE_END];
+
+void lightrec_register(enum mem_type type, unsigned int len)
+{
+       lightrec_bytes[type] += len;
+}
+
+void lightrec_unregister(enum mem_type type, unsigned int len)
+{
+       lightrec_bytes[type] -= len;
+}
+
+unsigned int lightrec_get_mem_usage(enum mem_type type)
+{
+       return lightrec_bytes[type];
+}
+#endif /* ENABLE_THREADED_COMPILER */
+
+unsigned int lightrec_get_total_mem_usage(void)
+{
+       unsigned int i, count;
+
+       for (i = 0, count = 0; i < MEM_TYPE_END; i++)
+               count += lightrec_get_mem_usage((enum mem_type)i);
+
+       return count;
+}
+
+void * lightrec_malloc(struct lightrec_state *state,
+                      enum mem_type type, unsigned int len)
+{
+       void *ptr;
+
+#if ENABLE_TINYMM
+       if (type == MEM_FOR_IR)
+               ptr = tinymm_malloc(state->tinymm, len);
+       else
+#endif
+               ptr = malloc(len);
+       if (!ptr)
+               return NULL;
+
+       lightrec_register(type, len);
+
+       return ptr;
+}
+
+void * lightrec_calloc(struct lightrec_state *state,
+                      enum mem_type type, unsigned int len)
+{
+       void *ptr;
+
+#if ENABLE_TINYMM
+       if (type == MEM_FOR_IR)
+               ptr = tinymm_zalloc(state->tinymm, len);
+       else
+#endif
+               ptr = calloc(1, len);
+       if (!ptr)
+               return NULL;
+
+       lightrec_register(type, len);
+
+       return ptr;
+}
+
+void lightrec_free(struct lightrec_state *state,
+                  enum mem_type type, unsigned int len, void *ptr)
+{
+       lightrec_unregister(type, len);
+#if ENABLE_TINYMM
+       if (type == MEM_FOR_IR)
+               tinymm_free(state->tinymm, ptr);
+       else
+#endif
+               free(ptr);
+}
+
+float lightrec_get_average_ipi(void)
+{
+       unsigned int code_mem = lightrec_get_mem_usage(MEM_FOR_CODE);
+       unsigned int native_mem = lightrec_get_mem_usage(MEM_FOR_MIPS_CODE);
+
+       return native_mem ? (float)code_mem / (float)native_mem : 0.0f;
+}
diff --git a/deps/lightrec/memmanager.h b/deps/lightrec/memmanager.h
new file mode 100644 (file)
index 0000000..bd5028d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __MEMMANAGER_H__
+#define __MEMMANAGER_H__
+
+#include "lightrec.h"
+
+void * lightrec_malloc(struct lightrec_state *state,
+                      enum mem_type type, unsigned int len);
+void * lightrec_calloc(struct lightrec_state *state,
+                      enum mem_type type, unsigned int len);
+void lightrec_free(struct lightrec_state *state,
+                  enum mem_type type, unsigned int len, void *ptr);
+
+void lightrec_register(enum mem_type type, unsigned int len);
+void lightrec_unregister(enum mem_type type, unsigned int len);
+
+#endif /* __MEMMANAGER_H__ */
diff --git a/deps/lightrec/optimizer.c b/deps/lightrec/optimizer.c
new file mode 100644 (file)
index 0000000..cf431f2
--- /dev/null
@@ -0,0 +1,1022 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "disassembler.h"
+#include "lightrec.h"
+#include "memmanager.h"
+#include "optimizer.h"
+#include "regcache.h"
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+struct optimizer_list {
+       void (**optimizers)(struct opcode *);
+       unsigned int nb_optimizers;
+};
+
+bool opcode_reads_register(union code op, u8 reg)
+{
+       switch (op.i.op) {
+       case OP_SPECIAL:
+               switch (op.r.op) {
+               case OP_SPECIAL_SYSCALL:
+               case OP_SPECIAL_BREAK:
+                       return false;
+               case OP_SPECIAL_JR:
+               case OP_SPECIAL_JALR:
+               case OP_SPECIAL_MTHI:
+               case OP_SPECIAL_MTLO:
+                       return op.r.rs == reg;
+               case OP_SPECIAL_MFHI:
+                       return reg == REG_HI;
+               case OP_SPECIAL_MFLO:
+                       return reg == REG_LO;
+               case OP_SPECIAL_SLL:
+               case OP_SPECIAL_SRL:
+               case OP_SPECIAL_SRA:
+                       return op.r.rt == reg;
+               default:
+                       return op.r.rs == reg || op.r.rt == reg;
+               }
+       case OP_CP0:
+               switch (op.r.rs) {
+               case OP_CP0_MTC0:
+               case OP_CP0_CTC0:
+                       return op.r.rt == reg;
+               default:
+                       return false;
+               }
+       case OP_CP2:
+               if (op.r.op == OP_CP2_BASIC) {
+                       switch (op.r.rs) {
+                       case OP_CP2_BASIC_MTC2:
+                       case OP_CP2_BASIC_CTC2:
+                               return op.r.rt == reg;
+                       default:
+                               return false;
+                       }
+               } else {
+                       return false;
+               }
+       case OP_J:
+       case OP_JAL:
+       case OP_LUI:
+               return false;
+       case OP_BEQ:
+       case OP_BNE:
+       case OP_LWL:
+       case OP_LWR:
+       case OP_SB:
+       case OP_SH:
+       case OP_SWL:
+       case OP_SW:
+       case OP_SWR:
+               return op.i.rs == reg || op.i.rt == reg;
+       default:
+               return op.i.rs == reg;
+       }
+}
+
+bool opcode_writes_register(union code op, u8 reg)
+{
+       switch (op.i.op) {
+       case OP_SPECIAL:
+               switch (op.r.op) {
+               case OP_SPECIAL_JR:
+               case OP_SPECIAL_JALR:
+               case OP_SPECIAL_SYSCALL:
+               case OP_SPECIAL_BREAK:
+                       return false;
+               case OP_SPECIAL_MULT:
+               case OP_SPECIAL_MULTU:
+               case OP_SPECIAL_DIV:
+               case OP_SPECIAL_DIVU:
+                       return reg == REG_LO || reg == REG_HI;
+               case OP_SPECIAL_MTHI:
+                       return reg == REG_HI;
+               case OP_SPECIAL_MTLO:
+                       return reg == REG_LO;
+               default:
+                       return op.r.rd == reg;
+               }
+       case OP_ADDI:
+       case OP_ADDIU:
+       case OP_SLTI:
+       case OP_SLTIU:
+       case OP_ANDI:
+       case OP_ORI:
+       case OP_XORI:
+       case OP_LUI:
+       case OP_LB:
+       case OP_LH:
+       case OP_LWL:
+       case OP_LW:
+       case OP_LBU:
+       case OP_LHU:
+       case OP_LWR:
+               return op.i.rt == reg;
+       case OP_CP0:
+               switch (op.r.rs) {
+               case OP_CP0_MFC0:
+               case OP_CP0_CFC0:
+                       return op.i.rt == reg;
+               default:
+                       return false;
+               }
+       case OP_CP2:
+               if (op.r.op == OP_CP2_BASIC) {
+                       switch (op.r.rs) {
+                       case OP_CP2_BASIC_MFC2:
+                       case OP_CP2_BASIC_CFC2:
+                               return op.i.rt == reg;
+                       default:
+                               return false;
+                       }
+               } else {
+                       return false;
+               }
+       case OP_META_MOV:
+               return op.r.rd == reg;
+       default:
+               return false;
+       }
+}
+
+/* TODO: Complete */
+static bool is_nop(union code op)
+{
+       if (opcode_writes_register(op, 0)) {
+               switch (op.i.op) {
+               case OP_CP0:
+                       return op.r.rs != OP_CP0_MFC0;
+               case OP_LB:
+               case OP_LH:
+               case OP_LWL:
+               case OP_LW:
+               case OP_LBU:
+               case OP_LHU:
+               case OP_LWR:
+                       return false;
+               default:
+                       return true;
+               }
+       }
+
+       switch (op.i.op) {
+       case OP_SPECIAL:
+               switch (op.r.op) {
+               case OP_SPECIAL_AND:
+                       return op.r.rd == op.r.rt && op.r.rd == op.r.rs;
+               case OP_SPECIAL_ADD:
+               case OP_SPECIAL_ADDU:
+                       return (op.r.rd == op.r.rt && op.r.rs == 0) ||
+                               (op.r.rd == op.r.rs && op.r.rt == 0);
+               case OP_SPECIAL_SUB:
+               case OP_SPECIAL_SUBU:
+                       return op.r.rd == op.r.rs && op.r.rt == 0;
+               case OP_SPECIAL_OR:
+                       if (op.r.rd == op.r.rt)
+                               return op.r.rd == op.r.rs || op.r.rs == 0;
+                       else
+                               return (op.r.rd == op.r.rs) && op.r.rt == 0;
+               case OP_SPECIAL_SLL:
+               case OP_SPECIAL_SRA:
+               case OP_SPECIAL_SRL:
+                       return op.r.rd == op.r.rt && op.r.imm == 0;
+               default:
+                       return false;
+               }
+       case OP_ORI:
+       case OP_ADDI:
+       case OP_ADDIU:
+               return op.i.rt == op.i.rs && op.i.imm == 0;
+       case OP_BGTZ:
+               return (op.i.rs == 0 || op.i.imm == 1);
+       case OP_REGIMM:
+               return (op.i.op == OP_REGIMM_BLTZ ||
+                               op.i.op == OP_REGIMM_BLTZAL) &&
+                       (op.i.rs == 0 || op.i.imm == 1);
+       case OP_BNE:
+               return (op.i.rs == op.i.rt || op.i.imm == 1);
+       default:
+               return false;
+       }
+}
+
+bool load_in_delay_slot(union code op)
+{
+       switch (op.i.op) {
+       case OP_CP0:
+               switch (op.r.rs) {
+               case OP_CP0_MFC0:
+               case OP_CP0_CFC0:
+                       return true;
+               default:
+                       break;
+               }
+
+               break;
+       case OP_CP2:
+               if (op.r.op == OP_CP2_BASIC) {
+                       switch (op.r.rs) {
+                       case OP_CP2_BASIC_MFC2:
+                       case OP_CP2_BASIC_CFC2:
+                               return true;
+                       default:
+                               break;
+                       }
+               }
+
+               break;
+       case OP_LB:
+       case OP_LH:
+       case OP_LW:
+       case OP_LWL:
+       case OP_LWR:
+       case OP_LBU:
+       case OP_LHU:
+               return true;
+       default:
+               break;
+       }
+
+       return false;
+}
+
+static u32 lightrec_propagate_consts(union code c, u32 known, u32 *v)
+{
+       switch (c.i.op) {
+       case OP_SPECIAL:
+               switch (c.r.op) {
+               case OP_SPECIAL_SLL:
+                       if (known & BIT(c.r.rt)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = v[c.r.rt] << c.r.imm;
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_SRL:
+                       if (known & BIT(c.r.rt)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = v[c.r.rt] >> c.r.imm;
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_SRA:
+                       if (known & BIT(c.r.rt)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = (s32)v[c.r.rt] >> c.r.imm;
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_SLLV:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = v[c.r.rt] << (v[c.r.rs] & 0x1f);
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_SRLV:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = v[c.r.rt] >> (v[c.r.rs] & 0x1f);
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_SRAV:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = (s32)v[c.r.rt]
+                                         >> (v[c.r.rs] & 0x1f);
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_ADD:
+               case OP_SPECIAL_ADDU:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = (s32)v[c.r.rt] + (s32)v[c.r.rs];
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_SUB:
+               case OP_SPECIAL_SUBU:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = v[c.r.rt] - v[c.r.rs];
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_AND:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = v[c.r.rt] & v[c.r.rs];
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_OR:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = v[c.r.rt] | v[c.r.rs];
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_XOR:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = v[c.r.rt] ^ v[c.r.rs];
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_NOR:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = ~(v[c.r.rt] | v[c.r.rs]);
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_SLT:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = (s32)v[c.r.rs] < (s32)v[c.r.rt];
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               case OP_SPECIAL_SLTU:
+                       if (known & BIT(c.r.rt) && known & BIT(c.r.rs)) {
+                               known |= BIT(c.r.rd);
+                               v[c.r.rd] = v[c.r.rs] < v[c.r.rt];
+                       } else {
+                               known &= ~BIT(c.r.rd);
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case OP_REGIMM:
+               break;
+       case OP_ADDI:
+       case OP_ADDIU:
+               if (known & BIT(c.i.rs)) {
+                       known |= BIT(c.i.rt);
+                       v[c.i.rt] = v[c.i.rs] + (s32)(s16)c.i.imm;
+               } else {
+                       known &= ~BIT(c.i.rt);
+               }
+               break;
+       case OP_SLTI:
+               if (known & BIT(c.i.rs)) {
+                       known |= BIT(c.i.rt);
+                       v[c.i.rt] = (s32)v[c.i.rs] < (s32)(s16)c.i.imm;
+               } else {
+                       known &= ~BIT(c.i.rt);
+               }
+               break;
+       case OP_SLTIU:
+               if (known & BIT(c.i.rs)) {
+                       known |= BIT(c.i.rt);
+                       v[c.i.rt] = v[c.i.rs] < (u32)(s32)(s16)c.i.imm;
+               } else {
+                       known &= ~BIT(c.i.rt);
+               }
+               break;
+       case OP_ANDI:
+               if (known & BIT(c.i.rs)) {
+                       known |= BIT(c.i.rt);
+                       v[c.i.rt] = v[c.i.rs] & c.i.imm;
+               } else {
+                       known &= ~BIT(c.i.rt);
+               }
+               break;
+       case OP_ORI:
+               if (known & BIT(c.i.rs)) {
+                       known |= BIT(c.i.rt);
+                       v[c.i.rt] = v[c.i.rs] | c.i.imm;
+               } else {
+                       known &= ~BIT(c.i.rt);
+               }
+               break;
+       case OP_XORI:
+               if (known & BIT(c.i.rs)) {
+                       known |= BIT(c.i.rt);
+                       v[c.i.rt] = v[c.i.rs] ^ c.i.imm;
+               } else {
+                       known &= ~BIT(c.i.rt);
+               }
+               break;
+       case OP_LUI:
+               known |= BIT(c.i.rt);
+               v[c.i.rt] = c.i.imm << 16;
+               break;
+       case OP_CP0:
+               switch (c.r.rs) {
+               case OP_CP0_MFC0:
+               case OP_CP0_CFC0:
+                       known &= ~BIT(c.r.rt);
+                       break;
+               }
+               break;
+       case OP_CP2:
+               if (c.r.op == OP_CP2_BASIC) {
+                       switch (c.r.rs) {
+                       case OP_CP2_BASIC_MFC2:
+                       case OP_CP2_BASIC_CFC2:
+                               known &= ~BIT(c.r.rt);
+                               break;
+                       }
+               }
+               break;
+       case OP_LB:
+       case OP_LH:
+       case OP_LWL:
+       case OP_LW:
+       case OP_LBU:
+       case OP_LHU:
+       case OP_LWR:
+       case OP_LWC2:
+               known &= ~BIT(c.i.rt);
+               break;
+       case OP_META_MOV:
+               if (known & BIT(c.r.rs)) {
+                       known |= BIT(c.r.rd);
+                       v[c.r.rd] = v[c.r.rs];
+               } else {
+                       known &= ~BIT(c.r.rd);
+               }
+               break;
+       default:
+               break;
+       }
+
+       return known;
+}
+
+static int lightrec_add_meta(struct block *block,
+                            struct opcode *op, union code code)
+{
+       struct opcode *meta;
+
+       meta = lightrec_malloc(block->state, MEM_FOR_IR, sizeof(*meta));
+       if (!meta)
+               return -ENOMEM;
+
+       meta->c = code;
+       meta->flags = 0;
+
+       if (op) {
+               meta->offset = op->offset;
+               meta->next = op->next;
+               op->next = meta;
+       } else {
+               meta->offset = 0;
+               meta->next = block->opcode_list;
+               block->opcode_list = meta;
+       }
+
+       return 0;
+}
+
+static int lightrec_add_sync(struct block *block, struct opcode *prev)
+{
+       return lightrec_add_meta(block, prev, (union code){
+                                .j.op = OP_META_SYNC,
+                                });
+}
+
+static int lightrec_transform_ops(struct block *block)
+{
+       struct opcode *list = block->opcode_list;
+
+       for (; list; list = list->next) {
+
+               /* Transform all opcodes detected as useless to real NOPs
+                * (0x0: SLL r0, r0, #0) */
+               if (list->opcode != 0 && is_nop(list->c)) {
+                       pr_debug("Converting useless opcode 0x%08x to NOP\n",
+                                       list->opcode);
+                       list->opcode = 0x0;
+               }
+
+               if (!list->opcode)
+                       continue;
+
+               switch (list->i.op) {
+               /* Transform BEQ / BNE to BEQZ / BNEZ meta-opcodes if one of the
+                * two registers is zero. */
+               case OP_BEQ:
+                       if ((list->i.rs == 0) ^ (list->i.rt == 0)) {
+                               list->i.op = OP_META_BEQZ;
+                               if (list->i.rs == 0) {
+                                       list->i.rs = list->i.rt;
+                                       list->i.rt = 0;
+                               }
+                       } else if (list->i.rs == list->i.rt) {
+                               list->i.rs = 0;
+                               list->i.rt = 0;
+                       }
+                       break;
+               case OP_BNE:
+                       if (list->i.rs == 0) {
+                               list->i.op = OP_META_BNEZ;
+                               list->i.rs = list->i.rt;
+                               list->i.rt = 0;
+                       } else if (list->i.rt == 0) {
+                               list->i.op = OP_META_BNEZ;
+                       }
+                       break;
+
+               /* Transform ORI/ADDI/ADDIU with imm #0 or ORR/ADD/ADDU/SUB/SUBU
+                * with register $zero to the MOV meta-opcode */
+               case OP_ORI:
+               case OP_ADDI:
+               case OP_ADDIU:
+                       if (list->i.imm == 0) {
+                               pr_debug("Convert ORI/ADDI/ADDIU #0 to MOV\n");
+                               list->i.op = OP_META_MOV;
+                               list->r.rd = list->i.rt;
+                       }
+                       break;
+               case OP_SPECIAL:
+                       switch (list->r.op) {
+                       case OP_SPECIAL_SLL:
+                       case OP_SPECIAL_SRA:
+                       case OP_SPECIAL_SRL:
+                               if (list->r.imm == 0) {
+                                       pr_debug("Convert SLL/SRL/SRA #0 to MOV\n");
+                                       list->i.op = OP_META_MOV;
+                                       list->r.rs = list->r.rt;
+                               }
+                               break;
+                       case OP_SPECIAL_OR:
+                       case OP_SPECIAL_ADD:
+                       case OP_SPECIAL_ADDU:
+                               if (list->r.rs == 0) {
+                                       pr_debug("Convert OR/ADD $zero to MOV\n");
+                                       list->i.op = OP_META_MOV;
+                                       list->r.rs = list->r.rt;
+                               }
+                       case OP_SPECIAL_SUB: /* fall-through */
+                       case OP_SPECIAL_SUBU:
+                               if (list->r.rt == 0) {
+                                       pr_debug("Convert OR/ADD/SUB $zero to MOV\n");
+                                       list->i.op = OP_META_MOV;
+                               }
+                       default: /* fall-through */
+                               break;
+                       }
+               default: /* fall-through */
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int lightrec_switch_delay_slots(struct block *block)
+{
+       struct opcode *list, *prev;
+       u8 flags;
+
+       for (list = block->opcode_list, prev = NULL; list->next;
+            prev = list, list = list->next) {
+               union code op = list->c;
+               union code next_op = list->next->c;
+
+               if (!has_delay_slot(op) ||
+                   list->flags & (LIGHTREC_NO_DS | LIGHTREC_EMULATE_BRANCH) ||
+                   op.opcode == 0)
+                       continue;
+
+               if (prev && has_delay_slot(prev->c))
+                       continue;
+
+               switch (list->i.op) {
+               case OP_SPECIAL:
+                       switch (op.r.op) {
+                       case OP_SPECIAL_JALR:
+                               if (opcode_reads_register(next_op, op.r.rd) ||
+                                   opcode_writes_register(next_op, op.r.rd))
+                                       continue;
+                       case OP_SPECIAL_JR: /* fall-through */
+                               if (opcode_writes_register(next_op, op.r.rs))
+                                       continue;
+                       default: /* fall-through */
+                               break;
+                       }
+               case OP_J: /* fall-through */
+                       break;
+               case OP_JAL:
+                       if (opcode_reads_register(next_op, 31) ||
+                           opcode_writes_register(next_op, 31))
+                               continue;
+                       else
+                               break;
+               case OP_BEQ:
+               case OP_BNE:
+                       if (op.i.rt && opcode_writes_register(next_op, op.i.rt))
+                               continue;
+               case OP_BLEZ: /* fall-through */
+               case OP_BGTZ:
+               case OP_META_BEQZ:
+               case OP_META_BNEZ:
+                       if (op.i.rs && opcode_writes_register(next_op, op.i.rs))
+                               continue;
+                       break;
+               case OP_REGIMM:
+                       switch (op.r.rt) {
+                       case OP_REGIMM_BLTZAL:
+                       case OP_REGIMM_BGEZAL:
+                               if (opcode_reads_register(next_op, 31) ||
+                                   opcode_writes_register(next_op, 31))
+                                       continue;
+                       case OP_REGIMM_BLTZ: /* fall-through */
+                       case OP_REGIMM_BGEZ:
+                               if (op.i.rs &&
+                                   opcode_writes_register(next_op, op.i.rs))
+                                       continue;
+                               break;
+                       }
+               default: /* fall-through */
+                       break;
+               }
+
+               pr_debug("Swap branch and delay slot opcodes "
+                        "at offsets 0x%x / 0x%x\n", list->offset << 2,
+                        list->next->offset << 2);
+
+               flags = list->next->flags;
+               list->c = next_op;
+               list->next->c = op;
+               list->next->flags = list->flags | LIGHTREC_NO_DS;
+               list->flags = flags | LIGHTREC_NO_DS;
+               list->offset++;
+               list->next->offset--;
+       }
+
+       return 0;
+}
+
+static int lightrec_detect_impossible_branches(struct block *block)
+{
+       struct opcode *op, *next;
+
+       for (op = block->opcode_list, next = op->next; next;
+            op = next, next = op->next) {
+               if (!has_delay_slot(op->c) ||
+                   (!load_in_delay_slot(next->c) &&
+                    !has_delay_slot(next->c) &&
+                    !(next->i.op == OP_CP0 && next->r.rs == OP_CP0_RFE)))
+                       continue;
+
+               if (op->c.opcode == next->c.opcode) {
+                       /* The delay slot is the exact same opcode as the branch
+                        * opcode: this is effectively a NOP */
+                       next->c.opcode = 0;
+                       continue;
+               }
+
+               if (op == block->opcode_list) {
+                       /* If the first opcode is an 'impossible' branch, we
+                        * only keep the first two opcodes of the block (the
+                        * branch itself + its delay slot) */
+                       lightrec_free_opcode_list(block->state, next->next);
+                       next->next = NULL;
+                       block->nb_ops = 2;
+               }
+
+               op->flags |= LIGHTREC_EMULATE_BRANCH;
+       }
+
+       return 0;
+}
+
+static int lightrec_local_branches(struct block *block)
+{
+       struct opcode *list, *target, *prev;
+       s32 offset;
+       int ret;
+
+       for (list = block->opcode_list; list; list = list->next) {
+               if (list->flags & LIGHTREC_EMULATE_BRANCH)
+                       continue;
+
+               switch (list->i.op) {
+               case OP_BEQ:
+               case OP_BNE:
+               case OP_BLEZ:
+               case OP_BGTZ:
+               case OP_REGIMM:
+               case OP_META_BEQZ:
+               case OP_META_BNEZ:
+                       offset = list->offset + 1 + (s16)list->i.imm;
+                       if (offset >= 0 && offset < block->nb_ops)
+                               break;
+               default: /* fall-through */
+                       continue;
+               }
+
+               pr_debug("Found local branch to offset 0x%x\n", offset << 2);
+
+               for (target = block->opcode_list, prev = NULL;
+                    target; prev = target, target = target->next) {
+                       if (target->offset != offset ||
+                           target->j.op == OP_META_SYNC)
+                               continue;
+
+                       if (target->flags & LIGHTREC_EMULATE_BRANCH) {
+                               pr_debug("Branch target must be emulated"
+                                        " - skip\n");
+                               break;
+                       }
+
+                       if (prev && has_delay_slot(prev->c)) {
+                               pr_debug("Branch target is a delay slot"
+                                        " - skip\n");
+                               break;
+                       }
+
+                       if (prev && prev->j.op != OP_META_SYNC) {
+                               pr_debug("Adding sync before offset "
+                                        "0x%x\n", offset << 2);
+                               ret = lightrec_add_sync(block, prev);
+                               if (ret)
+                                       return ret;
+
+                               prev->next->offset = target->offset;
+                       }
+
+                       list->flags |= LIGHTREC_LOCAL_BRANCH;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+bool has_delay_slot(union code op)
+{
+       switch (op.i.op) {
+       case OP_SPECIAL:
+               switch (op.r.op) {
+               case OP_SPECIAL_JR:
+               case OP_SPECIAL_JALR:
+                       return true;
+               default:
+                       return false;
+               }
+       case OP_J:
+       case OP_JAL:
+       case OP_BEQ:
+       case OP_BNE:
+       case OP_BLEZ:
+       case OP_BGTZ:
+       case OP_REGIMM:
+       case OP_META_BEQZ:
+       case OP_META_BNEZ:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static int lightrec_add_unload(struct block *block, struct opcode *op, u8 reg)
+{
+       return lightrec_add_meta(block, op, (union code){
+                                .i.op = OP_META_REG_UNLOAD,
+                                .i.rs = reg,
+                                });
+}
+
+static int lightrec_early_unload(struct block *block)
+{
+       struct opcode *list = block->opcode_list;
+       u8 i;
+
+       for (i = 1; i < 34; i++) {
+               struct opcode *op, *last_r = NULL, *last_w = NULL;
+               unsigned int last_r_id = 0, last_w_id = 0, id = 0;
+               int ret;
+
+               for (op = list; op->next; op = op->next, id++) {
+                       if (opcode_reads_register(op->c, i)) {
+                               last_r = op;
+                               last_r_id = id;
+                       }
+
+                       if (opcode_writes_register(op->c, i)) {
+                               last_w = op;
+                               last_w_id = id;
+                       }
+               }
+
+               if (last_w_id > last_r_id) {
+                       if (has_delay_slot(last_w->c) &&
+                           !(last_w->flags & LIGHTREC_NO_DS))
+                               last_w = last_w->next;
+
+                       if (last_w->next) {
+                               ret = lightrec_add_unload(block, last_w, i);
+                               if (ret)
+                                       return ret;
+                       }
+               } else if (last_r) {
+                       if (has_delay_slot(last_r->c) &&
+                           !(last_r->flags & LIGHTREC_NO_DS))
+                               last_r = last_r->next;
+
+                       if (last_r->next) {
+                               ret = lightrec_add_unload(block, last_r, i);
+                               if (ret)
+                                       return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int lightrec_flag_stores(struct block *block)
+{
+       struct opcode *list;
+       u32 known = BIT(0);
+       u32 values[32] = { 0 };
+
+       for (list = block->opcode_list; list; list = list->next) {
+               /* Register $zero is always, well, zero */
+               known |= BIT(0);
+               values[0] = 0;
+
+               switch (list->i.op) {
+               case OP_SB:
+               case OP_SH:
+               case OP_SW:
+                       /* Mark all store operations that target $sp or $gp
+                        * as not requiring code invalidation. This is based
+                        * on the heuristic that stores using one of these
+                        * registers as address will never hit a code page. */
+                       if (list->i.rs >= 28 && list->i.rs <= 29 &&
+                           !block->state->maps[PSX_MAP_KERNEL_USER_RAM].ops) {
+                               pr_debug("Flaging opcode 0x%08x as not requiring invalidation\n",
+                                        list->opcode);
+                               list->flags |= LIGHTREC_NO_INVALIDATE;
+                       }
+
+                       /* Detect writes whose destination address is inside the
+                        * current block, using constant propagation. When these
+                        * occur, we mark the blocks as not compilable. */
+                       if ((known & BIT(list->i.rs)) &&
+                           kunseg(values[list->i.rs]) >= kunseg(block->pc) &&
+                           kunseg(values[list->i.rs]) < (kunseg(block->pc) +
+                                                         block->nb_ops * 4)) {
+                               pr_debug("Self-modifying block detected\n");
+                               block->flags |= BLOCK_NEVER_COMPILE;
+                               list->flags |= LIGHTREC_SMC;
+                       }
+               default: /* fall-through */
+                       break;
+               }
+
+               known = lightrec_propagate_consts(list->c, known, values);
+       }
+
+       return 0;
+}
+
+static bool is_mult32(const struct block *block, const struct opcode *op)
+{
+       const struct opcode *next, *last = NULL;
+       u32 offset;
+
+       for (op = op->next; op != last; op = op->next) {
+               switch (op->i.op) {
+               case OP_BEQ:
+               case OP_BNE:
+               case OP_BLEZ:
+               case OP_BGTZ:
+               case OP_REGIMM:
+               case OP_META_BEQZ:
+               case OP_META_BNEZ:
+                       /* TODO: handle backwards branches too */
+                       if ((op->flags & LIGHTREC_LOCAL_BRANCH) &&
+                           (s16)op->c.i.imm >= 0) {
+                               offset = op->offset + 1 + (s16)op->c.i.imm;
+
+                               for (next = op; next->offset != offset;
+                                    next = next->next);
+
+                               if (!is_mult32(block, next))
+                                       return false;
+
+                               last = next;
+                               continue;
+                       } else {
+                               return false;
+                       }
+               case OP_SPECIAL:
+                       switch (op->r.op) {
+                       case OP_SPECIAL_MULT:
+                       case OP_SPECIAL_MULTU:
+                       case OP_SPECIAL_DIV:
+                       case OP_SPECIAL_DIVU:
+                       case OP_SPECIAL_MTHI:
+                               return true;
+                       case OP_SPECIAL_JR:
+                               return op->r.rs == 31 &&
+                                       ((op->flags & LIGHTREC_NO_DS) ||
+                                        !(op->next->i.op == OP_SPECIAL &&
+                                          op->next->r.op == OP_SPECIAL_MFHI));
+                       case OP_SPECIAL_JALR:
+                       case OP_SPECIAL_MFHI:
+                               return false;
+                       default:
+                               continue;
+                       }
+               default:
+                       continue;
+               }
+       }
+
+       return last != NULL;
+}
+
+static int lightrec_flag_mults(struct block *block)
+{
+       struct opcode *list, *prev;
+
+       for (list = block->opcode_list, prev = NULL; list;
+            prev = list, list = list->next) {
+               if (list->i.op != OP_SPECIAL)
+                       continue;
+
+               switch (list->r.op) {
+               case OP_SPECIAL_MULT:
+               case OP_SPECIAL_MULTU:
+                       break;
+               default:
+                       continue;
+               }
+
+               /* Don't support MULT(U) opcodes in delay slots */
+               if (prev && has_delay_slot(prev->c))
+                       continue;
+
+               if (is_mult32(block, list)) {
+                       pr_debug("Mark MULT(U) opcode at offset 0x%x as"
+                                " 32-bit\n", list->offset << 2);
+                       list->flags |= LIGHTREC_MULT32;
+               }
+       }
+
+       return 0;
+}
+
+static int (*lightrec_optimizers[])(struct block *) = {
+       &lightrec_detect_impossible_branches,
+       &lightrec_transform_ops,
+       &lightrec_local_branches,
+       &lightrec_switch_delay_slots,
+       &lightrec_flag_stores,
+       &lightrec_flag_mults,
+       &lightrec_early_unload,
+};
+
+int lightrec_optimize(struct block *block)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(lightrec_optimizers); i++) {
+               int ret = lightrec_optimizers[i](block);
+
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
diff --git a/deps/lightrec/optimizer.h b/deps/lightrec/optimizer.h
new file mode 100644 (file)
index 0000000..84a8fc9
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __OPTIMIZER_H__
+#define __OPTIMIZER_H__
+
+#include "disassembler.h"
+
+struct block;
+
+_Bool opcode_reads_register(union code op, u8 reg);
+_Bool opcode_writes_register(union code op, u8 reg);
+_Bool has_delay_slot(union code op);
+_Bool load_in_delay_slot(union code op);
+
+int lightrec_optimize(struct block *block);
+
+#endif /* __OPTIMIZER_H__ */
diff --git a/deps/lightrec/reaper.c b/deps/lightrec/reaper.c
new file mode 100644 (file)
index 0000000..377685c
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "blockcache.h"
+#include "debug.h"
+#include "lightrec-private.h"
+#include "memmanager.h"
+#include "slist.h"
+#include "reaper.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+struct reaper_elm {
+       reap_func_t func;
+       void *data;
+       struct slist_elm slist;
+};
+
+struct reaper {
+       struct lightrec_state *state;
+       pthread_mutex_t mutex;
+       struct slist_elm reap_list;
+};
+
+struct reaper *lightrec_reaper_init(struct lightrec_state *state)
+{
+       struct reaper *reaper;
+       int ret;
+
+       reaper = lightrec_malloc(state, MEM_FOR_LIGHTREC, sizeof(*reaper));
+       if (!reaper) {
+               pr_err("Cannot create reaper: Out of memory\n");
+               return NULL;
+       }
+
+       reaper->state = state;
+       slist_init(&reaper->reap_list);
+
+       ret = pthread_mutex_init(&reaper->mutex, NULL);
+       if (ret) {
+               pr_err("Cannot init mutex variable: %d\n", ret);
+               lightrec_free(reaper->state, MEM_FOR_LIGHTREC,
+                             sizeof(*reaper), reaper);
+               return NULL;
+       }
+
+       return reaper;
+}
+
+void lightrec_reaper_destroy(struct reaper *reaper)
+{
+       pthread_mutex_destroy(&reaper->mutex);
+       lightrec_free(reaper->state, MEM_FOR_LIGHTREC, sizeof(*reaper), reaper);
+}
+
+int lightrec_reaper_add(struct reaper *reaper, reap_func_t f, void *data)
+{
+       struct reaper_elm *reaper_elm;
+       struct slist_elm *elm;
+       int ret = 0;
+
+       pthread_mutex_lock(&reaper->mutex);
+
+       for (elm = reaper->reap_list.next; elm; elm = elm->next) {
+               reaper_elm = container_of(elm, struct reaper_elm, slist);
+
+               if (reaper_elm->data == data)
+                       goto out_unlock;
+       }
+
+       reaper_elm = lightrec_malloc(reaper->state, MEM_FOR_LIGHTREC,
+                                    sizeof(*reaper_elm));
+       if (!reaper_elm) {
+               pr_err("Cannot add reaper entry: Out of memory\n");
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+
+       reaper_elm->func = f;
+       reaper_elm->data = data;
+       slist_append(&reaper->reap_list, &reaper_elm->slist);
+
+out_unlock:
+       pthread_mutex_unlock(&reaper->mutex);
+       return ret;
+}
+
+void lightrec_reaper_reap(struct reaper *reaper)
+{
+       struct reaper_elm *reaper_elm;
+       struct slist_elm *elm;
+
+       pthread_mutex_lock(&reaper->mutex);
+
+       while (!!(elm = slist_first(&reaper->reap_list))) {
+               slist_remove(&reaper->reap_list, elm);
+               pthread_mutex_unlock(&reaper->mutex);
+
+               reaper_elm = container_of(elm, struct reaper_elm, slist);
+
+               (*reaper_elm->func)(reaper_elm->data);
+
+               lightrec_free(reaper->state, MEM_FOR_LIGHTREC,
+                             sizeof(*reaper_elm), reaper_elm);
+
+               pthread_mutex_lock(&reaper->mutex);
+       }
+
+       pthread_mutex_unlock(&reaper->mutex);
+}
diff --git a/deps/lightrec/reaper.h b/deps/lightrec/reaper.h
new file mode 100644 (file)
index 0000000..0309b64
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __LIGHTREC_REAPER_H__
+#define __LIGHTREC_REAPER_H__
+
+struct lightrec_state;
+struct reaper;
+
+typedef void (*reap_func_t)(void *);
+
+struct reaper *lightrec_reaper_init(struct lightrec_state *state);
+void lightrec_reaper_destroy(struct reaper *reaper);
+
+int lightrec_reaper_add(struct reaper *reaper, reap_func_t f, void *data);
+void lightrec_reaper_reap(struct reaper *reaper);
+
+#endif /* __LIGHTREC_REAPER_H__ */
diff --git a/deps/lightrec/recompiler.c b/deps/lightrec/recompiler.c
new file mode 100644 (file)
index 0000000..634d3d0
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2019-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "debug.h"
+#include "interpreter.h"
+#include "lightrec-private.h"
+#include "memmanager.h"
+#include "slist.h"
+
+#include <errno.h>
+#include <stdatomic.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+struct block_rec {
+       struct block *block;
+       struct slist_elm slist;
+};
+
+struct recompiler {
+       struct lightrec_state *state;
+       pthread_t thd;
+       pthread_cond_t cond;
+       pthread_mutex_t mutex;
+       bool stop;
+       struct block *current_block;
+       struct slist_elm slist;
+};
+
+static void lightrec_compile_list(struct recompiler *rec)
+{
+       struct block_rec *block_rec;
+       struct slist_elm *next;
+       struct block *block;
+       int ret;
+
+       while (!!(next = slist_first(&rec->slist))) {
+               block_rec = container_of(next, struct block_rec, slist);
+               block = block_rec->block;
+               rec->current_block = block;
+
+               pthread_mutex_unlock(&rec->mutex);
+
+               ret = lightrec_compile_block(block);
+               if (ret) {
+                       pr_err("Unable to compile block at PC 0x%x: %d\n",
+                              block->pc, ret);
+               }
+
+               pthread_mutex_lock(&rec->mutex);
+
+               slist_remove(&rec->slist, next);
+               lightrec_free(rec->state, MEM_FOR_LIGHTREC,
+                             sizeof(*block_rec), block_rec);
+               pthread_cond_signal(&rec->cond);
+       }
+
+       rec->current_block = NULL;
+}
+
+static void * lightrec_recompiler_thd(void *d)
+{
+       struct recompiler *rec = d;
+
+       pthread_mutex_lock(&rec->mutex);
+
+       while (!rec->stop) {
+               do {
+                       pthread_cond_wait(&rec->cond, &rec->mutex);
+
+                       if (rec->stop)
+                               goto out_unlock;
+
+               } while (slist_empty(&rec->slist));
+
+               lightrec_compile_list(rec);
+       }
+
+out_unlock:
+       pthread_mutex_unlock(&rec->mutex);
+       return NULL;
+}
+
+struct recompiler *lightrec_recompiler_init(struct lightrec_state *state)
+{
+       struct recompiler *rec;
+       int ret;
+
+       rec = lightrec_malloc(state, MEM_FOR_LIGHTREC, sizeof(*rec));
+       if (!rec) {
+               pr_err("Cannot create recompiler: Out of memory\n");
+               return NULL;
+       }
+
+       rec->state = state;
+       rec->stop = false;
+       rec->current_block = NULL;
+       slist_init(&rec->slist);
+
+       ret = pthread_cond_init(&rec->cond, NULL);
+       if (ret) {
+               pr_err("Cannot init cond variable: %d\n", ret);
+               goto err_free_rec;
+       }
+
+       ret = pthread_mutex_init(&rec->mutex, NULL);
+       if (ret) {
+               pr_err("Cannot init mutex variable: %d\n", ret);
+               goto err_cnd_destroy;
+       }
+
+       ret = pthread_create(&rec->thd, NULL, lightrec_recompiler_thd, rec);
+       if (ret) {
+               pr_err("Cannot create recompiler thread: %d\n", ret);
+               goto err_mtx_destroy;
+       }
+
+       return rec;
+
+err_mtx_destroy:
+       pthread_mutex_destroy(&rec->mutex);
+err_cnd_destroy:
+       pthread_cond_destroy(&rec->cond);
+err_free_rec:
+       lightrec_free(state, MEM_FOR_LIGHTREC, sizeof(*rec), rec);
+       return NULL;
+}
+
+void lightrec_free_recompiler(struct recompiler *rec)
+{
+       rec->stop = true;
+
+       /* Stop the thread */
+       pthread_mutex_lock(&rec->mutex);
+       pthread_cond_signal(&rec->cond);
+       pthread_mutex_unlock(&rec->mutex);
+       pthread_join(rec->thd, NULL);
+
+       pthread_mutex_destroy(&rec->mutex);
+       pthread_cond_destroy(&rec->cond);
+       lightrec_free(rec->state, MEM_FOR_LIGHTREC, sizeof(*rec), rec);
+}
+
+int lightrec_recompiler_add(struct recompiler *rec, struct block *block)
+{
+       struct slist_elm *elm, *prev;
+       struct block_rec *block_rec;
+       int ret = 0;
+
+       pthread_mutex_lock(&rec->mutex);
+
+       /* If the block is marked as dead, don't compile it, it will be removed
+        * as soon as it's safe. */
+       if (block->flags & BLOCK_IS_DEAD)
+               goto out_unlock;
+
+       for (elm = slist_first(&rec->slist), prev = NULL; elm;
+            prev = elm, elm = elm->next) {
+               block_rec = container_of(elm, struct block_rec, slist);
+
+               if (block_rec->block == block) {
+                       /* The block to compile is already in the queue - bump
+                        * it to the top of the list, unless the block is being
+                        * recompiled. */
+                       if (prev && !(block->flags & BLOCK_SHOULD_RECOMPILE)) {
+                               slist_remove_next(prev);
+                               slist_append(&rec->slist, elm);
+                       }
+
+                       goto out_unlock;
+               }
+       }
+
+       /* By the time this function was called, the block has been recompiled
+        * and ins't in the wait list anymore. Just return here. */
+       if (block->function && !(block->flags & BLOCK_SHOULD_RECOMPILE))
+               goto out_unlock;
+
+       block_rec = lightrec_malloc(rec->state, MEM_FOR_LIGHTREC,
+                                   sizeof(*block_rec));
+       if (!block_rec) {
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+
+       pr_debug("Adding block PC 0x%x to recompiler\n", block->pc);
+
+       block_rec->block = block;
+
+       elm = &rec->slist;
+
+       /* If the block is being recompiled, push it to the end of the queue;
+        * otherwise push it to the front of the queue. */
+       if (block->flags & BLOCK_SHOULD_RECOMPILE)
+               for (; elm->next; elm = elm->next);
+
+       slist_append(elm, &block_rec->slist);
+
+       /* Signal the thread */
+       pthread_cond_signal(&rec->cond);
+
+out_unlock:
+       pthread_mutex_unlock(&rec->mutex);
+       return ret;
+}
+
+void lightrec_recompiler_remove(struct recompiler *rec, struct block *block)
+{
+       struct block_rec *block_rec;
+       struct slist_elm *elm;
+
+       pthread_mutex_lock(&rec->mutex);
+
+       for (elm = slist_first(&rec->slist); elm; elm = elm->next) {
+               block_rec = container_of(elm, struct block_rec, slist);
+
+               if (block_rec->block == block) {
+                       if (block == rec->current_block) {
+                               /* Block is being recompiled - wait for
+                                * completion */
+                               do {
+                                       pthread_cond_wait(&rec->cond,
+                                                         &rec->mutex);
+                               } while (block == rec->current_block);
+                       } else {
+                               /* Block is not yet being processed - remove it
+                                * from the list */
+                               slist_remove(&rec->slist, elm);
+                               lightrec_free(rec->state, MEM_FOR_LIGHTREC,
+                                             sizeof(*block_rec), block_rec);
+                       }
+
+                       break;
+               }
+       }
+
+       pthread_mutex_unlock(&rec->mutex);
+}
+
+void * lightrec_recompiler_run_first_pass(struct block *block, u32 *pc)
+{
+       bool freed;
+
+       if (likely(block->function)) {
+               if (block->flags & BLOCK_FULLY_TAGGED) {
+                       freed = atomic_flag_test_and_set(&block->op_list_freed);
+
+                       if (!freed) {
+                               pr_debug("Block PC 0x%08x is fully tagged"
+                                        " - free opcode list\n", block->pc);
+
+                               /* The block was already compiled but the opcode list
+                                * didn't get freed yet - do it now */
+                               lightrec_free_opcode_list(block->state,
+                                                         block->opcode_list);
+                               block->opcode_list = NULL;
+                       }
+               }
+
+               return block->function;
+       }
+
+       /* Mark the opcode list as freed, so that the threaded compiler won't
+        * free it while we're using it in the interpreter. */
+       freed = atomic_flag_test_and_set(&block->op_list_freed);
+
+       /* Block wasn't compiled yet - run the interpreter */
+       *pc = lightrec_emulate_block(block, *pc);
+
+       if (!freed)
+               atomic_flag_clear(&block->op_list_freed);
+
+       /* The block got compiled while the interpreter was running.
+        * We can free the opcode list now. */
+       if (block->function && (block->flags & BLOCK_FULLY_TAGGED) &&
+           !atomic_flag_test_and_set(&block->op_list_freed)) {
+               pr_debug("Block PC 0x%08x is fully tagged"
+                        " - free opcode list\n", block->pc);
+
+               lightrec_free_opcode_list(block->state, block->opcode_list);
+               block->opcode_list = NULL;
+       }
+
+       return NULL;
+}
diff --git a/deps/lightrec/recompiler.h b/deps/lightrec/recompiler.h
new file mode 100644 (file)
index 0000000..999a49f
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __LIGHTREC_RECOMPILER_H__
+#define __LIGHTREC_RECOMPILER_H__
+
+struct block;
+struct lightrec_state;
+struct recompiler;
+
+struct recompiler *lightrec_recompiler_init(struct lightrec_state *state);
+void lightrec_free_recompiler(struct recompiler *rec);
+int lightrec_recompiler_add(struct recompiler *rec, struct block *block);
+void lightrec_recompiler_remove(struct recompiler *rec, struct block *block);
+
+void * lightrec_recompiler_run_first_pass(struct block *block, u32 *pc);
+
+#endif /* __LIGHTREC_RECOMPILER_H__ */
diff --git a/deps/lightrec/regcache.c b/deps/lightrec/regcache.c
new file mode 100644 (file)
index 0000000..0256015
--- /dev/null
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#include "debug.h"
+#include "memmanager.h"
+#include "regcache.h"
+
+#include <lightning.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct native_register {
+       bool used, loaded, dirty, output, extend, extended, locked;
+       s8 emulated_register;
+};
+
+struct regcache {
+       struct lightrec_state *state;
+       struct native_register lightrec_regs[NUM_REGS + NUM_TEMPS];
+};
+
+static const char * mips_regs[] = {
+       "zero",
+       "at",
+       "v0", "v1",
+       "a0", "a1", "a2", "a3",
+       "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+       "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+       "t8", "t9",
+       "k0", "k1",
+       "gp", "sp", "fp", "ra",
+       "lo", "hi",
+};
+
+const char * lightrec_reg_name(u8 reg)
+{
+       return mips_regs[reg];
+}
+
+static inline u8 lightrec_reg_number(const struct regcache *cache,
+               const struct native_register *nreg)
+{
+       return (u8) (((uintptr_t) nreg - (uintptr_t) cache->lightrec_regs)
+                       / sizeof(*nreg));
+}
+
+static inline u8 lightrec_reg_to_lightning(const struct regcache *cache,
+               const struct native_register *nreg)
+{
+       u8 offset = lightrec_reg_number(cache, nreg);
+       return offset < NUM_REGS ? JIT_V(offset) : JIT_R(offset - NUM_REGS);
+}
+
+static inline struct native_register * lightning_reg_to_lightrec(
+               struct regcache *cache, u8 reg)
+{
+       if ((JIT_V0 > JIT_R0 && reg >= JIT_V0) ||
+                       (JIT_V0 < JIT_R0 && reg < JIT_R0)) {
+               if (JIT_V1 > JIT_V0)
+                       return &cache->lightrec_regs[reg - JIT_V0];
+               else
+                       return &cache->lightrec_regs[JIT_V0 - reg];
+       } else {
+               if (JIT_R1 > JIT_R0)
+                       return &cache->lightrec_regs[NUM_REGS + reg - JIT_R0];
+               else
+                       return &cache->lightrec_regs[NUM_REGS + JIT_R0 - reg];
+       }
+}
+
+static struct native_register * alloc_temp(struct regcache *cache)
+{
+       unsigned int i;
+
+       /* We search the register list in reverse order. As temporaries are
+        * meant to be used only in the emitter functions, they can be mapped to
+        * caller-saved registers, as they won't have to be saved back to
+        * memory. */
+       for (i = ARRAY_SIZE(cache->lightrec_regs); i; i--) {
+               struct native_register *nreg = &cache->lightrec_regs[i - 1];
+               if (!nreg->used && !nreg->loaded && !nreg->dirty)
+                       return nreg;
+       }
+
+       for (i = ARRAY_SIZE(cache->lightrec_regs); i; i--) {
+               struct native_register *nreg = &cache->lightrec_regs[i - 1];
+               if (!nreg->used)
+                       return nreg;
+       }
+
+       return NULL;
+}
+
+static struct native_register * find_mapped_reg(struct regcache *cache,
+                                               u8 reg, bool out)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++) {
+               struct native_register *nreg = &cache->lightrec_regs[i];
+               if ((!reg || nreg->loaded || nreg->dirty) &&
+                               nreg->emulated_register == reg &&
+                               (!out || !nreg->locked))
+                       return nreg;
+       }
+
+       return NULL;
+}
+
+static struct native_register * alloc_in_out(struct regcache *cache,
+                                            u8 reg, bool out)
+{
+       struct native_register *nreg;
+       unsigned int i;
+
+       /* Try to find if the register is already mapped somewhere */
+       nreg = find_mapped_reg(cache, reg, out);
+       if (nreg)
+               return nreg;
+
+       /* Try to allocate a non-dirty, non-loaded register.
+        * Loaded registers may be re-used later, so it's better to avoid
+        * re-using one if possible. */
+       for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++) {
+               nreg = &cache->lightrec_regs[i];
+               if (!nreg->used && !nreg->dirty && !nreg->loaded)
+                       return nreg;
+       }
+
+       /* Try to allocate a non-dirty register */
+       for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++) {
+               nreg = &cache->lightrec_regs[i];
+               if (!nreg->used && !nreg->dirty)
+                       return nreg;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++) {
+               nreg = &cache->lightrec_regs[i];
+               if (!nreg->used)
+                       return nreg;
+       }
+
+       return NULL;
+}
+
+static void lightrec_discard_nreg(struct native_register *nreg)
+{
+       nreg->extended = false;
+       nreg->loaded = false;
+       nreg->output = false;
+       nreg->dirty = false;
+       nreg->used = false;
+       nreg->locked = false;
+       nreg->emulated_register = -1;
+}
+
+static void lightrec_unload_nreg(struct regcache *cache, jit_state_t *_jit,
+               struct native_register *nreg, u8 jit_reg)
+{
+       /* If we get a dirty register, store back the old value */
+       if (nreg->dirty) {
+               s16 offset = offsetof(struct lightrec_state, native_reg_cache)
+                       + (nreg->emulated_register << 2);
+
+               jit_stxi_i(offset, LIGHTREC_REG_STATE, jit_reg);
+       }
+
+       lightrec_discard_nreg(nreg);
+}
+
+void lightrec_unload_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
+{
+       lightrec_unload_nreg(cache, _jit,
+                       lightning_reg_to_lightrec(cache, jit_reg), jit_reg);
+}
+
+/* lightrec_lock_reg: the register will be cleaned if dirty, then locked.
+ * A locked register cannot only be used as input, not output. */
+void lightrec_lock_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
+{
+       struct native_register *reg = lightning_reg_to_lightrec(cache, jit_reg);
+
+       lightrec_clean_reg(cache, _jit, jit_reg);
+
+       reg->locked = true;
+}
+
+u8 lightrec_alloc_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
+{
+       struct native_register *reg = lightning_reg_to_lightrec(cache, jit_reg);
+
+       lightrec_unload_nreg(cache, _jit, reg, jit_reg);
+
+       reg->used = true;
+       return jit_reg;
+}
+
+u8 lightrec_alloc_reg_temp(struct regcache *cache, jit_state_t *_jit)
+{
+       u8 jit_reg;
+       struct native_register *nreg = alloc_temp(cache);
+       if (!nreg) {
+               /* No free register, no dirty register to free. */
+               pr_err("No more registers! Abandon ship!\n");
+               return 0;
+       }
+
+       jit_reg = lightrec_reg_to_lightning(cache, nreg);
+       lightrec_unload_nreg(cache, _jit, nreg, jit_reg);
+
+       nreg->used = true;
+       return jit_reg;
+}
+
+u8 lightrec_alloc_reg_out(struct regcache *cache, jit_state_t *_jit, u8 reg)
+{
+       u8 jit_reg;
+       struct native_register *nreg = alloc_in_out(cache, reg, true);
+       if (!nreg) {
+               /* No free register, no dirty register to free. */
+               pr_err("No more registers! Abandon ship!\n");
+               return 0;
+       }
+
+       jit_reg = lightrec_reg_to_lightning(cache, nreg);
+
+       /* If we get a dirty register that doesn't correspond to the one
+        * we're requesting, store back the old value */
+       if (nreg->emulated_register != reg)
+               lightrec_unload_nreg(cache, _jit, nreg, jit_reg);
+
+       nreg->extend = false;
+       nreg->used = true;
+       nreg->output = true;
+       nreg->emulated_register = reg;
+       return jit_reg;
+}
+
+u8 lightrec_alloc_reg_in(struct regcache *cache, jit_state_t *_jit, u8 reg)
+{
+       u8 jit_reg;
+       bool reg_changed;
+       struct native_register *nreg = alloc_in_out(cache, reg, false);
+       if (!nreg) {
+               /* No free register, no dirty register to free. */
+               pr_err("No more registers! Abandon ship!\n");
+               return 0;
+       }
+
+       jit_reg = lightrec_reg_to_lightning(cache, nreg);
+
+       /* If we get a dirty register that doesn't correspond to the one
+        * we're requesting, store back the old value */
+       reg_changed = nreg->emulated_register != reg;
+       if (reg_changed)
+               lightrec_unload_nreg(cache, _jit, nreg, jit_reg);
+
+       if (!nreg->loaded && !nreg->dirty && reg != 0) {
+               s16 offset = offsetof(struct lightrec_state, native_reg_cache)
+                       + (reg << 2);
+
+               /* Load previous value from register cache */
+               jit_ldxi_i(jit_reg, LIGHTREC_REG_STATE, offset);
+               nreg->loaded = true;
+               nreg->extended = true;
+       }
+
+       /* Clear register r0 before use */
+       if (reg == 0 && (!nreg->loaded || nreg->dirty)) {
+               jit_movi(jit_reg, 0);
+               nreg->extended = true;
+               nreg->loaded = true;
+       }
+
+       nreg->used = true;
+       nreg->output = false;
+       nreg->emulated_register = reg;
+       return jit_reg;
+}
+
+u8 lightrec_alloc_reg_out_ext(struct regcache *cache, jit_state_t *_jit, u8 reg)
+{
+       struct native_register *nreg;
+       u8 jit_reg;
+
+       jit_reg = lightrec_alloc_reg_out(cache, _jit, reg);
+       nreg = lightning_reg_to_lightrec(cache, jit_reg);
+
+       nreg->extend = true;
+
+       return jit_reg;
+}
+
+u8 lightrec_alloc_reg_in_ext(struct regcache *cache, jit_state_t *_jit, u8 reg)
+{
+       struct native_register *nreg;
+       u8 jit_reg;
+
+       jit_reg = lightrec_alloc_reg_in(cache, _jit, reg);
+       nreg = lightning_reg_to_lightrec(cache, jit_reg);
+
+#if __WORDSIZE == 64
+       if (!nreg->extended) {
+               nreg->extended = true;
+               jit_extr_i(jit_reg, jit_reg);
+       }
+#endif
+
+       return jit_reg;
+}
+
+u8 lightrec_request_reg_in(struct regcache *cache, jit_state_t *_jit,
+                          u8 reg, u8 jit_reg)
+{
+       struct native_register *nreg;
+       u16 offset;
+
+       nreg = find_mapped_reg(cache, reg, false);
+       if (nreg) {
+               jit_reg = lightrec_reg_to_lightning(cache, nreg);
+               nreg->used = true;
+               return jit_reg;
+       }
+
+       nreg = lightning_reg_to_lightrec(cache, jit_reg);
+       lightrec_unload_nreg(cache, _jit, nreg, jit_reg);
+
+       /* Load previous value from register cache */
+       offset = offsetof(struct lightrec_state, native_reg_cache) + (reg << 2);
+       jit_ldxi_i(jit_reg, LIGHTREC_REG_STATE, offset);
+
+       nreg->extended = true;
+       nreg->used = true;
+       nreg->loaded = true;
+       nreg->emulated_register = reg;
+
+       return jit_reg;
+}
+
+static void free_reg(struct native_register *nreg)
+{
+       /* Set output registers as dirty */
+       if (nreg->used && nreg->output && nreg->emulated_register > 0)
+               nreg->dirty = true;
+       if (nreg->output)
+               nreg->extended = nreg->extend;
+       nreg->used = false;
+}
+
+void lightrec_free_reg(struct regcache *cache, u8 jit_reg)
+{
+       free_reg(lightning_reg_to_lightrec(cache, jit_reg));
+}
+
+void lightrec_free_regs(struct regcache *cache)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(cache->lightrec_regs); i++)
+               free_reg(&cache->lightrec_regs[i]);
+}
+
+static void clean_reg(jit_state_t *_jit,
+               struct native_register *nreg, u8 jit_reg, bool clean)
+{
+       if (nreg->dirty) {
+               s16 offset = offsetof(struct lightrec_state, native_reg_cache)
+                       + (nreg->emulated_register << 2);
+
+               jit_stxi_i(offset, LIGHTREC_REG_STATE, jit_reg);
+               nreg->loaded |= nreg->dirty;
+               nreg->dirty ^= clean;
+       }
+}
+
+static void clean_regs(struct regcache *cache, jit_state_t *_jit, bool clean)
+{
+       unsigned int i;
+
+       for (i = 0; i < NUM_REGS; i++)
+               clean_reg(_jit, &cache->lightrec_regs[i], JIT_V(i), clean);
+       for (i = 0; i < NUM_TEMPS; i++) {
+               clean_reg(_jit, &cache->lightrec_regs[i + NUM_REGS],
+                               JIT_R(i), clean);
+       }
+}
+
+void lightrec_storeback_regs(struct regcache *cache, jit_state_t *_jit)
+{
+       clean_regs(cache, _jit, false);
+}
+
+void lightrec_clean_regs(struct regcache *cache, jit_state_t *_jit)
+{
+       clean_regs(cache, _jit, true);
+}
+
+void lightrec_clean_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg)
+{
+       struct native_register *reg = lightning_reg_to_lightrec(cache, jit_reg);
+       clean_reg(_jit, reg, jit_reg, true);
+}
+
+void lightrec_clean_reg_if_loaded(struct regcache *cache, jit_state_t *_jit,
+                                 u8 reg, bool unload)
+{
+       struct native_register *nreg;
+       u8 jit_reg;
+
+       nreg = find_mapped_reg(cache, reg, false);
+       if (nreg) {
+               jit_reg = lightrec_reg_to_lightning(cache, nreg);
+
+               if (unload)
+                       lightrec_unload_nreg(cache, _jit, nreg, jit_reg);
+               else
+                       clean_reg(_jit, nreg, jit_reg, true);
+       }
+}
+
+struct native_register * lightrec_regcache_enter_branch(struct regcache *cache)
+{
+       struct native_register *backup;
+
+       backup = lightrec_malloc(cache->state, MEM_FOR_LIGHTREC,
+                                sizeof(cache->lightrec_regs));
+       memcpy(backup, &cache->lightrec_regs, sizeof(cache->lightrec_regs));
+
+       return backup;
+}
+
+void lightrec_regcache_leave_branch(struct regcache *cache,
+                       struct native_register *regs)
+{
+       memcpy(&cache->lightrec_regs, regs, sizeof(cache->lightrec_regs));
+       lightrec_free(cache->state, MEM_FOR_LIGHTREC,
+                     sizeof(cache->lightrec_regs), regs);
+}
+
+void lightrec_regcache_reset(struct regcache *cache)
+{
+       memset(&cache->lightrec_regs, 0, sizeof(cache->lightrec_regs));
+}
+
+struct regcache * lightrec_regcache_init(struct lightrec_state *state)
+{
+       struct regcache *cache;
+
+       cache = lightrec_calloc(state, MEM_FOR_LIGHTREC, sizeof(*cache));
+       if (!cache)
+               return NULL;
+
+       cache->state = state;
+
+       return cache;
+}
+
+void lightrec_free_regcache(struct regcache *cache)
+{
+       return lightrec_free(cache->state, MEM_FOR_LIGHTREC,
+                            sizeof(*cache), cache);
+}
+
+void lightrec_regcache_mark_live(struct regcache *cache, jit_state_t *_jit)
+{
+       struct native_register *nreg;
+       unsigned int i;
+
+#ifdef _WIN32
+       /* FIXME: GNU Lightning on Windows seems to use our mapped registers as
+        * temporaries. Until the actual bug is found and fixed, unconditionally
+        * mark our registers as live here. */
+       for (i = 0; i < NUM_REGS; i++) {
+               nreg = &cache->lightrec_regs[i];
+
+               if (nreg->used || nreg->loaded || nreg->dirty)
+                       jit_live(JIT_V(i));
+       }
+#endif
+
+       for (i = 0; i < NUM_TEMPS; i++) {
+               nreg = &cache->lightrec_regs[NUM_REGS + i];
+
+               if (nreg->used || nreg->loaded || nreg->dirty)
+                       jit_live(JIT_R(i));
+       }
+}
diff --git a/deps/lightrec/regcache.h b/deps/lightrec/regcache.h
new file mode 100644 (file)
index 0000000..8678cc6
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2014-2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __REGCACHE_H__
+#define __REGCACHE_H__
+
+#include "lightrec-private.h"
+
+#define NUM_REGS (JIT_V_NUM - 2)
+#define NUM_TEMPS (JIT_R_NUM)
+#define LIGHTREC_REG_STATE (JIT_V(JIT_V_NUM - 1))
+#define LIGHTREC_REG_CYCLE (JIT_V(JIT_V_NUM - 2))
+
+#define REG_LO 32
+#define REG_HI 33
+
+struct register_value {
+       _Bool known;
+       u32 value;
+};
+
+struct native_register;
+struct regcache;
+
+u8 lightrec_alloc_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg);
+u8 lightrec_alloc_reg_temp(struct regcache *cache, jit_state_t *_jit);
+u8 lightrec_alloc_reg_out(struct regcache *cache, jit_state_t *_jit, u8 reg);
+u8 lightrec_alloc_reg_in(struct regcache *cache, jit_state_t *_jit, u8 reg);
+u8 lightrec_alloc_reg_out_ext(struct regcache *cache,
+                             jit_state_t *_jit, u8 reg);
+u8 lightrec_alloc_reg_in_ext(struct regcache *cache, jit_state_t *_jit, u8 reg);
+
+u8 lightrec_request_reg_in(struct regcache *cache, jit_state_t *_jit,
+                          u8 reg, u8 jit_reg);
+
+void lightrec_regcache_reset(struct regcache *cache);
+
+void lightrec_lock_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg);
+void lightrec_free_reg(struct regcache *cache, u8 jit_reg);
+void lightrec_free_regs(struct regcache *cache);
+void lightrec_clean_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg);
+void lightrec_clean_regs(struct regcache *cache, jit_state_t *_jit);
+void lightrec_unload_reg(struct regcache *cache, jit_state_t *_jit, u8 jit_reg);
+void lightrec_storeback_regs(struct regcache *cache, jit_state_t *_jit);
+
+void lightrec_clean_reg_if_loaded(struct regcache *cache, jit_state_t *_jit,
+                                 u8 reg, _Bool unload);
+
+u8 lightrec_alloc_reg_in_address(struct regcache *cache,
+               jit_state_t *_jit, u8 reg, s16 offset);
+
+struct native_register * lightrec_regcache_enter_branch(struct regcache *cache);
+void lightrec_regcache_leave_branch(struct regcache *cache,
+                       struct native_register *regs);
+
+struct regcache * lightrec_regcache_init(struct lightrec_state *state);
+void lightrec_free_regcache(struct regcache *cache);
+
+const char * lightrec_reg_name(u8 reg);
+
+void lightrec_regcache_mark_live(struct regcache *cache, jit_state_t *_jit);
+
+#endif /* __REGCACHE_H__ */
diff --git a/deps/lightrec/slist.h b/deps/lightrec/slist.h
new file mode 100644 (file)
index 0000000..18195e8
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 Paul Cercueil <paul@crapouillou.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ */
+
+#ifndef __LIGHTREC_SLIST_H__
+#define __LIGHTREC_SLIST_H__
+
+#define container_of(ptr, type, member)        \
+       ((type *)((void *)(ptr) - offsetof(type, member)))
+
+struct slist_elm {
+       struct slist_elm *next;
+};
+
+static inline void slist_init(struct slist_elm *head)
+{
+       head->next = NULL;
+}
+
+static inline struct slist_elm * slist_first(struct slist_elm *head)
+{
+       return head->next;
+}
+
+static inline _Bool slist_empty(const struct slist_elm *head)
+{
+       return head->next == NULL;
+}
+
+static inline void slist_remove_next(struct slist_elm *elm)
+{
+       if (elm->next)
+               elm->next = elm->next->next;
+}
+
+static inline void slist_remove(struct slist_elm *head, struct slist_elm *elm)
+{
+       struct slist_elm *prev;
+
+       if (head->next == elm) {
+               head->next = elm->next;
+       } else {
+               for (prev = head->next; prev && prev->next != elm; )
+                       prev = prev->next;
+               if (prev)
+                       slist_remove_next(prev);
+       }
+}
+
+static inline void slist_append(struct slist_elm *head, struct slist_elm *elm)
+{
+       elm->next = head->next;
+       head->next = elm;
+}
+
+#endif /* __LIGHTREC_SLIST_H__ */
diff --git a/deps/mman/.gitignore b/deps/mman/.gitignore
new file mode 100644 (file)
index 0000000..5f778db
--- /dev/null
@@ -0,0 +1,2 @@
+x64
+mman.VC.db
\ No newline at end of file
diff --git a/deps/mman/.gitrepo b/deps/mman/.gitrepo
new file mode 100644 (file)
index 0000000..7e6585b
--- /dev/null
@@ -0,0 +1,12 @@
+; DO NOT EDIT (unless you know what you are doing)
+;
+; This subdirectory is a git "subrepo", and this file is maintained by the
+; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
+;
+[subrepo]
+       remote = https://github.com/witwall/mman-win32
+       branch = master
+       commit = 2d1c576e62b99e85d99407e1a88794c6e44c3310
+       parent = 19599a744a114b242c401d5ac1f0bcfc369453ee
+       method = merge
+       cmdver = 0.4.1
diff --git a/deps/mman/.vs/mman/v14/.suo b/deps/mman/.vs/mman/v14/.suo
new file mode 100644 (file)
index 0000000..57e963c
Binary files /dev/null and b/deps/mman/.vs/mman/v14/.suo differ
diff --git a/deps/mman/CMakeLists.txt b/deps/mman/CMakeLists.txt
new file mode 100644 (file)
index 0000000..72b9c26
--- /dev/null
@@ -0,0 +1,33 @@
+project (mman-win32 C)
+
+cmake_minimum_required (VERSION 2.8)
+
+option (BUILD_SHARED_LIBS "shared/static libs" ON) 
+option (BUILD_TESTS "tests?" OFF)
+
+set (headers mman.h)
+set (sources mman.c)
+
+add_library (mman ${sources})
+
+if (BUILD_SHARED_LIBS)
+       target_compile_definitions(mman
+               PUBLIC MMAN_LIBRARY_DLL
+               PRIVATE MMAN_LIBRARY
+       )
+endif()
+
+install (TARGETS mman RUNTIME DESTINATION bin
+                      LIBRARY DESTINATION lib${LIB_SUFFIX}
+                      ARCHIVE DESTINATION lib${LIB_SUFFIX})
+
+install (FILES ${headers} DESTINATION include/sys)
+
+if (BUILD_TESTS)
+  enable_testing ()
+  add_executable (t_mman test.c)
+  target_link_libraries (t_mman mman)
+  add_test (NAME t_mman COMMAND t_mman${CMAKE_EXECUTABLE_SUFFIX})
+endif ()
+
+
diff --git a/deps/mman/Makefile b/deps/mman/Makefile
new file mode 100644 (file)
index 0000000..f6af361
--- /dev/null
@@ -0,0 +1,68 @@
+#
+# mman-win32 (mingw32) Makefile
+#
+include config.mak
+
+CFLAGS=-Wall -O3 -fomit-frame-pointer
+
+ifeq ($(BUILD_STATIC),yes)
+       TARGETS+=libmman.a
+       INSTALL+=static-install
+endif
+
+ifeq ($(BUILD_SHARED),yes)
+       TARGETS+=libmman.dll
+       INSTALL+=shared-install
+       CFLAGS+=-DMMAN_LIBRARY_DLL -DMMAN_LIBRARY
+endif
+
+ifeq ($(BUILD_MSVC),yes)
+       SHFLAGS+=-Wl,--output-def,libmman.def
+       INSTALL+=lib-install
+endif
+
+all: $(TARGETS)
+
+mman.o: mman.c mman.h
+       $(CC) -o mman.o -c mman.c $(CFLAGS)
+
+libmman.a: mman.o
+       $(AR) cru libmman.a mman.o
+       $(RANLIB) libmman.a
+
+libmman.dll: mman.o
+       $(CC) -shared -o libmman.dll mman.o -Wl,--out-implib,libmman.dll.a
+
+header-install:
+       mkdir -p $(DESTDIR)$(incdir)
+       cp mman.h $(DESTDIR)$(incdir)
+
+static-install: header-install
+       mkdir -p $(DESTDIR)$(libdir)
+       cp libmman.a $(DESTDIR)$(libdir)
+
+shared-install: header-install
+       mkdir -p $(DESTDIR)$(libdir)
+       cp libmman.dll.a $(DESTDIR)$(libdir)
+       mkdir -p $(DESTDIR)$(bindir)
+       cp libmman.dll $(DESTDIR)$(bindir)
+
+lib-install:
+       mkdir -p $(DESTDIR)$(libdir)
+       cp libmman.lib $(DESTDIR)$(libdir)
+
+install: $(INSTALL)
+
+test.exe: test.c mman.c mman.h
+       $(CC) -o test.exe test.c -L. -lmman
+
+test: $(TARGETS) test.exe
+       test.exe
+
+clean::
+       rm -f mman.o libmman.a libmman.dll.a libmman.dll libmman.def libmman.lib test.exe *.dat
+
+distclean: clean
+       rm -f config.mak
+
+.PHONY: clean distclean install test
diff --git a/deps/mman/README.md b/deps/mman/README.md
new file mode 100644 (file)
index 0000000..9df50e3
--- /dev/null
@@ -0,0 +1,10 @@
+mman-win32
+==========
+
+mman library for Windows. mirror of https://code.google.com/p/mman-win32/
+
+A light implementation of the mmap functions for MinGW.
+
+The mmap-win32 library implements a wrapper for mmap functions around the memory mapping Windows API.
+
+License: MIT License
diff --git a/deps/mman/UpgradeLog.htm b/deps/mman/UpgradeLog.htm
new file mode 100644 (file)
index 0000000..c15fdf0
Binary files /dev/null and b/deps/mman/UpgradeLog.htm differ
diff --git a/deps/mman/configure b/deps/mman/configure
new file mode 100755 (executable)
index 0000000..665cb1e
--- /dev/null
@@ -0,0 +1,170 @@
+#!/bin/sh
+# mmap-win32 configure script
+#
+# Parts copied from FFmpeg's configure
+#
+
+set_all(){
+    value=$1
+    shift
+    for var in $*; do
+        eval $var=$value
+    done
+}
+
+enable(){
+    set_all yes $*
+}
+
+disable(){
+    set_all no $*
+}
+
+enabled(){
+    eval test "x\$$1" = "xyes"
+}
+
+disabled(){
+    eval test "x\$$1" = "xno"
+}
+
+show_help(){
+  echo "Usage: configure [options]"
+  echo "Options: [defaults in brackets after descriptions]"
+  echo "All \"enable\" options have \"disable\" counterparts"
+  echo
+  echo "  --help                    print this message"
+  echo "  --prefix=PREFIX           install in PREFIX [$PREFIX]"
+  echo "  --bindir=DIR              install binaries in DIR [$PREFIX/bin]"
+  echo "  --libdir=DIR              install libs in DIR [$PREFIX/lib]"
+  echo "  --incdir=DIR              install includes in DIR [$PREFIX/include]"
+  echo "  --enable-static           build static libraries [yes]"
+  echo "  --enable-shared           build shared libraries [no]"
+  echo "  --enable-msvc             create msvc-compatible import lib [auto]"
+  echo
+  echo "  --cc=CC                   use C compiler CC [$cc_default]"
+  echo "  --cross-prefix=PREFIX     use PREFIX for compilation tools [$cross_prefix]"
+  exit 1
+}
+
+die_unknown(){
+    echo "Unknown option \"$1\"."
+    echo "See $0 --help for available options."
+    exit 1
+}
+
+PREFIX="/mingw"
+ar="ar"
+cc_default="gcc"
+ranlib="ranlib"
+strip="strip"
+
+DEFAULT="msvc
+"
+
+DEFAULT_YES="static
+    stripping
+"
+
+DEFAULT_NO="shared
+"
+
+CMDLINE_SELECT="$DEFAULT
+    $DEFAULT_NO
+    $DEFAULT_YES
+"
+
+enable  $DEFAULT_YES
+disable $DEFAULT_NO
+
+for opt do
+    optval="${opt#*=}"
+    case "$opt" in
+    --help)
+        show_help
+    ;;
+    --prefix=*)
+        PREFIX="$optval"
+    ;;
+    --bindir=*)
+        bindir="$optval"
+    ;;
+    --libdir=*)
+        libdir="$optval"
+    ;;
+    --incdir=*)
+        incdir="$optval"
+    ;;
+    --cc=*)
+        cc="$optval"
+    ;;
+    --cross-prefix=*)
+        cross_prefix="$optval"
+    ;;
+    --enable-?*|--disable-?*)
+        eval `echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g'`
+        echo "$CMDLINE_SELECT" | grep -q "^ *$option\$" || die_unknown $opt
+        $action $option
+    ;;
+    *)
+        die_unknown $opt
+    ;;
+    esac
+done
+
+bindir="${PREFIX}/bin"
+libdir="${PREFIX}/lib"
+incdir="${PREFIX}/include/sys"
+ar="${cross_prefix}${ar}"
+cc_default="${cross_prefix}${cc_default}"
+ranlib="${cross_prefix}${ranlib}"
+strip="${cross_prefix}${strip}"
+
+if ! test -z $cc; then
+    cc_default="${cc}"
+fi
+cc="${cc_default}"
+
+disabled static && disabled shared && {
+    echo "At least one library type must be set.";
+    exit 1;
+}
+
+if enabled msvc; then
+    lib /? > /dev/null 2>&1 /dev/null || {
+        echo "MSVC's lib command not found."
+        echo "Make sure MSVC is installed and its bin folder is in your \$PATH."
+        exit 1
+    }
+fi
+
+if ! enabled stripping; then
+    strip="echo ignoring strip"
+fi
+
+enabled msvc && libcmd="lib" || libcmd="echo ignoring lib"
+
+echo "# Automatically generated by configure" > config.mak
+echo "PREFIX=$PREFIX" >> config.mak
+echo "bindir=$bindir" >> config.mak
+echo "libdir=$libdir" >> config.mak
+echo "incdir=$incdir" >> config.mak
+echo "AR=$ar" >> config.mak
+echo "CC=$cc" >> config.mak
+echo "RANLIB=$ranlib" >> config.mak
+echo "STRIP=$strip" >> config.mak
+echo "BUILD_STATIC=$static" >> config.mak
+echo "BUILD_SHARED=$shared" >> config.mak
+echo "BUILD_MSVC=$msvc" >> config.mak
+echo "LIBCMD=$libcmd" >> config.mak
+
+echo "prefix: $PREFIX"
+echo "bindir: $bindir"
+echo "libdir: $libdir"
+echo "incdir: $incdir"
+echo "ar:     $ar"
+echo "cc:     $cc"
+echo "ranlib: $ranlib"
+echo "strip:  $strip"
+echo "static: $static"
+echo "shared: $shared"
diff --git a/deps/mman/mman-win32.pro b/deps/mman/mman-win32.pro
new file mode 100644 (file)
index 0000000..b58b4d9
--- /dev/null
@@ -0,0 +1,13 @@
+QT -= core gui\r
+\r
+TARGET = mman\r
+TEMPLATE = lib\r
+\r
+DEFINES += MMAN_LIBRARY_DLL\r
+DEFINES += MMAN_LIBRARY\r
+\r
+HEADERS += \\r
+    mman.h\r
+\r
+SOURCES += \\r
+    mman.c\r
diff --git a/deps/mman/mman.c b/deps/mman/mman.c
new file mode 100644 (file)
index 0000000..e71666c
--- /dev/null
@@ -0,0 +1,185 @@
+
+#include <windows.h>
+#include <errno.h>
+#include <io.h>
+
+#include "mman.h"
+
+#ifndef FILE_MAP_EXECUTE
+#define FILE_MAP_EXECUTE    0x0020
+#endif /* FILE_MAP_EXECUTE */
+
+static int __map_mman_error(const DWORD err, const int deferr)
+{
+    if (err == 0)
+        return 0;
+    //TODO: implement
+    return err;
+}
+
+static DWORD __map_mmap_prot_page(const int prot)
+{
+    DWORD protect = 0;
+    
+    if (prot == PROT_NONE)
+        return protect;
+        
+    if ((prot & PROT_EXEC) != 0)
+    {
+        protect = ((prot & PROT_WRITE) != 0) ? 
+                    PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
+    }
+    else
+    {
+        protect = ((prot & PROT_WRITE) != 0) ?
+                    PAGE_READWRITE : PAGE_READONLY;
+    }
+    
+    return protect;
+}
+
+static DWORD __map_mmap_prot_file(const int prot)
+{
+    DWORD desiredAccess = 0;
+    
+    if (prot == PROT_NONE)
+        return desiredAccess;
+        
+    if ((prot & PROT_READ) != 0)
+        desiredAccess |= FILE_MAP_READ;
+    if ((prot & PROT_WRITE) != 0)
+        desiredAccess |= FILE_MAP_WRITE;
+    if ((prot & PROT_EXEC) != 0)
+        desiredAccess |= FILE_MAP_EXECUTE;
+    
+    return desiredAccess;
+}
+
+void* mmap(void *addr, size_t len, int prot, int flags, int fildes, OffsetType off)
+{
+    HANDLE fm, h;
+    
+    void * map = MAP_FAILED;
+    
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4293)
+#endif
+
+    const DWORD dwFileOffsetLow = (sizeof(OffsetType) <= sizeof(DWORD)) ?
+                    (DWORD)off : (DWORD)(off & 0xFFFFFFFFL);
+    const DWORD dwFileOffsetHigh = (sizeof(OffsetType) <= sizeof(DWORD)) ?
+                    (DWORD)0 : (DWORD)((off >> 32) & 0xFFFFFFFFL);
+    const DWORD protect = __map_mmap_prot_page(prot);
+    const DWORD desiredAccess = __map_mmap_prot_file(prot);
+
+    const OffsetType maxSize = off + (OffsetType)len;
+
+    const DWORD dwMaxSizeLow = (sizeof(OffsetType) <= sizeof(DWORD)) ?
+                    (DWORD)maxSize : (DWORD)(maxSize & 0xFFFFFFFFL);
+    const DWORD dwMaxSizeHigh = (sizeof(OffsetType) <= sizeof(DWORD)) ?
+                    (DWORD)0 : (DWORD)((maxSize >> 32) & 0xFFFFFFFFL);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+    errno = 0;
+    
+    if (len == 0 
+        /* Usupported protection combinations */
+        || prot == PROT_EXEC)
+    {
+        errno = EINVAL;
+        return MAP_FAILED;
+    }
+    
+    h = ((flags & MAP_ANONYMOUS) == 0) ? 
+                    (HANDLE)_get_osfhandle(fildes) : INVALID_HANDLE_VALUE;
+
+    if ((flags & MAP_ANONYMOUS) == 0 && h == INVALID_HANDLE_VALUE)
+    {
+        errno = EBADF;
+        return MAP_FAILED;
+    }
+
+    fm = CreateFileMapping(h, NULL, protect, dwMaxSizeHigh, dwMaxSizeLow, NULL);
+
+    if (fm == NULL)
+    {
+        errno = __map_mman_error(GetLastError(), EPERM);
+        return MAP_FAILED;
+    }
+  
+    if ((flags & MAP_FIXED) == 0)
+    {
+        map = MapViewOfFile(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len);
+    }
+    else
+    {
+        map = MapViewOfFileEx(fm, desiredAccess, dwFileOffsetHigh, dwFileOffsetLow, len, addr);
+    }
+
+    CloseHandle(fm);
+  
+    if (map == NULL)
+    {
+        errno = __map_mman_error(GetLastError(), EPERM);
+        return MAP_FAILED;
+    }
+
+    return map;
+}
+
+int munmap(void *addr, size_t len)
+{
+    if (UnmapViewOfFile(addr))
+        return 0;
+        
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
+
+int _mprotect(void *addr, size_t len, int prot)
+{
+    DWORD newProtect = __map_mmap_prot_page(prot);
+    DWORD oldProtect = 0;
+    
+    if (VirtualProtect(addr, len, newProtect, &oldProtect))
+        return 0;
+    
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
+
+int msync(void *addr, size_t len, int flags)
+{
+    if (FlushViewOfFile(addr, len))
+        return 0;
+    
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
+
+int mlock(const void *addr, size_t len)
+{
+    if (VirtualLock((LPVOID)addr, len))
+        return 0;
+        
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
+
+int munlock(const void *addr, size_t len)
+{
+    if (VirtualUnlock((LPVOID)addr, len))
+        return 0;
+        
+    errno =  __map_mman_error(GetLastError(), EPERM);
+    
+    return -1;
+}
diff --git a/deps/mman/mman.h b/deps/mman/mman.h
new file mode 100644 (file)
index 0000000..047d3a0
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * sys/mman.h
+ * mman-win32
+ */
+
+#ifndef _SYS_MMAN_H_
+#define _SYS_MMAN_H_
+
+#ifndef _WIN32_WINNT           // Allow use of features specific to Windows XP or later.                   
+#define _WIN32_WINNT 0x0501    // Change this to the appropriate value to target other versions of Windows.
+#endif                                         
+
+/* All the headers include this file. */
+#ifndef _MSC_VER
+#include <_mingw.h>
+#endif
+
+#if defined(MMAN_LIBRARY_DLL)
+/* Windows shared libraries (DLL) must be declared export when building the lib and import when building the 
+application which links against the library. */
+#if defined(MMAN_LIBRARY)
+#define MMANSHARED_EXPORT __declspec(dllexport)
+#else
+#define MMANSHARED_EXPORT __declspec(dllimport)
+#endif /* MMAN_LIBRARY */
+#else
+/* Static libraries do not require a __declspec attribute.*/
+#define MMANSHARED_EXPORT
+#endif /* MMAN_LIBRARY_DLL */
+
+/* Determine offset type */
+#include <stdint.h>
+#if defined(_WIN64)
+typedef int64_t OffsetType;
+#else
+typedef uint32_t OffsetType;
+#endif
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PROT_NONE       0
+#define PROT_READ       1
+#define PROT_WRITE      2
+#define PROT_EXEC       4
+
+#define MAP_FILE        0
+#define MAP_SHARED      1
+#define MAP_PRIVATE     2
+#define MAP_TYPE        0xf
+#define MAP_FIXED       0x10
+#define MAP_ANONYMOUS   0x20
+#define MAP_ANON        MAP_ANONYMOUS
+
+#define MAP_FAILED      ((void *)-1)
+
+/* Flags for msync. */
+#define MS_ASYNC        1
+#define MS_SYNC         2
+#define MS_INVALIDATE   4
+
+MMANSHARED_EXPORT void*   mmap(void *addr, size_t len, int prot, int flags, int fildes, OffsetType off);
+MMANSHARED_EXPORT int     munmap(void *addr, size_t len);
+MMANSHARED_EXPORT int     _mprotect(void *addr, size_t len, int prot);
+MMANSHARED_EXPORT int     msync(void *addr, size_t len, int flags);
+MMANSHARED_EXPORT int     mlock(const void *addr, size_t len);
+MMANSHARED_EXPORT int     munlock(const void *addr, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*  _SYS_MMAN_H_ */
diff --git a/deps/mman/mman.sln b/deps/mman/mman.sln
new file mode 100644 (file)
index 0000000..69fb506
--- /dev/null
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mman", "mman.vcxproj", "{592F578E-6F24-47C0-9F6C-07BC9B730E27}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|x64 = Debug|x64
+               Debug|x86 = Debug|x86
+               Release|x64 = Release|x64
+               Release|x86 = Release|x86
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {592F578E-6F24-47C0-9F6C-07BC9B730E27}.Debug|x64.ActiveCfg = Debug|x64
+               {592F578E-6F24-47C0-9F6C-07BC9B730E27}.Debug|x64.Build.0 = Debug|x64
+               {592F578E-6F24-47C0-9F6C-07BC9B730E27}.Debug|x86.ActiveCfg = Debug|Win32
+               {592F578E-6F24-47C0-9F6C-07BC9B730E27}.Debug|x86.Build.0 = Debug|Win32
+               {592F578E-6F24-47C0-9F6C-07BC9B730E27}.Release|x64.ActiveCfg = Release|x64
+               {592F578E-6F24-47C0-9F6C-07BC9B730E27}.Release|x64.Build.0 = Release|x64
+               {592F578E-6F24-47C0-9F6C-07BC9B730E27}.Release|x86.ActiveCfg = Release|Win32
+               {592F578E-6F24-47C0-9F6C-07BC9B730E27}.Release|x86.Build.0 = Release|Win32
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+EndGlobal
diff --git a/deps/mman/mman.vcxproj b/deps/mman/mman.vcxproj
new file mode 100644 (file)
index 0000000..e8dffa2
--- /dev/null
@@ -0,0 +1,122 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{592F578E-6F24-47C0-9F6C-07BC9B730E27}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v140</PlatformToolset>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <Optimization>Disabled</Optimization>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <WarningLevel>Level3</WarningLevel>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+    </ClCompile>
+    <Link>
+      <TargetMachine>MachineX86</TargetMachine>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="mman.c" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="mman.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="UpgradeLog.htm" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/deps/mman/mman.vcxproj.filters b/deps/mman/mman.vcxproj.filters
new file mode 100644 (file)
index 0000000..a08c8d5
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="mman.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="mman.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="UpgradeLog.htm" />
+  </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/deps/mman/mman.vcxproj.user b/deps/mman/mman.vcxproj.user
new file mode 100644 (file)
index 0000000..abe8dd8
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup />
+</Project>
\ No newline at end of file
diff --git a/deps/mman/test.c b/deps/mman/test.c
new file mode 100644 (file)
index 0000000..9374b9f
--- /dev/null
@@ -0,0 +1,235 @@
+
+#include "mman.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifndef NULL
+#define NULL    (void*)0
+#endif
+
+const char* map_file_name = "map_file.dat";
+
+int test_anon_map_readwrite()
+{    
+    void* map = mmap(NULL, 1024, PROT_READ | PROT_WRITE,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    if (map == MAP_FAILED)
+    {
+        printf("mmap (MAP_ANONYMOUS, PROT_READ | PROT_WRITE) returned unexpected error: %d\n", errno);
+        return -1;
+    }
+        
+    *((unsigned char*)map) = 1;
+    
+    int result = munmap(map, 1024);
+    
+    if (result != 0)
+        printf("munmap (MAP_ANONYMOUS, PROT_READ | PROT_WRITE) returned unexpected error: %d\n", errno);
+        
+    return result;
+}
+
+int test_anon_map_readonly()
+{    
+    void* map = mmap(NULL, 1024, PROT_READ,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    if (map == MAP_FAILED)
+    {
+        printf("mmap (MAP_ANONYMOUS, PROT_READ) returned unexpected error: %d\n", errno);
+        return -1;
+    }
+        
+    *((unsigned char*)map) = 1;
+    
+    int result = munmap(map, 1024);
+    
+    if (result != 0)
+        printf("munmap (MAP_ANONYMOUS, PROT_READ) returned unexpected error: %d\n", errno);
+        
+    return result;
+}
+
+int test_anon_map_writeonly()
+{    
+    void* map = mmap(NULL, 1024, PROT_WRITE,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    if (map == MAP_FAILED)
+    {
+        printf("mmap (MAP_ANONYMOUS, PROT_WRITE) returned unexpected error: %d\n", errno);
+        return -1;
+    }
+        
+    *((unsigned char*)map) = 1;
+    
+    int result = munmap(map, 1024);
+    
+    if (result != 0)
+        printf("munmap (MAP_ANONYMOUS, PROT_WRITE) returned unexpected error: %d\n", errno);
+        
+    return result;
+}
+
+int test_anon_map_readonly_nowrite()
+{    
+    void* map = mmap(NULL, 1024, PROT_READ,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    if (map == MAP_FAILED)
+    {
+        printf("mmap (MAP_ANONYMOUS, PROT_READ) returned unexpected error: %d\n", errno);
+        return -1;
+    }
+    
+    if (*((unsigned char*)map) != 0)
+        printf("test_anon_map_readonly_nowrite (MAP_ANONYMOUS, PROT_READ) returned unexpected value: %d\n", 
+                (int)*((unsigned char*)map));
+        
+    int result = munmap(map, 1024);
+    
+    if (result != 0)
+        printf("munmap (MAP_ANONYMOUS, PROT_READ) returned unexpected error: %d\n", errno);
+        
+    return result;
+}
+
+int test_file_map_readwrite()
+{
+    mode_t mode = S_IRUSR | S_IWUSR;
+    int o = open(map_file_name, O_TRUNC | O_BINARY | O_RDWR | O_CREAT, mode);
+
+    void* map = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_PRIVATE, o, 0);
+    if (map == MAP_FAILED)
+    {
+        printf("mmap returned unexpected error: %d\n", errno);
+        return -1;
+    }
+
+    *((unsigned char*)map) = 1;
+    
+    int result = munmap(map, 1024);
+    
+    if (result != 0)
+        printf("munmap returned unexpected error: %d\n", errno);
+    
+    close(o);
+    
+    /*TODO: get file info and content and compare it with the sources conditions */
+    unlink(map_file_name);
+    
+    return result;
+}
+
+int test_file_map_mlock_munlock()
+{
+    const size_t map_size = 1024;
+    
+    int result = 0;
+    mode_t mode = S_IRUSR | S_IWUSR;
+    int o = open(map_file_name, O_TRUNC | O_BINARY | O_RDWR | O_CREAT, mode);
+    if (o == -1)
+    {
+        printf("unable to create file %s: %d\n", map_file_name, errno);
+        return -1;
+    }
+
+    void* map = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, o, 0);
+    if (map == MAP_FAILED)
+    {
+        printf("mmap returned unexpected error: %d\n", errno);
+        result = -1;
+        goto done_close;
+    }
+     
+    if (mlock(map, map_size) != 0)
+    {
+        printf("mlock returned unexpected error: %d\n", errno);
+        result = -1;
+        goto done_munmap;        
+    }
+    
+    *((unsigned char*)map) = 1;
+    
+    if (munlock(map, map_size) != 0)
+    {
+        printf("munlock returned unexpected error: %d\n", errno);
+        result = -1;
+    }
+    
+done_munmap:
+    result = munmap(map, map_size);
+    
+    if (result != 0)
+        printf("munmap returned unexpected error: %d\n", errno);
+        
+done_close:
+    close(o);
+    
+    unlink(map_file_name);
+done:
+    return result;
+}
+
+int test_file_map_msync()
+{
+    const size_t map_size = 1024;
+    
+    int result = 0;
+    mode_t mode = S_IRUSR | S_IWUSR;
+    int o = open(map_file_name, O_TRUNC | O_BINARY | O_RDWR | O_CREAT, mode);
+    if (o == -1)
+    {
+        printf("unable to create file %s: %d\n", map_file_name, errno);
+        return -1;
+    }
+
+    void* map = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, o, 0);
+    if (map == MAP_FAILED)
+    {
+        printf("mmap returned unexpected error: %d\n", errno);
+        result = -1;
+        goto done_close;
+    }
+     
+    *((unsigned char*)map) = 1;
+
+    if (msync(map, map_size, MS_SYNC) != 0)
+    {
+        printf("msync returned unexpected error: %d\n", errno);
+        result = -1;
+    }
+    
+    result = munmap(map, map_size);
+    
+    if (result != 0)
+        printf("munmap returned unexpected error: %d\n", errno);
+        
+done_close:
+    close(o);
+    
+    unlink(map_file_name);
+done:
+    return result;
+}
+
+#define EXEC_TEST(name) \
+    if (name() != 0) { result = -1; printf( #name ": fail\n"); } \
+    else { printf(#name ": pass\n"); }
+
+int main()
+{
+    int result = 0;
+    
+    EXEC_TEST(test_anon_map_readwrite);
+    //NOTE: this test must cause an access violation exception
+    //EXEC_TEST(test_anon_map_readonly);
+    EXEC_TEST(test_anon_map_readonly_nowrite);
+    EXEC_TEST(test_anon_map_writeonly);
+    
+    EXEC_TEST(test_file_map_readwrite);
+    EXEC_TEST(test_file_map_mlock_munlock);
+    EXEC_TEST(test_file_map_msync);
+    //TODO: EXEC_TEST(test_file_map_mprotect);
+    
+    return result;
+}
diff --git a/frontend/320240/caanoo.gpe b/frontend/320240/caanoo.gpe
deleted file mode 100755 (executable)
index 9d6154a..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-
-# Wiz's timings are already good, apply this for Caanoo
-if [ -e /dev/accel ]; then
-  ./pollux_set "ram_timings=3,9,4,1,1,1,1"
-fi
-
-# the sync mount causes problems when writing saves,
-# probably due to many write calls, so have to get rid of it
-if grep mmcblk /proc/mounts | grep -q '\<sync\>'; then
-  oldmount=`grep mmcblk /proc/mounts | grep '\<sync\>' | awk '{print $4}'`
-  mount /dev/mmcblk0p1 /mnt/sd/ -o remount,dirsync,noatime
-fi
-
-./pcsx "$@"
-sync
-
-if [ -n "$oldmount" ]; then
-  mount /dev/mmcblk0p1 /mnt/sd/ -o remount,$oldmount
-fi
-
-cd /usr/gp2x
-exec ./gp2xmenu
diff --git a/frontend/320240/haptic_s.cfg b/frontend/320240/haptic_s.cfg
deleted file mode 100644 (file)
index 624056d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-0      126
-100    -126
-115    0
diff --git a/frontend/320240/haptic_w.cfg b/frontend/320240/haptic_w.cfg
deleted file mode 100644 (file)
index 3585a71..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-0       54
-100     -126
-105     0
diff --git a/frontend/320240/pcsx26.png b/frontend/320240/pcsx26.png
deleted file mode 100644 (file)
index ed220a0..0000000
Binary files a/frontend/320240/pcsx26.png and /dev/null differ
diff --git a/frontend/320240/pcsx_rearmed.ini b/frontend/320240/pcsx_rearmed.ini
deleted file mode 100644 (file)
index b15497f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[info]
-name="PCSX ReARMed"
-icon="/pcsx_rearmed/pcsx26.png"
-path="/pcsx_rearmed/pcsx.gpe"
-title="/pcsx_rearmed/pcsxb.png"
-group="GAMES"
diff --git a/frontend/320240/pcsxb.png b/frontend/320240/pcsxb.png
deleted file mode 100644 (file)
index ff5a48a..0000000
Binary files a/frontend/320240/pcsxb.png and /dev/null differ
diff --git a/frontend/320240/pollux_set.c b/frontend/320240/pollux_set.c
deleted file mode 100644 (file)
index f49e777..0000000
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * quick tool to set various timings for Wiz
- *
- * Copyright (c) Gražvydas "notaz" Ignotas, 2009
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the organization nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * HTOTAL:    X VTOTAL:  341
- * HSWIDTH:   1 VSWIDTH:   0
- * HASTART:  37 VASTART:  17
- * HAEND:   277 VAEND:   337
- *
- * 120Hz
- * pcd  8, 447: + 594us
- * pcd  9, 397: +  36us
- * pcd 10, 357: - 523us
- * pcd 11, 325: +1153us
- *
- * 'lcd_timings=397,1,37,277,341,0,17,337;dpc_clkdiv0=9'
- * 'ram_timings=2,9,4,1,1,1,1'
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-//#include "pollux_set.h"
-#define BINARY
-
-/* parse stuff */
-static int parse_lcd_timings(const char *str, void *data)
-{
-       int *lcd_timings = data;
-       const char *p = str;
-       int ret, c;
-       ret = sscanf(str, "%d,%d,%d,%d,%d,%d,%d,%d",
-                       &lcd_timings[0], &lcd_timings[1], &lcd_timings[2], &lcd_timings[3],
-                       &lcd_timings[4], &lcd_timings[5], &lcd_timings[6], &lcd_timings[7]);
-       if (ret != 8)
-               return -1;
-       /* skip seven commas */
-       for (c = 0; c < 7 && *p != 0; p++)
-               if (*p == ',')
-                       c++;
-       if (c != 7)
-               return -1;
-       /* skip last number */
-       while ('0' <= *p && *p <= '9')
-               p++;
-
-       return p - str;
-}
-
-static int parse_ram_timings(const char *str, void *data)
-{
-       int *ram_timings = data;
-       const char *p = str;
-       int ret, c;
-       float cas;
-
-       ret = sscanf(p, "%f,%d,%d,%d,%d,%d,%d",
-                       &cas, &ram_timings[1], &ram_timings[2], &ram_timings[3],
-                       &ram_timings[4], &ram_timings[5], &ram_timings[6]);
-       if (ret != 7)
-               return -1;
-       if (cas == 2)
-               ram_timings[0] = 1;
-       else if (cas == 2.5)
-               ram_timings[0] = 2;
-       else if (cas == 3)
-               ram_timings[0] = 3;
-       else
-               return -1;
-       for (c = 0; c < 6 && *p != 0; p++)
-               if (*p == ',')
-                       c++;
-       if (c != 6)
-               return -1;
-       while ('0' <= *p && *p <= '9')
-               p++;
-
-       return p - str;
-}
-
-static int parse_decimal(const char *str, void *data)
-{
-       char *ep;
-
-       *(int *)data = strtoul(str, &ep, 10);
-       if (ep == str)
-               return -1;
-
-       return ep - str;
-}
-
-/* validate and apply stuff */
-static int apply_lcd_timings(volatile unsigned short *memregs, void *data)
-{
-       int *lcd_timings = data;
-       int i;
-
-       for (i = 0; i < 8; i++) {
-               if (lcd_timings[i] & ~0xffff) {
-                       fprintf(stderr, "pollux_set: invalid lcd timing %d: %d\n", i, lcd_timings[i]);
-                       return -1;
-               }
-       }
-
-       for (i = 0; i < 8; i++)
-               memregs[(0x307c>>1) + i] = lcd_timings[i];
-
-       return 0;
-}
-
-static const struct {
-       signed char adj;        /* how to adjust value passed by user */
-       signed short min;       /* range of */
-       signed short max;       /* allowed values (inclusive) */
-}
-ram_ranges[] = {
-       {  0,  1,  3 }, /* cas (cl) */
-       { -2,  0, 15 }, /* trc */
-       { -2,  0, 15 }, /* tras */
-       {  0,  0, 15 }, /* twr */
-       {  0,  0, 15 }, /* tmrd */
-       {  0,  0, 15 }, /* trp */
-       {  0,  0, 15 }, /* trcd */
-};
-
-static int apply_ram_timings(volatile unsigned short *memregs, void *data)
-{
-       int *ram_timings = data;
-       int i, val;
-
-       for (i = 0; i < 7; i++)
-       {
-               ram_timings[i] += ram_ranges[i].adj;
-               if (ram_timings[i] < ram_ranges[i].min || ram_timings[i] > ram_ranges[i].max) {
-                       fprintf(stderr, "pollux_set: invalid RAM timing %d\n", i);
-                       return -1;
-               }
-       }
-
-       val = memregs[0x14802>>1] & 0x0f00;
-       val |= (ram_timings[4] << 12) | (ram_timings[5] << 4) | ram_timings[6];
-       memregs[0x14802>>1] = val;
-
-       val = memregs[0x14804>>1] & 0x4000;
-       val |= (ram_timings[0] << 12) | (ram_timings[1] << 8) |
-               (ram_timings[2] << 4) | ram_timings[3];
-       val |= 0x8000;
-       memregs[0x14804>>1] = val;
-
-       for (i = 0; i < 0x100000 && (memregs[0x14804>>1] & 0x8000); i++)
-               ;
-
-       return 0;
-}
-
-static int apply_dpc_clkdiv0(volatile unsigned short *memregs, void *data)
-{
-       int pcd = *(int *)data;
-       int tmp;
-
-       if ((pcd - 1) & ~0x3f) {
-               fprintf(stderr, "pollux_set: invalid lcd clkdiv0: %d\n", pcd);
-               return -1;
-       }
-
-       pcd = (pcd - 1) & 0x3f;
-       tmp = memregs[0x31c4>>1];
-       memregs[0x31c4>>1] = (tmp & ~0x3f0) | (pcd << 4);
-
-       return 0;
-}
-
-static int apply_cpuclk(volatile unsigned short *memregs, void *data)
-{
-       volatile unsigned int *memregl = (volatile void *)memregs;
-       int mhz = *(int *)data;
-       int adiv, mdiv, pdiv, sdiv = 0;
-       int i, vf000, vf004;
-
-       // m = MDIV, p = PDIV, s = SDIV
-       #define SYS_CLK_FREQ 27
-       pdiv = 9;
-       mdiv = (mhz * pdiv) / SYS_CLK_FREQ;
-       if (mdiv & ~0x3ff)
-               return -1;
-       vf004 = (pdiv<<18) | (mdiv<<8) | sdiv;
-
-       // attempt to keep AHB the divider close to 250, but not higher
-       for (adiv = 1; mhz / adiv > 250; adiv++)
-               ;
-
-       vf000 = memregl[0xf000>>2];
-       vf000 = (vf000 & ~0x3c0) | ((adiv - 1) << 6);
-       memregl[0xf000>>2] = vf000;
-       memregl[0xf004>>2] = vf004;
-       memregl[0xf07c>>2] |= 0x8000;
-       for (i = 0; (memregl[0xf07c>>2] & 0x8000) && i < 0x100000; i++)
-               ;
-
-       printf("clock set to %dMHz, AHB set to %dMHz\n", mhz, mhz / adiv);
-       return 0;
-}
-
-static int lcd_timings[8];
-static int ram_timings[7];
-static int dpc_clkdiv0;
-static int cpuclk;
-
-static const char lcd_t_help[] = "htotal,hswidth,hastart,haend,vtotal,vswidth,vastart,vaend";
-static const char ram_t_help[] = "CAS,tRC,tRAS,tWR,tMRD,tRP,tRCD";
-
-static const struct {
-       const char *name;
-       const char *help;
-       int (*parse)(const char *str, void *data);
-       int (*apply)(volatile unsigned short *memregs, void *data);
-       void *data;
-}
-all_params[] = {
-       { "lcd_timings", lcd_t_help, parse_lcd_timings, apply_lcd_timings, lcd_timings  },
-       { "ram_timings", ram_t_help, parse_ram_timings, apply_ram_timings, ram_timings  },
-       { "dpc_clkdiv0", "divider",  parse_decimal,     apply_dpc_clkdiv0, &dpc_clkdiv0 },
-       { "clkdiv0",     "divider",  parse_decimal,     apply_dpc_clkdiv0, &dpc_clkdiv0 }, /* alias */
-       { "cpuclk",      "MHZ",      parse_decimal,     apply_cpuclk,      &cpuclk      },
-};
-#define ALL_PARAM_COUNT (sizeof(all_params) / sizeof(all_params[0]))
-
-/*
- * set timings based on preformated string
- * returns 0 on success.
- */
-int pollux_set(volatile unsigned short *memregs, const char *str)
-{
-       int parsed_params[ALL_PARAM_COUNT];
-       int applied_params[ALL_PARAM_COUNT];
-       int applied_something = 0;
-       const char *p, *po;
-       int i, ret;
-
-       if (str == NULL)
-               return -1;
-
-       memset(parsed_params, 0, sizeof(parsed_params));
-       memset(applied_params, 0, sizeof(applied_params));
-
-       p = str;
-       while (1)
-       {
-again:
-               while (*p == ';' || *p == ' ')
-                       p++;
-               if (*p == 0)
-                       break;
-
-               for (i = 0; i < ALL_PARAM_COUNT; i++)
-               {
-                       int param_len = strlen(all_params[i].name);
-                       if (strncmp(p, all_params[i].name, param_len) == 0 && p[param_len] == '=')
-                       {
-                               p += param_len + 1;
-                               ret = all_params[i].parse(p, all_params[i].data);
-                               if (ret < 0) {
-                                       fprintf(stderr, "pollux_set parser: error at %-10s\n", p);
-                                       fprintf(stderr, "  valid format is: <%s>\n", all_params[i].help);
-                                       return -1;
-                               }
-                               parsed_params[i] = 1;
-                               p += ret;
-                               goto again;
-                       }
-               }
-
-               /* Unknown param. Attempt to be forward compatible and ignore it. */
-               for (po = p; *p != 0 && *p != ';'; p++)
-                       ;
-
-               fprintf(stderr, "unhandled param: ");
-               fwrite(po, 1, p - po, stderr);
-               fprintf(stderr, "\n");
-       }
-
-       /* validate and apply */
-       for (i = 0; i < ALL_PARAM_COUNT; i++)
-       {
-               if (!parsed_params[i])
-                       continue;
-
-               ret = all_params[i].apply(memregs, all_params[i].data);
-               if (ret < 0) {
-                       fprintf(stderr, "pollux_set: failed to apply %s (bad value?)\n",
-                               all_params[i].name);
-                       continue;
-               }
-
-               applied_something = 1;
-               applied_params[i] = 1;
-       }
-
-       if (applied_something)
-       {
-               int c;
-               printf("applied: ");
-               for (i = c = 0; i < ALL_PARAM_COUNT; i++)
-               {
-                       if (!applied_params[i])
-                               continue;
-                       if (c != 0)
-                               printf(", ");
-                       printf("%s", all_params[i].name);
-                       c++;
-               }
-               printf("\n");
-       }
-
-       return 0;
-}
-
-#ifdef BINARY
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-static void usage(const char *binary)
-{
-       int i;
-       printf("usage:\n%s <set_str[;set_str[;...]]>\n"
-               "set_str:\n", binary);
-       for (i = 0; i < ALL_PARAM_COUNT; i++)
-               printf("  %s=<%s>\n", all_params[i].name, all_params[i].help);
-}
-
-int main(int argc, char *argv[])
-{
-       volatile unsigned short *memregs;
-       int ret, memdev;
-
-       if (argc != 2) {
-               usage(argv[0]);
-               return 1;
-       }
-
-       memdev = open("/dev/mem", O_RDWR);
-       if (memdev == -1)
-       {
-               perror("open(/dev/mem) failed");
-               return 1;
-       }
-
-       memregs = mmap(0, 0x20000, PROT_READ|PROT_WRITE, MAP_SHARED, memdev, 0xc0000000);
-       if (memregs == MAP_FAILED)
-       {
-               perror("mmap(memregs) failed");
-               close(memdev);
-               return 1;
-       }
-
-       ret = pollux_set(memregs, argv[1]);
-
-       munmap((void *)memregs, 0x20000);
-       close(memdev);
-
-       return ret;
-}
-#endif
diff --git a/frontend/320240/skin/background.png b/frontend/320240/skin/background.png
deleted file mode 100644 (file)
index 0efdd18..0000000
Binary files a/frontend/320240/skin/background.png and /dev/null differ
diff --git a/frontend/320240/skin/font.png b/frontend/320240/skin/font.png
deleted file mode 100644 (file)
index c526a08..0000000
Binary files a/frontend/320240/skin/font.png and /dev/null differ
diff --git a/frontend/320240/skin/readme.txt b/frontend/320240/skin/readme.txt
deleted file mode 100644 (file)
index dd83963..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-The skin images can be customized, but there are several limitations:\r
-\r
-background.png - must be 320x240 image with 24bit RGB colors.\r
-font.png       - must be 128x160 8bit grayscale image.\r
-selector.png   - must be 8x10 8bit grayscale image.\r
-\r
-Font and selector colors can be changed by editing skin.txt.\r
-\r
diff --git a/frontend/320240/skin/selector.png b/frontend/320240/skin/selector.png
deleted file mode 100644 (file)
index 5062cc2..0000000
Binary files a/frontend/320240/skin/selector.png and /dev/null differ
diff --git a/frontend/320240/skin/skin.txt b/frontend/320240/skin/skin.txt
deleted file mode 100644 (file)
index 1d6979f..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-// html-style hex color codes, ex. ff0000 is red, 0000ff is blue, etc.\r
-text_color=ffffc0\r
-selection_color=808010\r
-\r
diff --git a/frontend/320240/ui_gp2x.h b/frontend/320240/ui_gp2x.h
deleted file mode 100644 (file)
index a9c4413..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef UI_FEATURES_H
-#define UI_FEATURES_H
-
-#define MENU_BIOS_PATH "pcsx_rearmed/bios/"
-#define MENU_SHOW_VARSCALER 0
-#define MENU_SHOW_VOUTMODE 0
-#define MENU_SHOW_SCALER2 1
-#define MENU_SHOW_NUBS_BTNS 0
-#define MENU_SHOW_VIBRATION 1
-#define MENU_SHOW_DEADZONE 1
-#define MENU_SHOW_MINIMIZE 0
-#define MENU_SHOW_FULLSCREEN 0
-#define MENU_SHOW_VOLUME 1
-
-#endif // UI_FEATURES_H
diff --git a/frontend/3ds/3ds_utils.h b/frontend/3ds/3ds_utils.h
new file mode 100644 (file)
index 0000000..9211a9e
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef _3DS_UTILS_H
+#define _3DS_UTILS_H
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <3ds.h>
+
+#ifdef OS_HEAP_AREA_BEGIN // defined in libctru 2.0+
+#define USE_CTRULIB_2 1
+#endif
+
+#define MEMOP_PROT      6
+#define MEMOP_MAP       4
+#define MEMOP_UNMAP     5
+
+#define DEBUG_HOLD() do{printf("%s@%s:%d.\n",__FUNCTION__, __FILE__, __LINE__);fflush(stdout);wait_for_input();}while(0)
+
+void wait_for_input(void);
+
+extern __attribute__((weak)) int  __ctr_svchax;
+
+static bool has_rosalina;
+
+static void check_rosalina() {
+  int64_t version;
+  uint32_t major;
+
+  has_rosalina = false;
+
+  if (!svcGetSystemInfo(&version, 0x10000, 0)) {
+     major = GET_VERSION_MAJOR(version);
+
+     if (major >= 8)
+       has_rosalina = true;
+  }
+}
+
+void ctr_clear_cache(void);
+
+typedef int32_t (*ctr_callback_type)(void);
+
+static inline void ctr_invalidate_ICache_kernel(void)
+{
+   __asm__ volatile(
+      "cpsid aif\n\t"
+      "mov r0, #0\n\t"
+      "mcr p15, 0, r0, c7, c5, 0\n\t");
+}
+
+static inline void ctr_flush_DCache_kernel(void)
+{
+   __asm__ volatile(
+      "cpsid aif\n\t"
+      "mov r0, #0\n\t"
+      "mcr p15, 0, r0, c7, c10, 0\n\t");
+}
+
+static inline void ctr_invalidate_ICache(void)
+{
+   svcBackdoor((ctr_callback_type)ctr_invalidate_ICache_kernel);
+}
+
+static inline void ctr_flush_DCache(void)
+{
+   svcBackdoor((ctr_callback_type)ctr_flush_DCache_kernel);
+}
+
+static inline void ctr_flush_invalidate_cache(void)
+{
+   if (has_rosalina) {
+      ctr_clear_cache();
+   } else {
+      ctr_flush_DCache();
+      ctr_invalidate_ICache();
+   }
+}
+
+#endif // _3DS_UTILS_H
diff --git a/frontend/3ds/pthread.h b/frontend/3ds/pthread.h
new file mode 100644 (file)
index 0000000..76f1681
--- /dev/null
@@ -0,0 +1,321 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (gx_pthread.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _CTR_PTHREAD_WRAP_CTR_
+#define _CTR_PTHREAD_WRAP_CTR_
+
+#include "3ds_utils.h"
+
+#include <time.h>
+#include <errno.h>
+
+#define STACKSIZE (4 * 1024)
+#define FALSE 0
+
+#ifndef PTHREAD_SCOPE_PROCESS
+/* An earlier version of devkitARM does not define the pthread types. Can remove in r54+. */
+
+typedef Thread     pthread_t;
+typedef LightLock  pthread_mutex_t;
+typedef void*      pthread_mutexattr_t;
+typedef int        pthread_attr_t;
+typedef LightEvent pthread_cond_t;
+typedef int        pthread_condattr_t;
+#endif
+
+#ifndef USE_CTRULIB_2
+/* Backported CondVar API from libctru 2.0, and under its license:
+   https://github.com/devkitPro/libctru
+   Slightly modified for compatibility with older libctru. */
+
+typedef s32 CondVar;
+
+static inline Result syncArbitrateAddress(s32* addr, ArbitrationType type, s32 value)
+{
+   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, 0);
+}
+
+static inline Result syncArbitrateAddressWithTimeout(s32* addr, ArbitrationType type, s32 value, s64 timeout_ns)
+{
+   return svcArbitrateAddress(__sync_get_arbiter(), (u32)addr, type, value, timeout_ns);
+}
+
+static inline void __dmb(void)
+{
+       __asm__ __volatile__("mcr p15, 0, %[val], c7, c10, 5" :: [val] "r" (0) : "memory");
+}
+
+static inline void CondVar_BeginWait(CondVar* cv, LightLock* lock)
+{
+       s32 val;
+       do
+               val = __ldrex(cv) - 1;
+       while (__strex(cv, val));
+       LightLock_Unlock(lock);
+}
+
+static inline bool CondVar_EndWait(CondVar* cv, s32 num_threads)
+{
+       bool hasWaiters;
+       s32 val;
+
+       do {
+               val = __ldrex(cv);
+               hasWaiters = val < 0;
+               if (hasWaiters)
+               {
+                       if (num_threads < 0)
+                               val = 0;
+                       else if (val <= -num_threads)
+                               val += num_threads;
+                       else
+                               val = 0;
+               }
+       } while (__strex(cv, val));
+
+       return hasWaiters;
+}
+
+static inline void CondVar_Init(CondVar* cv)
+{
+       *cv = 0;
+}
+
+static inline void CondVar_Wait(CondVar* cv, LightLock* lock)
+{
+       CondVar_BeginWait(cv, lock);
+       syncArbitrateAddress(cv, ARBITRATION_WAIT_IF_LESS_THAN, 0);
+       LightLock_Lock(lock);
+}
+
+static inline int CondVar_WaitTimeout(CondVar* cv, LightLock* lock, s64 timeout_ns)
+{
+       CondVar_BeginWait(cv, lock);
+
+       bool timedOut = false;
+       Result rc = syncArbitrateAddressWithTimeout(cv, ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT, 0, timeout_ns);
+       if (R_DESCRIPTION(rc) == RD_TIMEOUT)
+       {
+               timedOut = CondVar_EndWait(cv, 1);
+               __dmb();
+       }
+
+       LightLock_Lock(lock);
+       return timedOut;
+}
+
+static inline void CondVar_WakeUp(CondVar* cv, s32 num_threads)
+{
+       __dmb();
+       if (CondVar_EndWait(cv, num_threads))
+               syncArbitrateAddress(cv, ARBITRATION_SIGNAL, num_threads);
+       else
+               __dmb();
+}
+
+static inline void CondVar_Signal(CondVar* cv)
+{
+       CondVar_WakeUp(cv, 1);
+}
+
+static inline void CondVar_Broadcast(CondVar* cv)
+{
+       CondVar_WakeUp(cv, ARBITRATION_SIGNAL_ALL);
+}
+/* End libctru 2.0 backport */
+#endif
+
+/* libctru threads return void but pthreads return void pointer */
+static bool mutex_inited = false;
+static LightLock safe_double_thread_launch;
+static void *(*start_routine_jump)(void*);
+
+static void ctr_thread_launcher(void* data)
+{
+       void *(*start_routine_jump_safe)(void*) = start_routine_jump;
+       LightLock_Unlock(&safe_double_thread_launch);
+       start_routine_jump_safe(data);
+}
+
+static inline int pthread_create(pthread_t *thread,
+      const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
+{
+   s32 prio = 0;
+   Thread new_ctr_thread;
+   int procnum = -2; // use default cpu
+   bool isNew3DS;
+
+   APT_CheckNew3DS(&isNew3DS);
+
+   if (isNew3DS)
+      procnum = 2;
+
+   if (!mutex_inited)
+   {
+      LightLock_Init(&safe_double_thread_launch);
+      mutex_inited = true;
+   }
+
+   /*Must wait if attempting to launch 2 threads at once to prevent corruption of function pointer*/
+   while (LightLock_TryLock(&safe_double_thread_launch) != 0);
+
+   svcGetThreadPriority(&prio, CUR_THREAD_HANDLE);
+
+   start_routine_jump = start_routine;
+   new_ctr_thread     = threadCreate(ctr_thread_launcher, arg, STACKSIZE, prio - 1, procnum, FALSE);
+
+   if (!new_ctr_thread)
+   {
+      LightLock_Unlock(&safe_double_thread_launch);
+      return EAGAIN;
+   }
+
+   *thread = (pthread_t)new_ctr_thread;
+   return 0;
+}
+
+static inline pthread_t pthread_self(void)
+{
+   return (pthread_t)threadGetCurrent();
+}
+
+static inline int pthread_mutex_init(pthread_mutex_t *mutex,
+      const pthread_mutexattr_t *attr)
+{
+   LightLock_Init((LightLock *)mutex);
+   return 0;
+}
+
+static inline int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+   /*Nothing to destroy*/
+   return 0;
+}
+
+static inline int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+   LightLock_Lock((LightLock *)mutex);
+   return 0;
+}
+
+static inline int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+   LightLock_Unlock((LightLock *)mutex);
+   return 0;
+}
+
+static inline void pthread_exit(void *retval)
+{
+   /*Yes the pointer to int cast is not ideal*/
+   /*threadExit((int)retval);*/
+   (void)retval;
+
+   threadExit(0);
+}
+
+static inline int pthread_detach(pthread_t thread)
+{
+   threadDetach((Thread)thread);
+   return 0;
+}
+
+static inline int pthread_join(pthread_t thread, void **retval)
+{
+   /*retval is ignored*/
+   if(threadJoin((Thread)thread, INT64_MAX))
+      return -1;
+
+   threadFree((Thread)thread);
+
+   return 0;
+}
+
+static inline int pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+   return LightLock_TryLock((LightLock *)mutex);
+}
+
+static inline int pthread_cond_wait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex)
+{
+   CondVar_Wait((CondVar *)cond, (LightLock *)mutex);
+   return 0;
+}
+
+static inline int pthread_cond_timedwait(pthread_cond_t *cond,
+      pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+   struct timespec now = {0};
+   /* Missing clock_gettime*/
+   struct timeval tm;
+   int retval = 0;
+
+   gettimeofday(&tm, NULL);
+   now.tv_sec = tm.tv_sec;
+   now.tv_nsec = tm.tv_usec * 1000;
+   s64 timeout = (abstime->tv_sec - now.tv_sec) * 1000000000 + (abstime->tv_nsec - now.tv_nsec);
+
+   if (timeout < 0)
+   {
+      retval = ETIMEDOUT;
+   }
+   else if (CondVar_WaitTimeout((CondVar *)cond, (LightLock *)mutex, timeout))
+   {
+      retval = ETIMEDOUT;
+   }
+
+   return retval;
+}
+
+static inline int pthread_cond_init(pthread_cond_t *cond,
+      const pthread_condattr_t *attr)
+{
+   CondVar_Init((CondVar *)cond);
+   return 0;
+}
+
+static inline int pthread_cond_signal(pthread_cond_t *cond)
+{
+   CondVar_Signal((CondVar *)cond);
+   return 0;
+}
+
+static inline int pthread_cond_broadcast(pthread_cond_t *cond)
+{
+   CondVar_Broadcast((CondVar *)cond);
+   return 0;
+}
+
+static inline int pthread_cond_destroy(pthread_cond_t *cond)
+{
+   /*Nothing to destroy*/
+   return 0;
+}
+
+static inline int pthread_equal(pthread_t t1, pthread_t t2)
+{
+       if (threadGetHandle((Thread)t1) == threadGetHandle((Thread)t2))
+               return 1;
+       return 0;
+}
+
+#endif
diff --git a/frontend/3ds/semaphore.h b/frontend/3ds/semaphore.h
new file mode 100644 (file)
index 0000000..6eddd98
--- /dev/null
@@ -0,0 +1,35 @@
+
+#ifndef _3DS_SEMAPHORE_WRAP__
+#define _3DS_SEMAPHORE_WRAP__
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "3ds_utils.h"
+
+typedef uint32_t sem_t;
+
+static inline int sem_init(sem_t *sem, int pshared, unsigned int value)
+{
+   return svcCreateSemaphore(sem, value, INT32_MAX);
+}
+
+static inline int sem_post(sem_t *sem)
+{
+   int32_t count;
+   return svcReleaseSemaphore(&count, *sem, 1);
+}
+
+static inline int sem_wait(sem_t *sem)
+{
+   return svcWaitSynchronization(*sem, INT64_MAX);
+}
+
+static inline int sem_destroy(sem_t *sem)
+{
+   return svcCloseHandle(*sem);
+}
+
+#endif //_3DS_SEMAPHORE_WRAP__
+
diff --git a/frontend/3ds/sys/mman.h b/frontend/3ds/sys/mman.h
new file mode 100644 (file)
index 0000000..61dde6c
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef MMAN_H
+#define MMAN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <malloc.h>
+
+#include "3ds_utils.h"
+
+#define PROT_READ       0b001
+#define PROT_WRITE      0b010
+#define PROT_EXEC       0b100
+#define MAP_PRIVATE     2
+#define MAP_FIXED       0x10
+#define MAP_ANONYMOUS   0x20
+
+#define MAP_FAILED      ((void *)-1)
+
+static void* dynarec_cache = NULL;
+static void* dynarec_cache_mapping = NULL;
+
+static inline void* mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+   (void)fd;
+   (void)offset;
+
+   void* addr_out;
+
+   if((prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) &&
+      (flags == (MAP_PRIVATE | MAP_ANONYMOUS)))
+   {
+      if(__ctr_svchax)
+      {
+         /* this hack works only for pcsx_rearmed */
+         uint32_t currentHandle;
+
+         if(!dynarec_cache)
+            dynarec_cache = memalign(0x1000, len);
+
+         svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+         svcControlProcessMemory(currentHandle, addr, dynarec_cache,
+                                 len, MEMOP_MAP, prot);
+         svcCloseHandle(currentHandle);
+         dynarec_cache_mapping = addr;
+         return addr;
+      }
+      else
+      {
+         printf("tried to mmap RWX pages without svcControlProcessMemory access !\n");
+         return MAP_FAILED;
+      }
+
+   }
+
+   addr_out = malloc(len);
+   if(!addr_out)
+      return MAP_FAILED;
+
+   return addr_out;
+}
+
+static inline int mprotect(void *addr, size_t len, int prot)
+{
+   if(__ctr_svchax)
+   {
+      uint32_t currentHandle;
+      svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+      svcControlProcessMemory(currentHandle, addr, NULL,
+                              len, MEMOP_PROT, prot);
+      svcCloseHandle(currentHandle);
+      return 0;
+   }
+
+   printf("mprotect called without svcControlProcessMemory access !\n");
+   return -1;
+}
+
+static inline int munmap(void *addr, size_t len)
+{
+   if((addr == dynarec_cache_mapping) && __ctr_svchax)
+   {
+      uint32_t currentHandle;
+      svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+      svcControlProcessMemory(currentHandle,
+                              dynarec_cache, dynarec_cache_mapping,
+                              len, MEMOP_UNMAP, 0b111);
+      svcCloseHandle(currentHandle);
+      dynarec_cache_mapping = NULL;
+
+   }
+   else
+      free(addr);
+
+   return 0;
+}
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // MMAN_H
+
diff --git a/frontend/3ds/utils.S b/frontend/3ds/utils.S
new file mode 100644 (file)
index 0000000..c8df651
--- /dev/null
@@ -0,0 +1,25 @@
+  .text
+  .arm
+  .balign 4
+
+  .func ctr_clear_cache_kernel
+ctr_clear_cache_kernel:
+  cpsid aif
+  mov r0, #0
+  mcr p15, 0, r0, c7, c10, 0    @ Clean entire data cache
+  mcr p15, 0, r0, c7, c10, 5    @ Data Memory Barrier
+  mcr p15, 0, r0, c7, c5, 0     @ Invalidate entire instruction cache / Flush BTB
+  mcr p15, 0, r0, c7, c10, 4    @ Data Sync Barrier
+  bx lr
+  .endfunc
+
+  @@ Clear the entire data cache / invalidate the instruction cache. Uses
+  @@ Rosalina svcCustomBackdoor to avoid svcBackdoor stack corruption
+  @@ during interrupts.
+  .global ctr_clear_cache
+  .func ctr_clear_cache
+ctr_clear_cache:
+  ldr r0, =ctr_clear_cache_kernel
+  svc 0x80                      @ svcCustomBackdoor
+  bx lr
+  .endfunc
diff --git a/frontend/3ds/zconf.h b/frontend/3ds/zconf.h
new file mode 100644 (file)
index 0000000..996fff2
--- /dev/null
@@ -0,0 +1,511 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
+#  define Z_PREFIX_SET
+
+/* all linked symbols */
+#  define _dist_code            z__dist_code
+#  define _length_code          z__length_code
+#  define _tr_align             z__tr_align
+#  define _tr_flush_bits        z__tr_flush_bits
+#  define _tr_flush_block       z__tr_flush_block
+#  define _tr_init              z__tr_init
+#  define _tr_stored_block      z__tr_stored_block
+#  define _tr_tally             z__tr_tally
+#  define adler32               z_adler32
+#  define adler32_combine       z_adler32_combine
+#  define adler32_combine64     z_adler32_combine64
+#  ifndef Z_SOLO
+#    define compress              z_compress
+#    define compress2             z_compress2
+#    define compressBound         z_compressBound
+#  endif
+#  define crc32                 z_crc32
+#  define crc32_combine         z_crc32_combine
+#  define crc32_combine64       z_crc32_combine64
+#  define deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateInit_          z_deflateInit_
+#  define deflateParams         z_deflateParams
+#  define deflatePending        z_deflatePending
+#  define deflatePrime          z_deflatePrime
+#  define deflateReset          z_deflateReset
+#  define deflateResetKeep      z_deflateResetKeep
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateSetHeader      z_deflateSetHeader
+#  define deflateTune           z_deflateTune
+#  define deflate_copyright     z_deflate_copyright
+#  define get_crc_table         z_get_crc_table
+#  ifndef Z_SOLO
+#    define gz_error              z_gz_error
+#    define gz_intmax             z_gz_intmax
+#    define gz_strwinerror        z_gz_strwinerror
+#    define gzbuffer              z_gzbuffer
+#    define gzclearerr            z_gzclearerr
+#    define gzclose               z_gzclose
+#    define gzclose_r             z_gzclose_r
+#    define gzclose_w             z_gzclose_w
+#    define gzdirect              z_gzdirect
+#    define gzdopen               z_gzdopen
+#    define gzeof                 z_gzeof
+#    define gzerror               z_gzerror
+#    define gzflush               z_gzflush
+#    define gzgetc                z_gzgetc
+#    define gzgetc_               z_gzgetc_
+#    define gzgets                z_gzgets
+#    define gzoffset              z_gzoffset
+#    define gzoffset64            z_gzoffset64
+#    define gzopen                z_gzopen
+#    define gzopen64              z_gzopen64
+#    ifdef _WIN32
+#      define gzopen_w              z_gzopen_w
+#    endif
+#    define gzprintf              z_gzprintf
+#    define gzvprintf             z_gzvprintf
+#    define gzputc                z_gzputc
+#    define gzputs                z_gzputs
+#    define gzread                z_gzread
+#    define gzrewind              z_gzrewind
+#    define gzseek                z_gzseek
+#    define gzseek64              z_gzseek64
+#    define gzsetparams           z_gzsetparams
+#    define gztell                z_gztell
+#    define gztell64              z_gztell64
+#    define gzungetc              z_gzungetc
+#    define gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetHeader      z_inflateGetHeader
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateInit_          z_inflateInit_
+#  define inflateMark           z_inflateMark
+#  define inflatePrime          z_inflatePrime
+#  define inflateReset          z_inflateReset
+#  define inflateReset2         z_inflateReset2
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateResetKeep      z_inflateResetKeep
+#  define inflate_copyright     z_inflate_copyright
+#  define inflate_fast          z_inflate_fast
+#  define inflate_table         z_inflate_table
+#  ifndef Z_SOLO
+#    define uncompress            z_uncompress
+#  endif
+#  define zError                z_zError
+#  ifndef Z_SOLO
+#    define zcalloc               z_zcalloc
+#    define zcfree                z_zcfree
+#  endif
+#  define zlibCompileFlags      z_zlibCompileFlags
+#  define zlibVersion           z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+#  define Byte                  z_Byte
+#  define Bytef                 z_Bytef
+#  define alloc_func            z_alloc_func
+#  define charf                 z_charf
+#  define free_func             z_free_func
+#  ifndef Z_SOLO
+#    define gzFile                z_gzFile
+#  endif
+#  define gz_header             z_gz_header
+#  define gz_headerp            z_gz_headerp
+#  define in_func               z_in_func
+#  define intf                  z_intf
+#  define out_func              z_out_func
+#  define uInt                  z_uInt
+#  define uIntf                 z_uIntf
+#  define uLong                 z_uLong
+#  define uLongf                z_uLongf
+#  define voidp                 z_voidp
+#  define voidpc                z_voidpc
+#  define voidpf                z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+#  define gz_header_s           z_gz_header_s
+#  define internal_state        z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+#  define z_const const
+#else
+#  define z_const
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#    define Z_ARG(args)  args
+#  else
+#    define Z_ARG(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+#  include <limits.h>
+#  if (UINT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned
+#  elif (ULONG_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned long
+#  elif (USHRT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned short
+#  endif
+#endif
+
+#ifdef Z_U4
+   typedef Z_U4 z_crc_t;
+#else
+   typedef unsigned long z_crc_t;
+#endif
+
+#if 1    /* was set to #if 1 by ./configure */
+#  define Z_HAVE_UNISTD_H
+#endif
+
+#if 1    /* was set to #if 1 by ./configure */
+#  define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+#  ifndef Z_SOLO
+#    include <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* for wchar_t */
+#  endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+#  undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* for off_t */
+#    endif
+#    ifndef z_off_t
+#      define z_off_t off_t
+#    endif
+#  endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+#  define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+#  define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+#  define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+#  define z_off64_t off64_t
+#else
+#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+#    define z_off64_t __int64
+#  else
+#    define z_off64_t z_off_t
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+  #pragma map(deflateInit_,"DEIN")
+  #pragma map(deflateInit2_,"DEIN2")
+  #pragma map(deflateEnd,"DEEND")
+  #pragma map(deflateBound,"DEBND")
+  #pragma map(inflateInit_,"ININ")
+  #pragma map(inflateInit2_,"ININ2")
+  #pragma map(inflateEnd,"INEND")
+  #pragma map(inflateSync,"INSY")
+  #pragma map(inflateSetDictionary,"INSEDI")
+  #pragma map(compressBound,"CMBND")
+  #pragma map(inflate_table,"INTABL")
+  #pragma map(inflate_fast,"INFA")
+  #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/frontend/3ds/zlib.h b/frontend/3ds/zlib.h
new file mode 100644 (file)
index 0000000..3e0c767
--- /dev/null
@@ -0,0 +1,1768 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.8, April 28th, 2013
+
+  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.8"
+#define ZLIB_VERNUM 0x1280
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 8
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+    The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed data.
+  This version of the library supports only one compression method (deflation)
+  but other algorithms will be added later and will have the same stream
+  interface.
+
+    Compression can be done in a single step if the buffers are large enough,
+  or can be done by repeated calls of the compression function.  In the latter
+  case, the application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+    The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+    The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+    This library can optionally read and write gzip streams in memory as well.
+
+    The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+    The library does not install any signal handler.  The decoder checks
+  the consistency of the compressed data, so the library should never crash
+  even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    z_const Bytef *next_in;     /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total number of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total number of bytes output so far */
+
+    z_const char *msg;  /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+     The application must update next_in and avail_in when avail_in has dropped
+   to zero.  It must update next_out and avail_out when avail_out has dropped
+   to zero.  The application must initialize zalloc, zfree and opaque before
+   calling the init function.  All other fields are set by the compression
+   library and must not be updated by the application.
+
+     The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree.  This can be useful for custom
+   memory management.  The compression library attaches no meaning to the
+   opaque value.
+
+     zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+     On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this if
+   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
+   returned by zalloc for objects of exactly 65536 bytes *must* have their
+   offset normalized to zero.  The default allocation function provided by this
+   library ensures this (see zutil.c).  To reduce memory requirements and avoid
+   any allocation of 64K objects, at the expense of compression ratio, compile
+   the library with -DMAX_WBITS=14 (see zconf.h).
+
+     The fields total_in and total_out can be used for statistics or progress
+   reports.  After compression, total_in holds the total size of the
+   uncompressed data and may be saved for use in the decompressor (particularly
+   if the decompressor wants to decompress everything in a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+#define Z_TREES         6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is not
+   compatible with the zlib.h header file used by the application.  This check
+   is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression.  The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+   allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at all
+   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
+   requests a default compromise between speed and compression (currently
+   equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if level is not a valid compression level, or
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
+   if there is no error message.  deflateInit does not perform any compression:
+   this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows.  deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).  Some
+    output may be provided even if flush is not set.
+
+    Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating avail_in or avail_out accordingly; avail_out should
+  never be zero before the call.  The application can consume the compressed
+  output when it wants, for example when the output buffer is full (avail_out
+  == 0), or after each call of deflate().  If deflate returns Z_OK and with
+  zero avail_out, it must be called again after making room in the output
+  buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumulate before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far.  (In
+  particular avail_in is zero after the call if enough output space has been
+  provided before the call.) Flushing may degrade compression for some
+  compression algorithms and so it should be used only when necessary.  This
+  completes the current deflate block and follows it with an empty stored block
+  that is three bits plus filler bits to the next byte, followed by four bytes
+  (00 00 ff ff).
+
+    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+  output buffer, but the output is not aligned to a byte boundary.  All of the
+  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+  This completes the current deflate block and follows it with an empty fixed
+  codes block that is 10 bits long.  This assures that enough bytes are output
+  in order for the decompressor to finish the block before the empty fixed code
+  block.
+
+    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+  seven bits of the current block are held to be written as the next byte after
+  the next deflate block is completed.  In this case, the decompressor may not
+  be provided enough bits at this point in order to complete decompression of
+  the data provided so far to the compressor.  It may need to wait for the next
+  block to be emitted.  This is for advanced applications that need to control
+  the emission of deflate blocks.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there was
+  enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error.  After
+  deflate has returned Z_STREAM_END, the only possible operations on the stream
+  are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step.  In this case, avail_out must be at least the
+  value returned by deflateBound (see below).  Then deflate is guaranteed to
+  return Z_STREAM_END.  If not enough output space is provided, deflate will
+  not return Z_STREAM_END, and it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
+  binary.  This field is only for information purposes and does not affect the
+  compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded).  In the error case, msg
+   may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression.  The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
+   exact value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit() does not process any header information -- that is deferred
+   until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows.  inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing will
+    resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there is
+    no more input data or no more space in the output buffer (see below about
+    the flush parameter).
+
+    Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating the next_* and avail_* values accordingly.  The
+  application can consume the uncompressed output when it wants, for example
+  when the output buffer is full (avail_out == 0), or after each call of
+  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
+  called again after making room in the output buffer because there might be
+  more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer.  Z_BLOCK requests that inflate()
+  stop if and when it gets to the next deflate block boundary.  When decoding
+  the zlib or gzip format, this will cause inflate() to return immediately
+  after the header and before the first block.  When doing a raw inflate,
+  inflate() will go ahead and process the first block, and will return when it
+  gets to the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64 if
+  inflate() is currently decoding the last block in the deflate stream, plus
+  128 if inflate() returned immediately after decoding an end-of-block code or
+  decoding the complete header up to just before the first byte of the deflate
+  stream.  The end-of-block will not be indicated until all of the uncompressed
+  data from that block has been written to strm->next_out.  The number of
+  unused bits may in general be greater than seven, except when bit 7 of
+  data_type is set, in which case the number of unused bits will be less than
+  eight.  data_type is set as noted here every time inflate() returns for all
+  flush options, and so can be used to determine the amount of currently
+  consumed input in bits.
+
+    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+  end of each deflate block header is reached, before any actual data in that
+  block is decoded.  This allows the caller to determine the length of the
+  deflate block header for later use in random access within a deflate block.
+  256 is added to the value of strm->data_type when inflate() returns
+  immediately after reaching the end of the deflate block header.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error.  However if all decompression is to be performed in a single step (a
+  single call of inflate), the parameter flush should be set to Z_FINISH.  In
+  this case all pending input is processed and all pending output is flushed;
+  avail_out must be large enough to hold all of the uncompressed data for the
+  operation to complete.  (The size of the uncompressed data may have been
+  saved by the compressor for this purpose.) The use of Z_FINISH is not
+  required to perform an inflation in one step.  However it may be used to
+  inform inflate that a faster approach can be used for the single inflate()
+  call.  Z_FINISH also informs inflate to not maintain a sliding window if the
+  stream completes, which reduces inflate's memory footprint.  If the stream
+  does not complete, either because not all of the stream is provided or not
+  enough output space is provided, then a sliding window will be allocated and
+  inflate() can be called again to continue the operation as if Z_NO_FLUSH had
+  been used.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call.  So the effects of the flush parameter in this implementation are
+  on the return value of inflate() as noted below, when inflate() returns early
+  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
+  memory for a sliding window when Z_FINISH is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the Adler-32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below.  At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically, if requested when
+  initializing with inflateInit2().  Any information contained in the gzip
+  header is not retained, so applications that need that information should
+  instead use raw inflate, see inflateInit2() below, or inflateBack() and
+  perform their own processing of the gzip header and trailer.  When processing
+  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
+  producted so far.  The CRC-32 is checked against the gzip trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing.  If Z_DATA_ERROR is returned, the application may
+  then call inflateSync() to look for a good compression block if a partial
+  recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent.  In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options.  The
+   fields next_in, zalloc, zfree and opaque must be initialized before by the
+   caller.
+
+     The method parameter is the compression method.  It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library.  Larger values of this parameter result in better
+   compression at the expense of memory usage.  The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
+   determines the window size.  deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding.  Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper.  The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero), no
+   header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state.  memLevel=1 uses minimum memory but is
+   slow and reduces compression ratio; memLevel=9 uses maximum memory for
+   optimal speed.  The default value is 8.  See zconf.h for total memory usage
+   as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm.  Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding).  Filtered data consists mostly of small values with a somewhat
+   random distribution.  In this case, the compression algorithm is tuned to
+   compress them better.  The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
+   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
+   strategy parameter only affects the compression ratio but not the
+   correctness of the compressed output even if it is not set appropriately.
+   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+   decoder for special applications.
+
+     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
+   set to null if there is no error message.  deflateInit2 does not perform any
+   compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output.  When using the zlib format, this
+   function must be called immediately after deflateInit, deflateInit2 or
+   deflateReset, and before any call of deflate.  When doing raw deflate, this
+   function must be called either before any call of deflate, or immediately
+   after the completion of a deflate block, i.e. after all input has been
+   consumed and all output has been delivered when using any of the flush
+   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
+   compressor and decompressor must use exactly the same dictionary (see
+   inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary.  Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size
+   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
+   useful should be put at the end of the dictionary, not at the front.  In
+   addition, the current implementation of deflate will use at most the window
+   size minus 262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor.  (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if not at a block boundary for raw deflate).  deflateSetDictionary does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter.  The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and can
+   consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.  The
+   stream will keep the same compression level and any other attributes that
+   may have been set by deflateInit2.
+
+     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different strategy.
+   If the compression level is changed, the input available so far is
+   compressed with the old level (and may be flushed); the new level will take
+   effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to be
+   compressed and flushed.  In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+   strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit() or
+   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
+   to allocate an output buffer for deflation in a single pass, and so would be
+   called before deflate().  If that first deflate() call is provided the
+   sourceLen input bytes, an output buffer allocated to the size returned by
+   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
+   to return Z_STREAM_END.  Note that it is possible for the compressed size to
+   be larger than the value returned by deflateBound() if flush options other
+   than Z_FINISH or Z_NO_FLUSH are used.
+*/
+
+ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
+                                       unsigned *pending,
+                                       int *bits));
+/*
+     deflatePending() returns the number of bytes and bits of output that have
+   been generated, but not yet provided in the available output.  The bytes not
+   provided would be due to the available output space having being consumed.
+   The number of bits of output not provided are between 0 and 7, where they
+   await more bits to join them in order to fill out a full byte.  If pending
+   or bits are Z_NULL, then those values are not set.
+
+     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+ */
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+   is that this function is used to start off the deflate output with the bits
+   leftover from a previous deflate stream when appending to it.  As such, this
+   function can only be used for raw deflate, and must be used before the first
+   deflate() call after a deflateInit2() or deflateReset().  bits must be less
+   than or equal to 16, and that many of the least significant bits of value
+   will be inserted in the output.
+
+     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
+   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+     If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter.  The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library.  The default value is 15 if inflateInit is used
+   instead.  windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used.  If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be zero to request that inflate use the window size in
+   the zlib header of the compressed stream.
+
+     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
+   determines the window size.  inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream.  This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values.  If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is.  Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding.  Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
+   crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit2 does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit2() does not process any header information -- that is
+   deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence.  This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called at any
+   time to set the dictionary.  If the provided dictionary is smaller than the
+   window and there is already data in the window, then the provided dictionary
+   will amend what's there.  The application must insure that the dictionary
+   that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value).  inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
+                                             Bytef *dictionary,
+                                             uInt  *dictLength));
+/*
+     Returns the sliding dictionary being maintained by inflate.  dictLength is
+   set to the number of bytes in the dictionary, and that many bytes are copied
+   to dictionary.  dictionary must have enough space, where 32768 bytes is
+   always enough.  If inflateGetDictionary() is called with dictionary equal to
+   Z_NULL, then only the dictionary length is returned, and nothing is copied.
+   Similary, if dictLength is Z_NULL, then it is not set.
+
+     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
+   stream state is inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+     Skips invalid compressed data until a possible full flush point (see above
+   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
+   available input is skipped.  No output is provided.
+
+     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
+   All full flush points have this pattern, but not all occurrences of this
+   pattern are full flush points.
+
+     inflateSync returns Z_OK if a possible full flush point has been found,
+   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
+   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
+   In the success case, the application may save the current current value of
+   total_in which indicates where valid compressed data was found.  In the
+   error case, the application may repeatedly call inflateSync, providing more
+   input each time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.  The
+   stream will keep attributes that may have been set by inflateInit2.
+
+     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+                                      int windowBits));
+/*
+     This function is the same as inflateReset, but it also permits changing
+   the wrap and window size requests.  The windowBits parameter is interpreted
+   the same as it is for inflateInit2.
+
+     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+   the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+   that this function is used to start inflating at a bit position in the
+   middle of a byte.  The provided bits will be used before any bytes are used
+   from next_in.  This function should only be used with raw inflate, and
+   should be used before the first inflate() call after inflateInit2() or
+   inflateReset().  bits must be less than or equal to 16, and that many of the
+   least significant bits of value will be inserted in the input.
+
+     If bits is negative, then the input stream bit buffer is emptied.  Then
+   inflatePrime() can be called again to put bits in the buffer.  This is used
+   to clear out bits leftover after feeding inflate a block description prior
+   to feeding inflate codes.
+
+     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+     This function returns two values, one in the lower 16 bits of the return
+   value, and the other in the remaining upper bits, obtained by shifting the
+   return value down 16 bits.  If the upper value is -1 and the lower value is
+   zero, then inflate() is currently decoding information outside of a block.
+   If the upper value is -1 and the lower value is non-zero, then inflate is in
+   the middle of a stored block, with the lower value equaling the number of
+   bytes from the input remaining to copy.  If the upper value is not -1, then
+   it is the number of bits back from the current bit position in the input of
+   the code (literal or length/distance pair) currently being processed.  In
+   that case the lower value is the number of bytes already emitted for that
+   code.
+
+     A code is being processed if inflate is waiting for more input to complete
+   decoding of the code, or if it has completed decoding but is waiting for
+   more output space to write the literal or match data.
+
+     inflateMark() is used to mark locations in the input data for random
+   access, which may be at bit positions, and to note those cases where the
+   output of a code may span boundaries of random access blocks.  The current
+   location in the input stream can be determined from avail_in and data_type
+   as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+     inflateMark returns the value noted above or -1 << 16 if the provided
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
+   used to force inflate() to return immediately after header processing is
+   complete and before any actual data is decompressed.
+
+     The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When any
+   of extra, name, or comment are not Z_NULL and the respective field is not
+   present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+     If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
+   allocated, or Z_VERSION_ERROR if the version of the library does not match
+   the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *,
+                                z_const unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is potentially more efficient than
+   inflate() for file i/o applications, in that it avoids copying between the
+   output and the sliding window by simply making the window itself the output
+   buffer.  inflate() can be faster on modern CPUs when used with large
+   buffers.  inflateBack() trusts the application to not change the output
+   buffer passed by the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free the
+   allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects only
+   the raw deflate stream to decompress.  This is different from the normal
+   behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+   in the deflate stream (in which case strm->msg is set to indicate the nature
+   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+   In the case of Z_BUF_ERROR, an input or output error can be distinguished
+   using strm->next_in which will be Z_NULL only if in() returned an error.  If
+   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+   non-zero.  (in() will always be called before out(), so strm->next_in is
+   assured to be defined if out() returns non-zero.) Note that inflateBack()
+   cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+#ifndef Z_SOLO
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the basic
+   stream-oriented functions.  To simplify the interface, some default options
+   are assumed (compression level and memory usage, standard memory allocation
+   functions).  The source code of these utility functions can be modified if
+   you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer.  The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer.  Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before a
+   compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be large enough to hold the entire
+   uncompressed data.  (The size of the uncompressed data must have been saved
+   previously by the compressor and transmitted to the decompressor by some
+   mechanism outside the scope of this compression library.) Upon exit, destLen
+   is the actual size of the uncompressed buffer.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
+   the case where there is not enough room, uncompress() will fill the output
+   buffer with the uncompressed data up to that point.
+*/
+
+                        /* gzip file access functions */
+
+/*
+     This library supports reading and writing files in gzip (.gz) format with
+   an interface similar to that of stdio, using the functions that start with
+   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
+   wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
+   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+   for fixed code compression as in "wb9F".  (See the description of
+   deflateInit2 for more information about the strategy parameter.)  'T' will
+   request transparent writing or appending with no compression and not using
+   the gzip format.
+
+     "a" can be used instead of "w" to request that the gzip stream that will
+   be written be appended to the file.  "+" will result in an error, since
+   reading and writing to the same gzip file is not supported.  The addition of
+   "x" when writing will create the file exclusively, which fails if the file
+   already exists.  On systems that support it, the addition of "e" when
+   reading or writing will set the flag to close the file on an execve() call.
+
+     These functions, as well as gzip, will read and decode a sequence of gzip
+   streams in a file.  The append function of gzopen() can be used to create
+   such a file.  (Also see gzflush() for another way to do this.)  When
+   appending, gzopen does not test whether the file begins with a gzip stream,
+   nor does it look for the end of the gzip streams to begin appending.  gzopen
+   will simply append a gzip stream to the existing file.
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.  When
+   reading, this will be detected automatically by looking for the magic two-
+   byte gzip header.
+
+     gzopen returns NULL if the file could not be opened, if there was
+   insufficient memory to allocate the gzFile state, or if an invalid mode was
+   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+   errno can be checked to determine if the reason gzopen failed was that the
+   file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
+   are obtained from calls like open, dup, creat, pipe or fileno (if the file
+   has been previously opened with fopen).  The mode parameter is as in gzopen.
+
+     The next call of gzclose on the returned gzFile will also close the file
+   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+   mode);.  The duplicated descriptor should be saved to avoid a leak, since
+   gzdopen does not close fd if it fails.  If you are using fileno() to get the
+   file descriptor from a FILE *, then you will have to use dup() to avoid
+   double-close()ing the file descriptor.  Both gzclose() and fclose() will
+   close the associated file descriptor, so they need to have different file
+   descriptors.
+
+     gzdopen returns NULL if there was insufficient memory to allocate the
+   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
+   used until the next gz* read, write, seek, or close operation, so gzdopen
+   will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+     Set the internal buffer size used by this library's functions.  The
+   default buffer size is 8192 bytes.  This function must be called after
+   gzopen() or gzdopen(), and before any other calls that read or write the
+   file.  The buffer memory allocation is always deferred to the first read or
+   write.  Two buffers are allocated, either both of the specified size when
+   writing, or one of the specified size and the other twice that size when
+   reading.  A larger buffer size of, for example, 64K or 128K bytes will
+   noticeably increase the speed of decompression (reading).
+
+     The new buffer size also affects the maximum length for gzprintf().
+
+     gzbuffer() returns 0 on success, or -1 on failure, such as being called
+   too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy.  See the description
+   of deflateInit2 for the meaning of these parameters.
+
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.  If
+   the input file is not in gzip format, gzread copies the given number of
+   bytes into the buffer directly from the file.
+
+     After reaching the end of a gzip stream in the input, gzread will continue
+   to read, looking for another gzip stream.  Any number of gzip streams may be
+   concatenated in the input file, and will all be decompressed by gzread().
+   If something other than a gzip stream is encountered after a gzip stream,
+   that remaining trailing garbage is ignored (and no error is returned).
+
+     gzread can be used to read a gzip file that is being concurrently written.
+   Upon reaching the end of the input, gzread will return with the available
+   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
+   gzclearerr can be used to clear the end of file indicator in order to permit
+   gzread to be tried again.  Z_OK indicates that a gzip stream was completed
+   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the
+   middle of a gzip stream.  Note that gzread does not return -1 in the event
+   of an incomplete gzip stream.  This error is deferred until gzclose(), which
+   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
+   stream.  Alternatively, gzerror can be used before gzclose to detect this
+   case.
+
+     gzread returns the number of uncompressed bytes actually read, less than
+   len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+                                voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes written or 0 in case of
+   error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the arguments to the compressed file under
+   control of the format string, as in fprintf.  gzprintf returns the number of
+   uncompressed bytes actually written, or 0 in case of error.  The number of
+   uncompressed bytes written is limited to 8191, or one less than the buffer
+   size given to gzbuffer().  The caller should assure that this limit is not
+   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
+   nothing written.  In this case, there may also be a buffer overflow with
+   unpredictable consequences, which is possible only if zlib was compiled with
+   the insecure functions sprintf() or vsprintf() because the secure snprintf()
+   or vsnprintf() functions were not available.  This can be determined using
+   zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+     Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+
+     gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+     Reads bytes from the compressed file until len-1 characters are read, or a
+   newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  If any characters are read or if len == 1, the
+   string is terminated with a null character.  If no characters are read due
+   to an end-of-file or len < 1, then the buffer is left untouched.
+
+     gzgets returns buf which is a null-terminated string, or it returns NULL
+   for end-of-file or in case of error.  If there was an error, the contents at
+   buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+     Writes c, converted to an unsigned char, into the compressed file.  gzputc
+   returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+     Reads one byte from the compressed file.  gzgetc returns this byte or -1
+   in case of end of file or error.  This is implemented as a macro for speed.
+   As such, it does not do all of the checking the other functions do.  I.e.
+   it does not check to see if file is NULL, nor whether the structure file
+   points to has been clobbered or not.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+     Push one character back onto the stream to be read as the first character
+   on the next read.  At least one character of push-back is allowed.
+   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
+   fail if c is -1, and may fail if a character has been pushed but not read
+   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
+   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
+   The pushed character will be discarded if the stream is repositioned with
+   gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file.  The parameter flush
+   is as in the deflate() function.  The return value is the zlib error number
+   (see function gzerror below).  gzflush is only permitted when writing.
+
+     If the flush parameter is Z_FINISH, the remaining data is written and the
+   gzip stream is completed in the output.  If gzwrite() is called again, a new
+   gzip stream will be started in the output.  gzread() is able to read such
+   concatented gzip streams.
+
+     gzflush should be called only when strictly necessary because it will
+   degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+                                   z_off_t offset, int whence));
+
+     Sets the starting position for the next gzread or gzwrite on the given
+   compressed file.  The offset represents a number of bytes in the
+   uncompressed data stream.  The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow.  If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+     gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+
+     Returns the starting position for the next gzread or gzwrite on the given
+   compressed file.  This position represents a number of bytes in the
+   uncompressed data stream, and is zero when starting, even if appending or
+   reading a gzip stream from the middle of a file using gzdopen().
+
+     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+     Returns the current offset in the file being read or written.  This offset
+   includes the count of bytes that precede the gzip stream, for example when
+   appending or when using gzdopen() for reading.  When reading, the offset
+   does not include as yet unused buffered input.  This information can be used
+   for a progress indicator.  On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns true (1) if the end-of-file indicator has been set while reading,
+   false (0) otherwise.  Note that the end-of-file indicator is set only if the
+   read tried to go past the end of the input, but came up short.  Therefore,
+   just like feof(), gzeof() may return false even if there is no more data to
+   read, in the event that the last read request was for the exact number of
+   bytes remaining in the input file.  This will happen if the input file size
+   is an exact multiple of the buffer size.
+
+     If gzeof() returns true, then the read functions will return no more data,
+   unless the end-of-file indicator is reset by gzclearerr() and the input file
+   has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns true (1) if file is being copied directly while reading, or false
+   (0) if file is a gzip stream being decompressed.
+
+     If the input file is empty, gzdirect() will return true, since the input
+   does not contain a gzip stream.
+
+     If gzdirect() is used immediately after gzopen() or gzdopen() it will
+   cause buffers to be allocated to allow reading the file to determine if it
+   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
+   gzdirect().
+
+     When writing, gzdirect() returns true (1) if transparent writing was
+   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
+   gzdirect() is not needed when writing.  Transparent writing must be
+   explicitly requested, so the application already knows the answer.  When
+   linking statically, using gzdirect() will include all of the zlib code for
+   gzip file reading and decompression, which may not be desired.)
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file and
+   deallocates the (de)compression state.  Note that once file is closed, you
+   cannot call gzerror with file, since its structures have been deallocated.
+   gzclose must not be called more than once on the same file, just as free
+   must not be called more than once on the same allocation.
+
+     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
+   last read ended in the middle of a gzip stream, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+     Same as gzclose(), but gzclose_r() is only for use when reading, and
+   gzclose_w() is only for use when writing or appending.  The advantage to
+   using these instead of gzclose() is that they avoid linking in zlib
+   compression or decompression code that is not used when only reading or only
+   writing respectively.  If gzclose() is used, then both compression and
+   decompression code will be included the application when linking to a static
+   zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the given
+   compressed file.  errnum is set to zlib error number.  If an error occurred
+   in the file system and not in the compression library, errnum is set to
+   Z_ERRNO and the application may consult errno to get the exact error code.
+
+     The application must not modify the returned string.  Future calls to
+   this function may invalidate the previously returned string.  If file is
+   closed, then the string previously returned by gzerror will no longer be
+   available.
+
+     gzerror() should be used to distinguish errors from end-of-file for those
+   functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file.  This is analogous to the
+   clearerr() function in stdio.  This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+#endif /* !Z_SOLO */
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the compression
+   library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum.  If buf is Z_NULL, this function returns the
+   required initial value for the checksum.
+
+     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster.
+
+   Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
+   that the z_off_t type (like off_t) is a signed integer.  If len2 is
+   negative, the result has no meaning or utility.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32.  If buf is Z_NULL, this function returns the required
+   initial value for the crc.  Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+                      (int)sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+                      ZLIB_VERSION, (int)sizeof(z_stream))
+
+#ifndef Z_SOLO
+
+/* gzgetc() macro and its supporting function and exposed data structure.  Note
+ * that the real internal state is much larger than the exposed structure.
+ * This abbreviated structure exposes just enough for the gzgetc() macro.  The
+ * user should not mess with these exposed elements, since their names or
+ * behavior could change in the future, perhaps even capriciously.  They can
+ * only be used by the gzgetc() macro.  You have been warned.
+ */
+struct gzFile_s {
+    unsigned have;
+    unsigned char *next;
+    z_off64_t pos;
+};
+ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));  /* backward compatibility */
+#ifdef Z_PREFIX_SET
+#  undef z_gzgetc
+#  define z_gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#else
+#  define gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#endif
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#ifdef Z_LARGE64
+   ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+   ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+   ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+   ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+   ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
+#  ifdef Z_PREFIX_SET
+#    define z_gzopen z_gzopen64
+#    define z_gzseek z_gzseek64
+#    define z_gztell z_gztell64
+#    define z_gzoffset z_gzoffset64
+#    define z_adler32_combine z_adler32_combine64
+#    define z_crc32_combine z_crc32_combine64
+#  else
+#    define gzopen gzopen64
+#    define gzseek gzseek64
+#    define gztell gztell64
+#    define gzoffset gzoffset64
+#    define adler32_combine adler32_combine64
+#    define crc32_combine crc32_combine64
+#  endif
+#  ifndef Z_LARGE64
+     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#  endif
+#else
+   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+#else /* Z_SOLO */
+
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+
+#endif /* !Z_SOLO */
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table    OF((void));
+ZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));
+ZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));
+ZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));
+#if defined(_WIN32) && !defined(Z_SOLO)
+ZEXTERN gzFile         ZEXPORT gzopen_w OF((const wchar_t *path,
+                                            const char *mode));
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+ZEXTERN int            ZEXPORTVA gzvprintf Z_ARG((gzFile file,
+                                                  const char *format,
+                                                  va_list va));
+#  endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
index 434b52a..ea1d2a5 100644 (file)
@@ -1,3 +1,8 @@
+#ifndef __BLIT320_H__
+#define __BLIT320_H__
+
 void blit320_640(void *dst, const void *src, int unused);
 void blit320_512(void *dst, const void *src, int unused);
 void blit320_368(void *dst, const void *src, int unused);
+
+#endif /* __BLIT320_H__ */
index 33a981d..55d4ac6 100644 (file)
@@ -34,24 +34,46 @@ void bgr555_to_rgb565(void *dst_, const void *src_, int bytes)
 
 #endif
 
+#ifdef __arm64__
+
+void bgr888_to_rgb565(void *dst_, const void *src_, int bytes)
+{
+    const unsigned char *src = src_;
+    unsigned int *dst = dst_;
+    unsigned int r1, g1, b1, r2, g2, b2;
+
+    for (; bytes >= 6; bytes -= 6, src += 6, dst++) {
+        r1 = src[0] & 0xf8;
+        g1 = src[1] & 0xfc;
+        b1 = src[2] & 0xf8;
+        r2 = src[3] & 0xf8;
+        g2 = src[4] & 0xfc;
+        b2 = src[5] & 0xf8;
+        *dst = (r2 << 24) | (g2 << 19) | (b2 << 13) |
+               (r1 << 8) | (g1 << 3) | (b1 >> 3);
+    }
+}
+
+#endif
+
 #ifndef __ARM_NEON__
 
 void bgr888_to_rgb565(void *dst_, const void *src_, int bytes)
 {
-       const unsigned char *src = src_;
-       unsigned int *dst = dst_;
-       unsigned int r1, g1, b1, r2, g2, b2;
-
-       for (; bytes >= 6; bytes -= 6, src += 6, dst++) {
-               r1 = src[0] & 0xf8;
-               g1 = src[1] & 0xfc;
-               b1 = src[2] & 0xf8;
-               r2 = src[3] & 0xf8;
-               g2 = src[4] & 0xfc;
-               b2 = src[5] & 0xf8;
-               *dst = (r2 << 24) | (g2 << 19) | (b2 << 13) |
-                       (r1 << 8) | (g1 << 3) | (b1 >> 3);
-       }
+    const unsigned char *src = src_;
+    unsigned int *dst = dst_;
+    unsigned int r1, g1, b1, r2, g2, b2;
+
+    for (; bytes >= 6; bytes -= 6, src += 6, dst++) {
+        r1 = src[0] & 0xf8;
+        g1 = src[1] & 0xfc;
+        b1 = src[2] & 0xf8;
+        r2 = src[3] & 0xf8;
+        g2 = src[4] & 0xfc;
+        b2 = src[5] & 0xf8;
+        *dst = (r2 << 24) | (g2 << 19) | (b2 << 13) |
+               (r1 << 8) | (g1 << 3) | (b1 >> 3);
+    }
 }
 
 // TODO?
index 8c92d2d..6dbd5e0 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __CSPACE_H__
+#define __CSPACE_H__
+
 #ifdef __cplusplus
 extern "C"
 {
@@ -19,3 +22,5 @@ void bgr888_to_uyvy(void *d, const void *s, int pixels);
 #ifdef __cplusplus
 }
 #endif
+
+#endif /* __CSPACE_H__ */
index 82fab29..65a178f 100644 (file)
@@ -1 +1,6 @@
+#ifndef __IN_TSBUTTON_H__
+#define __IN_TSBUTTON_H__
+
 void in_tsbutton_init(void);
+
+#endif /* __IN_TSBUTTON_H__ */
diff --git a/frontend/libpicofe b/frontend/libpicofe
deleted file mode 160000 (submodule)
index 21604a0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 21604a047941b8fe81d381ede0371c75da964afd
index 940ff05..33f2a42 100644 (file)
 #include <sys/syscall.h>
 #endif
 
+#ifdef SWITCH
+#include <switch.h>
+#endif
+
 #include "../libpcsxcore/misc.h"
 #include "../libpcsxcore/psxcounters.h"
 #include "../libpcsxcore/psxmem_map.h"
 #include "../libpcsxcore/cdrom.h"
 #include "../libpcsxcore/cdriso.h"
 #include "../libpcsxcore/cheat.h"
+#include "../libpcsxcore/r3000a.h"
 #include "../plugins/dfsound/out.h"
 #include "../plugins/dfsound/spu_config.h"
 #include "../plugins/dfinput/externals.h"
 #include "cspace.h"
 #include "main.h"
+#include "menu.h"
 #include "plugin.h"
 #include "plugin_lib.h"
 #include "arm_features.h"
 #include "revision.h"
-#include "libretro.h"
+
+#include <libretro.h>
+#include "libretro_core_options.h"
+
+#ifdef USE_LIBRETRO_VFS
+#include <streams/file_stream_transforms.h>
+#endif
+
+#ifdef _3DS
+#include "3ds/3ds_utils.h"
+#endif
+
+#define PORTS_NUMBER 8
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#define ISHEXDEC ((buf[cursor] >= '0') && (buf[cursor] <= '9')) || ((buf[cursor] >= 'a') && (buf[cursor] <= 'f')) || ((buf[cursor] >= 'A') && (buf[cursor] <= 'F'))
+
+#define INTERNAL_FPS_SAMPLE_PERIOD 64
+
+//hack to prevent retroarch freezing when reseting in the menu but not while running with the hot key
+static int rebootemu = 0;
 
 static retro_video_refresh_t video_cb;
 static retro_input_poll_t input_poll_cb;
 static retro_input_state_t input_state_cb;
 static retro_environment_t environ_cb;
 static retro_audio_sample_batch_t audio_batch_cb;
-static struct retro_rumble_interface rumble;
+static retro_set_rumble_state_t rumble_cb;
+static struct retro_log_callback logging;
+static retro_log_printf_t log_cb;
+
+static unsigned msg_interface_version = 0;
 
 static void *vout_buf;
+static void *vout_buf_ptr;
 static int vout_width, vout_height;
 static int vout_doffs_old, vout_fb_dirty;
 static bool vout_can_dupe;
 static bool duping_enable;
+static bool found_bios;
+static bool display_internal_fps = false;
+static unsigned frame_count = 0;
+static bool libretro_supports_bitmasks = false;
+#ifdef GPU_PEOPS
+static int show_advanced_gpu_peops_settings = -1;
+#endif
+#ifdef GPU_UNAI
+static int show_advanced_gpu_unai_settings = -1;
+#endif
+static int show_other_input_settings = -1;
+static float mouse_sensitivity = 1.0f;
+
+static unsigned previous_width = 0;
+static unsigned previous_height = 0;
 
 static int plugins_opened;
 static int is_pal_mode;
 
 /* memory card data */
 extern char Mcd1Data[MCD_SIZE];
+extern char Mcd2Data[MCD_SIZE];
 extern char McdDisable[2];
 
 /* PCSX ReARMed core calls and stuff */
-int in_type1, in_type2;
-int in_a1[2] = { 127, 127 }, in_a2[2] = { 127, 127 };
-int in_keystate;
+int in_type[8] = {
+   PSE_PAD_TYPE_NONE, PSE_PAD_TYPE_NONE,
+   PSE_PAD_TYPE_NONE, PSE_PAD_TYPE_NONE,
+   PSE_PAD_TYPE_NONE, PSE_PAD_TYPE_NONE,
+   PSE_PAD_TYPE_NONE, PSE_PAD_TYPE_NONE
+};
+int in_analog_left[8][2] = { { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 } };
+int in_analog_right[8][2] = { { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 }, { 127, 127 } };
+unsigned short in_keystate[PORTS_NUMBER];
+int in_mouse[8][2];
+int multitap1 = 0;
+int multitap2 = 0;
 int in_enable_vibration = 1;
 
+// NegCon adjustment parameters
+// > The NegCon 'twist' action is somewhat awkward when mapped
+//   to a standard analog stick -> user should be able to tweak
+//   response/deadzone for comfort
+// > When response is linear, 'additional' deadzone (set here)
+//   may be left at zero, since this is normally handled via in-game
+//   options menus
+// > When response is non-linear, deadzone should be set to match the
+//   controller being used (otherwise precision may be lost)
+// > negcon_linearity:
+//   - 1: Response is linear - recommended when using racing wheel
+//        peripherals, not recommended for standard gamepads
+//   - 2: Response is quadratic - optimal setting for gamepads
+//   - 3: Response is cubic - enables precise fine control, but
+//        difficult to use...
+#define NEGCON_RANGE 0x7FFF
+static int negcon_deadzone = 0;
+static int negcon_linearity = 1;
+
+static bool axis_bounds_modifier;
+
 /* PSX max resolution is 640x512, but with enhancement it's 1024x512 */
-#define VOUT_MAX_WIDTH 1024
+#define VOUT_MAX_WIDTH  1024
 #define VOUT_MAX_HEIGHT 512
 
+//Dummy functions
+bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info) { return false; }
+void retro_unload_game(void) {}
+static int vout_open(void) { return 0; }
+static void vout_close(void) {}
+static int snd_init(void) { return 0; }
+static void snd_finish(void) {}
+static int snd_busy(void) { return 0; }
+
+#define GPU_PEOPS_ODD_EVEN_BIT         (1 << 0)
+#define GPU_PEOPS_EXPAND_SCREEN_WIDTH  (1 << 1)
+#define GPU_PEOPS_IGNORE_BRIGHTNESS    (1 << 2)
+#define GPU_PEOPS_DISABLE_COORD_CHECK  (1 << 3)
+#define GPU_PEOPS_LAZY_SCREEN_UPDATE   (1 << 6)
+#define GPU_PEOPS_OLD_FRAME_SKIP       (1 << 7)
+#define GPU_PEOPS_REPEATED_TRIANGLES   (1 << 8)
+#define GPU_PEOPS_QUADS_WITH_TRIANGLES (1 << 9)
+#define GPU_PEOPS_FAKE_BUSY_STATE      (1 << 10)
+
 static void init_memcard(char *mcd_data)
 {
-       unsigned off = 0;
-       unsigned i;
+   unsigned off = 0;
+   unsigned i;
 
-       memset(mcd_data, 0, MCD_SIZE);
+   memset(mcd_data, 0, MCD_SIZE);
 
-       mcd_data[off++] = 'M';
-       mcd_data[off++] = 'C';
-       off += 0x7d;
-       mcd_data[off++] = 0x0e;
+   mcd_data[off++] = 'M';
+   mcd_data[off++] = 'C';
+   off += 0x7d;
+   mcd_data[off++] = 0x0e;
 
-       for (i = 0; i < 15; i++) {
-               mcd_data[off++] = 0xa0;
-               off += 0x07;
-               mcd_data[off++] = 0xff;
-               mcd_data[off++] = 0xff;
-               off += 0x75;
-               mcd_data[off++] = 0xa0;
-       }
+   for (i = 0; i < 15; i++)
+   {
+      mcd_data[off++] = 0xa0;
+      off += 0x07;
+      mcd_data[off++] = 0xff;
+      mcd_data[off++] = 0xff;
+      off += 0x75;
+      mcd_data[off++] = 0xa0;
+   }
 
-       for (i = 0; i < 20; i++) {
-               mcd_data[off++] = 0xff;
-               mcd_data[off++] = 0xff;
-               mcd_data[off++] = 0xff;
-               mcd_data[off++] = 0xff;
-               off += 0x04;
-               mcd_data[off++] = 0xff;
-               mcd_data[off++] = 0xff;
-               off += 0x76;
-       }
+   for (i = 0; i < 20; i++)
+   {
+      mcd_data[off++] = 0xff;
+      mcd_data[off++] = 0xff;
+      mcd_data[off++] = 0xff;
+      mcd_data[off++] = 0xff;
+      off += 0x04;
+      mcd_data[off++] = 0xff;
+      mcd_data[off++] = 0xff;
+      off += 0x76;
+   }
 }
 
-static int vout_open(void)
+static void set_vout_fb()
 {
-       return 0;
+   struct retro_framebuffer fb = { 0 };
+
+   fb.width          = vout_width;
+   fb.height         = vout_height;
+   fb.access_flags   = RETRO_MEMORY_ACCESS_WRITE;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER, &fb) && fb.format == RETRO_PIXEL_FORMAT_RGB565)
+      vout_buf_ptr = (uint16_t *)fb.data;
+   else
+      vout_buf_ptr = vout_buf;
 }
 
 static void vout_set_mode(int w, int h, int raw_w, int raw_h, int bpp)
 {
-       vout_width = w;
-       vout_height = h;
+   vout_width = w;
+   vout_height = h;
+
+   if (previous_width != vout_width || previous_height != vout_height)
+   {
+      previous_width = vout_width;
+      previous_height = vout_height;
+
+      struct retro_system_av_info info;
+      retro_get_system_av_info(&info);
+      environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &info.geometry);
+   }
+
+   set_vout_fb();
 }
 
 #ifndef FRONTEND_SUPPORTS_RGB565
 static void convert(void *buf, size_t bytes)
 {
-       unsigned int i, v, *p = buf;
+   unsigned int i, v, *p = buf;
 
-       for (i = 0; i < bytes / 4; i++) {
-               v = p[i];
-               p[i] = (v & 0x001f001f) | ((v >> 1) & 0x7fe07fe0);
-       }
+   for (i = 0; i < bytes / 4; i++)
+   {
+      v = p[i];
+      p[i] = (v & 0x001f001f) | ((v >> 1) & 0x7fe07fe0);
+   }
 }
 #endif
 
 static void vout_flip(const void *vram, int stride, int bgr24, int w, int h)
 {
-       unsigned short *dest = vout_buf;
-       const unsigned short *src = vram;
-       int dstride = vout_width, h1 = h;
-       int doffs;
-
-       if (vram == NULL) {
-               // blanking
-               memset(vout_buf, 0, dstride * h * 2);
-               goto out;
-       }
-
-       doffs = (vout_height - h) * dstride;
-       doffs += (dstride - w) / 2 & ~1;
-       if (doffs != vout_doffs_old) {
-               // clear borders
-               memset(vout_buf, 0, dstride * h * 2);
-               vout_doffs_old = doffs;
-       }
-       dest += doffs;
-
-       if (bgr24)
-       {
-               // XXX: could we switch to RETRO_PIXEL_FORMAT_XRGB8888 here?
-               for (; h1-- > 0; dest += dstride, src += stride)
-               {
-                       bgr888_to_rgb565(dest, src, w * 3);
-               }
-       }
-       else
-       {
-               for (; h1-- > 0; dest += dstride, src += stride)
-               {
-                       bgr555_to_rgb565(dest, src, w * 2);
-               }
-       }
+   unsigned short *dest = vout_buf_ptr;
+   const unsigned short *src = vram;
+   int dstride = vout_width, h1 = h;
+   int doffs;
+
+   if (vram == NULL)
+   {
+      // blanking
+      memset(vout_buf_ptr, 0, dstride * h * 2);
+      goto out;
+   }
+
+   doffs = (vout_height - h) * dstride;
+   doffs += (dstride - w) / 2 & ~1;
+   if (doffs != vout_doffs_old)
+   {
+      // clear borders
+      memset(vout_buf_ptr, 0, dstride * h * 2);
+      vout_doffs_old = doffs;
+   }
+   dest += doffs;
+
+   if (bgr24)
+   {
+      // XXX: could we switch to RETRO_PIXEL_FORMAT_XRGB8888 here?
+      for (; h1-- > 0; dest += dstride, src += stride)
+      {
+         bgr888_to_rgb565(dest, src, w * 3);
+      }
+   }
+   else
+   {
+      for (; h1-- > 0; dest += dstride, src += stride)
+      {
+         bgr555_to_rgb565(dest, src, w * 2);
+      }
+   }
 
 out:
 #ifndef FRONTEND_SUPPORTS_RGB565
-       convert(vout_buf, vout_width * vout_height * 2);
+   convert(vout_buf_ptr, vout_width * vout_height * 2);
+#endif
+   vout_fb_dirty = 1;
+   pl_rearmed_cbs.flip_cnt++;
+}
+
+#ifdef _3DS
+typedef struct
+{
+   void *buffer;
+   uint32_t target_map;
+   size_t size;
+   enum psxMapTag tag;
+} psx_map_t;
+
+psx_map_t custom_psx_maps[] = {
+   { NULL, 0x13000000, 0x210000, MAP_TAG_RAM }, // 0x80000000
+   { NULL, 0x12800000, 0x010000, MAP_TAG_OTHER }, // 0x1f800000
+   { NULL, 0x12c00000, 0x080000, MAP_TAG_OTHER }, // 0x1fc00000
+   { NULL, 0x11000000, 0x800000, MAP_TAG_LUTS }, // 0x08000000
+   { NULL, 0x12000000, 0x200000, MAP_TAG_VRAM }, // 0x00000000
+};
+
+void *pl_3ds_mmap(unsigned long addr, size_t size, int is_fixed,
+    enum psxMapTag tag)
+{
+   (void)is_fixed;
+   (void)addr;
+
+   if (__ctr_svchax)
+   {
+      psx_map_t *custom_map = custom_psx_maps;
+
+      for (; custom_map->size; custom_map++)
+      {
+         if ((custom_map->size == size) && (custom_map->tag == tag))
+         {
+            uint32_t ptr_aligned, tmp;
+
+            custom_map->buffer = malloc(size + 0x1000);
+            ptr_aligned = (((u32)custom_map->buffer) + 0xFFF) & ~0xFFF;
+
+            if (svcControlMemory(&tmp, (void *)custom_map->target_map, (void *)ptr_aligned, size, MEMOP_MAP, 0x3) < 0)
+            {
+               SysPrintf("could not map memory @0x%08X\n", custom_map->target_map);
+               exit(1);
+            }
+
+            return (void *)custom_map->target_map;
+         }
+      }
+   }
+
+   return malloc(size);
+}
+
+void pl_3ds_munmap(void *ptr, size_t size, enum psxMapTag tag)
+{
+   (void)tag;
+
+   if (__ctr_svchax)
+   {
+      psx_map_t *custom_map = custom_psx_maps;
+
+      for (; custom_map->size; custom_map++)
+      {
+         if ((custom_map->target_map == (uint32_t)ptr))
+         {
+            uint32_t ptr_aligned, tmp;
+
+            ptr_aligned = (((u32)custom_map->buffer) + 0xFFF) & ~0xFFF;
+
+            svcControlMemory(&tmp, (void *)custom_map->target_map, (void *)ptr_aligned, size, MEMOP_UNMAP, 0x3);
+
+            free(custom_map->buffer);
+            custom_map->buffer = NULL;
+            return;
+         }
+      }
+   }
+
+   free(ptr);
+}
+#endif
+
+#ifdef VITA
+typedef struct
+{
+   void *buffer;
+   uint32_t target_map;
+   size_t size;
+   enum psxMapTag tag;
+} psx_map_t;
+
+void *addr = NULL;
+
+psx_map_t custom_psx_maps[] = {
+   { NULL, NULL, 0x210000, MAP_TAG_RAM }, // 0x80000000
+   { NULL, NULL, 0x010000, MAP_TAG_OTHER }, // 0x1f800000
+   { NULL, NULL, 0x080000, MAP_TAG_OTHER }, // 0x1fc00000
+   { NULL, NULL, 0x800000, MAP_TAG_LUTS }, // 0x08000000
+   { NULL, NULL, 0x200000, MAP_TAG_VRAM }, // 0x00000000
+};
+
+int init_vita_mmap()
+{
+   int n;
+   void *tmpaddr;
+   addr = malloc(64 * 1024 * 1024);
+   if (addr == NULL)
+      return -1;
+   tmpaddr = ((u32)(addr + 0xFFFFFF)) & ~0xFFFFFF;
+   custom_psx_maps[0].buffer = tmpaddr + 0x2000000;
+   custom_psx_maps[1].buffer = tmpaddr + 0x1800000;
+   custom_psx_maps[2].buffer = tmpaddr + 0x1c00000;
+   custom_psx_maps[3].buffer = tmpaddr + 0x0000000;
+   custom_psx_maps[4].buffer = tmpaddr + 0x1000000;
+#if 0
+   for(n = 0; n < 5; n++){
+   sceClibPrintf("addr reserved %x\n",custom_psx_maps[n].buffer);
+   }
 #endif
-       vout_fb_dirty = 1;
-       pl_rearmed_cbs.flip_cnt++;
+   return 0;
+}
+
+void deinit_vita_mmap()
+{
+   free(addr);
+}
+
+void *pl_vita_mmap(unsigned long addr, size_t size, int is_fixed,
+    enum psxMapTag tag)
+{
+   (void)is_fixed;
+   (void)addr;
+
+   psx_map_t *custom_map = custom_psx_maps;
+
+   for (; custom_map->size; custom_map++)
+   {
+      if ((custom_map->size == size) && (custom_map->tag == tag))
+      {
+         return custom_map->buffer;
+      }
+   }
+
+   return malloc(size);
 }
 
-static void vout_close(void)
+void pl_vita_munmap(void *ptr, size_t size, enum psxMapTag tag)
 {
+   (void)tag;
+
+   psx_map_t *custom_map = custom_psx_maps;
+
+   for (; custom_map->size; custom_map++)
+   {
+      if ((custom_map->buffer == ptr))
+      {
+         return;
+      }
+   }
+
+   free(ptr);
 }
+#endif
 
 static void *pl_mmap(unsigned int size)
 {
-       return psxMap(0, size, 0, MAP_TAG_VRAM);
+   return psxMap(0, size, 0, MAP_TAG_VRAM);
 }
 
 static void pl_munmap(void *ptr, unsigned int size)
 {
-       psxUnmap(ptr, size, MAP_TAG_VRAM);
+   psxUnmap(ptr, size, MAP_TAG_VRAM);
 }
 
 struct rearmed_cbs pl_rearmed_cbs = {
-       .pl_vout_open = vout_open,
-       .pl_vout_set_mode = vout_set_mode,
-       .pl_vout_flip = vout_flip,
-       .pl_vout_close = vout_close,
-       .mmap = pl_mmap,
-       .munmap = pl_munmap,
-       /* from psxcounters */
-       .gpu_hcnt = &hSyncCount,
-       .gpu_frame_count = &frame_counter,
+   .pl_vout_open     = vout_open,
+   .pl_vout_set_mode = vout_set_mode,
+   .pl_vout_flip     = vout_flip,
+   .pl_vout_close    = vout_close,
+   .mmap             = pl_mmap,
+   .munmap           = pl_munmap,
+   /* from psxcounters */
+   .gpu_hcnt         = &hSyncCount,
+   .gpu_frame_count  = &frame_counter,
 };
 
 void pl_frame_limit(void)
 {
-       /* called once per frame, make psxCpu->Execute() above return */
-       stop = 1;
+   /* called once per frame, make psxCpu->Execute() above return */
+   stop = 1;
 }
 
 void pl_timing_prepare(int is_pal)
 {
-       is_pal_mode = is_pal;
+   is_pal_mode = is_pal;
 }
 
 void plat_trigger_vibrate(int pad, int low, int high)
 {
-    rumble.set_rumble_state(pad, RETRO_RUMBLE_STRONG, high << 8);
-    rumble.set_rumble_state(pad, RETRO_RUMBLE_WEAK, low ? 0xffff : 0x0);
+   if (!rumble_cb)
+      return;
+
+   if (in_enable_vibration)
+   {
+      rumble_cb(pad, RETRO_RUMBLE_STRONG, high << 8);
+      rumble_cb(pad, RETRO_RUMBLE_WEAK, low ? 0xffff : 0x0);
+   }
 }
 
 void pl_update_gun(int *xn, int *yn, int *xres, int *yres, int *in)
@@ -213,60 +505,77 @@ void pl_update_gun(int *xn, int *yn, int *xres, int *yres, int *in)
 }
 
 /* sound calls */
-static int snd_init(void)
+static void snd_feed(void *buf, int bytes)
 {
-       return 0;
+   if (audio_batch_cb != NULL)
+      audio_batch_cb(buf, bytes / 4);
 }
 
-static void snd_finish(void)
+void out_register_libretro(struct out_driver *drv)
 {
+   drv->name   = "libretro";
+   drv->init   = snd_init;
+   drv->finish = snd_finish;
+   drv->busy   = snd_busy;
+   drv->feed   = snd_feed;
 }
 
-static int snd_busy(void)
-{
-       return 0;
-}
+#define RETRO_DEVICE_PSE_STANDARD   RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD,   0)
+#define RETRO_DEVICE_PSE_ANALOG     RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG,   0)
+#define RETRO_DEVICE_PSE_DUALSHOCK  RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG,   1)
+#define RETRO_DEVICE_PSE_NEGCON     RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG,   2)
+#define RETRO_DEVICE_PSE_GUNCON     RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 0)
+#define RETRO_DEVICE_PSE_MOUSE      RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE,    0)
 
-static void snd_feed(void *buf, int bytes)
+static char *get_pse_pad_label[] = {
+   "none", "mouse", "negcon", "konami gun", "standard", "analog", "guncon", "dualshock"
+};
+
+static const struct retro_controller_description pads[7] =
 {
-       if (audio_batch_cb != NULL)
-               audio_batch_cb(buf, bytes / 4);
-}
+   { "standard",  RETRO_DEVICE_JOYPAD },
+   { "analog",    RETRO_DEVICE_PSE_ANALOG },
+   { "dualshock", RETRO_DEVICE_PSE_DUALSHOCK },
+   { "negcon",    RETRO_DEVICE_PSE_NEGCON },
+   { "guncon",    RETRO_DEVICE_PSE_GUNCON },
+   { "mouse",     RETRO_DEVICE_PSE_MOUSE },
+   { NULL, 0 },
+};
 
-void out_register_libretro(struct out_driver *drv)
+static const struct retro_controller_info ports[9] =
 {
-       drv->name = "libretro";
-       drv->init = snd_init;
-       drv->finish = snd_finish;
-       drv->busy = snd_busy;
-       drv->feed = snd_feed;
-}
+   { pads, 7 },
+   { pads, 7 },
+   { pads, 7 },
+   { pads, 7 },
+   { pads, 7 },
+   { pads, 7 },
+   { pads, 7 },
+   { pads, 7 },
+   { NULL, 0 },
+};
 
 /* libretro */
 void retro_set_environment(retro_environment_t cb)
 {
-   static const struct retro_variable vars[] = {
-      { "pcsx_rearmed_frameskip", "Frameskip; 0|1|2|3" },
-      { "pcsx_rearmed_region", "Region; Auto|NTSC|PAL" },
-      { "pcsx_rearmed_pad1type", "Pad 1 Type; standard|analog" },
-      { "pcsx_rearmed_pad2type", "Pad 2 Type; standard|analog" },
-#ifndef DRC_DISABLE
-      { "pcsx_rearmed_drc", "Dynamic recompiler; enabled|disabled" },
+#ifdef USE_LIBRETRO_VFS
+   struct retro_vfs_interface_info vfs_iface_info;
 #endif
-#ifdef __ARM_NEON__
-      { "pcsx_rearmed_neon_interlace_enable", "Enable interlacing mode(s); disabled|enabled" },
-      { "pcsx_rearmed_neon_enhancement_enable", "Enhanced resolution (slow); disabled|enabled" },
-      { "pcsx_rearmed_neon_enhancement_no_main", "Enhanced resolution speed hack; disabled|enabled" },
-#endif
-      { "pcsx_rearmed_duping_enable", "Frame duping; on|off" },
-      { "pcsx_rearmed_spu_reverb", "Sound: Reverb; on|off" },
-      { "pcsx_rearmed_spu_interpolation", "Sound: Interpolation; simple|gaussian|cubic|off" },
-      { NULL, NULL },
-   };
 
    environ_cb = cb;
 
-   cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars);
+   if (cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &logging))
+      log_cb = logging.log;
+
+   environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);
+   libretro_set_core_options(environ_cb);
+
+#ifdef USE_LIBRETRO_VFS
+   vfs_iface_info.required_interface_version = 1;
+   vfs_iface_info.iface                      = NULL;
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VFS_INTERFACE, &vfs_iface_info))
+          filestream_vfs_init(&vfs_iface_info);
+#endif
 }
 
 void retro_set_video_refresh(retro_video_refresh_t cb) { video_cb = cb; }
@@ -277,315 +586,549 @@ void retro_set_input_state(retro_input_state_t cb) { input_state_cb = cb; }
 
 unsigned retro_api_version(void)
 {
-       return RETRO_API_VERSION;
+   return RETRO_API_VERSION;
+}
+
+static void update_multitap(void)
+{
+   struct retro_variable var = { 0 };
+
+   multitap1 = 0;
+   multitap2 = 0;
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_multitap";
+   if (environ_cb && (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value))
+   {
+      if (strcmp(var.value, "port 1") == 0)
+         multitap1 = 1;
+      else if (strcmp(var.value, "port 2") == 0)
+         multitap2 = 1;
+      else if (strcmp(var.value, "ports 1 and 2") == 0)
+      {
+         multitap1 = 1;
+         multitap2 = 1;
+      }
+   }
 }
 
 void retro_set_controller_port_device(unsigned port, unsigned device)
 {
+   if (port >= PORTS_NUMBER)
+      return;
+
+   switch (device)
+   {
+   case RETRO_DEVICE_JOYPAD:
+   case RETRO_DEVICE_PSE_STANDARD:
+      in_type[port] = PSE_PAD_TYPE_STANDARD;
+      break;
+   case RETRO_DEVICE_PSE_ANALOG:
+      in_type[port] = PSE_PAD_TYPE_ANALOGJOY;
+      break;
+   case RETRO_DEVICE_PSE_DUALSHOCK:
+      in_type[port] = PSE_PAD_TYPE_ANALOGPAD;
+      break;
+   case RETRO_DEVICE_PSE_MOUSE:
+      in_type[port] = PSE_PAD_TYPE_MOUSE;
+      break;
+   case RETRO_DEVICE_PSE_NEGCON:
+      in_type[port] = PSE_PAD_TYPE_NEGCON;
+      break;
+   case RETRO_DEVICE_PSE_GUNCON:
+      in_type[port] = PSE_PAD_TYPE_GUNCON;
+      break;
+   case RETRO_DEVICE_NONE:
+   default:
+      in_type[port] = PSE_PAD_TYPE_NONE;
+      break;
+   }
+
+   SysPrintf("port: %u  device: %s\n", port + 1, get_pse_pad_label[in_type[port]]);
 }
 
 void retro_get_system_info(struct retro_system_info *info)
 {
-       memset(info, 0, sizeof(*info));
-       info->library_name = "PCSX-ReARMed";
-       info->library_version = "r22";
-       info->valid_extensions = "bin|cue|img|mdf|pbp|toc|cbn|m3u";
-       info->need_fullpath = true;
+#ifndef GIT_VERSION
+#define GIT_VERSION ""
+#endif
+   memset(info, 0, sizeof(*info));
+   info->library_name     = "PCSX-ReARMed";
+   info->library_version  = "r22" GIT_VERSION;
+   info->valid_extensions = "bin|cue|img|mdf|pbp|toc|cbn|m3u|chd";
+   info->need_fullpath    = true;
 }
 
 void retro_get_system_av_info(struct retro_system_av_info *info)
 {
-       memset(info, 0, sizeof(*info));
-       info->timing.fps            = is_pal_mode ? 50 : 60;
-       info->timing.sample_rate    = 44100;
-       info->geometry.base_width   = 320;
-       info->geometry.base_height  = 240;
-       info->geometry.max_width    = VOUT_MAX_WIDTH;
-       info->geometry.max_height   = VOUT_MAX_HEIGHT;
-       info->geometry.aspect_ratio = 4.0 / 3.0;
+   unsigned geom_height          = vout_height > 0 ? vout_height : 240;
+   unsigned geom_width           = vout_width > 0 ? vout_width : 320;
+
+   memset(info, 0, sizeof(*info));
+   info->timing.fps              = is_pal_mode ? 50.0 : 60.0;
+   info->timing.sample_rate      = 44100.0;
+   info->geometry.base_width     = geom_width;
+   info->geometry.base_height    = geom_height;
+   info->geometry.max_width      = VOUT_MAX_WIDTH;
+   info->geometry.max_height     = VOUT_MAX_HEIGHT;
+   info->geometry.aspect_ratio   = 4.0 / 3.0;
 }
 
 /* savestates */
-size_t retro_serialize_size(void) 
-{ 
-       // it's currently 4380651-4397047 bytes,
-       // but have some reserved for future
-       return 0x440000;
+size_t retro_serialize_size(void)
+{
+   // it's currently 4380651-4397047 bytes,
+   // but have some reserved for future
+   return 0x440000;
 }
 
-struct save_fp {
-       char *buf;
-       size_t pos;
-       int is_write;
+struct save_fp
+{
+   char *buf;
+   size_t pos;
+   int is_write;
 };
 
 static void *save_open(const char *name, const char *mode)
 {
-       struct save_fp *fp;
+   struct save_fp *fp;
 
-       if (name == NULL || mode == NULL)
-               return NULL;
+   if (name == NULL || mode == NULL)
+      return NULL;
 
-       fp = malloc(sizeof(*fp));
-       if (fp == NULL)
-               return NULL;
+   fp = malloc(sizeof(*fp));
+   if (fp == NULL)
+      return NULL;
 
-       fp->buf = (char *)name;
-       fp->pos = 0;
-       fp->is_write = (mode[0] == 'w' || mode[1] == 'w');
+   fp->buf = (char *)name;
+   fp->pos = 0;
+   fp->is_write = (mode[0] == 'w' || mode[1] == 'w');
 
-       return fp;
+   return fp;
 }
 
 static int save_read(void *file, void *buf, u32 len)
 {
-       struct save_fp *fp = file;
-       if (fp == NULL || buf == NULL)
-               return -1;
+   struct save_fp *fp = file;
+   if (fp == NULL || buf == NULL)
+      return -1;
 
-       memcpy(buf, fp->buf + fp->pos, len);
-       fp->pos += len;
-       return len;
+   memcpy(buf, fp->buf + fp->pos, len);
+   fp->pos += len;
+   return len;
 }
 
 static int save_write(void *file, const void *buf, u32 len)
 {
-       struct save_fp *fp = file;
-       if (fp == NULL || buf == NULL)
-               return -1;
+   struct save_fp *fp = file;
+   if (fp == NULL || buf == NULL)
+      return -1;
 
-       memcpy(fp->buf + fp->pos, buf, len);
-       fp->pos += len;
-       return len;
+   memcpy(fp->buf + fp->pos, buf, len);
+   fp->pos += len;
+   return len;
 }
 
 static long save_seek(void *file, long offs, int whence)
 {
-       struct save_fp *fp = file;
-       if (fp == NULL)
-               return -1;
+   struct save_fp *fp = file;
+   if (fp == NULL)
+      return -1;
 
-       switch (whence) {
-       case SEEK_CUR:
-               fp->pos += offs;
-               return fp->pos;
-       case SEEK_SET:
-               fp->pos = offs;
-               return fp->pos;
-       default:
-               return -1;
-       }
+   switch (whence)
+   {
+   case SEEK_CUR:
+      fp->pos += offs;
+      return fp->pos;
+   case SEEK_SET:
+      fp->pos = offs;
+      return fp->pos;
+   default:
+      return -1;
+   }
 }
 
 static void save_close(void *file)
 {
-       struct save_fp *fp = file;
-       size_t r_size = retro_serialize_size();
-       if (fp == NULL)
-               return;
-
-       if (fp->pos > r_size)
-               SysPrintf("ERROR: save buffer overflow detected\n");
-       else if (fp->is_write && fp->pos < r_size)
-               // make sure we don't save trash in leftover space
-               memset(fp->buf + fp->pos, 0, r_size - fp->pos);
-       free(fp);
+   struct save_fp *fp = file;
+   size_t r_size = retro_serialize_size();
+   if (fp == NULL)
+      return;
+
+   if (fp->pos > r_size)
+      SysPrintf("ERROR: save buffer overflow detected\n");
+   else if (fp->is_write && fp->pos < r_size)
+      // make sure we don't save trash in leftover space
+      memset(fp->buf + fp->pos, 0, r_size - fp->pos);
+   free(fp);
 }
 
 bool retro_serialize(void *data, size_t size)
-{ 
-       int ret = SaveState(data);
-       return ret == 0 ? true : false;
+{
+   int ret = SaveState(data);
+   return ret == 0 ? true : false;
 }
 
 bool retro_unserialize(const void *data, size_t size)
 {
-       int ret = LoadState(data);
-       return ret == 0 ? true : false;
+   int ret = LoadState(data);
+   return ret == 0 ? true : false;
 }
 
 /* cheats */
 void retro_cheat_reset(void)
 {
-       ClearAllCheats();
+   ClearAllCheats();
 }
 
 void retro_cheat_set(unsigned index, bool enabled, const char *code)
 {
-       char buf[256];
-       int ret;
+   char buf[256];
+   int ret;
 
-       // cheat funcs are destructive, need a copy..
-       strncpy(buf, code, sizeof(buf));
-       buf[sizeof(buf) - 1] = 0;
+   // cheat funcs are destructive, need a copy..
+   strncpy(buf, code, sizeof(buf));
+   buf[sizeof(buf) - 1] = 0;
+
+   //Prepare buffered cheat for PCSX's AddCheat fucntion.
+   int cursor = 0;
+   int nonhexdec = 0;
+   while (buf[cursor])
+   {
+      if (!(ISHEXDEC))
+      {
+         if (++nonhexdec % 2)
+         {
+            buf[cursor] = ' ';
+         }
+         else
+         {
+            buf[cursor] = '\n';
+         }
+      }
+      cursor++;
+   }
 
-       if (index < NumCheats)
-               ret = EditCheat(index, "", buf);
-       else
-               ret = AddCheat("", buf);
+   if (index < NumCheats)
+      ret = EditCheat(index, "", buf);
+   else
+      ret = AddCheat("", buf);
 
-       if (ret != 0)
-               SysPrintf("Failed to set cheat %#u\n", index);
-       else if (index < NumCheats)
-               Cheats[index].Enabled = enabled;
+   if (ret != 0)
+      SysPrintf("Failed to set cheat %#u\n", index);
+   else if (index < NumCheats)
+      Cheats[index].Enabled = enabled;
 }
 
+// just in case, maybe a win-rt port in the future?
+#ifdef _WIN32
+#define SLASH '\\'
+#else
+#define SLASH '/'
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
 /* multidisk support */
+static unsigned int disk_initial_index;
+static char disk_initial_path[PATH_MAX];
 static bool disk_ejected;
 static unsigned int disk_current_index;
 static unsigned int disk_count;
-static struct disks_state {
-       char *fname;
-       int internal_index; // for multidisk eboots
+static struct disks_state
+{
+   char *fname;
+   char *flabel;
+   int internal_index; // for multidisk eboots
 } disks[8];
 
+static void get_disk_label(char *disk_label, const char *disk_path, size_t len)
+{
+   const char *base = NULL;
+
+   if (!disk_path || (*disk_path == '\0'))
+      return;
+
+   base = strrchr(disk_path, SLASH);
+   if (!base)
+      base = disk_path;
+
+   if (*base == SLASH)
+      base++;
+
+   strncpy(disk_label, base, len - 1);
+   disk_label[len - 1] = '\0';
+
+   char *ext = strrchr(disk_label, '.');
+   if (ext)
+      *ext = '\0';
+}
+
+static void disk_init(void)
+{
+   size_t i;
+
+   disk_ejected       = false;
+   disk_current_index = 0;
+   disk_count         = 0;
+
+   for (i = 0; i < sizeof(disks) / sizeof(disks[0]); i++)
+   {
+      if (disks[i].fname != NULL)
+      {
+         free(disks[i].fname);
+         disks[i].fname = NULL;
+      }
+      if (disks[i].flabel != NULL)
+      {
+         free(disks[i].flabel);
+         disks[i].flabel = NULL;
+      }
+      disks[i].internal_index = 0;
+   }
+}
+
 static bool disk_set_eject_state(bool ejected)
 {
-       // weird PCSX API..
-       SetCdOpenCaseTime(ejected ? -1 : (time(NULL) + 2));
-       LidInterrupt();
+   // weird PCSX API..
+   SetCdOpenCaseTime(ejected ? -1 : (time(NULL) + 2));
+   LidInterrupt();
 
-       disk_ejected = ejected;
-       return true;
+   disk_ejected = ejected;
+   return true;
 }
 
 static bool disk_get_eject_state(void)
 {
-       /* can't be controlled by emulated software */
-       return disk_ejected;
+   /* can't be controlled by emulated software */
+   return disk_ejected;
 }
 
 static unsigned int disk_get_image_index(void)
 {
-       return disk_current_index;
+   return disk_current_index;
 }
 
 static bool disk_set_image_index(unsigned int index)
 {
-       if (index >= sizeof(disks) / sizeof(disks[0]))
-               return false;
+   if (index >= sizeof(disks) / sizeof(disks[0]))
+      return false;
 
-       CdromId[0] = '\0';
-       CdromLabel[0] = '\0';
+   CdromId[0] = '\0';
+   CdromLabel[0] = '\0';
 
-       if (disks[index].fname == NULL) {
-               SysPrintf("missing disk #%u\n", index);
-               CDR_shutdown();
+   if (disks[index].fname == NULL)
+   {
+      SysPrintf("missing disk #%u\n", index);
+      CDR_shutdown();
 
-               // RetroArch specifies "no disk" with index == count,
-               // so don't fail here..
-               disk_current_index = index;
-               return true;
-       }
+      // RetroArch specifies "no disk" with index == count,
+      // so don't fail here..
+      disk_current_index = index;
+      return true;
+   }
 
-       SysPrintf("switching to disk %u: \"%s\" #%d\n", index,
-               disks[index].fname, disks[index].internal_index);
+   SysPrintf("switching to disk %u: \"%s\" #%d\n", index,
+       disks[index].fname, disks[index].internal_index);
 
-       cdrIsoMultidiskSelect = disks[index].internal_index;
-       set_cd_image(disks[index].fname);
-       if (ReloadCdromPlugin() < 0) {
-               SysPrintf("failed to load cdr plugin\n");
-               return false;
-       }
-       if (CDR_open() < 0) {
-               SysPrintf("failed to open cdr plugin\n");
-               return false;
-       }
+   cdrIsoMultidiskSelect = disks[index].internal_index;
+   set_cd_image(disks[index].fname);
+   if (ReloadCdromPlugin() < 0)
+   {
+      SysPrintf("failed to load cdr plugin\n");
+      return false;
+   }
+   if (CDR_open() < 0)
+   {
+      SysPrintf("failed to open cdr plugin\n");
+      return false;
+   }
 
-       if (!disk_ejected) {
-               SetCdOpenCaseTime(time(NULL) + 2);
-               LidInterrupt();
-       }
+   if (!disk_ejected)
+   {
+      SetCdOpenCaseTime(time(NULL) + 2);
+      LidInterrupt();
+   }
 
-       disk_current_index = index;
-       return true;
+   disk_current_index = index;
+   return true;
 }
 
 static unsigned int disk_get_num_images(void)
 {
-       return disk_count;
+   return disk_count;
 }
 
 static bool disk_replace_image_index(unsigned index,
-       const struct retro_game_info *info)
+    const struct retro_game_info *info)
 {
-       char *old_fname;
-       bool ret = true;
+   char *old_fname  = NULL;
+   char *old_flabel = NULL;
+   bool ret         = true;
+
+   if (index >= sizeof(disks) / sizeof(disks[0]))
+      return false;
+
+   old_fname  = disks[index].fname;
+   old_flabel = disks[index].flabel;
+
+   disks[index].fname          = NULL;
+   disks[index].flabel         = NULL;
+   disks[index].internal_index = 0;
+
+   if (info != NULL)
+   {
+      char disk_label[PATH_MAX];
+      disk_label[0] = '\0';
 
-       if (index >= sizeof(disks) / sizeof(disks[0]))
-               return false;
+      disks[index].fname = strdup(info->path);
 
-       old_fname = disks[index].fname;
-       disks[index].fname = NULL;
-       disks[index].internal_index = 0;
+      get_disk_label(disk_label, info->path, PATH_MAX);
+      disks[index].flabel = strdup(disk_label);
 
-       if (info != NULL) {
-               disks[index].fname = strdup(info->path);
-               if (index == disk_current_index)
-                       ret = disk_set_image_index(index);
-       }
+      if (index == disk_current_index)
+         ret = disk_set_image_index(index);
+   }
+
+   if (old_fname != NULL)
+      free(old_fname);
 
-       if (old_fname != NULL)
-               free(old_fname);
+   if (old_flabel != NULL)
+      free(old_flabel);
 
-       return ret;
+   return ret;
 }
 
 static bool disk_add_image_index(void)
 {
-       if (disk_count >= 8)
-               return false;
+   if (disk_count >= 8)
+      return false;
+
+   disk_count++;
+   return true;
+}
+
+static bool disk_set_initial_image(unsigned index, const char *path)
+{
+   if (index >= sizeof(disks) / sizeof(disks[0]))
+      return false;
+
+   if (!path || (*path == '\0'))
+      return false;
+
+   disk_initial_index = index;
+
+   strncpy(disk_initial_path, path, sizeof(disk_initial_path) - 1);
+   disk_initial_path[sizeof(disk_initial_path) - 1] = '\0';
+
+   return true;
+}
+
+static bool disk_get_image_path(unsigned index, char *path, size_t len)
+{
+   const char *fname = NULL;
+
+   if (len < 1)
+      return false;
+
+   if (index >= sizeof(disks) / sizeof(disks[0]))
+      return false;
+
+   fname = disks[index].fname;
+
+   if (!fname || (*fname == '\0'))
+      return false;
+
+   strncpy(path, fname, len - 1);
+   path[len - 1] = '\0';
+
+   return true;
+}
+
+static bool disk_get_image_label(unsigned index, char *label, size_t len)
+{
+   const char *flabel = NULL;
+
+   if (len < 1)
+      return false;
+
+   if (index >= sizeof(disks) / sizeof(disks[0]))
+      return false;
 
-       disk_count++;
-       return true;
+   flabel = disks[index].flabel;
+
+   if (!flabel || (*flabel == '\0'))
+      return false;
+
+   strncpy(label, flabel, len - 1);
+   label[len - 1] = '\0';
+
+   return true;
 }
 
 static struct retro_disk_control_callback disk_control = {
-       .set_eject_state = disk_set_eject_state,
-       .get_eject_state = disk_get_eject_state,
-       .get_image_index = disk_get_image_index,
-       .set_image_index = disk_set_image_index,
-       .get_num_images = disk_get_num_images,
-       .replace_image_index = disk_replace_image_index,
-       .add_image_index = disk_add_image_index,
+   .set_eject_state     = disk_set_eject_state,
+   .get_eject_state     = disk_get_eject_state,
+   .get_image_index     = disk_get_image_index,
+   .set_image_index     = disk_set_image_index,
+   .get_num_images      = disk_get_num_images,
+   .replace_image_index = disk_replace_image_index,
+   .add_image_index     = disk_add_image_index,
 };
 
-// just in case, maybe a win-rt port in the future?
-#ifdef _WIN32
-#define SLASH '\\'
-#else
-#define SLASH '/'
-#endif
+static struct retro_disk_control_ext_callback disk_control_ext = {
+   .set_eject_state     = disk_set_eject_state,
+   .get_eject_state     = disk_get_eject_state,
+   .get_image_index     = disk_get_image_index,
+   .set_image_index     = disk_set_image_index,
+   .get_num_images      = disk_get_num_images,
+   .replace_image_index = disk_replace_image_index,
+   .add_image_index     = disk_add_image_index,
+   .set_initial_image   = disk_set_initial_image,
+   .get_image_path      = disk_get_image_path,
+   .get_image_label     = disk_get_image_label,
+};
 
-static char base_dir[PATH_MAX];
+static char base_dir[1024];
 
 static bool read_m3u(const char *file)
 {
-       char line[PATH_MAX];
-       char name[PATH_MAX];
-       FILE *f = fopen(file, "r");
-       if (!f)
-               return false;
-
-       while (fgets(line, sizeof(line), f) && disk_count < sizeof(disks) / sizeof(disks[0])) {
-               if (line[0] == '#')
-                       continue;
-               char *carrige_return = strchr(line, '\r');
-               if (carrige_return)
-                       *carrige_return = '\0';
-               char *newline = strchr(line, '\n');
-               if (newline)
-                       *newline = '\0';
-
-               if (line[0] != '\0')
-               {
-                       snprintf(name, sizeof(name), "%s%c%s", base_dir, SLASH, line);
-                       disks[disk_count++].fname = strdup(name);
-               }
-       }
-
-       fclose(f);
-       return (disk_count != 0);
+   char line[1024];
+   char name[PATH_MAX];
+   FILE *fp = fopen(file, "r");
+   if (!fp)
+      return false;
+
+   while (fgets(line, sizeof(line), fp) && disk_count < sizeof(disks) / sizeof(disks[0]))
+   {
+      if (line[0] == '#')
+         continue;
+      char *carrige_return = strchr(line, '\r');
+      if (carrige_return)
+         *carrige_return = '\0';
+      char *newline = strchr(line, '\n');
+      if (newline)
+         *newline = '\0';
+
+      if (line[0] != '\0')
+      {
+         char disk_label[PATH_MAX];
+         disk_label[0] = '\0';
+
+         snprintf(name, sizeof(name), "%s%c%s", base_dir, SLASH, line);
+         disks[disk_count].fname = strdup(name);
+
+         get_disk_label(disk_label, name, PATH_MAX);
+         disks[disk_count].flabel = strdup(disk_label);
+
+         disk_count++;
+      }
+   }
+
+   fclose(fp);
+   return (disk_count != 0);
 }
 
 static void extract_directory(char *buf, const char *path, size_t size)
@@ -614,361 +1157,337 @@ static void extract_directory(char *buf, const char *path, size_t size)
  * Find the first occurrence of find in s, ignore case.
  */
 char *
-strcasestr(const char *s, const char*find)
-{
-       char c, sc;
-       size_t len;
-
-       if ((c = *find++) != 0) {
-               c = tolower((unsigned char)c);
-               len = strlen(find);
-               do {
-                       do {
-                               if ((sc = *s++) == 0)
-                                       return (NULL);
-                       } while ((char)tolower((unsigned char)sc) != c);
-               } while (strncasecmp(s, find, len) != 0);
-               s--;
-       }
-       return ((char *)s);
+strcasestr(const char *s, const char *find)
+{
+   char c, sc;
+   size_t len;
+
+   if ((c = *find++) != 0)
+   {
+      c = tolower((unsigned char)c);
+      len = strlen(find);
+      do
+      {
+         do
+         {
+            if ((sc = *s++) == 0)
+               return (NULL);
+         } while ((char)tolower((unsigned char)sc) != c);
+      } while (strncasecmp(s, find, len) != 0);
+      s--;
+   }
+   return ((char *)s);
 }
 #endif
 
+static void set_retro_memmap(void)
+{
+#ifndef NDEBUG
+   struct retro_memory_map retromap = { 0 };
+   struct retro_memory_descriptor mmap = {
+      0, psxM, 0, 0, 0, 0, 0x200000
+   };
+
+   retromap.descriptors = &mmap;
+   retromap.num_descriptors = 1;
+
+   environ_cb(RETRO_ENVIRONMENT_SET_MEMORY_MAPS, &retromap);
+#endif
+}
+
+static void update_variables(bool in_flight);
 bool retro_load_game(const struct retro_game_info *info)
 {
-       size_t i;
-       bool is_m3u = (strcasestr(info->path, ".m3u") != NULL);
+   size_t i;
+   unsigned int cd_index = 0;
+   bool is_m3u = (strcasestr(info->path, ".m3u") != NULL);
 
    struct retro_input_descriptor desc[] = {
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Cross" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "Circle" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Triangle" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Square" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L1" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,    "L2" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,    "L3" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R1" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,    "R2" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,    "R3" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,    "Select" },
-      { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
-      { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
-      { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
-      { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
-      { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
-
-
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Cross" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "Circle" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Triangle" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Square" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L1" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,    "L2" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,    "L3" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R1" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,    "R2" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,    "R3" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,    "Select" },
-      { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
-      { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
-      { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
-      { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
-      { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
-
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Cross" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "Circle" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Triangle" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Square" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L1" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,    "L2" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,    "L3" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R1" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,    "R2" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,    "R3" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,    "Select" },
-      { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
-      { 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
-      { 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
-      { 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
-      { 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
-
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Cross" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "Circle" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Triangle" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Square" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L1" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,    "L2" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,    "L3" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R1" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,    "R2" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,    "R3" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,    "Select" },
-      { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
-      { 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
-      { 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
-      { 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
-      { 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
-
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Cross" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "Circle" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Triangle" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Square" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L1" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,    "L2" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,    "L3" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R1" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,    "R2" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,    "R3" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,    "Select" },
-      { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" },
-      { 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
-      { 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
-      { 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
-      { 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
-
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Cross" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "Circle" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Triangle" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Square" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L1" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,    "L2" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,    "L3" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R1" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,    "R2" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,    "R3" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,    "Select" },
-      { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" }, 
-      { 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
-      { 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
-      { 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
-      { 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
-
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Cross" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "Circle" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Triangle" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Square" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L1" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,    "L2" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,    "L3" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R1" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,    "R2" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,    "R3" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,    "Select" },
-      { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" }, 
-      { 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
-      { 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
-      { 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
-      { 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
-
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,  "D-Pad Left" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,    "D-Pad Up" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,  "D-Pad Down" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,     "Cross" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,     "Circle" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,     "Triangle" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,     "Square" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,     "L1" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,    "L2" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,    "L3" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,     "R1" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,    "R2" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,    "R3" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT,    "Select" },
-      { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,    "Start" }, 
-      { 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
-      { 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
-      { 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
-      { 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
+#define JOYP(port)                                                                                                \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT,   "D-Pad Left" },                              \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP,     "D-Pad Up" },                                \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN,   "D-Pad Down" },                              \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT,  "D-Pad Right" },                             \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B,      "Cross" },                                   \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A,      "Circle" },                                  \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X,      "Triangle" },                                \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y,      "Square" },                                  \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L,      "L1" },                                      \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2,     "L2" },                                      \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3,     "L3" },                                      \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R,      "R1" },                                      \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2,     "R2" },                                      \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3,     "R3" },                                      \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },                                  \
+      { port, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START,  "Start" },                                   \
+      { port, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X,  "Left Analog X" },  \
+      { port, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y,  "Left Analog Y" },  \
+      { port, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" }, \
+      { port, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
+
+      JOYP(0)
+      JOYP(1)
+      JOYP(2)
+      JOYP(3)
+      JOYP(4)
+      JOYP(5)
+      JOYP(6)
+      JOYP(7)
 
       { 0 },
    };
 
+   frame_count = 0;
+
    environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
 
 #ifdef FRONTEND_SUPPORTS_RGB565
-       enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
-       if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt)) {
-               SysPrintf("RGB565 supported, using it\n");
-       }
+   enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_RGB565;
+   if (environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
+   {
+      SysPrintf("RGB565 supported, using it\n");
+   }
 #endif
 
-       if (info == NULL || info->path == NULL) {
-               SysPrintf("info->path required\n");
-               return false;
-       }
+   if (info == NULL || info->path == NULL)
+   {
+      SysPrintf("info->path required\n");
+      return false;
+   }
 
-       if (plugins_opened) {
-               ClosePlugins();
-               plugins_opened = 0;
-       }
+   update_variables(false);
 
-       for (i = 0; i < sizeof(disks) / sizeof(disks[0]); i++) {
-               if (disks[i].fname != NULL) {
-                       free(disks[i].fname);
-                       disks[i].fname = NULL;
-               }
-               disks[i].internal_index = 0;
-       }
+   if (plugins_opened)
+   {
+      ClosePlugins();
+      plugins_opened = 0;
+   }
 
-       disk_current_index = 0;
-       extract_directory(base_dir, info->path, sizeof(base_dir));
+   disk_init();
 
-       if (is_m3u) {
-               if (!read_m3u(info->path)) {
-                       SysPrintf("failed to read m3u file\n");
-                       return false;
-               }
-       } else {
-               disk_count = 1;
-               disks[0].fname = strdup(info->path);
-       }
+   extract_directory(base_dir, info->path, sizeof(base_dir));
 
-       set_cd_image(disks[0].fname);
+   if (is_m3u)
+   {
+      if (!read_m3u(info->path))
+      {
+         log_cb(RETRO_LOG_INFO, "failed to read m3u file\n");
+         return false;
+      }
+   }
+   else
+   {
+      char disk_label[PATH_MAX];
+      disk_label[0] = '\0';
 
-       /* have to reload after set_cd_image for correct cdr plugin */
-       if (LoadPlugins() == -1) {
-               SysPrintf("failed to load plugins\n");
-               return false;
-       }
+      disk_count = 1;
+      disks[0].fname = strdup(info->path);
 
-       plugins_opened = 1;
-       NetOpened = 0;
+      get_disk_label(disk_label, info->path, PATH_MAX);
+      disks[0].flabel = strdup(disk_label);
+   }
 
-       if (OpenPlugins() == -1) {
-               SysPrintf("failed to open plugins\n");
-               return false;
-       }
+   /* If this is an M3U file, attempt to set the
+    * initial disk image */
+   if (is_m3u && (disk_initial_index > 0) && (disk_initial_index < disk_count))
+   {
+      const char *fname = disks[disk_initial_index].fname;
 
-       plugin_call_rearmed_cbs();
-       dfinput_activate();
+      if (fname && (*fname != '\0'))
+         if (strcmp(disk_initial_path, fname) == 0)
+            cd_index = disk_initial_index;
+   }
 
-       Config.PsxAuto = 1;
-       if (CheckCdrom() == -1) {
-               SysPrintf("unsupported/invalid CD image: %s\n", info->path);
-               return false;
-       }
+   set_cd_image(disks[cd_index].fname);
+   disk_current_index = cd_index;
 
-       SysReset();
+   /* have to reload after set_cd_image for correct cdr plugin */
+   if (LoadPlugins() == -1)
+   {
+      log_cb(RETRO_LOG_INFO, "failed to load plugins\n");
+      return false;
+   }
 
-       if (LoadCdrom() == -1) {
-               SysPrintf("could not load CD-ROM!\n");
-               return false;
-       }
-       emu_on_new_cd(0);
+   plugins_opened = 1;
+   NetOpened = 0;
 
-       // multidisk images
-       if (!is_m3u) {
-               disk_count = cdrIsoMultidiskCount < 8 ? cdrIsoMultidiskCount : 8;
-               for (i = 1; i < sizeof(disks) / sizeof(disks[0]) && i < cdrIsoMultidiskCount; i++) {
-                       disks[i].fname = strdup(info->path);
-                       disks[i].internal_index = i;
-               }
-       }
+   if (OpenPlugins() == -1)
+   {
+      log_cb(RETRO_LOG_INFO, "failed to open plugins\n");
+      return false;
+   }
 
-       return true;
-}
+   /* Handle multi-disk images (i.e. PBP)
+    * > Cannot do this until after OpenPlugins() is
+    *   called (since this sets the value of
+    *   cdrIsoMultidiskCount) */
+   if (!is_m3u && (cdrIsoMultidiskCount > 1))
+   {
+      disk_count = cdrIsoMultidiskCount < 8 ? cdrIsoMultidiskCount : 8;
 
-bool retro_load_game_special(unsigned game_type, const struct retro_game_info *info, size_t num_info)
-{
-       return false;
-}
+      /* Small annoyance: We need to change the label
+       * of disk 0, so have to clear existing entries */
+      if (disks[0].fname != NULL)
+         free(disks[0].fname);
+      disks[0].fname = NULL;
 
-void retro_unload_game(void) 
-{
+      if (disks[0].flabel != NULL)
+         free(disks[0].flabel);
+      disks[0].flabel = NULL;
+
+      for (i = 0; i < sizeof(disks) / sizeof(disks[0]) && i < cdrIsoMultidiskCount; i++)
+      {
+         char disk_name[PATH_MAX - 16] = { 0 };
+         char disk_label[PATH_MAX] = { 0 };
+
+         disks[i].fname = strdup(info->path);
+
+         get_disk_label(disk_name, info->path, sizeof(disk_name));
+         snprintf(disk_label, sizeof(disk_label), "%s #%u", disk_name, (unsigned)i + 1);
+         disks[i].flabel = strdup(disk_label);
+
+         disks[i].internal_index = i;
+      }
+
+      /* This is not an M3U file, so initial disk
+       * image has not yet been set - attempt to
+       * do so now */
+      if ((disk_initial_index > 0) && (disk_initial_index < disk_count))
+      {
+         const char *fname = disks[disk_initial_index].fname;
+
+         if (fname && (*fname != '\0'))
+            if (strcmp(disk_initial_path, fname) == 0)
+               cd_index = disk_initial_index;
+      }
+
+      if (cd_index > 0)
+      {
+         CdromId[0] = '\0';
+         CdromLabel[0] = '\0';
+
+         cdrIsoMultidiskSelect = disks[cd_index].internal_index;
+         disk_current_index = cd_index;
+         set_cd_image(disks[cd_index].fname);
+
+         if (ReloadCdromPlugin() < 0)
+         {
+            log_cb(RETRO_LOG_INFO, "failed to reload cdr plugins\n");
+            return false;
+         }
+         if (CDR_open() < 0)
+         {
+            log_cb(RETRO_LOG_INFO, "failed to open cdr plugin\n");
+            return false;
+         }
+      }
+   }
+
+   /* set ports to use "standard controller" initially */
+   for (i = 0; i < 8; ++i)
+      in_type[i] = PSE_PAD_TYPE_STANDARD;
+
+   plugin_call_rearmed_cbs();
+   /* dfinput_activate(); */
+
+   if (CheckCdrom() == -1)
+   {
+      log_cb(RETRO_LOG_INFO, "unsupported/invalid CD image: %s\n", info->path);
+      return false;
+   }
+
+   SysReset();
+
+   if (LoadCdrom() == -1)
+   {
+      log_cb(RETRO_LOG_INFO, "could not load CD\n");
+      return false;
+   }
+   emu_on_new_cd(0);
+
+   set_retro_memmap();
+
+   return true;
 }
 
 unsigned retro_get_region(void)
 {
-       return is_pal_mode ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
+   return is_pal_mode ? RETRO_REGION_PAL : RETRO_REGION_NTSC;
 }
 
 void *retro_get_memory_data(unsigned id)
 {
-       if (id == RETRO_MEMORY_SAVE_RAM)
-               return Mcd1Data;
-       else
-               return NULL;
+   if (id == RETRO_MEMORY_SAVE_RAM)
+      return Mcd1Data;
+   else if (id == RETRO_MEMORY_SYSTEM_RAM)
+      return psxM;
+   else
+      return NULL;
 }
 
 size_t retro_get_memory_size(unsigned id)
 {
-       if (id == RETRO_MEMORY_SAVE_RAM)
-               return MCD_SIZE;
-       else
-               return 0;
+   if (id == RETRO_MEMORY_SAVE_RAM)
+      return MCD_SIZE;
+   else if (id == RETRO_MEMORY_SYSTEM_RAM)
+      return 0x200000;
+   else
+      return 0;
 }
 
 void retro_reset(void)
 {
-       SysReset();
+   //hack to prevent retroarch freezing when reseting in the menu but not while running with the hot key
+   rebootemu = 1;
+   //SysReset();
 }
 
 static const unsigned short retro_psx_map[] = {
-       [RETRO_DEVICE_ID_JOYPAD_B]      = 1 << DKEY_CROSS,
-       [RETRO_DEVICE_ID_JOYPAD_Y]      = 1 << DKEY_SQUARE,
-       [RETRO_DEVICE_ID_JOYPAD_SELECT] = 1 << DKEY_SELECT,
-       [RETRO_DEVICE_ID_JOYPAD_START]  = 1 << DKEY_START,
-       [RETRO_DEVICE_ID_JOYPAD_UP]     = 1 << DKEY_UP,
-       [RETRO_DEVICE_ID_JOYPAD_DOWN]   = 1 << DKEY_DOWN,
-       [RETRO_DEVICE_ID_JOYPAD_LEFT]   = 1 << DKEY_LEFT,
-       [RETRO_DEVICE_ID_JOYPAD_RIGHT]  = 1 << DKEY_RIGHT,
-       [RETRO_DEVICE_ID_JOYPAD_A]      = 1 << DKEY_CIRCLE,
-       [RETRO_DEVICE_ID_JOYPAD_X]      = 1 << DKEY_TRIANGLE,
-       [RETRO_DEVICE_ID_JOYPAD_L]      = 1 << DKEY_L1,
-       [RETRO_DEVICE_ID_JOYPAD_R]      = 1 << DKEY_R1,
-       [RETRO_DEVICE_ID_JOYPAD_L2]     = 1 << DKEY_L2,
-       [RETRO_DEVICE_ID_JOYPAD_R2]     = 1 << DKEY_R2,
-       [RETRO_DEVICE_ID_JOYPAD_L3]     = 1 << DKEY_L3,
-       [RETRO_DEVICE_ID_JOYPAD_R3]     = 1 << DKEY_R3,
+   [RETRO_DEVICE_ID_JOYPAD_B]      = 1 << DKEY_CROSS,
+   [RETRO_DEVICE_ID_JOYPAD_Y]      = 1 << DKEY_SQUARE,
+   [RETRO_DEVICE_ID_JOYPAD_SELECT] = 1 << DKEY_SELECT,
+   [RETRO_DEVICE_ID_JOYPAD_START]  = 1 << DKEY_START,
+   [RETRO_DEVICE_ID_JOYPAD_UP]     = 1 << DKEY_UP,
+   [RETRO_DEVICE_ID_JOYPAD_DOWN]   = 1 << DKEY_DOWN,
+   [RETRO_DEVICE_ID_JOYPAD_LEFT]   = 1 << DKEY_LEFT,
+   [RETRO_DEVICE_ID_JOYPAD_RIGHT]  = 1 << DKEY_RIGHT,
+   [RETRO_DEVICE_ID_JOYPAD_A]      = 1 << DKEY_CIRCLE,
+   [RETRO_DEVICE_ID_JOYPAD_X]      = 1 << DKEY_TRIANGLE,
+   [RETRO_DEVICE_ID_JOYPAD_L]      = 1 << DKEY_L1,
+   [RETRO_DEVICE_ID_JOYPAD_R]      = 1 << DKEY_R1,
+   [RETRO_DEVICE_ID_JOYPAD_L2]     = 1 << DKEY_L2,
+   [RETRO_DEVICE_ID_JOYPAD_R2]     = 1 << DKEY_R2,
+   [RETRO_DEVICE_ID_JOYPAD_L3]     = 1 << DKEY_L3,
+   [RETRO_DEVICE_ID_JOYPAD_R3]     = 1 << DKEY_R3,
 };
 #define RETRO_PSX_MAP_LEN (sizeof(retro_psx_map) / sizeof(retro_psx_map[0]))
 
+//Percentage distance of screen to adjust
+static int GunconAdjustX = 0;
+static int GunconAdjustY = 0;
+
+//Used when out by a percentage
+static float GunconAdjustRatioX = 1;
+static float GunconAdjustRatioY = 1;
+
 static void update_variables(bool in_flight)
 {
    struct retro_variable var;
-   
+#ifdef GPU_PEOPS
+   int gpu_peops_fix = 0;
+#endif
+
    var.value = NULL;
    var.key = "pcsx_rearmed_frameskip";
-
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
       pl_rearmed_cbs.frameskip = atoi(var.value);
 
    var.value = NULL;
    var.key = "pcsx_rearmed_region";
-
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    {
       Config.PsxAuto = 0;
-      if (strcmp(var.value, "Automatic") == 0)
+      if (strcmp(var.value, "auto") == 0)
          Config.PsxAuto = 1;
       else if (strcmp(var.value, "NTSC") == 0)
          Config.PsxType = 0;
@@ -976,31 +1495,87 @@ static void update_variables(bool in_flight)
          Config.PsxType = 1;
    }
 
+   update_multitap();
+
    var.value = NULL;
-   var.key = "pcsx_rearmed_pad1type";
+   var.key = "pcsx_rearmed_negcon_deadzone";
+   negcon_deadzone = 0;
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      negcon_deadzone = (int)(atoi(var.value) * 0.01f * NEGCON_RANGE);
+   }
 
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   var.value = NULL;
+   var.key = "pcsx_rearmed_negcon_response";
+   negcon_linearity = 1;
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    {
-      in_type1 = PSE_PAD_TYPE_STANDARD;
-      if (strcmp(var.value, "analog") == 0)
-         in_type1 = PSE_PAD_TYPE_ANALOGPAD;
+      if (strcmp(var.value, "quadratic") == 0)
+      {
+         negcon_linearity = 2;
+      }
+      else if (strcmp(var.value, "cubic") == 0)
+      {
+         negcon_linearity = 3;
+      }
    }
 
    var.value = NULL;
-   var.key = "pcsx_rearmed_pad2type";
+   var.key = "pcsx_rearmed_analog_axis_modifier";
+   axis_bounds_modifier = true;
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "square") == 0)
+      {
+         axis_bounds_modifier = true;
+      }
+      else if (strcmp(var.value, "circle") == 0)
+      {
+         axis_bounds_modifier = false;
+      }
+   }
 
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   var.value = NULL;
+   var.key = "pcsx_rearmed_vibration";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    {
-      in_type2 = PSE_PAD_TYPE_STANDARD;
-      if (strcmp(var.value, "analog") == 0)
-         in_type2 = PSE_PAD_TYPE_ANALOGPAD;
+      if (strcmp(var.value, "disabled") == 0)
+         in_enable_vibration = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         in_enable_vibration = 1;
    }
 
+   var.value = NULL;
+   var.key = "pcsx_rearmed_dithering";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+      {
+         pl_rearmed_cbs.gpu_peops.iUseDither = 0;
+         pl_rearmed_cbs.gpu_peopsgl.bDrawDither = 0;
+         pl_rearmed_cbs.gpu_unai.dithering = 0;
+#ifdef __ARM_NEON__
+         pl_rearmed_cbs.gpu_neon.allow_dithering = 0;
+#endif
+      }
+      else if (strcmp(var.value, "enabled") == 0)
+      {
+         pl_rearmed_cbs.gpu_peops.iUseDither    = 1;
+         pl_rearmed_cbs.gpu_peopsgl.bDrawDither = 1;
+         pl_rearmed_cbs.gpu_unai.dithering = 1;
 #ifdef __ARM_NEON__
-   var.value = "NULL";
+         pl_rearmed_cbs.gpu_neon.allow_dithering = 1;
+#endif
+      }
+   }
+
+#ifdef GPU_NEON
+   var.value = NULL;
    var.key = "pcsx_rearmed_neon_interlace_enable";
 
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    {
       if (strcmp(var.value, "disabled") == 0)
          pl_rearmed_cbs.gpu_neon.allow_interlace = 0;
@@ -1011,7 +1586,7 @@ static void update_variables(bool in_flight)
    var.value = NULL;
    var.key = "pcsx_rearmed_neon_enhancement_enable";
 
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    {
       if (strcmp(var.value, "disabled") == 0)
          pl_rearmed_cbs.gpu_neon.enhancement_enable = 0;
@@ -1022,7 +1597,7 @@ static void update_variables(bool in_flight)
    var.value = NULL;
    var.key = "pcsx_rearmed_neon_enhancement_no_main";
 
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    {
       if (strcmp(var.value, "disabled") == 0)
          pl_rearmed_cbs.gpu_neon.enhancement_no_main = 0;
@@ -1031,54 +1606,78 @@ static void update_variables(bool in_flight)
    }
 #endif
 
-   var.value = "NULL";
+   var.value = NULL;
    var.key = "pcsx_rearmed_duping_enable";
 
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    {
-      if (strcmp(var.value, "off") == 0)
+      if (strcmp(var.value, "disabled") == 0)
          duping_enable = false;
-      else if (strcmp(var.value, "on") == 0)
+      else if (strcmp(var.value, "enabled") == 0)
          duping_enable = true;
    }
 
-#ifndef DRC_DISABLE
+   var.value = NULL;
+   var.key = "pcsx_rearmed_display_internal_fps";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         display_internal_fps = false;
+      else if (strcmp(var.value, "enabled") == 0)
+         display_internal_fps = true;
+   }
+
+#if defined(LIGHTREC) || defined(NEW_DYNAREC)
    var.value = NULL;
    var.key = "pcsx_rearmed_drc";
 
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   if (!environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var))
+      var.value = "enabled";
+
    {
       R3000Acpu *prev_cpu = psxCpu;
+#if defined(LIGHTREC)
+      bool can_use_dynarec = found_bios;
+#else
+      bool can_use_dynarec = 1;
+#endif
 
-      if (strcmp(var.value, "disabled") == 0)
+#ifdef _3DS
+      if (!__ctr_svchax)
+         Config.Cpu = CPU_INTERPRETER;
+      else
+#endif
+      if (strcmp(var.value, "disabled") == 0 || !can_use_dynarec)
          Config.Cpu = CPU_INTERPRETER;
       else if (strcmp(var.value, "enabled") == 0)
          Config.Cpu = CPU_DYNAREC;
 
       psxCpu = (Config.Cpu == CPU_INTERPRETER) ? &psxInt : &psxRec;
-      if (psxCpu != prev_cpu) {
+      if (psxCpu != prev_cpu)
+      {
          prev_cpu->Shutdown();
          psxCpu->Init();
          psxCpu->Reset(); // not really a reset..
       }
    }
-#endif
+#endif /* LIGHTREC || NEW_DYNAREC */
 
-   var.value = "NULL";
+   var.value = NULL;
    var.key = "pcsx_rearmed_spu_reverb";
 
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    {
-      if (strcmp(var.value, "off") == 0)
+      if (strcmp(var.value, "disabled") == 0)
          spu_config.iUseReverb = false;
-      else if (strcmp(var.value, "on") == 0)
+      else if (strcmp(var.value, "enabled") == 0)
          spu_config.iUseReverb = true;
    }
 
-   var.value = "NULL";
+   var.value = NULL;
    var.key = "pcsx_rearmed_spu_interpolation";
 
-   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) || var.value)
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
    {
       if (strcmp(var.value, "simple") == 0)
          spu_config.iUseInterpolation = 1;
@@ -1090,103 +1689,891 @@ static void update_variables(bool in_flight)
          spu_config.iUseInterpolation = 0;
    }
 
-   if (in_flight) {
+   var.value = NULL;
+   var.key = "pcsx_rearmed_pe2_fix";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         Config.RCntFix = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         Config.RCntFix = 1;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_inuyasha_fix";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         Config.VSyncWA = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         Config.VSyncWA = 1;
+   }
+
+#ifndef _WIN32
+   var.value = NULL;
+   var.key = "pcsx_rearmed_async_cd";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "async") == 0)
+      {
+         Config.AsyncCD = 1;
+         Config.CHD_Precache = 0;
+      }
+      else if (strcmp(var.value, "sync") == 0)
+      {
+         Config.AsyncCD = 0;
+         Config.CHD_Precache = 0;
+      }
+      else if (strcmp(var.value, "precache") == 0)
+      {
+         Config.AsyncCD = 0;
+         Config.CHD_Precache = 1;
+      }
+   }
+#endif
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_noxadecoding";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         Config.Xa = 1;
+      else
+         Config.Xa = 0;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_nocdaudio";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         Config.Cdda = 1;
+      else
+         Config.Cdda = 0;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_spuirq";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         Config.SpuIrq = 0;
+      else
+         Config.SpuIrq = 1;
+   }
+
+#ifdef THREAD_RENDERING
+   var.key = "pcsx_rearmed_gpu_thread_rendering";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.thread_rendering = THREAD_RENDERING_OFF;
+      else if (strcmp(var.value, "sync") == 0)
+         pl_rearmed_cbs.thread_rendering = THREAD_RENDERING_SYNC;
+      else if (strcmp(var.value, "async") == 0)
+         pl_rearmed_cbs.thread_rendering = THREAD_RENDERING_ASYNC;
+   }
+#endif
+
+#ifdef GPU_PEOPS
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_peops_odd_even_bit";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_ODD_EVEN_BIT;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_peops_expand_screen_width";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_EXPAND_SCREEN_WIDTH;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_peops_ignore_brightness";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_IGNORE_BRIGHTNESS;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_peops_disable_coord_check";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_DISABLE_COORD_CHECK;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_peops_lazy_screen_update";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_LAZY_SCREEN_UPDATE;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_peops_old_frame_skip";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_OLD_FRAME_SKIP;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_peops_repeated_triangles";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_REPEATED_TRIANGLES;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_peops_quads_with_triangles";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_QUADS_WITH_TRIANGLES;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gpu_peops_fake_busy_state";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         gpu_peops_fix |= GPU_PEOPS_FAKE_BUSY_STATE;
+   }
+
+   if (pl_rearmed_cbs.gpu_peops.dwActFixes != gpu_peops_fix)
+      pl_rearmed_cbs.gpu_peops.dwActFixes = gpu_peops_fix;
+
+   /* Show/hide core options */
+
+   var.key = "pcsx_rearmed_show_gpu_peops_settings";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      int show_advanced_gpu_peops_settings_prev = show_advanced_gpu_peops_settings;
+
+      show_advanced_gpu_peops_settings = 1;
+      if (strcmp(var.value, "disabled") == 0)
+         show_advanced_gpu_peops_settings = 0;
+
+      if (show_advanced_gpu_peops_settings != show_advanced_gpu_peops_settings_prev)
+      {
+         unsigned i;
+         struct retro_core_option_display option_display;
+         char gpu_peops_option[9][45] = {
+            "pcsx_rearmed_gpu_peops_odd_even_bit",
+            "pcsx_rearmed_gpu_peops_expand_screen_width",
+            "pcsx_rearmed_gpu_peops_ignore_brightness",
+            "pcsx_rearmed_gpu_peops_disable_coord_check",
+            "pcsx_rearmed_gpu_peops_lazy_screen_update",
+            "pcsx_rearmed_gpu_peops_old_frame_skip",
+            "pcsx_rearmed_gpu_peops_repeated_triangles",
+            "pcsx_rearmed_gpu_peops_quads_with_triangles",
+            "pcsx_rearmed_gpu_peops_fake_busy_state"
+         };
+
+         option_display.visible = show_advanced_gpu_peops_settings;
+
+         for (i = 0; i < 9; i++)
+         {
+            option_display.key = gpu_peops_option[i];
+            environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
+         }
+      }
+   }
+#endif
+
+#ifdef GPU_UNAI
+   var.key = "pcsx_rearmed_gpu_unai_ilace_force";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.ilace_force = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.ilace_force = 1;
+   }
+
+   var.key = "pcsx_rearmed_gpu_unai_pixel_skip";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.pixel_skip = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.pixel_skip = 1;
+   }
+
+   var.key = "pcsx_rearmed_gpu_unai_lighting";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.lighting = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.lighting = 1;
+   }
+
+   var.key = "pcsx_rearmed_gpu_unai_fast_lighting";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.fast_lighting = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.fast_lighting = 1;
+   }
+
+   var.key = "pcsx_rearmed_gpu_unai_blending";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.blending = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.blending = 1;
+   }
+
+   var.key = "pcsx_rearmed_gpu_unai_scale_hires";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "disabled") == 0)
+         pl_rearmed_cbs.gpu_unai.scale_hires = 0;
+      else if (strcmp(var.value, "enabled") == 0)
+         pl_rearmed_cbs.gpu_unai.scale_hires = 1;
+   }
+
+   var.key = "pcsx_rearmed_show_gpu_unai_settings";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      int show_advanced_gpu_unai_settings_prev = show_advanced_gpu_unai_settings;
+
+      show_advanced_gpu_unai_settings = 1;
+      if (strcmp(var.value, "disabled") == 0)
+         show_advanced_gpu_unai_settings = 0;
+
+      if (show_advanced_gpu_unai_settings != show_advanced_gpu_unai_settings_prev)
+      {
+         unsigned i;
+         struct retro_core_option_display option_display;
+         char gpu_unai_option[6][40] = {
+            "pcsx_rearmed_gpu_unai_blending",
+            "pcsx_rearmed_gpu_unai_lighting",
+            "pcsx_rearmed_gpu_unai_fast_lighting",
+            "pcsx_rearmed_gpu_unai_ilace_force",
+            "pcsx_rearmed_gpu_unai_pixel_skip",
+            "pcsx_rearmed_gpu_unai_scale_hires",
+         };
+
+         option_display.visible = show_advanced_gpu_unai_settings;
+
+         for (i = 0; i < 6; i++)
+         {
+            option_display.key = gpu_unai_option[i];
+            environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
+         }
+      }
+   }
+#endif // GPU_UNAI
+
+   //This adjustment process gives the user the ability to manually align the mouse up better
+   //with where the shots are in the emulator.
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gunconadjustx";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      GunconAdjustX = atoi(var.value);
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gunconadjusty";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      GunconAdjustY = atoi(var.value);
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gunconadjustratiox";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      GunconAdjustRatioX = atof(var.value);
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gunconadjustratioy";
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      GunconAdjustRatioY = atof(var.value);
+   }
+
+#ifdef NEW_DYNAREC
+   var.value = NULL;
+   var.key = "pcsx_rearmed_nosmccheck";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         new_dynarec_hacks |= NDHACK_NO_SMC_CHECK;
+      else
+         new_dynarec_hacks &= ~NDHACK_NO_SMC_CHECK;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_gteregsunneeded";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         new_dynarec_hacks |= NDHACK_GTE_UNNEEDED;
+      else
+         new_dynarec_hacks &= ~NDHACK_GTE_UNNEEDED;
+   }
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_nogteflags";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (strcmp(var.value, "enabled") == 0)
+         new_dynarec_hacks |= NDHACK_GTE_NO_FLAGS;
+      else
+         new_dynarec_hacks &= ~NDHACK_GTE_NO_FLAGS;
+   }
+
+   /* this probably is safe to change in real-time */
+   var.value = NULL;
+   var.key = "pcsx_rearmed_psxclock";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      int psxclock = atoi(var.value);
+      cycle_multiplier = 10000 / psxclock;
+   }
+#endif /* NEW_DYNAREC */
+
+   var.value = NULL;
+   var.key = "pcsx_rearmed_input_sensitivity";
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      mouse_sensitivity = atof(var.value);
+   }
+
+   var.key = "pcsx_rearmed_show_other_input_settings";
+   var.value = NULL;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      int previous_settings = show_other_input_settings;
+
+      show_other_input_settings = 1;
+      if (strcmp(var.value, "disabled") == 0)
+         show_other_input_settings = 0;
+
+      if (show_other_input_settings != previous_settings)
+      {
+         unsigned i;
+         struct retro_core_option_display option_display;
+         char gpu_peops_option[][50] = {
+            "pcsx_rearmed_negcon_deadzone",
+            "pcsx_rearmed_negcon_response",
+            "pcsx_rearmed_analog_axis_modifier",
+            "pcsx_rearmed_gunconadjustx",
+            "pcsx_rearmed_gunconadjusty",
+            "pcsx_rearmed_gunconadjustratiox",
+            "pcsx_rearmed_gunconadjustratioy"
+         };
+         #define INPUT_LIST (sizeof(gpu_peops_option) / sizeof(gpu_peops_option[0]))
+
+         option_display.visible = show_other_input_settings;
+
+         for (i = 0; i < INPUT_LIST; i++)
+         {
+            option_display.key = gpu_peops_option[i];
+            environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY, &option_display);
+         }
+      }
+   }
+
+   if (in_flight)
+   {
       // inform core things about possible config changes
       plugin_call_rearmed_cbs();
 
-      if (GPU_open != NULL && GPU_close != NULL) {
+      if (GPU_open != NULL && GPU_close != NULL)
+      {
          GPU_close();
          GPU_open(&gpuDisp, "PCSX", NULL);
       }
 
-      dfinput_activate();
+      /* dfinput_activate(); */
+   }
+   else
+   {
+      //not yet running
+
+      //bootlogo display hack
+      if (found_bios)
+      {
+         var.value = NULL;
+         var.key = "pcsx_rearmed_show_bios_bootlogo";
+         if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+         {
+            Config.SlowBoot = 0;
+            rebootemu = 0;
+            if (strcmp(var.value, "enabled") == 0)
+            {
+               Config.SlowBoot = 1;
+               rebootemu = 1;
+            }
+         }
+      }
    }
 }
 
-void retro_run(void) 
+// Taken from beetle-psx-libretro
+static uint16_t get_analog_button(int16_t ret, retro_input_state_t input_state_cb, int player_index, int id)
 {
-       int i;
+   // NOTE: Analog buttons were added Nov 2017. Not all front-ends support this
+   // feature (or pre-date it) so we need to handle this in a graceful way.
+
+   // First, try and get an analog value using the new libretro API constant
+   uint16_t button = input_state_cb(player_index,
+       RETRO_DEVICE_ANALOG,
+       RETRO_DEVICE_INDEX_ANALOG_BUTTON,
+       id);
+   button = MIN(button / 128, 255);
+
+   if (button == 0)
+   {
+      // If we got exactly zero, we're either not pressing the button, or the front-end
+      // is not reporting analog values. We need to do a second check using the classic
+      // digital API method, to at least get some response - better than nothing.
 
-       input_poll_cb();
+      // NOTE: If we're really just not holding the button, we're still going to get zero.
 
-       bool updated = false;
-       if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
-               update_variables(true);
+      button = (ret & (1 << id)) ? 255 : 0;
+   }
 
-       in_keystate = 0;
-       for (i = 0; i < RETRO_PSX_MAP_LEN; i++)
-               if (input_state_cb(1, RETRO_DEVICE_JOYPAD, 0, i))
-                       in_keystate |= retro_psx_map[i];
-       in_keystate <<= 16;
-       for (i = 0; i < RETRO_PSX_MAP_LEN; i++)
-               if (input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, i))
-                       in_keystate |= retro_psx_map[i];
+   return button;
+}
 
-       if (in_type1 == PSE_PAD_TYPE_ANALOGPAD)
-       {
-               in_a1[0] = (input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X) / 256) + 128;
-               in_a1[1] = (input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y) / 256) + 128;
-               in_a2[0] = (input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X) / 256) + 128;
-               in_a2[1] = (input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y) / 256) + 128;
-       }
+unsigned char axis_range_modifier(int16_t axis_value, bool is_square)
+{
+   float modifier_axis_range = 0;
 
-       stop = 0;
-       psxCpu->Execute();
+   if (is_square)
+   {
+      modifier_axis_range = round((axis_value >> 8) / 0.785) + 128;
+      if (modifier_axis_range < 0)
+      {
+         modifier_axis_range = 0;
+      }
+      else if (modifier_axis_range > 255)
+      {
+         modifier_axis_range = 255;
+      }
+   }
+   else
+   {
+      modifier_axis_range = MIN(((axis_value >> 8) + 128), 255);
+   }
 
-       video_cb((vout_fb_dirty || !vout_can_dupe || !duping_enable) ? vout_buf : NULL,
-               vout_width, vout_height, vout_width * 2);
-       vout_fb_dirty = 0;
+   return modifier_axis_range;
 }
 
-static bool try_use_bios(const char *path)
+static void update_input_guncon(int port, int ret)
 {
-       FILE *f;
-       long size;
-       const char *name;
+   //ToDo move across to:
+   //RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X
+   //RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y
+   //RETRO_DEVICE_ID_LIGHTGUN_TRIGGER
+   //RETRO_DEVICE_ID_LIGHTGUN_RELOAD
+   //RETRO_DEVICE_ID_LIGHTGUN_AUX_A
+   //RETRO_DEVICE_ID_LIGHTGUN_AUX_B
+   //Though not sure these are hooked up properly on the Pi
+
+   //GUNCON has 3 controls, Trigger,A,B which equal Circle,Start,Cross
+
+   // Trigger
+   //The 1 is hardcoded instead of port to prevent the overlay mouse button libretro crash bug
+   if (input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT))
+   {
+      in_keystate[port] |= (1 << DKEY_CIRCLE);
+   }
 
-       f = fopen(path, "rb");
-       if (f == NULL)
-               return false;
+   // A
+   if (input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT))
+   {
+      in_keystate[port] |= (1 << DKEY_START);
+   }
 
-       fseek(f, 0, SEEK_END);
-       size = ftell(f);
-       fclose(f);
+   // B
+   if (input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_MIDDLE))
+   {
+      in_keystate[port] |= (1 << DKEY_CROSS);
+   }
 
-       if (size != 512 * 1024)
-               return false;
+   int gunx = input_state_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
+   int guny = input_state_cb(port, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
 
-       name = strrchr(path, SLASH);
-       if (name++ == NULL)
-               name = path;
-       snprintf(Config.Bios, sizeof(Config.Bios), "%s", name);
-       return true;
+   //Mouse range is -32767 -> 32767
+   //1% is about 655
+   //Use the left analog stick field to store the absolute coordinates
+   in_analog_left[port][0] = (gunx * GunconAdjustRatioX) + (GunconAdjustX * 655);
+   in_analog_left[port][1] = (guny * GunconAdjustRatioY) + (GunconAdjustY * 655);
 }
 
-#if 1
+static void update_input_negcon(int port, int ret)
+{
+   int lsx;
+   int rsy;
+   int negcon_i_rs;
+   int negcon_ii_rs;
+   float negcon_twist_amplitude;
+
+   // Query digital inputs
+   //
+   // > Pad-Up
+   if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_UP))
+      in_keystate[port] |= (1 << DKEY_UP);
+   // > Pad-Right
+   if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_RIGHT))
+      in_keystate[port] |= (1 << DKEY_RIGHT);
+   // > Pad-Down
+   if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_DOWN))
+      in_keystate[port] |= (1 << DKEY_DOWN);
+   // > Pad-Left
+   if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_LEFT))
+      in_keystate[port] |= (1 << DKEY_LEFT);
+   // > Start
+   if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_START))
+      in_keystate[port] |= (1 << DKEY_START);
+   // > neGcon A
+   if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_A))
+      in_keystate[port] |= (1 << DKEY_CIRCLE);
+   // > neGcon B
+   if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_X))
+      in_keystate[port] |= (1 << DKEY_TRIANGLE);
+   // > neGcon R shoulder (digital)
+   if (ret & (1 << RETRO_DEVICE_ID_JOYPAD_R))
+      in_keystate[port] |= (1 << DKEY_R1);
+   // Query analog inputs
+   //
+   // From studying 'libpcsxcore/plugins.c' and 'frontend/plugin.c':
+   // >> pad->leftJoyX  == in_analog_left[port][0]  == NeGcon II
+   // >> pad->leftJoyY  == in_analog_left[port][1]  == NeGcon L
+   // >> pad->rightJoyX == in_analog_right[port][0] == NeGcon twist
+   // >> pad->rightJoyY == in_analog_right[port][1] == NeGcon I
+   // So we just have to map in_analog_left/right to more
+   // appropriate inputs...
+   //
+   // > NeGcon twist
+   // >> Get raw analog stick value and account for deadzone
+   lsx = input_state_cb(port, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X);
+   if (lsx > negcon_deadzone)
+      lsx = lsx - negcon_deadzone;
+   else if (lsx < -negcon_deadzone)
+      lsx = lsx + negcon_deadzone;
+   else
+      lsx = 0;
+   // >> Convert to an 'amplitude' [-1.0,1.0] and adjust response
+   negcon_twist_amplitude = (float)lsx / (float)(NEGCON_RANGE - negcon_deadzone);
+   if (negcon_linearity == 2)
+   {
+      if (negcon_twist_amplitude < 0.0)
+         negcon_twist_amplitude = -(negcon_twist_amplitude * negcon_twist_amplitude);
+      else
+         negcon_twist_amplitude = negcon_twist_amplitude * negcon_twist_amplitude;
+   }
+   else if (negcon_linearity == 3)
+      negcon_twist_amplitude = negcon_twist_amplitude * negcon_twist_amplitude * negcon_twist_amplitude;
+   // >> Convert to final 'in_analog' integer value [0,255]
+   in_analog_right[port][0] = MAX(MIN((int)(negcon_twist_amplitude * 128.0f) + 128, 255), 0);
+   // > NeGcon I + II
+   // >> Handle right analog stick vertical axis mapping...
+   //    - Up (-Y) == accelerate == neGcon I
+   //    - Down (+Y) == brake == neGcon II
+   negcon_i_rs = 0;
+   negcon_ii_rs = 0;
+   rsy = input_state_cb(port, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y);
+   if (rsy >= 0)
+   {
+      // Account for deadzone
+      // (Note: have never encountered a gamepad with significant differences
+      // in deadzone between left/right analog sticks, so use the regular 'twist'
+      // deadzone here)
+      if (rsy > negcon_deadzone)
+         rsy = rsy - negcon_deadzone;
+      else
+         rsy = 0;
+      // Convert to 'in_analog' integer value [0,255]
+      negcon_ii_rs = MIN((int)(((float)rsy / (float)(NEGCON_RANGE - negcon_deadzone)) * 255.0f), 255);
+   }
+   else
+   {
+      if (rsy < -negcon_deadzone)
+         rsy = -1 * (rsy + negcon_deadzone);
+      else
+         rsy = 0;
+      negcon_i_rs = MIN((int)(((float)rsy / (float)(NEGCON_RANGE - negcon_deadzone)) * 255.0f), 255);
+   }
+   // >> NeGcon I
+   in_analog_right[port][1] = MAX(
+       MAX(
+           get_analog_button(ret, input_state_cb, port, RETRO_DEVICE_ID_JOYPAD_R2),
+           get_analog_button(ret, input_state_cb, port, RETRO_DEVICE_ID_JOYPAD_B)),
+       negcon_i_rs);
+   // >> NeGcon II
+   in_analog_left[port][0] = MAX(
+       MAX(
+           get_analog_button(ret, input_state_cb, port, RETRO_DEVICE_ID_JOYPAD_L2),
+           get_analog_button(ret, input_state_cb, port, RETRO_DEVICE_ID_JOYPAD_Y)),
+       negcon_ii_rs);
+   // > NeGcon L
+   in_analog_left[port][1] = get_analog_button(ret, input_state_cb, port, RETRO_DEVICE_ID_JOYPAD_L);
+}
+
+static void update_input_mouse(int port, int ret)
+{
+   float raw_x = input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
+   float raw_y = input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
+
+   int x = (int)roundf(raw_x * mouse_sensitivity);
+   int y = (int)roundf(raw_y * mouse_sensitivity);
+
+   if (x > 127) x = 127;
+   else if (x < -128) x = -128;
+
+   if (y > 127) y = 127;
+   else if (y < -128) y = -128;
+
+   in_mouse[port][0] = x; /* -128..+128 left/right movement, 0 = no movement */
+   in_mouse[port][1] = y; /* -128..+128 down/up movement, 0 = no movement    */
+
+   /* left mouse button state */
+   if (input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT))
+      in_keystate[port] |= 1 << 11;
+
+   /* right mouse button state */
+   if (input_state_cb(port, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT))
+      in_keystate[port] |= 1 << 10;
+}
+
+static void update_input(void)
+{
+   // reset all keystate, query libretro for keystate
+   int i;
+   int j;
+
+   for (i = 0; i < PORTS_NUMBER; i++)
+   {
+      int16_t ret = 0;
+      int type = in_type[i];
+
+      in_keystate[i] = 0;
+
+      if (type == PSE_PAD_TYPE_NONE)
+         continue;
+
+      if (libretro_supports_bitmasks)
+         ret = input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK);
+      else
+      {
+         for (j = 0; j < (RETRO_DEVICE_ID_JOYPAD_R3 + 1); j++)
+         {
+            if (input_state_cb(i, RETRO_DEVICE_JOYPAD, 0, j))
+               ret |= (1 << j);
+         }
+      }
+
+      switch (type)
+      {
+      case PSE_PAD_TYPE_GUNCON:
+         update_input_guncon(i, ret);
+         break;
+      case PSE_PAD_TYPE_NEGCON:
+         update_input_negcon(i, ret);
+         break;
+      case PSE_PAD_TYPE_MOUSE:
+         update_input_mouse(i, ret);
+         break;      
+      default:
+         // Query digital inputs
+         for (j = 0; j < RETRO_PSX_MAP_LEN; j++)
+            if (ret & (1 << j))
+               in_keystate[i] |= retro_psx_map[j];
+
+         // Query analog inputs
+         if (type == PSE_PAD_TYPE_ANALOGJOY || type == PSE_PAD_TYPE_ANALOGPAD)
+         {
+            in_analog_left[i][0]  = axis_range_modifier(input_state_cb(i, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X), axis_bounds_modifier);
+            in_analog_left[i][1]  = axis_range_modifier(input_state_cb(i, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y), axis_bounds_modifier);
+            in_analog_right[i][0] = axis_range_modifier(input_state_cb(i, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X), axis_bounds_modifier);
+            in_analog_right[i][1] = axis_range_modifier(input_state_cb(i, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y), axis_bounds_modifier);
+         }
+      }
+   }
+}
+
+static void print_internal_fps(void)
+{
+   if (display_internal_fps)
+   {
+      frame_count++;
+
+      if (frame_count % INTERNAL_FPS_SAMPLE_PERIOD == 0)
+      {
+         unsigned internal_fps = pl_rearmed_cbs.flip_cnt * (is_pal_mode ? 50 : 60) / INTERNAL_FPS_SAMPLE_PERIOD;
+         char str[64];
+         const char *strc = (const char *)str;
+
+         str[0] = '\0';
+
+         snprintf(str, sizeof(str), "Internal FPS: %2d", internal_fps);
+
+         pl_rearmed_cbs.flip_cnt = 0;
+
+         if (msg_interface_version >= 1)
+         {
+            struct retro_message_ext msg = {
+               strc,
+               3000,
+               1,
+               RETRO_LOG_INFO,
+               RETRO_MESSAGE_TARGET_OSD,
+               RETRO_MESSAGE_TYPE_STATUS,
+               -1
+            };
+            environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE_EXT, &msg);
+         }
+         else
+         {
+            struct retro_message msg = {
+               strc,
+               180
+            };
+            environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
+         }
+      }
+   }
+   else
+      frame_count = 0;
+}
+
+void retro_run(void)
+{
+   //SysReset must be run while core is running,Not in menu (Locks up Retroarch)
+   if (rebootemu != 0)
+   {
+      rebootemu = 0;
+      SysReset();
+      if (!Config.HLE && !Config.SlowBoot)
+      {
+         // skip BIOS logos
+         psxRegs.pc = psxRegs.GPR.n.ra;
+      }
+      return;
+   }
+
+   print_internal_fps();
+
+   input_poll_cb();
+
+   update_input();
+
+   bool updated = false;
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
+      update_variables(true);
+
+   stop = 0;
+   psxCpu->Execute();
+
+   video_cb((vout_fb_dirty || !vout_can_dupe || !duping_enable) ? vout_buf_ptr : NULL,
+       vout_width, vout_height, vout_width * 2);
+   vout_fb_dirty = 0;
+
+   set_vout_fb();
+}
+
+static bool try_use_bios(const char *path)
+{
+   long size;
+   const char *name;
+   FILE *fp = fopen(path, "rb");
+   if (fp == NULL)
+      return false;
+
+   fseek(fp, 0, SEEK_END);
+   size = ftell(fp);
+   fclose(fp);
+
+   if (size != 512 * 1024)
+      return false;
+
+   name = strrchr(path, SLASH);
+   if (name++ == NULL)
+      name = path;
+   snprintf(Config.Bios, sizeof(Config.Bios), "%s", name);
+   return true;
+}
+
+#ifndef VITA
 #include <sys/types.h>
 #include <dirent.h>
 
 static bool find_any_bios(const char *dirpath, char *path, size_t path_size)
 {
-       DIR *dir;
-       struct dirent *ent;
-       bool ret = false;
+   DIR *dir;
+   struct dirent *ent;
+   bool ret = false;
 
-       dir = opendir(dirpath);
-       if (dir == NULL)
-               return false;
+   dir = opendir(dirpath);
+   if (dir == NULL)
+      return false;
 
-       while ((ent = readdir(dir))) {
-               if (strncasecmp(ent->d_name, "scph", 4) != 0)
-                       continue;
+   while ((ent = readdir(dir)))
+   {
+      if ((strncasecmp(ent->d_name, "scph", 4) != 0) && (strncasecmp(ent->d_name, "psx", 3) != 0))
+         continue;
 
-               snprintf(path, path_size, "%s/%s", dirpath, ent->d_name);
-               ret = try_use_bios(path);
-               if (ret)
-                       break;
-       }
-       closedir(dir);
-       return ret;
+      snprintf(path, path_size, "%s%c%s", dirpath, SLASH, ent->d_name);
+      ret = try_use_bios(path);
+      if (ret)
+         break;
+   }
+   closedir(dir);
+   return ret;
 }
 #else
 #define find_any_bios(...) false
@@ -1198,91 +2585,286 @@ static void check_system_specs(void)
    environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
 }
 
+static int init_memcards(void)
+{
+   int ret = 0;
+   const char *dir;
+   struct retro_variable var = { .key = "pcsx_rearmed_memcard2", .value = NULL };
+   static const char CARD2_FILE[] = "pcsx-card2.mcd";
+
+   // Memcard2 will be handled and is re-enabled if needed using core
+   // operations.
+   // Memcard1 is handled by libretro, doing this will set core to
+   // skip file io operations for memcard1 like SaveMcd
+   snprintf(Config.Mcd1, sizeof(Config.Mcd1), "none");
+   snprintf(Config.Mcd2, sizeof(Config.Mcd2), "none");
+   init_memcard(Mcd1Data);
+   // Memcard 2 is managed by the emulator on the filesystem,
+   // There is no need to initialize Mcd2Data like Mcd1Data.
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      SysPrintf("Memcard 2: %s\n", var.value);
+      if (memcmp(var.value, "enabled", 7) == 0)
+      {
+         if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &dir) && dir)
+         {
+            if (strlen(dir) + strlen(CARD2_FILE) + 2 > sizeof(Config.Mcd2))
+            {
+               SysPrintf("Path '%s' is too long. Cannot use memcard 2. Use a shorter path.\n", dir);
+               ret = -1;
+            }
+            else
+            {
+               McdDisable[1] = 0;
+               snprintf(Config.Mcd2, sizeof(Config.Mcd2), "%s/%s", dir, CARD2_FILE);
+               SysPrintf("Use memcard 2: %s\n", Config.Mcd2);
+            }
+         }
+         else
+         {
+            SysPrintf("Could not get save directory! Could not create memcard 2.");
+            ret = -1;
+         }
+      }
+   }
+   return ret;
+}
+
+static void loadPSXBios(void)
+{
+   const char *dir;
+   char path[PATH_MAX];
+   unsigned useHLE = 0;
+
+   const char *bios[] = {
+      "PS1_ROM", "ps1_rom",
+      "PSXONPSP660", "psxonpsp660",
+      "SCPH101", "scph101",
+      "SCPH5501", "scph5501",
+      "SCPH7001", "scph7001",
+      "SCPH1001", "scph1001"
+   };
+
+   struct retro_variable var = {
+      .key = "pcsx_rearmed_bios",
+      .value = NULL
+   };
+
+   found_bios = 0;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+   {
+      if (!strcmp(var.value, "HLE"))
+         useHLE = 1;
+   }
+
+   if (!useHLE)
+   {
+      if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir)
+      {
+         unsigned i;
+         snprintf(Config.BiosDir, sizeof(Config.BiosDir), "%s", dir);
+
+         for (i = 0; i < sizeof(bios) / sizeof(bios[0]); i++)
+         {
+            snprintf(path, sizeof(path), "%s%c%s.bin", dir, SLASH, bios[i]);
+            found_bios = try_use_bios(path);
+            if (found_bios)
+               break;
+         }
+
+         if (!found_bios)
+            found_bios = find_any_bios(dir, path, sizeof(path));
+      }
+      if (found_bios)
+      {
+         SysPrintf("found BIOS file: %s\n", Config.Bios);
+      }
+   }
+
+   if (!found_bios)
+   {
+      const char *msg_str;
+      if (useHLE)
+      {
+         msg_str = "BIOS set to \'hle\' in core options - real BIOS will be ignored";
+         SysPrintf("Using HLE BIOS.\n");
+      }
+      else
+      {
+         msg_str = "No PlayStation BIOS file found - add for better compatibility";
+         SysPrintf("No BIOS files found.\n");
+      }
+
+      if (msg_interface_version >= 1)
+      {
+         struct retro_message_ext msg = {
+            msg_str,
+            3000,
+            3,
+            RETRO_LOG_WARN,
+            RETRO_MESSAGE_TARGET_ALL,
+            RETRO_MESSAGE_TYPE_NOTIFICATION,
+            -1
+         };
+         environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE_EXT, &msg);
+      }
+      else
+      {
+         struct retro_message msg = {
+            msg_str,
+            180
+         };
+         environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
+      }
+   }
+}
+
 void retro_init(void)
 {
-       const char *bios[] = { "scph1001", "scph5501", "scph7001" };
-       const char *dir;
-       char path[256];
-       int i, ret;
-       bool found_bios = false;
+   unsigned dci_version = 0;
+   struct retro_rumble_interface rumble;
+   int ret;
 
-#ifdef __MACH__
-       // magic sauce to make the dynarec work on iOS
-       syscall(SYS_ptrace, 0 /*PTRACE_TRACEME*/, 0, 0, 0);
+   msg_interface_version = 0;
+   environ_cb(RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION, &msg_interface_version);
+
+#if defined(__MACH__) && !defined(TVOS)
+   // magic sauce to make the dynarec work on iOS
+   syscall(SYS_ptrace, 0 /*PTRACE_TRACEME*/, 0, 0, 0);
 #endif
 
-       ret = emu_core_preinit();
-       ret |= emu_core_init();
-       if (ret != 0) {
-               SysPrintf("PCSX init failed.\n");
-               exit(1);
-       }
+#ifdef _3DS
+   psxMapHook = pl_3ds_mmap;
+   psxUnmapHook = pl_3ds_munmap;
+#endif
+#ifdef VITA
+   if (init_vita_mmap() < 0)
+      abort();
+   psxMapHook = pl_vita_mmap;
+   psxUnmapHook = pl_vita_munmap;
+#endif
+   ret = emu_core_preinit();
+#ifdef _3DS
+   /* emu_core_preinit sets the cpu to dynarec */
+   if (!__ctr_svchax)
+      Config.Cpu = CPU_INTERPRETER;
+#endif
+   ret |= init_memcards();
 
-#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)
-       posix_memalign(&vout_buf, 16, VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
+   ret |= emu_core_init();
+   if (ret != 0)
+   {
+      SysPrintf("PCSX init failed.\n");
+      exit(1);
+   }
+
+#ifdef _3DS
+   vout_buf = linearMemAlign(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2, 0x80);
+#elif defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L) && !defined(VITA) && !defined(__SWITCH__)
+   if (posix_memalign(&vout_buf, 16, VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2) != 0)
+      vout_buf = (void *) 0;
 #else
-       vout_buf = malloc(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
+   vout_buf = malloc(VOUT_MAX_WIDTH * VOUT_MAX_HEIGHT * 2);
 #endif
 
-       if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir)
-       {
-               snprintf(Config.BiosDir, sizeof(Config.BiosDir), "%s/", dir);
-
-               for (i = 0; i < sizeof(bios) / sizeof(bios[0]); i++) {
-                       snprintf(path, sizeof(path), "%s/%s.bin", dir, bios[i]);
-                       found_bios = try_use_bios(path);
-                       if (found_bios)
-                               break;
-               }
-
-               if (!found_bios)
-                       found_bios = find_any_bios(dir, path, sizeof(path));
-       }
-       if (found_bios) {
-               SysPrintf("found BIOS file: %s\n", Config.Bios);
-       }
-       else
-       {
-               SysPrintf("no BIOS files found.\n");
-               struct retro_message msg = 
-               {
-                       "no BIOS found, expect bugs!",
-                       180
-               };
-               environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, (void*)&msg);
-       }
-
-       environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &vout_can_dupe);
-       environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &disk_control);
-       environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble);
-
-       /* Set how much slower PSX CPU runs * 100 (so that 200 is 2 times)
-        * we have to do this because cache misses and some IO penalties
-        * are not emulated. Warning: changing this may break compatibility. */
-       cycle_multiplier = 175;
-#ifdef HAVE_PRE_ARMV7
-       cycle_multiplier = 200;
+   vout_buf_ptr = vout_buf;
+
+   loadPSXBios();
+
+   environ_cb(RETRO_ENVIRONMENT_GET_CAN_DUPE, &vout_can_dupe);
+
+   disk_initial_index = 0;
+   disk_initial_path[0] = '\0';
+   if (environ_cb(RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION, &dci_version) && (dci_version >= 1))
+      environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE, &disk_control_ext);
+   else
+      environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &disk_control);
+
+   rumble_cb = NULL;
+   if (environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble))
+      rumble_cb = rumble.set_rumble_state;
+
+   /* Set how much slower PSX CPU runs * 100 (so that 200 is 2 times)
+    * we have to do this because cache misses and some IO penalties
+    * are not emulated. Warning: changing this may break compatibility. */
+   cycle_multiplier = 175;
+#if defined(HAVE_PRE_ARMV7) && !defined(_3DS)
+   cycle_multiplier = 200;
 #endif
-       pl_rearmed_cbs.gpu_peops.iUseDither = 1;
-       spu_config.iUseFixedUpdates = 1;
+   pl_rearmed_cbs.gpu_peops.iUseDither = 1;
+   pl_rearmed_cbs.gpu_peops.dwActFixes = GPU_PEOPS_OLD_FRAME_SKIP;
+   spu_config.iUseFixedUpdates = 1;
 
-       McdDisable[0] = 0;
-       McdDisable[1] = 1;
-       init_memcard(Mcd1Data);
+   SaveFuncs.open = save_open;
+   SaveFuncs.read = save_read;
+   SaveFuncs.write = save_write;
+   SaveFuncs.seek = save_seek;
+   SaveFuncs.close = save_close;
 
-       SaveFuncs.open = save_open;
-       SaveFuncs.read = save_read;
-       SaveFuncs.write = save_write;
-       SaveFuncs.seek = save_seek;
-       SaveFuncs.close = save_close;
+   if (environ_cb(RETRO_ENVIRONMENT_GET_INPUT_BITMASKS, NULL))
+      libretro_supports_bitmasks = true;
 
-       update_variables(false);
-       check_system_specs();
+   check_system_specs();
 }
 
 void retro_deinit(void)
 {
-       SysClose();
-       free(vout_buf);
-       vout_buf = NULL;
+   if (plugins_opened)
+   {
+      ClosePlugins();
+      plugins_opened = 0;
+   }
+   SysClose();
+#ifdef _3DS
+   linearFree(vout_buf);
+#else
+   free(vout_buf);
+#endif
+   vout_buf = NULL;
+
+#ifdef VITA
+   deinit_vita_mmap();
+#endif
+   libretro_supports_bitmasks = false;
+
+   /* Have to reset disks struct, otherwise
+    * fnames/flabels will leak memory */
+   disk_init();
+}
+
+#ifdef VITA
+#include <psp2/kernel/threadmgr.h>
+int usleep(unsigned long us)
+{
+   sceKernelDelayThread(us);
+}
+#endif
+
+void SysPrintf(const char *fmt, ...)
+{
+   va_list list;
+   char msg[512];
+
+   va_start(list, fmt);
+   vsprintf(msg, fmt, list);
+   va_end(list);
+
+   if (log_cb)
+      log_cb(RETRO_LOG_INFO, "%s", msg);
+}
+
+/* Prints debug-level logs */
+void SysDLog(const char *fmt, ...)
+{
+   va_list list;
+   char msg[512];
+
+   va_start(list, fmt);
+   vsprintf(msg, fmt, list);
+   va_end(list);
+
+   if (log_cb)
+      log_cb(RETRO_LOG_DEBUG, "%s", msg);
 }
diff --git a/frontend/libretro.h b/frontend/libretro.h
deleted file mode 100755 (executable)
index 16c274a..0000000
+++ /dev/null
@@ -1,1926 +0,0 @@
-/* Copyright (C) 2010-2014 The RetroArch team
- *
- * ---------------------------------------------------------------------------------------
- * The following license statement only applies to this libretro API header (libretro.h).
- * ---------------------------------------------------------------------------------------
- *
- * Permission is hereby granted, free of charge,
- * to any person obtaining a copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
- * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#ifndef LIBRETRO_H__
-#define LIBRETRO_H__
-
-#include <stdint.h>
-#include <stddef.h>
-#include <limits.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef __cplusplus
-#if defined(_MSC_VER) && !defined(SN_TARGET_PS3)
-/* Hack applied for MSVC when compiling in C89 mode
- * as it isn't C99-compliant. */
-#define bool unsigned char
-#define true 1
-#define false 0
-#else
-#include <stdbool.h>
-#endif
-#endif
-
-/* Used for checking API/ABI mismatches that can break libretro 
- * implementations.
- * It is not incremented for compatible changes to the API.
- */
-#define RETRO_API_VERSION         1
-
-/*
- * Libretro's fundamental device abstractions.
- *
- * Libretro's input system consists of some standardized device types,
- * such as a joypad (with/without analog), mouse, keyboard, lightgun 
- * and a pointer.
- *
- * The functionality of these devices are fixed, and individual cores 
- * map their own concept of a controller to libretro's abstractions.
- * This makes it possible for frontends to map the abstract types to a 
- * real input device, and not having to worry about binding input 
- * correctly to arbitrary controller layouts.
- */
-
-#define RETRO_DEVICE_TYPE_SHIFT         8
-#define RETRO_DEVICE_MASK               ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1)
-#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base)
-
-/* Input disabled. */
-#define RETRO_DEVICE_NONE         0
-
-/* The JOYPAD is called RetroPad. It is essentially a Super Nintendo 
- * controller, but with additional L2/R2/L3/R3 buttons, similar to a 
- * PS1 DualShock. */
-#define RETRO_DEVICE_JOYPAD       1
-
-/* The mouse is a simple mouse, similar to Super Nintendo's mouse.
- * X and Y coordinates are reported relatively to last poll (poll callback).
- * It is up to the libretro implementation to keep track of where the mouse 
- * pointer is supposed to be on the screen.
- * The frontend must make sure not to interfere with its own hardware 
- * mouse pointer.
- */
-#define RETRO_DEVICE_MOUSE        2
-
-/* KEYBOARD device lets one poll for raw key pressed.
- * It is poll based, so input callback will return with the current 
- * pressed state.
- * For event/text based keyboard input, see
- * RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
- */
-#define RETRO_DEVICE_KEYBOARD     3
-
-/* Lightgun X/Y coordinates are reported relatively to last poll,
- * similar to mouse. */
-#define RETRO_DEVICE_LIGHTGUN     4
-
-/* The ANALOG device is an extension to JOYPAD (RetroPad).
- * Similar to DualShock it adds two analog sticks.
- * This is treated as a separate device type as it returns values in the 
- * full analog range of [-0x8000, 0x7fff]. Positive X axis is right.
- * Positive Y axis is down.
- * Only use ANALOG type when polling for analog values of the axes.
- */
-#define RETRO_DEVICE_ANALOG       5
-
-/* Abstracts the concept of a pointing mechanism, e.g. touch.
- * This allows libretro to query in absolute coordinates where on the 
- * screen a mouse (or something similar) is being placed.
- * For a touch centric device, coordinates reported are the coordinates
- * of the press.
- *
- * Coordinates in X and Y are reported as:
- * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
- * and 0x7fff corresponds to the far right/bottom of the screen.
- * The "screen" is here defined as area that is passed to the frontend and 
- * later displayed on the monitor.
- *
- * The frontend is free to scale/resize this screen as it sees fit, however,
- * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the 
- * game image, etc.
- *
- * To check if the pointer coordinates are valid (e.g. a touch display 
- * actually being touched), PRESSED returns 1 or 0.
- *
- * If using a mouse on a desktop, PRESSED will usually correspond to the 
- * left mouse button, but this is a frontend decision.
- * PRESSED will only return 1 if the pointer is inside the game screen.
- *
- * For multi-touch, the index variable can be used to successively query 
- * more presses.
- * If index = 0 returns true for _PRESSED, coordinates can be extracted
- * with _X, _Y for index = 0. One can then query _PRESSED, _X, _Y with 
- * index = 1, and so on.
- * Eventually _PRESSED will return false for an index. No further presses 
- * are registered at this point. */
-#define RETRO_DEVICE_POINTER      6
-
-/* Buttons for the RetroPad (JOYPAD).
- * The placement of these is equivalent to placements on the 
- * Super Nintendo controller.
- * L2/R2/L3/R3 buttons correspond to the PS1 DualShock. */
-#define RETRO_DEVICE_ID_JOYPAD_B        0
-#define RETRO_DEVICE_ID_JOYPAD_Y        1
-#define RETRO_DEVICE_ID_JOYPAD_SELECT   2
-#define RETRO_DEVICE_ID_JOYPAD_START    3
-#define RETRO_DEVICE_ID_JOYPAD_UP       4
-#define RETRO_DEVICE_ID_JOYPAD_DOWN     5
-#define RETRO_DEVICE_ID_JOYPAD_LEFT     6
-#define RETRO_DEVICE_ID_JOYPAD_RIGHT    7
-#define RETRO_DEVICE_ID_JOYPAD_A        8
-#define RETRO_DEVICE_ID_JOYPAD_X        9
-#define RETRO_DEVICE_ID_JOYPAD_L       10
-#define RETRO_DEVICE_ID_JOYPAD_R       11
-#define RETRO_DEVICE_ID_JOYPAD_L2      12
-#define RETRO_DEVICE_ID_JOYPAD_R2      13
-#define RETRO_DEVICE_ID_JOYPAD_L3      14
-#define RETRO_DEVICE_ID_JOYPAD_R3      15
-
-/* Index / Id values for ANALOG device. */
-#define RETRO_DEVICE_INDEX_ANALOG_LEFT   0
-#define RETRO_DEVICE_INDEX_ANALOG_RIGHT  1
-#define RETRO_DEVICE_ID_ANALOG_X         0
-#define RETRO_DEVICE_ID_ANALOG_Y         1
-
-/* Id values for MOUSE. */
-#define RETRO_DEVICE_ID_MOUSE_X          0
-#define RETRO_DEVICE_ID_MOUSE_Y          1
-#define RETRO_DEVICE_ID_MOUSE_LEFT       2
-#define RETRO_DEVICE_ID_MOUSE_RIGHT      3
-#define RETRO_DEVICE_ID_MOUSE_WHEELUP    4
-#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN  5
-#define RETRO_DEVICE_ID_MOUSE_MIDDLE     6
-
-/* Id values for LIGHTGUN types. */
-#define RETRO_DEVICE_ID_LIGHTGUN_X        0
-#define RETRO_DEVICE_ID_LIGHTGUN_Y        1
-#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER  2
-#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR   3
-#define RETRO_DEVICE_ID_LIGHTGUN_TURBO    4
-#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE    5
-#define RETRO_DEVICE_ID_LIGHTGUN_START    6
-
-/* Id values for POINTER. */
-#define RETRO_DEVICE_ID_POINTER_X         0
-#define RETRO_DEVICE_ID_POINTER_Y         1
-#define RETRO_DEVICE_ID_POINTER_PRESSED   2
-
-/* Returned from retro_get_region(). */
-#define RETRO_REGION_NTSC  0
-#define RETRO_REGION_PAL   1
-
-/* Id values for LANGUAGE */
-enum retro_language
-{
-   RETRO_LANGUAGE_ENGLISH             =  0,
-   RETRO_LANGUAGE_JAPANESE            =  1,
-   RETRO_LANGUAGE_FRENCH              =  2,
-   RETRO_LANGUAGE_SPANISH             =  3,
-   RETRO_LANGUAGE_GERMAN              =  4,
-   RETRO_LANGUAGE_ITALIAN             =  5,
-   RETRO_LANGUAGE_DUTCH               =  6,
-   RETRO_LANGUAGE_PORTUGUESE          =  7,
-   RETRO_LANGUAGE_RUSSIAN             =  8,
-   RETRO_LANGUAGE_KOREAN              =  9,
-   RETRO_LANGUAGE_CHINESE_TRADITIONAL = 10,
-   RETRO_LANGUAGE_CHINESE_SIMPLIFIED  = 11,
-   RETRO_LANGUAGE_LAST,
-
-   /* Ensure sizeof(enum) == sizeof(int) */
-   RETRO_LANGUAGE_DUMMY          = INT_MAX 
-};
-
-/* Passed to retro_get_memory_data/size().
- * If the memory type doesn't apply to the 
- * implementation NULL/0 can be returned.
- */
-#define RETRO_MEMORY_MASK        0xff
-
-/* Regular save RAM. This RAM is usually found on a game cartridge,
- * backed up by a battery.
- * If save game data is too complex for a single memory buffer,
- * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment
- * callback can be used. */
-#define RETRO_MEMORY_SAVE_RAM    0
-
-/* Some games have a built-in clock to keep track of time.
- * This memory is usually just a couple of bytes to keep track of time.
- */
-#define RETRO_MEMORY_RTC         1
-
-/* System ram lets a frontend peek into a game systems main RAM. */
-#define RETRO_MEMORY_SYSTEM_RAM  2
-
-/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */
-#define RETRO_MEMORY_VIDEO_RAM   3
-
-/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */
-enum retro_key
-{
-   RETROK_UNKNOWN        = 0,
-   RETROK_FIRST          = 0,
-   RETROK_BACKSPACE      = 8,
-   RETROK_TAB            = 9,
-   RETROK_CLEAR          = 12,
-   RETROK_RETURN         = 13,
-   RETROK_PAUSE          = 19,
-   RETROK_ESCAPE         = 27,
-   RETROK_SPACE          = 32,
-   RETROK_EXCLAIM        = 33,
-   RETROK_QUOTEDBL       = 34,
-   RETROK_HASH           = 35,
-   RETROK_DOLLAR         = 36,
-   RETROK_AMPERSAND      = 38,
-   RETROK_QUOTE          = 39,
-   RETROK_LEFTPAREN      = 40,
-   RETROK_RIGHTPAREN     = 41,
-   RETROK_ASTERISK       = 42,
-   RETROK_PLUS           = 43,
-   RETROK_COMMA          = 44,
-   RETROK_MINUS          = 45,
-   RETROK_PERIOD         = 46,
-   RETROK_SLASH          = 47,
-   RETROK_0              = 48,
-   RETROK_1              = 49,
-   RETROK_2              = 50,
-   RETROK_3              = 51,
-   RETROK_4              = 52,
-   RETROK_5              = 53,
-   RETROK_6              = 54,
-   RETROK_7              = 55,
-   RETROK_8              = 56,
-   RETROK_9              = 57,
-   RETROK_COLON          = 58,
-   RETROK_SEMICOLON      = 59,
-   RETROK_LESS           = 60,
-   RETROK_EQUALS         = 61,
-   RETROK_GREATER        = 62,
-   RETROK_QUESTION       = 63,
-   RETROK_AT             = 64,
-   RETROK_LEFTBRACKET    = 91,
-   RETROK_BACKSLASH      = 92,
-   RETROK_RIGHTBRACKET   = 93,
-   RETROK_CARET          = 94,
-   RETROK_UNDERSCORE     = 95,
-   RETROK_BACKQUOTE      = 96,
-   RETROK_a              = 97,
-   RETROK_b              = 98,
-   RETROK_c              = 99,
-   RETROK_d              = 100,
-   RETROK_e              = 101,
-   RETROK_f              = 102,
-   RETROK_g              = 103,
-   RETROK_h              = 104,
-   RETROK_i              = 105,
-   RETROK_j              = 106,
-   RETROK_k              = 107,
-   RETROK_l              = 108,
-   RETROK_m              = 109,
-   RETROK_n              = 110,
-   RETROK_o              = 111,
-   RETROK_p              = 112,
-   RETROK_q              = 113,
-   RETROK_r              = 114,
-   RETROK_s              = 115,
-   RETROK_t              = 116,
-   RETROK_u              = 117,
-   RETROK_v              = 118,
-   RETROK_w              = 119,
-   RETROK_x              = 120,
-   RETROK_y              = 121,
-   RETROK_z              = 122,
-   RETROK_DELETE         = 127,
-
-   RETROK_KP0            = 256,
-   RETROK_KP1            = 257,
-   RETROK_KP2            = 258,
-   RETROK_KP3            = 259,
-   RETROK_KP4            = 260,
-   RETROK_KP5            = 261,
-   RETROK_KP6            = 262,
-   RETROK_KP7            = 263,
-   RETROK_KP8            = 264,
-   RETROK_KP9            = 265,
-   RETROK_KP_PERIOD      = 266,
-   RETROK_KP_DIVIDE      = 267,
-   RETROK_KP_MULTIPLY    = 268,
-   RETROK_KP_MINUS       = 269,
-   RETROK_KP_PLUS        = 270,
-   RETROK_KP_ENTER       = 271,
-   RETROK_KP_EQUALS      = 272,
-
-   RETROK_UP             = 273,
-   RETROK_DOWN           = 274,
-   RETROK_RIGHT          = 275,
-   RETROK_LEFT           = 276,
-   RETROK_INSERT         = 277,
-   RETROK_HOME           = 278,
-   RETROK_END            = 279,
-   RETROK_PAGEUP         = 280,
-   RETROK_PAGEDOWN       = 281,
-
-   RETROK_F1             = 282,
-   RETROK_F2             = 283,
-   RETROK_F3             = 284,
-   RETROK_F4             = 285,
-   RETROK_F5             = 286,
-   RETROK_F6             = 287,
-   RETROK_F7             = 288,
-   RETROK_F8             = 289,
-   RETROK_F9             = 290,
-   RETROK_F10            = 291,
-   RETROK_F11            = 292,
-   RETROK_F12            = 293,
-   RETROK_F13            = 294,
-   RETROK_F14            = 295,
-   RETROK_F15            = 296,
-
-   RETROK_NUMLOCK        = 300,
-   RETROK_CAPSLOCK       = 301,
-   RETROK_SCROLLOCK      = 302,
-   RETROK_RSHIFT         = 303,
-   RETROK_LSHIFT         = 304,
-   RETROK_RCTRL          = 305,
-   RETROK_LCTRL          = 306,
-   RETROK_RALT           = 307,
-   RETROK_LALT           = 308,
-   RETROK_RMETA          = 309,
-   RETROK_LMETA          = 310,
-   RETROK_LSUPER         = 311,
-   RETROK_RSUPER         = 312,
-   RETROK_MODE           = 313,
-   RETROK_COMPOSE        = 314,
-
-   RETROK_HELP           = 315,
-   RETROK_PRINT          = 316,
-   RETROK_SYSREQ         = 317,
-   RETROK_BREAK          = 318,
-   RETROK_MENU           = 319,
-   RETROK_POWER          = 320,
-   RETROK_EURO           = 321,
-   RETROK_UNDO           = 322,
-
-   RETROK_LAST,
-
-   RETROK_DUMMY          = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
-};
-
-enum retro_mod
-{
-   RETROKMOD_NONE       = 0x0000,
-
-   RETROKMOD_SHIFT      = 0x01,
-   RETROKMOD_CTRL       = 0x02,
-   RETROKMOD_ALT        = 0x04,
-   RETROKMOD_META       = 0x08,
-
-   RETROKMOD_NUMLOCK    = 0x10,
-   RETROKMOD_CAPSLOCK   = 0x20,
-   RETROKMOD_SCROLLOCK  = 0x40,
-
-   RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
-};
-
-/* If set, this call is not part of the public libretro API yet. It can 
- * change or be removed at any time. */
-#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000
-/* Environment callback to be used internally in frontend. */
-#define RETRO_ENVIRONMENT_PRIVATE 0x20000
-
-/* Environment commands. */
-#define RETRO_ENVIRONMENT_SET_ROTATION  1  /* const unsigned * --
-                                            * Sets screen rotation of graphics.
-                                            * Is only implemented if rotation can be accelerated by hardware.
-                                            * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180, 
-                                            * 270 degrees counter-clockwise respectively.
-                                            */
-#define RETRO_ENVIRONMENT_GET_OVERSCAN  2  /* bool * --
-                                            * Boolean value whether or not the implementation should use overscan, 
-                                            * or crop away overscan.
-                                            */
-#define RETRO_ENVIRONMENT_GET_CAN_DUPE  3  /* bool * --
-                                            * Boolean value whether or not frontend supports frame duping,
-                                            * passing NULL to video frame callback.
-                                            */
-
-                                           /* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES), 
-                                            * and reserved to avoid possible ABI clash.
-                                            */
-
-#define RETRO_ENVIRONMENT_SET_MESSAGE   6  /* const struct retro_message * --
-                                            * Sets a message to be displayed in implementation-specific manner 
-                                            * for a certain amount of 'frames'.
-                                            * Should not be used for trivial messages, which should simply be 
-                                            * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a 
-                                            * fallback, stderr).
-                                            */
-#define RETRO_ENVIRONMENT_SHUTDOWN      7  /* N/A (NULL) --
-                                            * Requests the frontend to shutdown.
-                                            * Should only be used if game has a specific
-                                            * way to shutdown the game from a menu item or similar.
-                                            */
-#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8
-                                           /* const unsigned * --
-                                            * Gives a hint to the frontend how demanding this implementation
-                                            * is on a system. E.g. reporting a level of 2 means
-                                            * this implementation should run decently on all frontends
-                                            * of level 2 and up.
-                                            *
-                                            * It can be used by the frontend to potentially warn
-                                            * about too demanding implementations.
-                                            *
-                                            * The levels are "floating".
-                                            *
-                                            * This function can be called on a per-game basis,
-                                            * as certain games an implementation can play might be
-                                            * particularly demanding.
-                                            * If called, it should be called in retro_load_game().
-                                            */
-#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9
-                                           /* const char ** --
-                                            * Returns the "system" directory of the frontend.
-                                            * This directory can be used to store system specific 
-                                            * content such as BIOSes, configuration data, etc.
-                                            * The returned value can be NULL.
-                                            * If so, no such directory is defined,
-                                            * and it's up to the implementation to find a suitable directory.
-                                            *
-                                            * NOTE: Some cores used this folder also for "save" data such as 
-                                            * memory cards, etc, for lack of a better place to put it.
-                                            * This is now discouraged, and if possible, cores should try to 
-                                            * use the new GET_SAVE_DIRECTORY.
-                                            */
-#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10
-                                           /* const enum retro_pixel_format * --
-                                            * Sets the internal pixel format used by the implementation.
-                                            * The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555.
-                                            * This pixel format however, is deprecated (see enum retro_pixel_format).
-                                            * If the call returns false, the frontend does not support this pixel 
-                                            * format.
-                                            *
-                                            * This function should be called inside retro_load_game() or 
-                                            * retro_get_system_av_info().
-                                            */
-#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11
-                                           /* const struct retro_input_descriptor * --
-                                            * Sets an array of retro_input_descriptors.
-                                            * It is up to the frontend to present this in a usable way.
-                                            * The array is terminated by retro_input_descriptor::description 
-                                            * being set to NULL.
-                                            * This function can be called at any time, but it is recommended 
-                                            * to call it as early as possible.
-                                            */
-#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12
-                                           /* const struct retro_keyboard_callback * --
-                                            * Sets a callback function used to notify core about keyboard events.
-                                            */
-#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13
-                                           /* const struct retro_disk_control_callback * --
-                                            * Sets an interface which frontend can use to eject and insert 
-                                            * disk images.
-                                            * This is used for games which consist of multiple images and 
-                                            * must be manually swapped out by the user (e.g. PSX).
-                                            */
-#define RETRO_ENVIRONMENT_SET_HW_RENDER 14
-                                           /* struct retro_hw_render_callback * --
-                                            * Sets an interface to let a libretro core render with 
-                                            * hardware acceleration.
-                                            * Should be called in retro_load_game().
-                                            * If successful, libretro cores will be able to render to a 
-                                            * frontend-provided framebuffer.
-                                            * The size of this framebuffer will be at least as large as 
-                                            * max_width/max_height provided in get_av_info().
-                                            * If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or 
-                                            * NULL to retro_video_refresh_t.
-                                            */
-#define RETRO_ENVIRONMENT_GET_VARIABLE 15
-                                           /* struct retro_variable * --
-                                            * Interface to acquire user-defined information from environment
-                                            * that cannot feasibly be supported in a multi-system way.
-                                            * 'key' should be set to a key which has already been set by 
-                                            * SET_VARIABLES.
-                                            * 'data' will be set to a value or NULL.
-                                            */
-#define RETRO_ENVIRONMENT_SET_VARIABLES 16
-                                           /* const struct retro_variable * --
-                                            * Allows an implementation to signal the environment
-                                            * which variables it might want to check for later using 
-                                            * GET_VARIABLE.
-                                            * This allows the frontend to present these variables to 
-                                            * a user dynamically.
-                                            * This should be called as early as possible (ideally in 
-                                            * retro_set_environment).
-                                            *
-                                            * 'data' points to an array of retro_variable structs 
-                                            * terminated by a { NULL, NULL } element.
-                                            * retro_variable::key should be namespaced to not collide 
-                                            * with other implementations' keys. E.g. A core called 
-                                            * 'foo' should use keys named as 'foo_option'.
-                                            * retro_variable::value should contain a human readable 
-                                            * description of the key as well as a '|' delimited list 
-                                            * of expected values.
-                                            *
-                                            * The number of possible options should be very limited, 
-                                            * i.e. it should be feasible to cycle through options 
-                                            * without a keyboard.
-                                            *
-                                            * First entry should be treated as a default.
-                                            *
-                                            * Example entry:
-                                            * { "foo_option", "Speed hack coprocessor X; false|true" }
-                                            *
-                                            * Text before first ';' is description. This ';' must be 
-                                            * followed by a space, and followed by a list of possible 
-                                            * values split up with '|'.
-                                            *
-                                            * Only strings are operated on. The possible values will 
-                                            * generally be displayed and stored as-is by the frontend.
-                                            */
-#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17
-                                           /* bool * --
-                                            * Result is set to true if some variables are updated by
-                                            * frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE.
-                                            * Variables should be queried with GET_VARIABLE.
-                                            */
-#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18
-                                           /* const bool * --
-                                            * If true, the libretro implementation supports calls to 
-                                            * retro_load_game() with NULL as argument.
-                                            * Used by cores which can run without particular game data.
-                                            * This should be called within retro_set_environment() only.
-                                            */
-#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19
-                                           /* const char ** --
-                                            * Retrieves the absolute path from where this libretro 
-                                            * implementation was loaded.
-                                            * NULL is returned if the libretro was loaded statically 
-                                            * (i.e. linked statically to frontend), or if the path cannot be 
-                                            * determined.
-                                            * Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can 
-                                            * be loaded without ugly hacks.
-                                            */
-                                           
-                                           /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK. 
-                                            * It was not used by any known core at the time,
-                                            * and was removed from the API. */
-#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22
-                                           /* const struct retro_audio_callback * --
-                                            * Sets an interface which is used to notify a libretro core about audio 
-                                            * being available for writing.
-                                            * The callback can be called from any thread, so a core using this must 
-                                            * have a thread safe audio implementation.
-                                            * It is intended for games where audio and video are completely 
-                                            * asynchronous and audio can be generated on the fly.
-                                            * This interface is not recommended for use with emulators which have 
-                                            * highly synchronous audio.
-                                            *
-                                            * The callback only notifies about writability; the libretro core still 
-                                            * has to call the normal audio callbacks
-                                            * to write audio. The audio callbacks must be called from within the 
-                                            * notification callback.
-                                            * The amount of audio data to write is up to the implementation.
-                                            * Generally, the audio callback will be called continously in a loop.
-                                            *
-                                            * Due to thread safety guarantees and lack of sync between audio and 
-                                            * video, a frontend  can selectively disallow this interface based on 
-                                            * internal configuration. A core using this interface must also 
-                                            * implement the "normal" audio interface.
-                                            *
-                                            * A libretro core using SET_AUDIO_CALLBACK should also make use of 
-                                            * SET_FRAME_TIME_CALLBACK.
-                                            */
-#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21
-                                           /* const struct retro_frame_time_callback * --
-                                            * Lets the core know how much time has passed since last 
-                                            * invocation of retro_run().
-                                            * The frontend can tamper with the timing to fake fast-forward, 
-                                            * slow-motion, frame stepping, etc.
-                                            * In this case the delta time will use the reference value 
-                                            * in frame_time_callback..
-                                            */
-#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23
-                                           /* struct retro_rumble_interface * --
-                                            * Gets an interface which is used by a libretro core to set 
-                                            * state of rumble motors in controllers.
-                                            * A strong and weak motor is supported, and they can be 
-                                            * controlled indepedently.
-                                            */
-#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24
-                                           /* uint64_t * --
-                                            * Gets a bitmask telling which device type are expected to be 
-                                            * handled properly in a call to retro_input_state_t.
-                                            * Devices which are not handled or recognized always return 
-                                            * 0 in retro_input_state_t.
-                                            * Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG).
-                                            * Should only be called in retro_run().
-                                            */
-#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)
-                                           /* struct retro_sensor_interface * --
-                                            * Gets access to the sensor interface.
-                                            * The purpose of this interface is to allow
-                                            * setting state related to sensors such as polling rate, 
-                                            * enabling/disable it entirely, etc.
-                                            * Reading sensor state is done via the normal 
-                                            * input_state_callback API.
-                                            */
-#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)
-                                           /* struct retro_camera_callback * --
-                                            * Gets an interface to a video camera driver.
-                                            * A libretro core can use this interface to get access to a 
-                                            * video camera.
-                                            * New video frames are delivered in a callback in same 
-                                            * thread as retro_run().
-                                            *
-                                            * GET_CAMERA_INTERFACE should be called in retro_load_game().
-                                            *
-                                            * Depending on the camera implementation used, camera frames 
-                                            * will be delivered as a raw framebuffer,
-                                            * or as an OpenGL texture directly.
-                                            *
-                                            * The core has to tell the frontend here which types of 
-                                            * buffers can be handled properly.
-                                            * An OpenGL texture can only be handled when using a 
-                                            * libretro GL core (SET_HW_RENDER).
-                                            * It is recommended to use a libretro GL core when 
-                                            * using camera interface.
-                                            *
-                                            * The camera is not started automatically. The retrieved start/stop 
-                                            * functions must be used to explicitly
-                                            * start and stop the camera driver.
-                                            */
-#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27
-                                           /* struct retro_log_callback * --
-                                            * Gets an interface for logging. This is useful for 
-                                            * logging in a cross-platform way
-                                            * as certain platforms cannot use use stderr for logging. 
-                                            * It also allows the frontend to
-                                            * show logging information in a more suitable way.
-                                            * If this interface is not used, libretro cores should 
-                                            * log to stderr as desired.
-                                            */
-#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28
-                                           /* struct retro_perf_callback * --
-                                            * Gets an interface for performance counters. This is useful 
-                                            * for performance logging in a cross-platform way and for detecting 
-                                            * architecture-specific features, such as SIMD support.
-                                            */
-#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29
-                                           /* struct retro_location_callback * --
-                                            * Gets access to the location interface.
-                                            * The purpose of this interface is to be able to retrieve 
-                                            * location-based information from the host device,
-                                            * such as current latitude / longitude.
-                                            */
-#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30
-                                           /* const char ** --
-                                            * Returns the "content" directory of the frontend.
-                                            * This directory can be used to store specific assets that the 
-                                            * core relies upon, such as art assets,
-                                            * input data, etc etc.
-                                            * The returned value can be NULL.
-                                            * If so, no such directory is defined,
-                                            * and it's up to the implementation to find a suitable directory.
-                                            */
-#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31
-                                           /* const char ** --
-                                            * Returns the "save" directory of the frontend.
-                                            * This directory can be used to store SRAM, memory cards, 
-                                            * high scores, etc, if the libretro core
-                                            * cannot use the regular memory interface (retro_get_memory_data()).
-                                            *
-                                            * NOTE: libretro cores used to check GET_SYSTEM_DIRECTORY for 
-                                            * similar things before.
-                                            * They should still check GET_SYSTEM_DIRECTORY if they want to 
-                                            * be backwards compatible.
-                                            * The path here can be NULL. It should only be non-NULL if the 
-                                            * frontend user has set a specific save path.
-                                            */
-#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32
-                                           /* const struct retro_system_av_info * --
-                                            * Sets a new av_info structure. This can only be called from 
-                                            * within retro_run().
-                                            * This should *only* be used if the core is completely altering the 
-                                            * internal resolutions, aspect ratios, timings, sampling rate, etc.
-                                            * Calling this can require a full reinitialization of video/audio 
-                                            * drivers in the frontend,
-                                            *
-                                            * so it is important to call it very sparingly, and usually only with 
-                                            * the users explicit consent.
-                                            * An eventual driver reinitialize will happen so that video and 
-                                            * audio callbacks
-                                            * happening after this call within the same retro_run() call will 
-                                            * target the newly initialized driver.
-                                            *
-                                            * This callback makes it possible to support configurable resolutions 
-                                            * in games, which can be useful to
-                                            * avoid setting the "worst case" in max_width/max_height.
-                                            *
-                                            * ***HIGHLY RECOMMENDED*** Do not call this callback every time 
-                                            * resolution changes in an emulator core if it's
-                                            * expected to be a temporary change, for the reasons of possible 
-                                            * driver reinitialization.
-                                            * This call is not a free pass for not trying to provide 
-                                            * correct values in retro_get_system_av_info(). If you need to change 
-                                            * things like aspect ratio or nominal width/height, 
-                                            * use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant 
-                                            * of SET_SYSTEM_AV_INFO.
-                                            *
-                                            * If this returns false, the frontend does not acknowledge a 
-                                            * changed av_info struct.
-                                            */
-#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33
-                                           /* const struct retro_get_proc_address_interface * --
-                                            * Allows a libretro core to announce support for the 
-                                            * get_proc_address() interface.
-                                            * This interface allows for a standard way to extend libretro where 
-                                            * use of environment calls are too indirect,
-                                            * e.g. for cases where the frontend wants to call directly into the core.
-                                            *
-                                            * If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK 
-                                            * **MUST** be called from within retro_set_environment().
-                                            */
-#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34
-                                           /* const struct retro_subsystem_info * --
-                                            * This environment call introduces the concept of libretro "subsystems".
-                                            * A subsystem is a variant of a libretro core which supports 
-                                            * different kinds of games.
-                                            * The purpose of this is to support e.g. emulators which might 
-                                            * have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo.
-                                            * It can also be used to pick among subsystems in an explicit way 
-                                            * if the libretro implementation is a multi-system emulator itself.
-                                            *
-                                            * Loading a game via a subsystem is done with retro_load_game_special(),
-                                            * and this environment call allows a libretro core to expose which 
-                                            * subsystems are supported for use with retro_load_game_special().
-                                            * A core passes an array of retro_game_special_info which is terminated 
-                                            * with a zeroed out retro_game_special_info struct.
-                                            *
-                                            * If a core wants to use this functionality, SET_SUBSYSTEM_INFO
-                                            * **MUST** be called from within retro_set_environment().
-                                            */
-#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35
-                                           /* const struct retro_controller_info * --
-                                            * This environment call lets a libretro core tell the frontend 
-                                            * which controller types are recognized in calls to 
-                                            * retro_set_controller_port_device().
-                                            *
-                                            * Some emulators such as Super Nintendo
-                                            * support multiple lightgun types which must be specifically 
-                                            * selected from.
-                                            * It is therefore sometimes necessary for a frontend to be able 
-                                            * to tell the core about a special kind of input device which is 
-                                            * not covered by the libretro input API.
-                                            *
-                                            * In order for a frontend to understand the workings of an input device,
-                                            * it must be a specialized type
-                                            * of the generic device types already defined in the libretro API.
-                                            *
-                                            * Which devices are supported can vary per input port.
-                                            * The core must pass an array of const struct retro_controller_info which 
-                                            * is terminated with a blanked out struct. Each element of the struct 
-                                            * corresponds to an ascending port index to 
-                                            * retro_set_controller_port_device().
-                                            * Even if special device types are set in the libretro core, 
-                                            * libretro should only poll input based on the base input device types.
-                                            */
-#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)
-                                           /* const struct retro_memory_map * --
-                                            * This environment call lets a libretro core tell the frontend 
-                                            * about the memory maps this core emulates.
-                                            * This can be used to implement, for example, cheats in a core-agnostic way.
-                                            *
-                                            * Should only be used by emulators; it doesn't make much sense for 
-                                            * anything else.
-                                            * It is recommended to expose all relevant pointers through 
-                                            * retro_get_memory_* as well.
-                                            *
-                                            * Can be called from retro_init and retro_load_game.
-                                            */
-#define RETRO_ENVIRONMENT_SET_GEOMETRY 37
-                                           /* const struct retro_game_geometry * --
-                                            * This environment call is similar to SET_SYSTEM_AV_INFO for changing 
-                                            * video parameters, but provides a guarantee that drivers will not be 
-                                            * reinitialized.
-                                            * This can only be called from within retro_run().
-                                            *
-                                            * The purpose of this call is to allow a core to alter nominal 
-                                            * width/heights as well as aspect ratios on-the-fly, which can be 
-                                            * useful for some emulators to change in run-time.
-                                            *
-                                            * max_width/max_height arguments are ignored and cannot be changed
-                                            * with this call as this could potentially require a reinitialization or a 
-                                            * non-constant time operation.
-                                            * If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required.
-                                            *
-                                            * A frontend must guarantee that this environment call completes in 
-                                            * constant time.
-                                            */
-#define RETRO_ENVIRONMENT_GET_USERNAME 38 
-                                           /* const char **
-                                            * Returns the specified username of the frontend, if specified by the user.
-                                            * This username can be used as a nickname for a core that has online facilities 
-                                            * or any other mode where personalization of the user is desirable.
-                                            * The returned value can be NULL.
-                                            * If this environ callback is used by a core that requires a valid username, 
-                                            * a default username should be specified by the core.
-                                            */
-#define RETRO_ENVIRONMENT_GET_LANGUAGE 39
-                                           /* unsigned * --
-                                            * Returns the specified language of the frontend, if specified by the user.
-                                            * It can be used by the core for localization purposes.
-                                            */
-
-#define RETRO_MEMDESC_CONST     (1 << 0)   /* The frontend will never change this memory area once retro_load_game has returned. */
-#define RETRO_MEMDESC_BIGENDIAN (1 << 1)   /* The memory area contains big endian data. Default is little endian. */
-#define RETRO_MEMDESC_ALIGN_2   (1 << 16)  /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
-#define RETRO_MEMDESC_ALIGN_4   (2 << 16)
-#define RETRO_MEMDESC_ALIGN_8   (3 << 16)
-#define RETRO_MEMDESC_MINSIZE_2 (1 << 24)  /* All memory in this region is accessed at least 2 bytes at the time. */
-#define RETRO_MEMDESC_MINSIZE_4 (2 << 24)
-#define RETRO_MEMDESC_MINSIZE_8 (3 << 24)
-struct retro_memory_descriptor
-{
-   uint64_t flags;
-
-   /* Pointer to the start of the relevant ROM or RAM chip.
-    * It's strongly recommended to use 'offset' if possible, rather than 
-    * doing math on the pointer.
-    *
-    * If the same byte is mapped my multiple descriptors, their descriptors 
-    * must have the same pointer.
-    * If 'start' does not point to the first byte in the pointer, put the 
-    * difference in 'offset' instead.
-    *
-    * May be NULL if there's nothing usable here (e.g. hardware registers and 
-    * open bus). No flags should be set if the pointer is NULL.
-    * It's recommended to minimize the number of descriptors if possible,
-    * but not mandatory. */
-   void *ptr;
-   size_t offset;
-
-   /* This is the location in the emulated address space 
-    * where the mapping starts. */
-   size_t start;
-
-   /* Which bits must be same as in 'start' for this mapping to apply.
-    * The first memory descriptor to claim a certain byte is the one 
-    * that applies.
-    * A bit which is set in 'start' must also be set in this.
-    * Can be zero, in which case each byte is assumed mapped exactly once. 
-    * In this case, 'len' must be a power of two. */
-   size_t select;
-
-   /* If this is nonzero, the set bits are assumed not connected to the 
-    * memory chip's address pins. */
-   size_t disconnect;
-
-   /* This one tells the size of the current memory area.
-    * If, after start+disconnect are applied, the address is higher than 
-    * this, the highest bit of the address is cleared.
-    *
-    * If the address is still too high, the next highest bit is cleared.
-    * Can be zero, in which case it's assumed to be infinite (as limited 
-    * by 'select' and 'disconnect'). */
-   size_t len;
-
-   /* To go from emulated address to physical address, the following 
-    * order applies:
-    * Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'.
-    *
-    * The address space name must consist of only a-zA-Z0-9_-, 
-    * should be as short as feasible (maximum length is 8 plus the NUL),
-    * and may not be any other address space plus one or more 0-9A-F 
-    * at the end.
-    * However, multiple memory descriptors for the same address space is 
-    * allowed, and the address space name can be empty. NULL is treated 
-    * as empty.
-    *
-    * Address space names are case sensitive, but avoid lowercase if possible.
-    * The same pointer may exist in multiple address spaces.
-    *
-    * Examples:
-    * blank+blank - valid (multiple things may be mapped in the same namespace)
-    * 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace)
-    * 'A'+'B' - valid (neither is a prefix of each other)
-    * 'S'+blank - valid ('S' is not in 0-9A-F)
-    * 'a'+blank - valid ('a' is not in 0-9A-F)
-    * 'a'+'A' - valid (neither is a prefix of each other)
-    * 'AR'+blank - valid ('R' is not in 0-9A-F)
-    * 'ARB'+blank - valid (the B can't be part of the address either, because 
-    * there is no namespace 'AR')
-    * blank+'B' - not valid, because it's ambigous which address space B1234 
-    * would refer to.
-    * The length can't be used for that purpose; the frontend may want 
-    * to append arbitrary data to an address, without a separator. */
-   const char *addrspace;
-};
-
-/* The frontend may use the largest value of 'start'+'select' in a 
- * certain namespace to infer the size of the address space.
- *
- * If the address space is larger than that, a mapping with .ptr=NULL 
- * should be at the end of the array, with .select set to all ones for 
- * as long as the address space is big.
- *
- * Sample descriptors (minus .ptr, and RETRO_MEMFLAG_ on the flags):
- * SNES WRAM:
- * .start=0x7E0000, .len=0x20000
- * (Note that this must be mapped before the ROM in most cases; some of the 
- * ROM mappers 
- * try to claim $7E0000, or at least $7E8000.)
- * SNES SPC700 RAM:
- * .addrspace="S", .len=0x10000
- * SNES WRAM mirrors:
- * .flags=MIRROR, .start=0x000000, .select=0xC0E000, .len=0x2000
- * .flags=MIRROR, .start=0x800000, .select=0xC0E000, .len=0x2000
- * SNES WRAM mirrors, alternate equivalent descriptor:
- * .flags=MIRROR, .select=0x40E000, .disconnect=~0x1FFF
- * (Various similar constructions can be created by combining parts of 
- * the above two.)
- * SNES LoROM (512KB, mirrored a couple of times):
- * .flags=CONST, .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024
- * .flags=CONST, .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024
- * SNES HiROM (4MB):
- * .flags=CONST,                 .start=0x400000, .select=0x400000, .len=4*1024*1024
- * .flags=CONST, .offset=0x8000, .start=0x008000, .select=0x408000, .len=4*1024*1024
- * SNES ExHiROM (8MB):
- * .flags=CONST, .offset=0,                  .start=0xC00000, .select=0xC00000, .len=4*1024*1024
- * .flags=CONST, .offset=4*1024*1024,        .start=0x400000, .select=0xC00000, .len=4*1024*1024
- * .flags=CONST, .offset=0x8000,             .start=0x808000, .select=0xC08000, .len=4*1024*1024
- * .flags=CONST, .offset=4*1024*1024+0x8000, .start=0x008000, .select=0xC08000, .len=4*1024*1024
- * Clarify the size of the address space:
- * .ptr=NULL, .select=0xFFFFFF
- * .len can be implied by .select in many of them, but was included for clarity.
- */
-
-struct retro_memory_map
-{
-   const struct retro_memory_descriptor *descriptors;
-   unsigned num_descriptors;
-};
-
-struct retro_controller_description
-{
-   /* Human-readable description of the controller. Even if using a generic 
-    * input device type, this can be set to the particular device type the 
-    * core uses. */
-   const char *desc;
-
-   /* Device type passed to retro_set_controller_port_device(). If the device 
-    * type is a sub-class of a generic input device type, use the 
-    * RETRO_DEVICE_SUBCLASS macro to create an ID.
-    *
-    * E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */
-   unsigned id;
-};
-
-struct retro_controller_info
-{
-   const struct retro_controller_description *types;
-   unsigned num_types;
-};
-
-struct retro_subsystem_memory_info
-{
-   /* The extension associated with a memory type, e.g. "psram". */
-   const char *extension;
-
-   /* The memory type for retro_get_memory(). This should be at 
-    * least 0x100 to avoid conflict with standardized 
-    * libretro memory types. */
-   unsigned type;
-};
-
-struct retro_subsystem_rom_info
-{
-   /* Describes what the content is (SGB BIOS, GB ROM, etc). */
-   const char *desc;
-
-   /* Same definition as retro_get_system_info(). */
-   const char *valid_extensions;
-
-   /* Same definition as retro_get_system_info(). */
-   bool need_fullpath;
-
-   /* Same definition as retro_get_system_info(). */
-   bool block_extract;
-
-   /* This is set if the content is required to load a game. 
-    * If this is set to false, a zeroed-out retro_game_info can be passed. */
-   bool required;
-
-   /* Content can have multiple associated persistent 
-    * memory types (retro_get_memory()). */
-   const struct retro_subsystem_memory_info *memory;
-   unsigned num_memory;
-};
-
-struct retro_subsystem_info
-{
-   /* Human-readable string of the subsystem type, e.g. "Super GameBoy" */
-   const char *desc;
-
-   /* A computer friendly short string identifier for the subsystem type.
-    * This name must be [a-z].
-    * E.g. if desc is "Super GameBoy", this can be "sgb".
-    * This identifier can be used for command-line interfaces, etc.
-    */
-   const char *ident;
-
-   /* Infos for each content file. The first entry is assumed to be the 
-    * "most significant" content for frontend purposes.
-    * E.g. with Super GameBoy, the first content should be the GameBoy ROM, 
-    * as it is the most "significant" content to a user.
-    * If a frontend creates new file paths based on the content used 
-    * (e.g. savestates), it should use the path for the first ROM to do so. */
-   const struct retro_subsystem_rom_info *roms;
-
-   /* Number of content files associated with a subsystem. */
-   unsigned num_roms;
-   
-   /* The type passed to retro_load_game_special(). */
-   unsigned id;
-};
-
-typedef void (*retro_proc_address_t)(void);
-
-/* libretro API extension functions:
- * (None here so far).
- *
- * Get a symbol from a libretro core.
- * Cores should only return symbols which are actual 
- * extensions to the libretro API.
- *
- * Frontends should not use this to obtain symbols to standard 
- * libretro entry points (static linking or dlsym).
- *
- * The symbol name must be equal to the function name, 
- * e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo".
- * The returned function pointer must be cast to the corresponding type.
- */
-typedef retro_proc_address_t (*retro_get_proc_address_t)(const char *sym);
-
-struct retro_get_proc_address_interface
-{
-   retro_get_proc_address_t get_proc_address;
-};
-
-enum retro_log_level
-{
-   RETRO_LOG_DEBUG = 0,
-   RETRO_LOG_INFO,
-   RETRO_LOG_WARN,
-   RETRO_LOG_ERROR,
-
-   RETRO_LOG_DUMMY = INT_MAX
-};
-
-/* Logging function. Takes log level argument as well. */
-typedef void (*retro_log_printf_t)(enum retro_log_level level,
-      const char *fmt, ...);
-
-struct retro_log_callback
-{
-   retro_log_printf_t log;
-};
-
-/* Performance related functions */
-
-/* ID values for SIMD CPU features */
-#define RETRO_SIMD_SSE      (1 << 0)
-#define RETRO_SIMD_SSE2     (1 << 1)
-#define RETRO_SIMD_VMX      (1 << 2)
-#define RETRO_SIMD_VMX128   (1 << 3)
-#define RETRO_SIMD_AVX      (1 << 4)
-#define RETRO_SIMD_NEON     (1 << 5)
-#define RETRO_SIMD_SSE3     (1 << 6)
-#define RETRO_SIMD_SSSE3    (1 << 7)
-#define RETRO_SIMD_MMX      (1 << 8)
-#define RETRO_SIMD_MMXEXT   (1 << 9)
-#define RETRO_SIMD_SSE4     (1 << 10)
-#define RETRO_SIMD_SSE42    (1 << 11)
-#define RETRO_SIMD_AVX2     (1 << 12)
-#define RETRO_SIMD_VFPU     (1 << 13)
-#define RETRO_SIMD_PS       (1 << 14)
-#define RETRO_SIMD_AES      (1 << 15)
-
-typedef uint64_t retro_perf_tick_t;
-typedef int64_t retro_time_t;
-
-struct retro_perf_counter
-{
-   const char *ident;
-   retro_perf_tick_t start;
-   retro_perf_tick_t total;
-   retro_perf_tick_t call_cnt;
-
-   bool registered;
-};
-
-/* Returns current time in microseconds.
- * Tries to use the most accurate timer available.
- */
-typedef retro_time_t (*retro_perf_get_time_usec_t)(void);
-
-/* A simple counter. Usually nanoseconds, but can also be CPU cycles.
- * Can be used directly if desired (when creating a more sophisticated 
- * performance counter system).
- * */
-typedef retro_perf_tick_t (*retro_perf_get_counter_t)(void);
-
-/* Returns a bit-mask of detected CPU features (RETRO_SIMD_*). */
-typedef uint64_t (*retro_get_cpu_features_t)(void);
-
-/* Asks frontend to log and/or display the state of performance counters.
- * Performance counters can always be poked into manually as well.
- */
-typedef void (*retro_perf_log_t)(void);
-
-/* Register a performance counter.
- * ident field must be set with a discrete value and other values in 
- * retro_perf_counter must be 0.
- * Registering can be called multiple times. To avoid calling to 
- * frontend redundantly, you can check registered field first. */
-typedef void (*retro_perf_register_t)(struct retro_perf_counter *counter);
-
-/* Starts a registered counter. */
-typedef void (*retro_perf_start_t)(struct retro_perf_counter *counter);
-
-/* Stops a registered counter. */
-typedef void (*retro_perf_stop_t)(struct retro_perf_counter *counter);
-
-/* For convenience it can be useful to wrap register, start and stop in macros.
- * E.g.:
- * #ifdef LOG_PERFORMANCE
- * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name))
- * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name))
- * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name))
- * #else
- * ... Blank macros ...
- * #endif
- *
- * These can then be used mid-functions around code snippets.
- *
- * extern struct retro_perf_callback perf_cb;  * Somewhere in the core.
- *
- * void do_some_heavy_work(void)
- * {
- *    RETRO_PERFORMANCE_INIT(cb, work_1;
- *    RETRO_PERFORMANCE_START(cb, work_1);
- *    heavy_work_1();
- *    RETRO_PERFORMANCE_STOP(cb, work_1);
- *
- *    RETRO_PERFORMANCE_INIT(cb, work_2);
- *    RETRO_PERFORMANCE_START(cb, work_2);
- *    heavy_work_2();
- *    RETRO_PERFORMANCE_STOP(cb, work_2);
- * }
- *
- * void retro_deinit(void)
- * {
- *    perf_cb.perf_log();  * Log all perf counters here for example.
- * }
- */
-
-struct retro_perf_callback
-{
-   retro_perf_get_time_usec_t    get_time_usec;
-   retro_get_cpu_features_t      get_cpu_features;
-
-   retro_perf_get_counter_t      get_perf_counter;
-   retro_perf_register_t         perf_register;
-   retro_perf_start_t            perf_start;
-   retro_perf_stop_t             perf_stop;
-   retro_perf_log_t              perf_log;
-};
-
-/* FIXME: Document the sensor API and work out behavior.
- * It will be marked as experimental until then.
- */
-enum retro_sensor_action
-{
-   RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,
-   RETRO_SENSOR_ACCELEROMETER_DISABLE,
-
-   RETRO_SENSOR_DUMMY = INT_MAX
-};
-
-/* Id values for SENSOR types. */
-#define RETRO_SENSOR_ACCELEROMETER_X 0
-#define RETRO_SENSOR_ACCELEROMETER_Y 1
-#define RETRO_SENSOR_ACCELEROMETER_Z 2
-
-typedef bool (*retro_set_sensor_state_t)(unsigned port, 
-      enum retro_sensor_action action, unsigned rate);
-
-typedef float (*retro_sensor_get_input_t)(unsigned port, unsigned id);
-
-struct retro_sensor_interface
-{
-   retro_set_sensor_state_t set_sensor_state;
-   retro_sensor_get_input_t get_sensor_input;
-};
-
-enum retro_camera_buffer
-{
-   RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,
-   RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,
-
-   RETRO_CAMERA_BUFFER_DUMMY = INT_MAX
-};
-
-/* Starts the camera driver. Can only be called in retro_run(). */
-typedef bool (*retro_camera_start_t)(void);
-
-/* Stops the camera driver. Can only be called in retro_run(). */
-typedef void (*retro_camera_stop_t)(void);
-
-/* Callback which signals when the camera driver is initialized 
- * and/or deinitialized.
- * retro_camera_start_t can be called in initialized callback.
- */
-typedef void (*retro_camera_lifetime_status_t)(void);
-
-/* A callback for raw framebuffer data. buffer points to an XRGB8888 buffer.
- * Width, height and pitch are similar to retro_video_refresh_t.
- * First pixel is top-left origin.
- */
-typedef void (*retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer, 
-      unsigned width, unsigned height, size_t pitch);
-
-/* A callback for when OpenGL textures are used.
- *
- * texture_id is a texture owned by camera driver.
- * Its state or content should be considered immutable, except for things like 
- * texture filtering and clamping.
- *
- * texture_target is the texture target for the GL texture.
- * These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly 
- * more depending on extensions.
- *
- * affine points to a packed 3x3 column-major matrix used to apply an affine 
- * transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0))
- * After transform, normalized texture coord (0, 0) should be bottom-left 
- * and (1, 1) should be top-right (or (width, height) for RECTANGLE).
- *
- * GL-specific typedefs are avoided here to avoid relying on gl.h in 
- * the API definition.
- */
-typedef void (*retro_camera_frame_opengl_texture_t)(unsigned texture_id, 
-      unsigned texture_target, const float *affine);
-
-struct retro_camera_callback
-{
-   /* Set by libretro core. 
-    * Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER).
-    */
-   uint64_t caps; 
-
-   unsigned width; /* Desired resolution for camera. Is only used as a hint. */
-   unsigned height;
-   retro_camera_start_t start; /* Set by frontend. */
-   retro_camera_stop_t stop; /* Set by frontend. */
-
-   /* Set by libretro core if raw framebuffer callbacks will be used. */
-   retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;
-   /* Set by libretro core if OpenGL texture callbacks will be used. */
-   retro_camera_frame_opengl_texture_t frame_opengl_texture; 
-
-   /* Set by libretro core. Called after camera driver is initialized and 
-    * ready to be started.
-    * Can be NULL, in which this callback is not called.
-    */
-   retro_camera_lifetime_status_t initialized;
-
-   /* Set by libretro core. Called right before camera driver is 
-    * deinitialized.
-    * Can be NULL, in which this callback is not called.
-    */
-   retro_camera_lifetime_status_t deinitialized;
-};
-
-/* Sets the interval of time and/or distance at which to update/poll 
- * location-based data.
- *
- * To ensure compatibility with all location-based implementations,
- * values for both interval_ms and interval_distance should be provided.
- *
- * interval_ms is the interval expressed in milliseconds.
- * interval_distance is the distance interval expressed in meters.
- */
-typedef void (*retro_location_set_interval_t)(unsigned interval_ms,
-      unsigned interval_distance);
-
-/* Start location services. The device will start listening for changes to the
- * current location at regular intervals (which are defined with 
- * retro_location_set_interval_t). */
-typedef bool (*retro_location_start_t)(void);
-
-/* Stop location services. The device will stop listening for changes 
- * to the current location. */
-typedef void (*retro_location_stop_t)(void);
-
-/* Get the position of the current location. Will set parameters to 
- * 0 if no new  location update has happened since the last time. */
-typedef bool (*retro_location_get_position_t)(double *lat, double *lon,
-      double *horiz_accuracy, double *vert_accuracy);
-
-/* Callback which signals when the location driver is initialized 
- * and/or deinitialized.
- * retro_location_start_t can be called in initialized callback.
- */
-typedef void (*retro_location_lifetime_status_t)(void);
-
-struct retro_location_callback
-{
-   retro_location_start_t         start;
-   retro_location_stop_t          stop;
-   retro_location_get_position_t  get_position;
-   retro_location_set_interval_t  set_interval;
-
-   retro_location_lifetime_status_t initialized;
-   retro_location_lifetime_status_t deinitialized;
-};
-
-enum retro_rumble_effect
-{
-   RETRO_RUMBLE_STRONG = 0,
-   RETRO_RUMBLE_WEAK = 1,
-
-   RETRO_RUMBLE_DUMMY = INT_MAX
-};
-
-/* Sets rumble state for joypad plugged in port 'port'. 
- * Rumble effects are controlled independently,
- * and setting e.g. strong rumble does not override weak rumble.
- * Strength has a range of [0, 0xffff].
- *
- * Returns true if rumble state request was honored. 
- * Calling this before first retro_run() is likely to return false. */
-typedef bool (*retro_set_rumble_state_t)(unsigned port, 
-      enum retro_rumble_effect effect, uint16_t strength);
-
-struct retro_rumble_interface
-{
-   retro_set_rumble_state_t set_rumble_state;
-};
-
-/* Notifies libretro that audio data should be written. */
-typedef void (*retro_audio_callback_t)(void);
-
-/* True: Audio driver in frontend is active, and callback is 
- * expected to be called regularily.
- * False: Audio driver in frontend is paused or inactive. 
- * Audio callback will not be called until set_state has been 
- * called with true.
- * Initial state is false (inactive).
- */
-typedef void (*retro_audio_set_state_callback_t)(bool enabled);
-
-struct retro_audio_callback
-{
-   retro_audio_callback_t callback;
-   retro_audio_set_state_callback_t set_state;
-};
-
-/* Notifies a libretro core of time spent since last invocation 
- * of retro_run() in microseconds.
- *
- * It will be called right before retro_run() every frame.
- * The frontend can tamper with timing to support cases like 
- * fast-forward, slow-motion and framestepping.
- *
- * In those scenarios the reference frame time value will be used. */
-typedef int64_t retro_usec_t;
-typedef void (*retro_frame_time_callback_t)(retro_usec_t usec);
-struct retro_frame_time_callback
-{
-   retro_frame_time_callback_t callback;
-   /* Represents the time of one frame. It is computed as 
-    * 1000000 / fps, but the implementation will resolve the 
-    * rounding to ensure that framestepping, etc is exact. */
-   retro_usec_t reference;
-};
-
-/* Pass this to retro_video_refresh_t if rendering to hardware.
- * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
- * */
-#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)
-
-/* Invalidates the current HW context.
- * Any GL state is lost, and must not be deinitialized explicitly.
- * If explicit deinitialization is desired by the libretro core,
- * it should implement context_destroy callback.
- * If called, all GPU resources must be reinitialized.
- * Usually called when frontend reinits video driver.
- * Also called first time video driver is initialized, 
- * allowing libretro core to initialize resources.
- */
-typedef void (*retro_hw_context_reset_t)(void);
-
-/* Gets current framebuffer which is to be rendered to.
- * Could change every frame potentially.
- */
-typedef uintptr_t (*retro_hw_get_current_framebuffer_t)(void);
-
-/* Get a symbol from HW context. */
-typedef retro_proc_address_t (*retro_hw_get_proc_address_t)(const char *sym);
-
-enum retro_hw_context_type
-{
-   RETRO_HW_CONTEXT_NONE             = 0,
-   /* OpenGL 2.x. Driver can choose to use latest compatibility context. */
-   RETRO_HW_CONTEXT_OPENGL           = 1, 
-   /* OpenGL ES 2.0. */
-   RETRO_HW_CONTEXT_OPENGLES2        = 2,
-   /* Modern desktop core GL context. Use version_major/
-    * version_minor fields to set GL version. */
-   RETRO_HW_CONTEXT_OPENGL_CORE      = 3,
-   /* OpenGL ES 3.0 */
-   RETRO_HW_CONTEXT_OPENGLES3        = 4,
-   /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,
-    * use the corresponding enums directly. */
-   RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,
-
-   RETRO_HW_CONTEXT_DUMMY = INT_MAX
-};
-
-struct retro_hw_render_callback
-{
-   /* Which API to use. Set by libretro core. */
-   enum retro_hw_context_type context_type;
-
-   /* Called when a context has been created or when it has been reset.
-    * An OpenGL context is only valid after context_reset() has been called.
-    *
-    * When context_reset is called, OpenGL resources in the libretro 
-    * implementation are guaranteed to be invalid.
-    *
-    * It is possible that context_reset is called multiple times during an 
-    * application lifecycle.
-    * If context_reset is called without any notification (context_destroy),
-    * the OpenGL context was lost and resources should just be recreated
-    * without any attempt to "free" old resources.
-    */
-   retro_hw_context_reset_t context_reset;
-
-   /* Set by frontend. */
-   retro_hw_get_current_framebuffer_t get_current_framebuffer;
-
-   /* Set by frontend. */
-   retro_hw_get_proc_address_t get_proc_address;
-
-   /* Set if render buffers should have depth component attached. */
-   bool depth;
-
-   /* Set if stencil buffers should be attached. */
-   bool stencil;
-
-   /* If depth and stencil are true, a packed 24/8 buffer will be added. 
-    * Only attaching stencil is invalid and will be ignored. */
-
-   /* Use conventional bottom-left origin convention. If false, 
-    * standard libretro top-left origin semantics are used. */
-   bool bottom_left_origin;
-   
-   /* Major version number for core GL context or GLES 3.1+. */
-   unsigned version_major;
-
-   /* Minor version number for core GL context or GLES 3.1+. */
-   unsigned version_minor;
-
-   /* If this is true, the frontend will go very far to avoid 
-    * resetting context in scenarios like toggling fullscreen, etc.
-    */
-   bool cache_context;
-
-   /* The reset callback might still be called in extreme situations 
-    * such as if the context is lost beyond recovery.
-    *
-    * For optimal stability, set this to false, and allow context to be 
-    * reset at any time.
-    */
-   
-   /* A callback to be called before the context is destroyed in a 
-    * controlled way by the frontend. */
-   retro_hw_context_reset_t context_destroy;
-
-   /* OpenGL resources can be deinitialized cleanly at this step.
-    * context_destroy can be set to NULL, in which resources will 
-    * just be destroyed without any notification.
-    *
-    * Even when context_destroy is non-NULL, it is possible that 
-    * context_reset is called without any destroy notification.
-    * This happens if context is lost by external factors (such as 
-    * notified by GL_ARB_robustness).
-    *
-    * In this case, the context is assumed to be already dead,
-    * and the libretro implementation must not try to free any OpenGL 
-    * resources in the subsequent context_reset.
-    */
-
-   /* Creates a debug context. */
-   bool debug_context;
-};
-
-/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. 
- * Called by the frontend in response to keyboard events.
- * down is set if the key is being pressed, or false if it is being released.
- * keycode is the RETROK value of the char.
- * character is the text character of the pressed key. (UTF-32).
- * key_modifiers is a set of RETROKMOD values or'ed together.
- *
- * The pressed/keycode state can be indepedent of the character.
- * It is also possible that multiple characters are generated from a 
- * single keypress.
- * Keycode events should be treated separately from character events.
- * However, when possible, the frontend should try to synchronize these.
- * If only a character is posted, keycode should be RETROK_UNKNOWN.
- *
- * Similarily if only a keycode event is generated with no corresponding 
- * character, character should be 0.
- */
-typedef void (*retro_keyboard_event_t)(bool down, unsigned keycode, 
-      uint32_t character, uint16_t key_modifiers);
-
-struct retro_keyboard_callback
-{
-   retro_keyboard_event_t callback;
-};
-
-/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
- * Should be set for implementations which can swap out multiple disk 
- * images in runtime.
- *
- * If the implementation can do this automatically, it should strive to do so.
- * However, there are cases where the user must manually do so.
- *
- * Overview: To swap a disk image, eject the disk image with 
- * set_eject_state(true).
- * Set the disk index with set_image_index(index). Insert the disk again 
- * with set_eject_state(false).
- */
-
-/* If ejected is true, "ejects" the virtual disk tray.
- * When ejected, the disk image index can be set.
- */
-typedef bool (*retro_set_eject_state_t)(bool ejected);
-
-/* Gets current eject state. The initial state is 'not ejected'. */
-typedef bool (*retro_get_eject_state_t)(void);
-
-/* Gets current disk index. First disk is index 0.
- * If return value is >= get_num_images(), no disk is currently inserted.
- */
-typedef unsigned (*retro_get_image_index_t)(void);
-
-/* Sets image index. Can only be called when disk is ejected.
- * The implementation supports setting "no disk" by using an 
- * index >= get_num_images().
- */
-typedef bool (*retro_set_image_index_t)(unsigned index);
-
-/* Gets total number of images which are available to use. */
-typedef unsigned (*retro_get_num_images_t)(void);
-
-struct retro_game_info;
-
-/* Replaces the disk image associated with index.
- * Arguments to pass in info have same requirements as retro_load_game().
- * Virtual disk tray must be ejected when calling this.
- *
- * Replacing a disk image with info = NULL will remove the disk image 
- * from the internal list.
- * As a result, calls to get_image_index() can change.
- *
- * E.g. replace_image_index(1, NULL), and previous get_image_index() 
- * returned 4 before.
- * Index 1 will be removed, and the new index is 3.
- */
-typedef bool (*retro_replace_image_index_t)(unsigned index,
-      const struct retro_game_info *info);
-
-/* Adds a new valid index (get_num_images()) to the internal disk list.
- * This will increment subsequent return values from get_num_images() by 1.
- * This image index cannot be used until a disk image has been set 
- * with replace_image_index. */
-typedef bool (*retro_add_image_index_t)(void);
-
-struct retro_disk_control_callback
-{
-   retro_set_eject_state_t set_eject_state;
-   retro_get_eject_state_t get_eject_state;
-
-   retro_get_image_index_t get_image_index;
-   retro_set_image_index_t set_image_index;
-   retro_get_num_images_t  get_num_images;
-
-   retro_replace_image_index_t replace_image_index;
-   retro_add_image_index_t add_image_index;
-};
-
-enum retro_pixel_format
-{
-   /* 0RGB1555, native endian.
-    * 0 bit must be set to 0.
-    * This pixel format is default for compatibility concerns only.
-    * If a 15/16-bit pixel format is desired, consider using RGB565. */
-   RETRO_PIXEL_FORMAT_0RGB1555 = 0,
-
-   /* XRGB8888, native endian.
-    * X bits are ignored. */
-   RETRO_PIXEL_FORMAT_XRGB8888 = 1,
-
-   /* RGB565, native endian.
-    * This pixel format is the recommended format to use if a 15/16-bit
-    * format is desired as it is the pixel format that is typically 
-    * available on a wide range of low-power devices.
-    *
-    * It is also natively supported in APIs like OpenGL ES. */
-   RETRO_PIXEL_FORMAT_RGB565   = 2,
-
-   /* Ensure sizeof() == sizeof(int). */
-   RETRO_PIXEL_FORMAT_UNKNOWN  = INT_MAX
-};
-
-struct retro_message
-{
-   const char *msg;        /* Message to be displayed. */
-   unsigned    frames;     /* Duration in frames of message. */
-};
-
-/* Describes how the libretro implementation maps a libretro input bind
- * to its internal input system through a human readable string.
- * This string can be used to better let a user configure input. */
-struct retro_input_descriptor
-{
-   /* Associates given parameters with a description. */
-   unsigned port;
-   unsigned device;
-   unsigned index;
-   unsigned id;
-
-   /* Human readable description for parameters.
-    * The pointer must remain valid until
-    * retro_unload_game() is called. */
-   const char *description; 
-};
-
-struct retro_system_info
-{
-   /* All pointers are owned by libretro implementation, and pointers must 
-    * remain valid until retro_deinit() is called. */
-
-   const char *library_name;      /* Descriptive name of library. Should not 
-                                   * contain any version numbers, etc. */
-   const char *library_version;   /* Descriptive version of core. */
-
-   const char *valid_extensions;  /* A string listing probably content 
-                                   * extensions the core will be able to 
-                                   * load, separated with pipe.
-                                   * I.e. "bin|rom|iso".
-                                   * Typically used for a GUI to filter 
-                                   * out extensions. */
-
-   /* If true, retro_load_game() is guaranteed to provide a valid pathname 
-    * in retro_game_info::path.
-    * ::data and ::size are both invalid.
-    *
-    * If false, ::data and ::size are guaranteed to be valid, but ::path 
-    * might not be valid.
-    *
-    * This is typically set to true for libretro implementations that must 
-    * load from file.
-    * Implementations should strive for setting this to false, as it allows 
-    * the frontend to perform patching, etc. */
-   bool        need_fullpath;                                       
-
-   /* If true, the frontend is not allowed to extract any archives before 
-    * loading the real content.
-    * Necessary for certain libretro implementations that load games 
-    * from zipped archives. */
-   bool        block_extract;     
-};
-
-struct retro_game_geometry
-{
-   unsigned base_width;    /* Nominal video width of game. */
-   unsigned base_height;   /* Nominal video height of game. */
-   unsigned max_width;     /* Maximum possible width of game. */
-   unsigned max_height;    /* Maximum possible height of game. */
-
-   float    aspect_ratio;  /* Nominal aspect ratio of game. If
-                            * aspect_ratio is <= 0.0, an aspect ratio
-                            * of base_width / base_height is assumed.
-                            * A frontend could override this setting,
-                            * if desired. */
-};
-
-struct retro_system_timing
-{
-   double fps;             /* FPS of video content. */
-   double sample_rate;     /* Sampling rate of audio. */
-};
-
-struct retro_system_av_info
-{
-   struct retro_game_geometry geometry;
-   struct retro_system_timing timing;
-};
-
-struct retro_variable
-{
-   /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE.
-    * If NULL, obtains the complete environment string if more 
-    * complex parsing is necessary.
-    * The environment string is formatted as key-value pairs 
-    * delimited by semicolons as so:
-    * "key1=value1;key2=value2;..."
-    */
-   const char *key;
-   
-   /* Value to be obtained. If key does not exist, it is set to NULL. */
-   const char *value;
-};
-
-struct retro_game_info
-{
-   const char *path;       /* Path to game, UTF-8 encoded.
-                            * Usually used as a reference.
-                            * May be NULL if rom was loaded from stdin
-                            * or similar. 
-                            * retro_system_info::need_fullpath guaranteed 
-                            * that this path is valid. */
-   const void *data;       /* Memory buffer of loaded game. Will be NULL 
-                            * if need_fullpath was set. */
-   size_t      size;       /* Size of memory buffer. */
-   const char *meta;       /* String of implementation specific meta-data. */
-};
-
-/* Callbacks */
-
-/* Environment callback. Gives implementations a way of performing 
- * uncommon tasks. Extensible. */
-typedef bool (*retro_environment_t)(unsigned cmd, void *data);
-
-/* Render a frame. Pixel format is 15-bit 0RGB1555 native endian 
- * unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT).
- *
- * Width and height specify dimensions of buffer.
- * Pitch specifices length in bytes between two lines in buffer.
- *
- * For performance reasons, it is highly recommended to have a frame 
- * that is packed in memory, i.e. pitch == width * byte_per_pixel.
- * Certain graphic APIs, such as OpenGL ES, do not like textures 
- * that are not packed in memory.
- */
-typedef void (*retro_video_refresh_t)(const void *data, unsigned width,
-      unsigned height, size_t pitch);
-
-/* Renders a single audio frame. Should only be used if implementation 
- * generates a single sample at a time.
- * Format is signed 16-bit native endian.
- */
-typedef void (*retro_audio_sample_t)(int16_t left, int16_t right);
-
-/* Renders multiple audio frames in one go.
- *
- * One frame is defined as a sample of left and right channels, interleaved.
- * I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames.
- * Only one of the audio callbacks must ever be used.
- */
-typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data,
-      size_t frames);
-
-/* Polls input. */
-typedef void (*retro_input_poll_t)(void);
-
-/* Queries for input for player 'port'. device will be masked with 
- * RETRO_DEVICE_MASK.
- *
- * Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that 
- * have been set with retro_set_controller_port_device()
- * will still use the higher level RETRO_DEVICE_JOYPAD to request input.
- */
-typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device, 
-      unsigned index, unsigned id);
-
-/* Sets callbacks. retro_set_environment() is guaranteed to be called 
- * before retro_init().
- *
- * The rest of the set_* functions are guaranteed to have been called 
- * before the first call to retro_run() is made. */
-void retro_set_environment(retro_environment_t);
-void retro_set_video_refresh(retro_video_refresh_t);
-void retro_set_audio_sample(retro_audio_sample_t);
-void retro_set_audio_sample_batch(retro_audio_sample_batch_t);
-void retro_set_input_poll(retro_input_poll_t);
-void retro_set_input_state(retro_input_state_t);
-
-/* Library global initialization/deinitialization. */
-void retro_init(void);
-void retro_deinit(void);
-
-/* Must return RETRO_API_VERSION. Used to validate ABI compatibility
- * when the API is revised. */
-unsigned retro_api_version(void);
-
-/* Gets statically known system info. Pointers provided in *info 
- * must be statically allocated.
- * Can be called at any time, even before retro_init(). */
-void retro_get_system_info(struct retro_system_info *info);
-
-/* Gets information about system audio/video timings and geometry.
- * Can be called only after retro_load_game() has successfully completed.
- * NOTE: The implementation of this function might not initialize every 
- * variable if needed.
- * E.g. geom.aspect_ratio might not be initialized if core doesn't 
- * desire a particular aspect ratio. */
-void retro_get_system_av_info(struct retro_system_av_info *info);
-
-/* Sets device to be used for player 'port'.
- * By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all 
- * available ports.
- * Setting a particular device type is not a guarantee that libretro cores 
- * will only poll input based on that particular device type. It is only a 
- * hint to the libretro core when a core cannot automatically detect the 
- * appropriate input device type on its own. It is also relevant when a 
- * core can change its behavior depending on device type. */
-void retro_set_controller_port_device(unsigned port, unsigned device);
-
-/* Resets the current game. */
-void retro_reset(void);
-
-/* Runs the game for one video frame.
- * During retro_run(), input_poll callback must be called at least once.
- * 
- * If a frame is not rendered for reasons where a game "dropped" a frame,
- * this still counts as a frame, and retro_run() should explicitly dupe 
- * a frame if GET_CAN_DUPE returns true.
- * In this case, the video callback can take a NULL argument for data.
- */
-void retro_run(void);
-
-/* Returns the amount of data the implementation requires to serialize 
- * internal state (save states).
- * Between calls to retro_load_game() and retro_unload_game(), the 
- * returned size is never allowed to be larger than a previous returned 
- * value, to ensure that the frontend can allocate a save state buffer once.
- */
-size_t retro_serialize_size(void);
-
-/* Serializes internal state. If failed, or size is lower than
- * retro_serialize_size(), it should return false, true otherwise. */
-bool retro_serialize(void *data, size_t size);
-bool retro_unserialize(const void *data, size_t size);
-
-void retro_cheat_reset(void);
-void retro_cheat_set(unsigned index, bool enabled, const char *code);
-
-/* Loads a game. */
-bool retro_load_game(const struct retro_game_info *game);
-
-/* Loads a "special" kind of game. Should not be used,
- * except in extreme cases. */
-bool retro_load_game_special(
-  unsigned game_type,
-  const struct retro_game_info *info, size_t num_info
-);
-
-/* Unloads a currently loaded game. */
-void retro_unload_game(void);
-
-/* Gets region of game. */
-unsigned retro_get_region(void);
-
-/* Gets region of memory. */
-void *retro_get_memory_data(unsigned id);
-size_t retro_get_memory_size(unsigned id);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/frontend/libretro_core_options.h b/frontend/libretro_core_options.h
new file mode 100644 (file)
index 0000000..1dbcefa
--- /dev/null
@@ -0,0 +1,1204 @@
+#ifndef LIBRETRO_CORE_OPTIONS_H__
+#define LIBRETRO_CORE_OPTIONS_H__
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <libretro.h>
+#include <retro_inline.h>
+
+#ifndef HAVE_NO_LANGEXTRA
+#include "libretro_core_options_intl.h"
+#endif
+
+/*
+ ********************************
+ * VERSION: 1.3
+ ********************************
+ *
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_ENGLISH */
+
+/* Default language:
+ * - All other languages must include the same keys and values
+ * - Will be used as a fallback in the event that frontend language
+ *   is not available
+ * - Will be used as a fallback for any missing entries in
+ *   frontend language definition
+ */
+
+struct retro_core_option_definition option_defs_us[] = {
+   {
+      "pcsx_rearmed_frameskip",
+      "Frameskip",
+      "Choose how much frames should be skipped to improve performance at the expense of visual smoothness.",
+      {
+         { "0", NULL },
+         { "1", NULL },
+         { "2", NULL },
+         { "3", NULL },
+         { NULL, NULL },
+      },
+      "0",
+   },
+   {
+      "pcsx_rearmed_bios",
+      "Use BIOS",
+      "Allows you to use real bios file (if available) or emulated bios (HLE). Its recommended to use official bios file for better compatibility.",
+      {
+         { "auto", "auto" },
+         { "HLE",  "hle" },
+         { NULL, NULL },
+      },
+      "auto",
+   },
+   {
+      "pcsx_rearmed_region",
+      "Region",
+      "Choose what region the system is from. 60 Hz for NTSC, 50 Hz for PAL.",
+      {
+         { "auto", "auto" },
+         { "NTSC", "ntsc" },
+         { "PAL",  "pal" },
+         { NULL, NULL },
+      },
+      "auto",
+   },
+   {
+      "pcsx_rearmed_memcard2",
+      "Enable Second Memory Card (Shared)",
+      "Enabled the memory card slot 2. This memory card is shared amongst all games.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_show_other_input_settings",
+      "Show other input settings",
+      "Shows or hides other inputs settings like multitaps, player 3-8 ports, analog fine-tunings, etc.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_input_sensitivity",
+      "Emulated Mouse Sensitivity",
+      "Adjust responsiveness when using mouse controller (Default 1.0).",
+      {
+         { "0.05", NULL },
+         { "0.10", NULL },
+         { "0.15", NULL },
+         { "0.20", NULL },
+         { "0.25", NULL },
+         { "0.30", NULL },
+         { "0.35", NULL },
+         { "0.40", NULL },
+         { "0.45", NULL },
+         { "0.50", NULL },
+         { "0.55", NULL },
+         { "0.60", NULL },
+         { "0.65", NULL },
+         { "0.70", NULL },
+         { "0.75", NULL },
+         { "0.80", NULL },
+         { "0.85", NULL },
+         { "0.90", NULL },
+         { "0.95", NULL },
+         { "1.00", NULL },
+         { "1.05", NULL },
+         { "1.10", NULL },
+         { "1.15", NULL },
+         { "1.20", NULL },
+         { "1.25", NULL },
+         { "1.30", NULL },
+         { "1.35", NULL },
+         { "1.40", NULL },
+         { "1.45", NULL },
+         { "1.50", NULL },
+         { "1.55", NULL },
+         { "1.60", NULL },
+         { "1.65", NULL },
+         { "1.70", NULL },
+         { "1.75", NULL },
+         { "1.80", NULL },
+         { "1.85", NULL },
+         { "1.90", NULL },
+         { "1.95", NULL },
+         { "2.00", NULL },
+      },
+      "1.00",
+   },
+   {
+      "pcsx_rearmed_multitap",
+      "Multitap Mode (Restart)",
+      "Sets the playstation multitap peripheral to either controller port 1 or controller port 2 to support of upto 5 players simultaneously, or on both for upto 8 players simultaneously. Option depends on games that has support for multitap feature. Leave option on disabled if not such compatible games to avoid any input-related problems.",
+      {
+         { "disabled",      NULL },
+         { "port 1",        NULL },
+         { "port 2",        NULL },
+         { "ports 1 and 2", NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_negcon_deadzone",
+      "NegCon Twist Deadzone (Percent)",
+      "Sets the deadzone of the RetroPad left analog stick when simulating the 'twist' action of emulated neGcon Controllers. Used to eliminate drift/unwanted input.",
+      {
+         { "0",  NULL },
+         { "5",  NULL },
+         { "10", NULL },
+         { "15", NULL },
+         { "20", NULL },
+         { "25", NULL },
+         { "30", NULL },
+         { NULL, NULL },
+      },
+      "0",
+   },
+   {
+      "pcsx_rearmed_negcon_response",
+      "NegCon Twist Response",
+      "Specifies the analog response when using a RetroPad left analog stick to simulate the 'twist' action of emulated neGcon Controllers.",
+      {
+         { "linear",    NULL },
+         { "quadratic", NULL },
+         { "cubic",     NULL },
+         { NULL, NULL },
+      },
+      "linear",
+   },
+   {
+      "pcsx_rearmed_analog_axis_modifier",
+      "Analog axis bounds.",
+      "Range bounds for analog axis. Square bounds help controllers with highly circular ranges that are unable to fully saturate the x and y axis at 45degree deflections.",
+      {
+         { "circle", NULL },
+         { "square", NULL },
+         { NULL, NULL },
+      },
+      "circle",
+   },
+   {
+      "pcsx_rearmed_vibration",
+      "Enable Vibration",
+      "Enables vibration feedback for controllers that supports vibration features.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "enabled",
+   },
+   {
+      "pcsx_rearmed_gunconadjustx",
+      "Guncon Adjust X",
+      "When using Guncon mode, you can override aim in emulator if shots misaligned, this applies an increment on the x axis.",
+      {
+         { "0", NULL },
+         { "-25", NULL },
+         { "-24", NULL },
+         { "-23", NULL },
+         { "-22", NULL },
+         { "-21", NULL },
+         { "-20", NULL },
+         { "-19", NULL },
+         { "-18", NULL },
+         { "-17", NULL },
+         { "-16", NULL },
+         { "-15", NULL },
+         { "-14", NULL },
+         { "-13", NULL },
+         { "-12", NULL },
+         { "-11", NULL },
+         { "-10", NULL },
+         { "-09", NULL },
+         { "-08", NULL },
+         { "-07", NULL },
+         { "-06", NULL },
+         { "-05", NULL },
+         { "-04", NULL },
+         { "-03", NULL },
+         { "-02", NULL },
+         { "-01", NULL },
+         { "00", NULL },
+         { "01", NULL },
+         { "02", NULL },
+         { "03", NULL },
+         { "04", NULL },
+         { "05", NULL },
+         { "06", NULL },
+         { "07", NULL },
+         { "08", NULL },
+         { "09", NULL },
+         { "10", NULL },
+         { "11", NULL },
+         { "12", NULL },
+         { "13", NULL },
+         { "14", NULL },
+         { "15", NULL },
+         { "16", NULL },
+         { "17", NULL },
+         { "18", NULL },
+         { "19", NULL },
+         { "20", NULL },
+         { "21", NULL },
+         { "22", NULL },
+         { "23", NULL },
+         { "24", NULL },
+         { "25", NULL },
+         { NULL, NULL },
+      },
+      "0",
+   },
+   {
+      "pcsx_rearmed_gunconadjusty",
+      "Guncon Adjust Y",
+      "When using Guncon mode, you can override aim in emulator if shots misaligned, this applies an increment on the y axis.",
+      {
+         { "0", NULL },
+         { "-25", NULL },
+         { "-24", NULL },
+         { "-23", NULL },
+         { "-22", NULL },
+         { "-21", NULL },
+         { "-20", NULL },
+         { "-19", NULL },
+         { "-18", NULL },
+         { "-17", NULL },
+         { "-16", NULL },
+         { "-15", NULL },
+         { "-14", NULL },
+         { "-13", NULL },
+         { "-12", NULL },
+         { "-11", NULL },
+         { "-10", NULL },
+         { "-09", NULL },
+         { "-08", NULL },
+         { "-07", NULL },
+         { "-06", NULL },
+         { "-05", NULL },
+         { "-04", NULL },
+         { "-03", NULL },
+         { "-02", NULL },
+         { "-01", NULL },
+         { "00", NULL },
+         { "01", NULL },
+         { "02", NULL },
+         { "03", NULL },
+         { "04", NULL },
+         { "05", NULL },
+         { "06", NULL },
+         { "07", NULL },
+         { "08", NULL },
+         { "09", NULL },
+         { "10", NULL },
+         { "11", NULL },
+         { "12", NULL },
+         { "13", NULL },
+         { "14", NULL },
+         { "15", NULL },
+         { "16", NULL },
+         { "17", NULL },
+         { "18", NULL },
+         { "19", NULL },
+         { "20", NULL },
+         { "21", NULL },
+         { "22", NULL },
+         { "23", NULL },
+         { "24", NULL },
+         { "25", NULL },
+         { NULL, NULL },
+      },
+      "0",
+   },
+   {
+      "pcsx_rearmed_gunconadjustratiox",
+      "Guncon Adjust Ratio X",
+      "When using Guncon mode, you can override aim in emulator if shots misaligned, this applies a ratio on the x axis.",
+      {
+         { "1", NULL },
+         { "0.75", NULL },
+         { "0.76", NULL },
+         { "0.77", NULL },
+         { "0.78", NULL },
+         { "0.79", NULL },
+         { "0.80", NULL },
+         { "0.81", NULL },
+         { "0.82", NULL },
+         { "0.83", NULL },
+         { "0.84", NULL },
+         { "0.85", NULL },
+         { "0.86", NULL },
+         { "0.87", NULL },
+         { "0.88", NULL },
+         { "0.89", NULL },
+         { "0.90", NULL },
+         { "0.91", NULL },
+         { "0.92", NULL },
+         { "0.93", NULL },
+         { "0.94", NULL },
+         { "0.95", NULL },
+         { "0.96", NULL },
+         { "0.97", NULL },
+         { "0.98", NULL },
+         { "0.99", NULL },
+         { "1.00", NULL },
+         { "1.01", NULL },
+         { "1.02", NULL },
+         { "1.03", NULL },
+         { "1.04", NULL },
+         { "1.05", NULL },
+         { "1.06", NULL },
+         { "1.07", NULL },
+         { "1.08", NULL },
+         { "1.09", NULL },
+         { "1.10", NULL },
+         { "1.11", NULL },
+         { "1.12", NULL },
+         { "1.13", NULL },
+         { "1.14", NULL },
+         { "1.15", NULL },
+         { "1.16", NULL },
+         { "1.17", NULL },
+         { "1.18", NULL },
+         { "1.19", NULL },
+         { "1.20", NULL },
+         { "1.21", NULL },
+         { "1.22", NULL },
+         { "1.23", NULL },
+         { "1.24", NULL },
+         { "1.25", NULL },
+         { NULL, NULL },
+      },
+      "1",
+   },
+   {
+      "pcsx_rearmed_gunconadjustratioy",
+      "Guncon Adjust Ratio Y",
+      "When using Guncon mode, you can override aim in emulator if shots misaligned, this applies a ratio on the y axis.",
+      {
+         { "1", NULL },
+         { "0.75", NULL },
+         { "0.76", NULL },
+         { "0.77", NULL },
+         { "0.78", NULL },
+         { "0.79", NULL },
+         { "0.80", NULL },
+         { "0.81", NULL },
+         { "0.82", NULL },
+         { "0.83", NULL },
+         { "0.84", NULL },
+         { "0.85", NULL },
+         { "0.86", NULL },
+         { "0.87", NULL },
+         { "0.88", NULL },
+         { "0.89", NULL },
+         { "0.90", NULL },
+         { "0.91", NULL },
+         { "0.92", NULL },
+         { "0.93", NULL },
+         { "0.94", NULL },
+         { "0.95", NULL },
+         { "0.96", NULL },
+         { "0.97", NULL },
+         { "0.98", NULL },
+         { "0.99", NULL },
+         { "1.00", NULL },
+         { "1.01", NULL },
+         { "1.02", NULL },
+         { "1.03", NULL },
+         { "1.04", NULL },
+         { "1.05", NULL },
+         { "1.06", NULL },
+         { "1.07", NULL },
+         { "1.08", NULL },
+         { "1.09", NULL },
+         { "1.10", NULL },
+         { "1.11", NULL },
+         { "1.12", NULL },
+         { "1.13", NULL },
+         { "1.14", NULL },
+         { "1.15", NULL },
+         { "1.16", NULL },
+         { "1.17", NULL },
+         { "1.18", NULL },
+         { "1.19", NULL },
+         { "1.20", NULL },
+         { "1.21", NULL },
+         { "1.22", NULL },
+         { "1.23", NULL },
+         { "1.24", NULL },
+         { "1.25", NULL },
+         { NULL, NULL },
+      },
+      "1",
+   },
+   {
+      "pcsx_rearmed_dithering",
+      "Enable Dithering",
+      "If Off, disables the dithering pattern the PSX applies to combat color banding.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+#if defined HAVE_LIBNX || defined _3DS
+         "disabled",
+#else
+      "enabled",
+#endif
+   },
+
+#if defined(LIGHTREC) || defined(NEW_DYNAREC)
+   {
+      "pcsx_rearmed_drc",
+      "Dynamic Recompiler",
+      "Enables core to use dynamic recompiler or interpreter (slower) CPU instructions.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "enabled",
+   },
+#endif /* LIGHTREC || NEW_DYNAREC */
+
+#ifdef NEW_DYNAREC
+   {
+      "pcsx_rearmed_psxclock",
+      "PSX CPU Clock",
+#if defined(HAVE_PRE_ARMV7) && !defined(_3DS)
+      "Overclock or underclock the PSX clock. Default is 50",
+#else
+      "Overclock or underclock the PSX clock. Default is 57",
+#endif
+      {
+         { "30",  NULL },
+         { "31",  NULL },
+         { "32",  NULL },
+         { "33",  NULL },
+         { "34",  NULL },
+         { "35",  NULL },
+         { "36",  NULL },
+         { "37",  NULL },
+         { "38",  NULL },
+         { "39",  NULL },
+         { "40",  NULL },
+         { "41",  NULL },
+         { "42",  NULL },
+         { "43",  NULL },
+         { "44",  NULL },
+         { "45",  NULL },
+         { "46",  NULL },
+         { "47",  NULL },
+         { "48",  NULL },
+         { "49",  NULL },
+         { "50",  NULL },
+         { "51",  NULL },
+         { "52",  NULL },
+         { "53",  NULL },
+         { "54",  NULL },
+         { "55",  NULL },
+         { "56",  NULL },
+         { "57",  NULL },
+         { "58",  NULL },
+         { "59",  NULL },
+         { "60",  NULL },
+         { "61",  NULL },
+         { "62",  NULL },
+         { "63",  NULL },
+         { "64",  NULL },
+         { "65",  NULL },
+         { "66",  NULL },
+         { "67",  NULL },
+         { "68",  NULL },
+         { "69",  NULL },
+         { "70",  NULL },
+         { "71",  NULL },
+         { "72",  NULL },
+         { "73",  NULL },
+         { "74",  NULL },
+         { "75",  NULL },
+         { "76",  NULL },
+         { "77",  NULL },
+         { "78",  NULL },
+         { "79",  NULL },
+         { "80",  NULL },
+         { "81",  NULL },
+         { "82",  NULL },
+         { "83",  NULL },
+         { "84",  NULL },
+         { "85",  NULL },
+         { "86",  NULL },
+         { "87",  NULL },
+         { "88",  NULL },
+         { "89",  NULL },
+         { "90",  NULL },
+         { "91",  NULL },
+         { "92",  NULL },
+         { "93",  NULL },
+         { "94",  NULL },
+         { "95",  NULL },
+         { "96",  NULL },
+         { "97",  NULL },
+         { "98",  NULL },
+         { "99",  NULL },
+         { "100", NULL },
+         { NULL, NULL },
+      },
+#if defined(HAVE_PRE_ARMV7) && !defined(_3DS)
+      "50",
+#else
+      "57",
+#endif
+   },
+#endif /* NEW_DYNAREC */
+
+#ifdef GPU_NEON
+   {
+      "pcsx_rearmed_neon_interlace_enable",
+      "Enable Interlacing Mode",
+      "Enables fake scanlines effect.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_neon_enhancement_enable",
+      "Enhanced Resolution (Slow)",
+      "Renders in double resolution at the cost of lower performance.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_neon_enhancement_no_main",
+      "Enhanced Resolution (Speed Hack)",
+      "Speed hack for Enhanced resolution option (glitches some games).",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+#endif /* GPU_NEON */
+
+   {
+      "pcsx_rearmed_duping_enable",
+      "Frame Duping",
+      "A speedup, redraws/reuses the last frame if there was no new data.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "enabled",
+   },
+   {
+      "pcsx_rearmed_display_internal_fps",
+      "Display Internal FPS",
+      "Shows an on-screen frames per second counter when enabled.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+
+   /* GPU PEOPS OPTIONS */
+#ifdef GPU_PEOPS
+   {
+      "pcsx_rearmed_show_gpu_peops_settings",
+      "Advanced GPU P.E.Op.S. Settings",
+      "Shows or hides advanced GPU plugin settings. NOTE: Quick Menu must be toggled for this setting to take effect.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_peops_odd_even_bit",
+      "(GPU) Odd/Even Bit Hack",
+      "Needed for Chrono Cross.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_peops_expand_screen_width",
+      "(GPU) Expand Screen Width",
+      "Capcom fighting games",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_peops_ignore_brightness",
+      "(GPU) Ignore Brightness Color",
+      "Black screens in Lunar Silver Star Story games",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_peops_disable_coord_check",
+      "(GPU) Disable Coordinate Check",
+      "Compatibility mode",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_peops_lazy_screen_update",
+      "(GPU) Lazy Screen Update",
+      "Pandemonium 2",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_peops_old_frame_skip",
+      "(GPU) Old Frame Skipping",
+      "Skip every second frame",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "enabled",
+   },
+   {
+      "pcsx_rearmed_gpu_peops_repeated_triangles",
+      "(GPU) Repeated Flat Tex Triangles",
+      "Needed by Star Wars: Dark Forces",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_peops_quads_with_triangles",
+      "(GPU) Draw Quads with Triangles",
+      "Better g-colors, worse textures",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_peops_fake_busy_state",
+      "(GPU) Fake 'Gpu Busy' States",
+      "Toggle busy flags after drawing",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+#endif
+
+    /* GPU UNAI Advanced Options */
+#ifdef GPU_UNAI
+   {
+      "pcsx_rearmed_show_gpu_unai_settings",
+      "Advance GPU UNAI/PCSX4All Settings",
+      "Shows or hides advanced gpu settings. A core restart might be needed for settings to take effect. NOTE: Quick Menu must be toggled for this setting to take effect.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL},
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_unai_blending",
+      "(GPU) Enable Blending",
+      NULL,
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL},
+      },
+      "enabled",
+   },
+   {
+      "pcsx_rearmed_gpu_unai_lighting",
+      "(GPU) Enable Lighting",
+      NULL,
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL},
+      },
+      "enabled",
+   },
+   {
+      "pcsx_rearmed_gpu_unai_fast_lighting",
+      "(GPU) Enable Fast Lighting",
+      NULL,
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL},
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_unai_ilace_force",
+      "(GPU) Enable Forced Interlace",
+      NULL,
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL},
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_unai_pixel_skip",
+      "(GPU) Enable Pixel Skip",
+      NULL,
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL},
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gpu_unai_scale_hires",
+      "(GPU) Enable Hi-Res Downscaling",
+      "When enabled, will scale hi-res modes to 320x240, skipping unrendered pixels.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL},
+      },
+      "disabled",
+   },
+#endif /* GPU UNAI Advanced Settings */
+#ifdef THREAD_RENDERING
+   {
+      "pcsx_rearmed_gpu_thread_rendering",
+      "Threaded Rendering",
+      "When enabled, runs GPU commands in a thread. Sync waits for drawing to finish before vsync. Async will not wait unless there's another frame behind it.",
+      {
+         { "disabled", NULL },
+         { "sync",  NULL },
+         { "async",  NULL },
+         { NULL, NULL},
+      },
+      "disabled",
+   },
+#endif
+
+   {
+      "pcsx_rearmed_show_bios_bootlogo",
+      "Show Bios Bootlogo",
+      "When enabled, shows the PlayStation logo when starting or resetting. (Breaks some games).",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_spu_reverb",
+      "Sound Reverb",
+      "Enables or disables audio reverb effect.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "enabled",
+   },
+   {
+      "pcsx_rearmed_spu_interpolation",
+      "Sound Interpolation",
+      NULL,
+      {
+         { "simple",   "Simple" },
+         { "gaussian", "Gaussian" },
+         { "cubic",    "Cubic" },
+         { "off",      "disabled" },
+         { NULL, NULL },
+      },
+      "simple",
+   },
+   {
+      "pcsx_rearmed_pe2_fix",
+      "Parasite Eve 2/Vandal Hearts 1/2 Fix",
+      NULL,
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_inuyasha_fix",
+      "InuYasha Sengoku Battle Fix",
+      NULL,
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+#ifndef _WIN32
+   {
+      "pcsx_rearmed_async_cd",
+      "CD Access Method (Restart)",
+      "Select method used to read data from content disk images. 'Synchronous' mimics original hardware. 'Asynchronous' can reduce stuttering on devices with slow storage. 'Precache' loads disk image into memory for faster access (CHD only).",
+      {
+         { "sync",     "Synchronous" },
+         { "async",    "Asynchronous" },
+         { "precache", "Precache" },
+         { NULL, NULL},
+      },
+      "sync",
+   },
+#endif
+   /* ADVANCED OPTIONS */
+   {
+      "pcsx_rearmed_noxadecoding",
+      "XA Decoding",
+      NULL,
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "enabled",
+   },
+   {
+      "pcsx_rearmed_nocdaudio",
+      "CD Audio",
+      NULL,
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "enabled",
+   },
+   {
+      "pcsx_rearmed_spuirq",
+      "SPU IRQ Always Enabled",
+      "Compatibility tweak, should be left to off in most cases.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+
+#ifdef NEW_DYNAREC
+   {
+      "pcsx_rearmed_nosmccheck",
+      "(Speed Hack) Disable SMC Checks",
+      "Will cause crashes when loading, break memcards.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_gteregsunneeded",
+      "(Speed Hack) Assume GTE Regs Unneeded",
+      "May cause graphical glitches.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+   {
+      "pcsx_rearmed_nogteflags",
+      "(Speed Hack) Disable GTE Flags",
+      "Will cause graphical glitches.",
+      {
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "disabled",
+   },
+#endif /* NEW_DYNAREC */
+
+   { NULL, NULL, NULL, {{0}}, NULL },
+};
+
+/*
+ ********************************
+ * Language Mapping
+ ********************************
+*/
+
+#ifndef HAVE_NO_LANGEXTRA
+struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
+   option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
+   NULL,           /* RETRO_LANGUAGE_JAPANESE */
+   NULL,           /* RETRO_LANGUAGE_FRENCH */
+   NULL,           /* RETRO_LANGUAGE_SPANISH */
+   NULL,           /* RETRO_LANGUAGE_GERMAN */
+   NULL,           /* RETRO_LANGUAGE_ITALIAN */
+   NULL,           /* RETRO_LANGUAGE_DUTCH */
+   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+   NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+   NULL,           /* RETRO_LANGUAGE_RUSSIAN */
+   NULL,           /* RETRO_LANGUAGE_KOREAN */
+   NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+   NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+   NULL,           /* RETRO_LANGUAGE_ESPERANTO */
+   NULL,           /* RETRO_LANGUAGE_POLISH */
+   NULL,           /* RETRO_LANGUAGE_VIETNAMESE */
+   NULL,           /* RETRO_LANGUAGE_ARABIC */
+   NULL,           /* RETRO_LANGUAGE_GREEK */
+   option_defs_tr, /* RETRO_LANGUAGE_TURKISH */
+};
+#endif
+
+/*
+ ********************************
+ * Functions
+ ********************************
+*/
+
+/* Handles configuration/setting of core options.
+ * Should be called as early as possible - ideally inside
+ * retro_set_environment(), and no later than retro_load_game()
+ * > We place the function body in the header to avoid the
+ *   necessity of adding more .c files (i.e. want this to
+ *   be as painless as possible for core devs)
+ */
+
+static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
+{
+   unsigned version = 0;
+
+   if (!environ_cb)
+      return;
+
+   if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
+   {
+#ifndef HAVE_NO_LANGEXTRA
+      struct retro_core_options_intl core_options_intl;
+      unsigned language = 0;
+
+      core_options_intl.us    = option_defs_us;
+      core_options_intl.local = NULL;
+
+      if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
+          (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
+         core_options_intl.local = option_defs_intl[language];
+
+      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
+#else
+      environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
+#endif
+   }
+   else
+   {
+      size_t i;
+      size_t option_index              = 0;
+      size_t num_options               = 0;
+      struct retro_variable *variables = NULL;
+      char **values_buf                = NULL;
+
+      /* Determine number of options
+       * > Note: We are going to skip a number of irrelevant
+       *   core options when building the retro_variable array,
+       *   but we'll allocate space for all of them. The difference
+       *   in resource usage is negligible, and this allows us to
+       *   keep the code 'cleaner' */
+      while (true)
+      {
+         if (option_defs_us[num_options].key)
+            num_options++;
+         else
+            break;
+      }
+
+      /* Allocate arrays */
+      variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
+      values_buf = (char **)calloc(num_options, sizeof(char *));
+
+      if (!variables || !values_buf)
+         goto error;
+
+      /* Copy parameters from option_defs_us array */
+      for (i = 0; i < num_options; i++)
+      {
+         const char *key                        = option_defs_us[i].key;
+         const char *desc                       = option_defs_us[i].desc;
+         const char *default_value              = option_defs_us[i].default_value;
+         struct retro_core_option_value *values = option_defs_us[i].values;
+         size_t buf_len                         = 3;
+         size_t default_index                   = 0;
+
+         values_buf[i] = NULL;
+
+         /* Skip options that are irrelevant when using the
+          * old style core options interface */
+         if ((strcmp(key, "pcsx_rearmed_show_gpu_peops_settings") == 0))
+            continue;
+
+         if (desc)
+         {
+            size_t num_values = 0;
+
+            /* Determine number of values */
+            while (true)
+            {
+               if (values[num_values].value)
+               {
+                  /* Check if this is the default value */
+                  if (default_value)
+                     if (strcmp(values[num_values].value, default_value) == 0)
+                        default_index = num_values;
+
+                  buf_len += strlen(values[num_values].value);
+                  num_values++;
+               }
+               else
+                  break;
+            }
+
+            /* Build values string */
+            if (num_values > 0)
+            {
+               size_t j;
+
+               buf_len += num_values - 1;
+               buf_len += strlen(desc);
+
+               values_buf[i] = (char *)calloc(buf_len, sizeof(char));
+               if (!values_buf[i])
+                  goto error;
+
+               strcpy(values_buf[i], desc);
+               strcat(values_buf[i], "; ");
+
+               /* Default value goes first */
+               strcat(values_buf[i], values[default_index].value);
+
+               /* Add remaining values */
+               for (j = 0; j < num_values; j++)
+               {
+                  if (j != default_index)
+                  {
+                     strcat(values_buf[i], "|");
+                     strcat(values_buf[i], values[j].value);
+                  }
+               }
+            }
+         }
+
+         variables[option_index].key   = key;
+         variables[option_index].value = values_buf[i];
+         option_index++;
+      }
+
+      /* Set variables */
+      environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
+
+error:
+
+      /* Clean up */
+      if (values_buf)
+      {
+         for (i = 0; i < num_options; i++)
+         {
+            if (values_buf[i])
+            {
+               free(values_buf[i]);
+               values_buf[i] = NULL;
+            }
+         }
+
+         free(values_buf);
+         values_buf = NULL;
+      }
+
+      if (variables)
+      {
+         free(variables);
+         variables = NULL;
+      }
+   }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/frontend/libretro_core_options_intl.h b/frontend/libretro_core_options_intl.h
new file mode 100644 (file)
index 0000000..174bb93
--- /dev/null
@@ -0,0 +1,450 @@
+#ifndef LIBRETRO_CORE_OPTIONS_INTL_H__
+#define LIBRETRO_CORE_OPTIONS_INTL_H__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1500 && _MSC_VER < 1900)
+/* https://support.microsoft.com/en-us/kb/980263 */
+#pragma execution_character_set("utf-8")
+#pragma warning(disable:4566)
+#endif
+
+#include <libretro.h>
+
+/*
+ ********************************
+ * VERSION: 1.3
+ ********************************
+ *
+ * - 1.3: Move translations to libretro_core_options_intl.h
+ *        - libretro_core_options_intl.h includes BOM and utf-8
+ *          fix for MSVC 2010-2013
+ *        - Added HAVE_NO_LANGEXTRA flag to disable translations
+ *          on platforms/compilers without BOM support
+ * - 1.2: Use core options v1 interface when
+ *        RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
+ *        (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
+ * - 1.1: Support generation of core options v0 retro_core_option_value
+ *        arrays containing options with a single value
+ * - 1.0: First commit
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ ********************************
+ * Core Option Definitions
+ ********************************
+*/
+
+/* RETRO_LANGUAGE_JAPANESE */
+
+/* RETRO_LANGUAGE_FRENCH */
+
+/* RETRO_LANGUAGE_SPANISH */
+
+/* RETRO_LANGUAGE_GERMAN */
+
+/* RETRO_LANGUAGE_ITALIAN */
+
+/* RETRO_LANGUAGE_DUTCH */
+
+/* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
+
+/* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
+
+/* RETRO_LANGUAGE_RUSSIAN */
+
+/* RETRO_LANGUAGE_KOREAN */
+
+/* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
+
+/* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
+
+/* RETRO_LANGUAGE_ESPERANTO */
+
+/* RETRO_LANGUAGE_POLISH */
+
+/* RETRO_LANGUAGE_VIETNAMESE */
+
+/* RETRO_LANGUAGE_ARABIC */
+
+/* RETRO_LANGUAGE_GREEK */
+
+/* RETRO_LANGUAGE_TURKISH */
+
+struct retro_core_option_definition option_defs_tr[] = {
+   {
+      "pcsx_rearmed_frameskip",
+      "Kare Atlama",
+      "Görsel pürüzsüzlük pahasına performansı artırmak için ne kadar karenin atlanması gerektiÄŸini seçin.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_bios",
+      "BIOS Kullan",
+      "Gerçek bios dosyasını (varsa) veya Ã¶ykünmüş bios'u (HLE) kullanmanızı saÄŸlar. Daha iyi uyumluluk için resmi bios dosyasını kullanmanız Ã¶nerilir.",
+      {
+         { "auto", "otomatik" },
+         { "HLE",  "hle" },
+         { NULL, NULL },
+      },
+      "auto",
+   },
+   {
+      "pcsx_rearmed_region",
+      "Bölge",
+      "Sistemin hangi bölgeden olduÄŸunu seçin. NTSC için 60 Hz, PAL için 50 Hz.",
+      {
+         { "auto", "otomatik" },
+         { "NTSC", "ntsc" },
+         { "PAL",  "pal" },
+         { NULL, NULL },
+      },
+      "auto",
+   },
+   {
+      "pcsx_rearmed_memcard2",
+      "Ä°kinci Bellek Kartını EtkinleÅŸtir (Paylaşılan)",
+      "2. Hafıza kartı yuvasını etkinleÅŸtirin. Bu hafıza kartı tüm oyunlar arasında paylaşılır.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_multitap1",
+      "Multitap 1",
+      "BaÄŸlantı noktası 1'deki multitap'ı etkinleÅŸtirir / devre dışı bırakır ve izin veren oyunlarda 5 oyuncuya kadar izin verir.",
+      {
+         { "auto",     "otomatik" },
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "auto",
+   },
+   {
+      "pcsx_rearmed_multitap2",
+      "Multitap 2",
+      "BaÄŸlantı noktası 2'deki multitap'ı etkinleÅŸtirir/devre dışı bırakır ve izin veren oyunlarda 8 oyuncuya kadar izin verir. Bunun Ã§alışması için Multitap 1'in etkinleÅŸtirilmesi gerekir.",
+      {
+         { "auto",     "otomatik" },
+         { "disabled", NULL },
+         { "enabled",  NULL },
+         { NULL, NULL },
+      },
+      "auto",
+   },
+   {
+      "pcsx_rearmed_negcon_deadzone",
+      "NegCon Twist Deadzone (Yüzdelik)",
+      "Öykünülmüş neGcon kontrolörünün 'büküm' eylemini simüle ederken RetroPad sol analog Ã§ubuÄŸunun Ã¶lü bölgesini ayarlar. Sürüklenme/istenmeyen giriÅŸi ortadan kaldırmak için kullanılır.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_negcon_response",
+      "NegCon Twist Response",
+      "Öykünülmüş neGcon kontrolörünün 'bükümünü' simule etmek için bir RetroPad sol analog Ã§ubuÄŸu kullanırken analog cevabını belirtir.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_vibration",
+      "TitreÅŸimi EtkinleÅŸtir",
+      "TitreÅŸim Ã¶zelliklerini destekleyen kontrolörler için titreÅŸim geri bildirimini etkinleÅŸtirir.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_dithering",
+      "Dithering EtkinleÅŸtir",
+      "Kapalı ise, PSX'in renk bantlarıyla mücadele etmek için uyguladığı renk taklidi düzenini devre dışı bırakır.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+
+#ifdef NEW_DYNAREC
+   {
+      "pcsx_rearmed_drc",
+      "Dinamik Yeniden Derleyici",
+      "ÇekirdeÄŸin dinamik yeniden derleyici veya tercüman(daha yavaÅŸ) CPU talimatlarını kullanmasını saÄŸlar.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_psxclock",
+      "PSX CPU Saat Hızı",
+#ifdef HAVE_PRE_ARMV7
+      "Overclock or underclock the PSX clock. Default is 50",
+#else
+      "Overclock or underclock the PSX clock. Default is 57",
+#endif
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+#endif /* NEW_DYNAREC */
+
+#ifdef __ARM_NEON__
+   {
+      "pcsx_rearmed_neon_interlace_enable",
+      "Interlacing Mode'u etkinleÅŸtir",
+      "Sahte tarama Ã§izgileri efektini etkinleÅŸtirir.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_neon_enhancement_enable",
+      "GeliÅŸtirilmiÅŸ Ã‡Ã¶zünürlük (YavaÅŸ)",
+      "Düşük performans pahasına Ã§ift Ã§Ã¶zünürlükte iÅŸler.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_neon_enhancement_no_main",
+      "GeliÅŸtirilmiÅŸ Ã‡Ã¶zünürlük (Speed Hack)",
+      "GeliÅŸtirilmiÅŸ Ã§Ã¶zünürlük seçeneÄŸi için hız aşırtma(bazı oyunlarda sorun Ã§Ä±kartabilir).",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+#endif /* __ARM_NEON__ */
+
+   {
+      "pcsx_rearmed_duping_enable",
+      "Frame Duping",
+      "Yeni bir veri yoksa, bir hızlandırma, son kareyi yeniden Ã§izer/yeniden kullanır.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_display_internal_fps",
+      "Dahili FPS'yi görüntüle",
+      "EtkinleÅŸtirildiÄŸinde ekranda saniye başına kareyi gösterir.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+
+   /* GPU PEOPS OPTIONS */
+#ifdef GPU_PEOPS
+   {
+      "pcsx_rearmed_show_gpu_peops_settings",
+      "GeliÅŸmiÅŸ GPU Ayarlarını Göster",
+      "ÇeÅŸitli GPU düzeltmelerini etkinleÅŸtirin veya devre dışı bırakın. Ayarların etkili olması için core'un yeniden baÅŸlatılması gerekebilir. NOT: Bu ayarın etkili olabilmesi için Hızlı Menü’nün deÄŸiÅŸtirilmesi gerekir.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gpu_peops_odd_even_bit",
+      "(GPU) Odd/Even Bit Hack",
+      "Chrono Cross için gerekli.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gpu_peops_expand_screen_width",
+      "(GPU) Ekran GeniÅŸliÄŸini GeniÅŸlet",
+      "Capcom dövüş oyunları",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gpu_peops_ignore_brightness",
+      "(GPU) Parlaklık Rengini Yoksay",
+      "Lunar Silver Star Story oyunlarında siyah ekran",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gpu_peops_disable_coord_check",
+      "(GPU) Koordinat Kontrolünü Devre Dışı Bırak",
+      "Uyumluluk modu",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gpu_peops_lazy_screen_update",
+      "(GPU) Tembel Ekran Güncellemesi",
+      "Pandemonium 2",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gpu_peops_old_frame_skip",
+      "(GPU) Eski Ã‡erçeve Atlama",
+      "Her ikinci kareyi atla",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gpu_peops_repeated_triangles",
+      "(GPU) Tekrarlanan Düz Doku ÃœÃ§genleri",
+      "Star Wars: Dark Forces için gerekli",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gpu_peops_quads_with_triangles",
+      "(GPU) ÃœÃ§genler ile Dörtlü Ã‡iz",
+      "Daha iyi g renkler, daha kötü dokular",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gpu_peops_fake_busy_state",
+      "(GPU) Sahte 'Gpu MeÅŸgul' Konumları",
+      "Çizimden sonra meÅŸgul bayraklarını deÄŸiÅŸtir",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+#endif /* GPU_PEOPS */
+
+   {
+      "pcsx_rearmed_show_bios_bootlogo",
+      "Bios Bootlogo'yu Göster",
+      "EtkinleÅŸtirildiÄŸinde, baÅŸlatırken veya sıfırlarken PlayStation logosunu gösterir. (Bazı oyunları bozabilir).",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_spu_reverb",
+      "Ses Yankısı",
+      "Ses yankı efektini etkinleÅŸtirir veya devre dışı bırakır.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_spu_interpolation",
+      "Ses Enterpolasyonu",
+      NULL,
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_pe2_fix",
+      "Parasite Eve 2/Vandal Hearts 1/2 Düzeltmleri",
+      NULL,
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_inuyasha_fix",
+      "InuYasha Sengoku Battle Düzeltmesi",
+      NULL,
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+
+   /* ADVANCED OPTIONS */
+   {
+      "pcsx_rearmed_noxadecoding",
+      "XA Kod Ã‡Ã¶zme",
+      NULL,
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_nocdaudio",
+      "CD Ses",
+      NULL,
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+
+#ifdef NEW_DYNAREC
+   {
+      "pcsx_rearmed_nosmccheck",
+      "(Speed Hack) SMC Kontrollerini Devre Dışı Bırak",
+      "Yükleme sırasında Ã§Ã¶kmelere neden olabilir, hafıza kartını bozabilir.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_gteregsunneeded",
+      "(Speed Hack) GTE'nin Gereksiz OlduÄŸunu Varsayın",
+      "Grafiksel bozukluklara neden olabilir.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+   {
+      "pcsx_rearmed_nogteflags",
+      "(Speed Hack) GTE Bayraklarını Devredışı Bırakın",
+      "Grafiksel bozukluklara neden olur.",
+      {
+         { NULL, NULL },
+      },
+      NULL
+   },
+#endif /* NEW_DYNAREC */
+
+   { NULL, NULL, NULL, {{0}}, NULL },
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/frontend/link.T b/frontend/link.T
new file mode 100644 (file)
index 0000000..b0c262d
--- /dev/null
@@ -0,0 +1,5 @@
+{
+   global: retro_*;
+   local: *;
+};
+
index 43a5548..a64e9bb 100644 (file)
@@ -11,7 +11,7 @@
 #include <unistd.h>
 #include <signal.h>
 #include <time.h>
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(NO_DYLIB)
 #include <dlfcn.h>
 #endif
 
@@ -125,26 +125,35 @@ void emu_set_default_config(void)
        Config.SpuIrq = Config.RCntFix = Config.VSyncWA = 0;
        Config.PsxAuto = 1;
 
+       pl_rearmed_cbs.thread_rendering = 0;
+
        pl_rearmed_cbs.gpu_neon.allow_interlace = 2; // auto
        pl_rearmed_cbs.gpu_neon.enhancement_enable =
        pl_rearmed_cbs.gpu_neon.enhancement_no_main = 0;
        pl_rearmed_cbs.gpu_peops.iUseDither = 0;
        pl_rearmed_cbs.gpu_peops.dwActFixes = 1<<7;
+       pl_rearmed_cbs.gpu_unai.ilace_force = 0;
+       pl_rearmed_cbs.gpu_unai.pixel_skip = 1;
+       pl_rearmed_cbs.gpu_unai.lighting = 1;
+       pl_rearmed_cbs.gpu_unai.fast_lighting = 1;
+       pl_rearmed_cbs.gpu_unai.blending = 1;
+       pl_rearmed_cbs.gpu_unai.dithering = 0;
+       // old gpu_unai config
        pl_rearmed_cbs.gpu_unai.abe_hack =
        pl_rearmed_cbs.gpu_unai.no_light =
        pl_rearmed_cbs.gpu_unai.no_blend = 0;
+       pl_rearmed_cbs.gpu_unai.scale_hires = 0;
        memset(&pl_rearmed_cbs.gpu_peopsgl, 0, sizeof(pl_rearmed_cbs.gpu_peopsgl));
        pl_rearmed_cbs.gpu_peopsgl.iVRamSize = 64;
        pl_rearmed_cbs.gpu_peopsgl.iTexGarbageCollection = 1;
 
        spu_config.iUseReverb = 1;
-       spu_config.idiablofix = 0;
        spu_config.iUseInterpolation = 1;
        spu_config.iXAPitch = 0;
        spu_config.iVolume = 768;
        spu_config.iTempo = 0;
        spu_config.iUseThread = 1; // no effect if only 1 core is detected
-#ifdef HAVE_PRE_ARMV7 /* XXX GPH hack */
+#if defined(HAVE_PRE_ARMV7) && !defined(_3DS) /* XXX GPH hack */
        spu_config.iUseReverb = 0;
        spu_config.iUseInterpolation = 0;
        spu_config.iTempo = 1;
@@ -152,8 +161,8 @@ void emu_set_default_config(void)
        new_dynarec_hacks = 0;
        cycle_multiplier = 200;
 
-       in_type1 = PSE_PAD_TYPE_STANDARD;
-       in_type2 = PSE_PAD_TYPE_STANDARD;
+       in_type[0] = PSE_PAD_TYPE_STANDARD;
+       in_type[1] = PSE_PAD_TYPE_STANDARD;
 }
 
 void do_emu_action(void)
@@ -300,7 +309,7 @@ static int cdidcmp(const char *id1, const char *id2)
 
 static void parse_cwcheat(void)
 {
-       char line[256], buf[64], name[64], *p;
+       char line[256], buf[256], name[256], *p;
        int newcheat = 1;
        u32 a, v;
        FILE *f;
@@ -722,10 +731,10 @@ void SysReset() {
        // reset can run code, timing must be set
        pl_timing_prepare(Config.PsxType);
 
-       EmuReset();
-
-       // hmh core forgets this
+   // hmh core forgets this
        CDR_stop();
+   
+       EmuReset();
 
        GPU_updateLace = real_lace;
        g_emu_resetting = 0;
@@ -773,7 +782,7 @@ int emu_save_state(int slot)
                return ret;
 
        ret = SaveState(fname);
-#ifdef HAVE_PRE_ARMV7 /* XXX GPH hack */
+#if defined(HAVE_PRE_ARMV7) && !defined(_3DS) && !defined(__SWITCH__) /* XXX GPH hack */
        sync();
 #endif
        SysPrintf("* %s \"%s\" [%d]\n",
@@ -795,6 +804,7 @@ int emu_load_state(int slot)
        return LoadState(fname);
 }
 
+#ifndef HAVE_LIBRETRO
 #ifndef ANDROID
 
 void SysPrintf(const char *fmt, ...) {
@@ -819,6 +829,7 @@ void SysPrintf(const char *fmt, ...) {
 }
 
 #endif
+#endif /* HAVE_LIBRETRO */
 
 void SysMessage(const char *fmt, ...) {
        va_list list;
@@ -868,14 +879,15 @@ static int _OpenPlugins(void) {
 
        if (Config.UseNet && !NetOpened) {
                netInfo info;
-               char path[MAXPATHLEN];
+               char path[MAXPATHLEN * 2];
                char dotdir[MAXPATHLEN];
 
                MAKE_PATH(dotdir, "/.pcsx/plugins/", NULL);
 
                strcpy(info.EmuName, "PCSX");
-               strncpy(info.CdromID, CdromId, 9);
-               strncpy(info.CdromLabel, CdromLabel, 9);
+               memcpy(info.CdromID, CdromId, 9); /* no \0 trailing character? */
+               memcpy(info.CdromLabel, CdromLabel, 9);
+               info.CdromLabel[9] = '\0';
                info.psxMem = psxM;
                info.GPU_showScreenPic = GPU_showScreenPic;
                info.GPU_displayText = GPU_displayText;
@@ -987,7 +999,7 @@ void *SysLoadLibrary(const char *lib) {
                                return (void *)(long)(PLUGIN_DL_BASE + builtin_plugin_ids[i]);
        }
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(NO_DYLIB)
        ret = dlopen(lib, RTLD_NOW);
        if (ret == NULL)
                SysMessage("dlopen: %s", dlerror());
@@ -1004,7 +1016,7 @@ void *SysLoadSym(void *lib, const char *sym) {
        if (PLUGIN_DL_BASE <= plugid && plugid < PLUGIN_DL_BASE + ARRAY_SIZE(builtin_plugins))
                return plugin_link(plugid - PLUGIN_DL_BASE, sym);
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(NO_DYLIB)
        return dlsym(lib, sym);
 #else
        return NULL;
@@ -1012,7 +1024,9 @@ void *SysLoadSym(void *lib, const char *sym) {
 }
 
 const char *SysLibError() {
-#ifndef _WIN32
+#if defined(NO_DYLIB)
+   return NULL;
+#elif !defined(_WIN32)
        return dlerror();
 #else
        return "not supported";
@@ -1025,8 +1039,7 @@ void SysCloseLibrary(void *lib) {
        if (PLUGIN_DL_BASE <= plugid && plugid < PLUGIN_DL_BASE + ARRAY_SIZE(builtin_plugins))
                return;
 
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(NO_DYLIB)
        dlclose(lib);
 #endif
 }
-
index 6d75373..0f7933d 100644 (file)
@@ -101,13 +101,10 @@ int scanlines, scanline_level = 20;
 int soft_scaling, analog_deadzone; // for Caanoo
 int soft_filter;
 
-#ifndef HAVE_PRE_ARMV7
-#define DEFAULT_PSX_CLOCK 57
-#define DEFAULT_PSX_CLOCK_S "57"
-#else
-#define DEFAULT_PSX_CLOCK 50
-#define DEFAULT_PSX_CLOCK_S "50"
-#endif
+// Default to 100% CPU speed as most hardware can handle it nowadays using the dynamic recompiler.
+// If not, the option is in the advanced speed hacks menu, so in a logical place.
+#define DEFAULT_PSX_CLOCK 100
+#define DEFAULT_PSX_CLOCK_S "100"
 
 static const char *bioses[24];
 static const char *gpu_plugins[16];
@@ -308,14 +305,14 @@ static void menu_sync_config(void)
        cycle_multiplier = 10000 / psx_clock;
 
        switch (in_type_sel1) {
-       case 1:  in_type1 = PSE_PAD_TYPE_ANALOGPAD; break;
-       case 2:  in_type1 = PSE_PAD_TYPE_GUNCON;    break;
-       default: in_type1 = PSE_PAD_TYPE_STANDARD;
+       case 1:  in_type[0] = PSE_PAD_TYPE_ANALOGPAD; break;
+       case 2:  in_type[0] = PSE_PAD_TYPE_NEGCON;    break;
+       default: in_type[0] = PSE_PAD_TYPE_STANDARD;
        }
        switch (in_type_sel2) {
-       case 1:  in_type2 = PSE_PAD_TYPE_ANALOGPAD; break;
-       case 2:  in_type2 = PSE_PAD_TYPE_GUNCON;    break;
-       default: in_type2 = PSE_PAD_TYPE_STANDARD;
+       case 1:  in_type[1] = PSE_PAD_TYPE_ANALOGPAD; break;
+       case 2:  in_type[1] = PSE_PAD_TYPE_NEGCON;    break;
+       default: in_type[1] = PSE_PAD_TYPE_STANDARD;
        }
        if (in_evdev_allow_abs_only != allow_abs_only_old) {
                in_probe();
@@ -423,12 +420,20 @@ static const struct {
        CE_INTVAL_N("adev0_is_nublike", in_adev_is_nublike[0]),
        CE_INTVAL_N("adev1_is_nublike", in_adev_is_nublike[1]),
        CE_INTVAL_V(frameskip, 3),
+       CE_INTVAL_P(thread_rendering),
        CE_INTVAL_P(gpu_peops.iUseDither),
        CE_INTVAL_P(gpu_peops.dwActFixes),
+       CE_INTVAL_P(gpu_unai.ilace_force),
+       CE_INTVAL_P(gpu_unai.pixel_skip),
+       CE_INTVAL_P(gpu_unai.lighting),
+       CE_INTVAL_P(gpu_unai.fast_lighting),
+       CE_INTVAL_P(gpu_unai.blending),
+       CE_INTVAL_P(gpu_unai.dithering),
        CE_INTVAL_P(gpu_unai.lineskip),
        CE_INTVAL_P(gpu_unai.abe_hack),
        CE_INTVAL_P(gpu_unai.no_light),
        CE_INTVAL_P(gpu_unai.no_blend),
+       CE_INTVAL_P(gpu_unai.scale_hires),
        CE_INTVAL_P(gpu_neon.allow_interlace),
        CE_INTVAL_P(gpu_neon.enhancement_enable),
        CE_INTVAL_P(gpu_neon.enhancement_no_main),
@@ -443,7 +448,6 @@ static const struct {
        CE_INTVAL_P(gpu_peopsgl.iTexGarbageCollection),
        CE_INTVAL_P(gpu_peopsgl.dwActFixes),
        CE_INTVAL(spu_config.iUseReverb),
-       CE_INTVAL(spu_config.idiablofix),
        CE_INTVAL(spu_config.iXAPitch),
        CE_INTVAL(spu_config.iUseInterpolation),
        CE_INTVAL(spu_config.iTempo),
@@ -1361,10 +1365,16 @@ static int menu_loop_plugin_gpu_neon(int id, int keys)
 
 static menu_entry e_menu_plugin_gpu_unai[] =
 {
-       mee_onoff     ("Skip every 2nd line",        0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
-       mee_onoff     ("Abe's Odyssey hack",         0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
-       mee_onoff     ("Disable lighting",           0, pl_rearmed_cbs.gpu_unai.no_light, 1),
-       mee_onoff     ("Disable blending",           0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
+       //mee_onoff     ("Skip every 2nd line",        0, pl_rearmed_cbs.gpu_unai.lineskip, 1),
+       //mee_onoff     ("Abe's Odyssey hack",         0, pl_rearmed_cbs.gpu_unai.abe_hack, 1),
+       //mee_onoff     ("Disable lighting",           0, pl_rearmed_cbs.gpu_unai.no_light, 1),
+       //mee_onoff     ("Disable blending",           0, pl_rearmed_cbs.gpu_unai.no_blend, 1),
+       mee_onoff     ("Interlace",                  0, pl_rearmed_cbs.gpu_unai.ilace_force, 1),
+       mee_onoff     ("Dithering",                  0, pl_rearmed_cbs.gpu_unai.dithering, 1),
+       mee_onoff     ("Lighting",                   0, pl_rearmed_cbs.gpu_unai.lighting, 1),
+       mee_onoff     ("Fast lighting",              0, pl_rearmed_cbs.gpu_unai.fast_lighting, 1),
+       mee_onoff     ("Blending",                   0, pl_rearmed_cbs.gpu_unai.blending, 1),
+       mee_onoff     ("Pixel skip",                 0, pl_rearmed_cbs.gpu_unai.pixel_skip, 1),
        mee_end,
 };
 
@@ -1455,7 +1465,6 @@ static menu_entry e_menu_plugin_spu[] =
        mee_range_h   ("Volume boost",              0, volume_boost, -5, 30, h_spu_volboost),
        mee_onoff     ("Reverb",                    0, spu_config.iUseReverb, 1),
        mee_enum      ("Interpolation",             0, spu_config.iUseInterpolation, men_spu_interp),
-       mee_onoff     ("Diablo Music fix",          0, spu_config.idiablofix, 1),
        mee_onoff     ("Adjust XA pitch",           0, spu_config.iXAPitch, 1),
        mee_onoff_h   ("Adjust tempo",              0, spu_config.iTempo, 1, h_spu_tempo),
        mee_end,
index 81cd1ba..8f5acda 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __MENU_H__
+#define __MENU_H__
+
 void menu_init(void);
 void menu_prepare_emu(void);
 void menu_loop(void);
@@ -35,3 +38,5 @@ extern int soft_filter;
 
 extern int g_menuscreen_w;
 extern int g_menuscreen_h;
+
+#endif /* __MENU_H__ */
index d664f80..1815983 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __NOPIC_H__
+#define __NOPIC_H__
+
 /* these are just deps, to be removed */
 
 static const struct {
@@ -54,4 +57,4 @@ void DrawNumBorPic(unsigned char *pMem, int lSelectedSlot)
   }
 }
 
-
+#endif /* __NOPIC_H__ */
diff --git a/frontend/pandora/pcsx.png b/frontend/pandora/pcsx.png
deleted file mode 100644 (file)
index 71f36d0..0000000
Binary files a/frontend/pandora/pcsx.png and /dev/null differ
diff --git a/frontend/pandora/pcsx.pxml.templ b/frontend/pandora/pcsx.pxml.templ
deleted file mode 100644 (file)
index f748065..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<PXML xmlns="http://openpandora.org/namespaces/PXML" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PXML_schema.xsd">
-<package id="package.pcsx_rearmed.notaz">
-  <titles>
-    <title lang="en_US">PCSX ReARMed</title>
-  </titles>
-  <version major="1" minor="9" release="93" build="%PR%"/>
-  <author name="PCSX team/notaz" website="http://notaz.gp2x.de/"/>
-</package>
-<application id="pcsx_rearmed.notaz.%PR%" appdata="pcsx_rearmed">
-  <titles>
-    <title lang="en_US">PCSX ReARMed %PR%</title>
-  </titles>
-  <title lang="en_US">PCSX ReARMed %PR%</title>
-
-  <descriptions>
-    <description lang="en_US">PCSX ReARMed is heavily optimized PlayStation Emulator. It's a PCSX fork based on the PCSX-Reloaded project, which itself contains code from PCSX, PCSX-df and PCSX-Revolution.
-
-The emulator features MIPS->ARM recompiler by Ari64 and ARM NEON GPU by Exophase, that in many cases produces pixel perfect graphics at very high performance. There is also NEON-optimized GTE code, optimized P.E.Op.S. (Pete's) SPU; PCSX4ALL and traditional P.E.Op.S. GPUs are also available.</description>
-  </descriptions>
-
-  <exec command="pcsx.sh"/>
-
-  <icon src="pcsx.png"/>
-
-  <author name="PCSX team/notaz" website="http://notaz.gp2x.de/"/>
-
-  <version major="1" minor="9" release="93" build="%PR%"/>
-
-  <licenses>
-    <license name="GPLv2+" url="http://www.gnu.org/licenses/gpl-2.0.html" sourcecodeurl="http://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git"/>
-  </licenses>
-
-  <info name="PCSX ReARMed %PR% readme" type="text/plain" src="readme.txt"/>
-  <categories>
-    <category name="Game">
-    <subcategory name="Emulator"/>
-    </category>
-  </categories>
-</application>
-</PXML>
diff --git a/frontend/pandora/pcsx.sh b/frontend/pandora/pcsx.sh
deleted file mode 100755 (executable)
index 710f641..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-
-# stupid nub mode thing
-nub0mode=`cat /proc/pandora/nub0/mode`
-nub1mode=`cat /proc/pandora/nub1/mode`
-/usr/pandora/scripts/op_nubchange.sh absolute absolute
-
-# 4MB for RAM (2+align) + 2MB for vram (1+overdraw)
-#  + 10MB for gpu_neon (8+overdraw) + 8MB LUTs
-# no big deal if this fails, only performance loss
-sudo -n /usr/pandora/scripts/op_hugetlb.sh 24
-
-# C64x DSP for SPU
-sudo -n /usr/pandora/scripts/op_dsp_c64.sh
-
-./pcsx "$@"
-
-# restore stuff if pcsx crashes
-./picorestore
-sudo -n /usr/pandora/scripts/op_lcdrate.sh 60
-sudo -n /usr/pandora/scripts/op_gamma.sh 0
-sudo -n /usr/pandora/scripts/op_hugetlb.sh 0
-
-/usr/pandora/scripts/op_nubchange.sh $nub0mode $nub1mode
diff --git a/frontend/pandora/picorestore.c b/frontend/pandora/picorestore.c
deleted file mode 100644 (file)
index 77f5720..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * picorestore - clean up after an omapfb program crash
- *
- * Copyright (c) Gražvydas "notaz" Ignotas, 2010
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of the organization nor the
- *       names of its contributors may be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <linux/fb.h>
-#include <linux/omapfb.h>
-#include <linux/kd.h>
-
-int main()
-{
-       struct fb_var_screeninfo fbvar;
-       struct omapfb_plane_info pi;
-       struct omapfb_mem_info mi;
-       int ret, fbdev, kbdfd;
-
-       fbdev = open("/dev/fb0", O_RDWR);
-       if (fbdev == -1) {
-               perror("open fb0");
-               goto end_fb0;
-       }
-
-       ret = ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar);
-       if (ret == -1) {
-               perror("FBIOGET_VSCREENINFO ioctl");
-               goto end_fb0;
-       }
-
-       if (fbvar.yoffset != 0) {
-               printf("fixing yoffset.. ");
-               fbvar.yoffset = 0;
-               ret = ioctl(fbdev, FBIOPAN_DISPLAY, &fbvar);
-               if (ret < 0)
-                       perror("ioctl FBIOPAN_DISPLAY");
-               else
-                       printf("ok\n");
-       }
-
-end_fb0:
-       if (fbdev >= 0)
-               close(fbdev);
-
-       fbdev = open("/dev/fb1", O_RDWR);
-       if (fbdev == -1) {
-               perror("open fb1");
-               goto end_fb1;
-       }
-
-       ret  = ioctl(fbdev, OMAPFB_QUERY_PLANE, &pi);
-       ret |= ioctl(fbdev, OMAPFB_QUERY_MEM, &mi);
-       if (ret != 0)
-               perror("QUERY_*");
-
-       pi.enabled = 0;
-       ret = ioctl(fbdev, OMAPFB_SETUP_PLANE, &pi);
-       if (ret != 0)
-               perror("SETUP_PLANE");
-
-       mi.size = 0;
-       ret = ioctl(fbdev, OMAPFB_SETUP_MEM, &mi);
-       if (ret != 0)
-               perror("SETUP_MEM");
-
-end_fb1:
-       if (fbdev >= 0)
-               close(fbdev);
-
-       kbdfd = open("/dev/tty", O_RDWR);
-       if (kbdfd == -1) {
-               perror("open /dev/tty");
-               return 1;
-       }
-
-       if (ioctl(kbdfd, KDSETMODE, KD_TEXT) == -1)
-               perror("KDSETMODE KD_TEXT");
-
-       close(kbdfd);
-
-       return 0;
-}
diff --git a/frontend/pandora/skin/background.png b/frontend/pandora/skin/background.png
deleted file mode 100644 (file)
index f4b4523..0000000
Binary files a/frontend/pandora/skin/background.png and /dev/null differ
diff --git a/frontend/pandora/skin/font.png b/frontend/pandora/skin/font.png
deleted file mode 100644 (file)
index 707a5b4..0000000
Binary files a/frontend/pandora/skin/font.png and /dev/null differ
diff --git a/frontend/pandora/skin/readme.txt b/frontend/pandora/skin/readme.txt
deleted file mode 100644 (file)
index dd83963..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-The skin images can be customized, but there are several limitations:\r
-\r
-background.png - must be 320x240 image with 24bit RGB colors.\r
-font.png       - must be 128x160 8bit grayscale image.\r
-selector.png   - must be 8x10 8bit grayscale image.\r
-\r
-Font and selector colors can be changed by editing skin.txt.\r
-\r
diff --git a/frontend/pandora/skin/selector.png b/frontend/pandora/skin/selector.png
deleted file mode 100644 (file)
index a439169..0000000
Binary files a/frontend/pandora/skin/selector.png and /dev/null differ
diff --git a/frontend/pandora/skin/skin.txt b/frontend/pandora/skin/skin.txt
deleted file mode 100644 (file)
index 1d6979f..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-// html-style hex color codes, ex. ff0000 is red, 0000ff is blue, etc.\r
-text_color=ffffc0\r
-selection_color=808010\r
-\r
diff --git a/frontend/pandora/ui_feat.h b/frontend/pandora/ui_feat.h
deleted file mode 100644 (file)
index 3bb808a..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef UI_FEATURES_H
-#define UI_FEATURES_H
-
-#define MENU_BIOS_PATH "<SD card>/pandora/appdata/pcsx_rearmed/bios/"
-#define BOOT_MSG "Booting up...  (press SPACE for menu)"
-#define MENU_SHOW_VARSCALER 1
-#define MENU_SHOW_VOUTMODE 0
-#define MENU_SHOW_SCALER2 0
-#define MENU_SHOW_NUBS_BTNS 1
-#define MENU_SHOW_VIBRATION 0
-#define MENU_SHOW_DEADZONE 0
-#define MENU_SHOW_MINIMIZE 1
-#define MENU_SHOW_FULLSCREEN 0
-#define MENU_SHOW_VOLUME 0
-
-#endif // UI_FEATURES_H
index 4e3d195..8a33627 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __PL_GUN_TS_H__
+#define __PL_GUN_TS_H__
+
 #ifdef HAVE_TSLIB
 
 struct tsdev;
@@ -16,3 +19,5 @@ int pl_gun_ts_get_fd(struct tsdev *ts);
 #define pl_set_gun_rect(...) do {} while (0)
 
 #endif
+
+#endif /* __PL_GUN_TS_H__ */
index 6b0cd65..8a296ea 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __PLAT_H__
+#define __PLAT_H__
+
 void plat_init(void);
 void plat_finish(void);
 void plat_minimize(void);
@@ -8,3 +11,5 @@ void  plat_gvideo_open(int is_pal);
 void *plat_gvideo_set_mode(int *w, int *h, int *bpp);
 void *plat_gvideo_flip(void);
 void  plat_gvideo_close(void);
+
+#endif /* __PLAT_H__ */
index e47410a..151f09c 100644 (file)
@@ -1,5 +1,8 @@
+#ifndef __PLAT_OMAP_H__
+#define __PLAT_OMAP_H__
 
 void plat_omap_init(void);
 void plat_omap_finish(void);
 void plat_omap_gvideo_open(void);
 
+#endif /* __PLAT_OMAP_H__ */
index d9eb04a..a617c24 100644 (file)
@@ -49,23 +49,65 @@ extern void CALLBACK SPUasync(unsigned int, unsigned int);
 extern int  CALLBACK SPUplayCDDAchannel(short *, int);
 
 /* PAD */
-static long PADreadPort1(PadDataS *pad)
-{
-       pad->controllerType = in_type1;
-       pad->buttonStatus = ~in_keystate;
-       if (in_type1 == PSE_PAD_TYPE_ANALOGPAD) {
-               pad->leftJoyX = in_a1[0];
-               pad->leftJoyY = in_a1[1];
-               pad->rightJoyX = in_a2[0];
-               pad->rightJoyY = in_a2[1];
+static long PADreadPort1(PadDataS *pad) {
+       int pad_index = pad->requestPadIndex;
+
+       pad->controllerType = in_type[pad_index];
+       pad->buttonStatus = ~in_keystate[pad_index];
+
+       if (multitap1 == 1)
+               pad->portMultitap = 1;
+       else
+               pad->portMultitap = 0;
+
+       if (in_type[pad_index] == PSE_PAD_TYPE_ANALOGJOY || in_type[pad_index] == PSE_PAD_TYPE_ANALOGPAD || in_type[pad_index] == PSE_PAD_TYPE_NEGCON || in_type[pad_index] == PSE_PAD_TYPE_GUNCON)
+       {
+               pad->leftJoyX = in_analog_left[pad_index][0];
+               pad->leftJoyY = in_analog_left[pad_index][1];
+               pad->rightJoyX = in_analog_right[pad_index][0];
+               pad->rightJoyY = in_analog_right[pad_index][1];
+
+               pad->absoluteX = in_analog_left[pad_index][0];
+               pad->absoluteY = in_analog_left[pad_index][1];
+       }
+
+       if (in_type[pad_index] == PSE_PAD_TYPE_MOUSE)
+       {
+               pad->moveX = in_mouse[pad_index][0];
+               pad->moveY = in_mouse[pad_index][1];
        }
+
        return 0;
 }
 
-static long PADreadPort2(PadDataS *pad)
-{
-       pad->controllerType = in_type2;
-       pad->buttonStatus = ~in_keystate >> 16;
+static long PADreadPort2(PadDataS *pad) {
+       int pad_index = pad->requestPadIndex;
+
+       pad->controllerType = in_type[pad_index];
+       pad->buttonStatus = ~in_keystate[pad_index];
+
+       if (multitap2 == 1)
+               pad->portMultitap = 2;
+       else
+               pad->portMultitap = 0;
+
+       if (in_type[pad_index] == PSE_PAD_TYPE_ANALOGJOY || in_type[pad_index] == PSE_PAD_TYPE_ANALOGPAD || in_type[pad_index] == PSE_PAD_TYPE_NEGCON || in_type[pad_index] == PSE_PAD_TYPE_GUNCON)
+       {
+               pad->leftJoyX = in_analog_left[pad_index][0];
+               pad->leftJoyY = in_analog_left[pad_index][1];
+               pad->rightJoyX = in_analog_right[pad_index][0];
+               pad->rightJoyY = in_analog_right[pad_index][1];
+
+               pad->absoluteX = in_analog_left[pad_index][0];
+               pad->absoluteY = in_analog_left[pad_index][1];
+       }
+
+       if (in_type[pad_index] == PSE_PAD_TYPE_MOUSE)
+       {
+               pad->moveX = in_mouse[pad_index][0];
+               pad->moveY = in_mouse[pad_index][1];
+       }
+
        return 0;
 }
 
index e7a5645..5e12f90 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __PLUGIN_H__
+#define __PLUGIN_H__
+
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 
 #define PLUGIN_DL_BASE 0xfbad0000
@@ -12,3 +15,5 @@ enum builtint_plugins_e {
 
 void *plugin_link(enum builtint_plugins_e id, const char *sym);
 void plugin_call_rearmed_cbs(void);
+
+#endif /* __PLUGIN_H__ */
index ab4d415..eee255b 100644 (file)
 
 #define HUD_HEIGHT 10
 
-int in_type1, in_type2;
-int in_a1[2] = { 127, 127 }, in_a2[2] = { 127, 127 };
+int in_type[8];
+int multitap1;
+int multitap2;
+int in_analog_left[8][2] = {{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 }};
+int in_analog_right[8][2] = {{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 },{ 127, 127 }};
 int in_adev[2] = { -1, -1 }, in_adev_axis[2][2] = {{ 0, 1 }, { 0, 1 }};
 int in_adev_is_nublike[2];
-int in_keystate, in_state_gun;
+unsigned short in_keystate[8];
+int in_state_gun;
 int in_enable_vibration;
 void *tsdev;
 void *pl_vout_buf;
@@ -560,7 +564,7 @@ static void update_analog_nub_adjust(int *x_, int *y_)
 
 static void update_analogs(void)
 {
-       int *nubp[2] = { in_a1, in_a2 };
+       int *nubp[2] = { in_analog_left[0], in_analog_right[0] };
        int vals[2];
        int i, a, v, ret;
 
@@ -597,7 +601,7 @@ static void update_input(void)
        unsigned int emu_act;
 
        in_update(actions);
-       if (in_type1 == PSE_PAD_TYPE_ANALOGPAD)
+       if (in_type[0] == PSE_PAD_TYPE_ANALOGJOY || in_type[0] == PSE_PAD_TYPE_ANALOGPAD)
                update_analogs();
        emu_act = actions[IN_BINDTYPE_EMU];
        in_state_gun = (emu_act & SACTION_GUN_MASK) >> SACTION_GUN_TRIGGER;
@@ -611,7 +615,7 @@ static void update_input(void)
        }
        emu_set_action(emu_act);
 
-       in_keystate = actions[IN_BINDTYPE_PLAYER12];
+       in_keystate[0] = actions[IN_BINDTYPE_PLAYER12];
 }
 #else /* MAEMO */
 extern void update_input(void);
index 4a11002..71dfcb5 100644 (file)
@@ -1,3 +1,9 @@
+#ifndef __PLUGIN_LIB_H__
+#define __PLUGIN_LIB_H__
+
+#define THREAD_RENDERING_OFF   0
+#define THREAD_RENDERING_SYNC  1
+#define THREAD_RENDERING_ASYNC 2
 
 enum {
        DKEY_SELECT = 0,
@@ -17,8 +23,15 @@ enum {
        DKEY_CROSS,
        DKEY_SQUARE,
 };
-extern int in_type1, in_type2;
-extern int in_keystate, in_state_gun, in_a1[2], in_a2[2];
+extern int in_state_gun;
+extern int in_type[8];
+extern int multitap1;
+extern int multitap2;
+extern int in_analog_left[8][2];
+extern int in_analog_right[8][2];
+extern unsigned short in_keystate[8];
+extern int in_mouse[8][2];
+
 extern int in_adev[2], in_adev_axis[2][2];
 extern int in_adev_is_nublike[2];
 extern int in_enable_vibration;
@@ -61,10 +74,12 @@ struct rearmed_cbs {
        unsigned int *gpu_hcnt;
        unsigned int flip_cnt; // increment manually if not using pl_vout_flip
        unsigned int only_16bpp; // platform is 16bpp-only
+       unsigned int thread_rendering;
        struct {
                int   allow_interlace; // 0 off, 1 on, 2 guess
                int   enhancement_enable;
                int   enhancement_no_main;
+               int   allow_dithering;
        } gpu_neon;
        struct {
                int   iUseDither;
@@ -73,9 +88,17 @@ struct rearmed_cbs {
                int   dwFrameRateTicks;
        } gpu_peops;
        struct {
+               int ilace_force;
+               int pixel_skip;
+               int lighting;
+               int fast_lighting;
+               int blending;
+               int dithering;
+               // old gpu_unai config for compatibility
                int   abe_hack;
                int   no_light, no_blend;
                int   lineskip;
+               int   scale_hires;
        } gpu_unai;
        struct {
                int   dwActFixes;
@@ -103,3 +126,5 @@ extern void (*pl_plat_hud_print)(int x, int y, const char *str, int bpp);
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 #endif
+
+#endif /* __PLUGIN_LIB_H__ */
diff --git a/frontend/switch/sys/mman.h b/frontend/switch/sys/mman.h
new file mode 100644 (file)
index 0000000..5e8d22e
--- /dev/null
@@ -0,0 +1,125 @@
+#ifndef MMAN_H
+#define MMAN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <malloc.h>
+#include <switch.h>
+#include <stdlib.h>
+
+//#include "3ds_utils.h"
+
+#define PROT_READ       0b001
+#define PROT_WRITE      0b010
+#define PROT_EXEC       0b100
+#define MAP_PRIVATE     2
+#define MAP_FIXED       0x10
+#define MAP_ANONYMOUS   0x20
+
+#define MAP_FAILED      ((void *)-1)
+
+static void* dynarec_cache = NULL;
+static void* dynarec_cache_mapping = NULL;
+
+static inline void* mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+   (void)fd;
+   (void)offset;
+
+   //void* addr_out;
+    Result rc = svcMapPhysicalMemory(addr, len);
+    if (R_FAILED(rc))
+    {
+        printf("mmap failed\n");
+        return malloc(len);
+    }
+
+    return addr;
+
+//   if((prot == (PROT_READ | PROT_WRITE | PROT_EXEC)) &&
+//      (flags == (MAP_PRIVATE | MAP_ANONYMOUS)))
+//   {
+//      if(true)// __ctr_svchax)
+//     {
+//         /* this hack works only for pcsx_rearmed */
+//         uint32_t currentHandle;
+//
+//         if(!dynarec_cache)
+//            dynarec_cache = memalign(0x1000, len);
+//
+//         //svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+//         //svcControlProcessMemory(currentHandle, addr, dynarec_cache,
+//         //                        len, MEMOP_MAP, prot);
+//         svcCloseHandle(currentHandle);
+//         dynarec_cache_mapping = addr;
+//         return addr;
+//      }
+//      else
+//      {
+//         printf("tried to mmap RWX pages without svcControlProcessMemory access !\n");
+//         return MAP_FAILED;
+//      }
+//
+//   }
+
+//   addr_out = memalign(0x1000, len);
+//   if(!addr_out)
+//      return MAP_FAILED;
+//
+//   return addr_out;
+}
+
+static inline int mprotect(void *addr, size_t len, int prot)
+{
+    return 0;
+   //if(true) // __ctr_svchax)
+   //{
+   //   uint32_t currentHandle;
+   //   //svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+   //   //svcControlProcessMemory(currentHandle, addr, NULL,
+   //   //                        len, MEMOP_PROT, prot);
+   //   svcCloseHandle(currentHandle);
+   //   return 0;
+   //}
+
+   //printf("mprotect called without svcControlProcessMemory access !\n");
+   //return -1;
+}
+
+static inline int munmap(void *addr, size_t len)
+{
+    Result rc = svcUnmapPhysicalMemory(addr, len);
+    if (R_FAILED(rc))
+    {
+        printf("munmap failed\n");
+        free(addr);
+    }
+    return 0;
+//   if((addr == dynarec_cache_mapping) && true)//__ctr_svchax)
+//   {
+//      uint32_t currentHandle;
+//      //svcDuplicateHandle(&currentHandle, 0xFFFF8001);
+//      //svcControlProcessMemory(currentHandle,
+//      //                        dynarec_cache, dynarec_cache_mapping,
+//      //                        len, MEMOP_UNMAP, 0b111);
+//      svcCloseHandle(currentHandle);
+//      dynarec_cache_mapping = NULL;
+//
+//   }
+//   else
+      free(addr);
+
+   return 0;
+}
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // MMAN_H
+
diff --git a/frontend/switch/zconf.h b/frontend/switch/zconf.h
new file mode 100644 (file)
index 0000000..996fff2
--- /dev/null
@@ -0,0 +1,511 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX     /* may be set to #if 1 by ./configure */
+#  define Z_PREFIX_SET
+
+/* all linked symbols */
+#  define _dist_code            z__dist_code
+#  define _length_code          z__length_code
+#  define _tr_align             z__tr_align
+#  define _tr_flush_bits        z__tr_flush_bits
+#  define _tr_flush_block       z__tr_flush_block
+#  define _tr_init              z__tr_init
+#  define _tr_stored_block      z__tr_stored_block
+#  define _tr_tally             z__tr_tally
+#  define adler32               z_adler32
+#  define adler32_combine       z_adler32_combine
+#  define adler32_combine64     z_adler32_combine64
+#  ifndef Z_SOLO
+#    define compress              z_compress
+#    define compress2             z_compress2
+#    define compressBound         z_compressBound
+#  endif
+#  define crc32                 z_crc32
+#  define crc32_combine         z_crc32_combine
+#  define crc32_combine64       z_crc32_combine64
+#  define deflate               z_deflate
+#  define deflateBound          z_deflateBound
+#  define deflateCopy           z_deflateCopy
+#  define deflateEnd            z_deflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateInit_          z_deflateInit_
+#  define deflateParams         z_deflateParams
+#  define deflatePending        z_deflatePending
+#  define deflatePrime          z_deflatePrime
+#  define deflateReset          z_deflateReset
+#  define deflateResetKeep      z_deflateResetKeep
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateSetHeader      z_deflateSetHeader
+#  define deflateTune           z_deflateTune
+#  define deflate_copyright     z_deflate_copyright
+#  define get_crc_table         z_get_crc_table
+#  ifndef Z_SOLO
+#    define gz_error              z_gz_error
+#    define gz_intmax             z_gz_intmax
+#    define gz_strwinerror        z_gz_strwinerror
+#    define gzbuffer              z_gzbuffer
+#    define gzclearerr            z_gzclearerr
+#    define gzclose               z_gzclose
+#    define gzclose_r             z_gzclose_r
+#    define gzclose_w             z_gzclose_w
+#    define gzdirect              z_gzdirect
+#    define gzdopen               z_gzdopen
+#    define gzeof                 z_gzeof
+#    define gzerror               z_gzerror
+#    define gzflush               z_gzflush
+#    define gzgetc                z_gzgetc
+#    define gzgetc_               z_gzgetc_
+#    define gzgets                z_gzgets
+#    define gzoffset              z_gzoffset
+#    define gzoffset64            z_gzoffset64
+#    define gzopen                z_gzopen
+#    define gzopen64              z_gzopen64
+#    ifdef _WIN32
+#      define gzopen_w              z_gzopen_w
+#    endif
+#    define gzprintf              z_gzprintf
+#    define gzvprintf             z_gzvprintf
+#    define gzputc                z_gzputc
+#    define gzputs                z_gzputs
+#    define gzread                z_gzread
+#    define gzrewind              z_gzrewind
+#    define gzseek                z_gzseek
+#    define gzseek64              z_gzseek64
+#    define gzsetparams           z_gzsetparams
+#    define gztell                z_gztell
+#    define gztell64              z_gztell64
+#    define gzungetc              z_gzungetc
+#    define gzwrite               z_gzwrite
+#  endif
+#  define inflate               z_inflate
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define inflateBackInit_      z_inflateBackInit_
+#  define inflateCopy           z_inflateCopy
+#  define inflateEnd            z_inflateEnd
+#  define inflateGetHeader      z_inflateGetHeader
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateInit_          z_inflateInit_
+#  define inflateMark           z_inflateMark
+#  define inflatePrime          z_inflatePrime
+#  define inflateReset          z_inflateReset
+#  define inflateReset2         z_inflateReset2
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateGetDictionary  z_inflateGetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateUndermine      z_inflateUndermine
+#  define inflateResetKeep      z_inflateResetKeep
+#  define inflate_copyright     z_inflate_copyright
+#  define inflate_fast          z_inflate_fast
+#  define inflate_table         z_inflate_table
+#  ifndef Z_SOLO
+#    define uncompress            z_uncompress
+#  endif
+#  define zError                z_zError
+#  ifndef Z_SOLO
+#    define zcalloc               z_zcalloc
+#    define zcfree                z_zcfree
+#  endif
+#  define zlibCompileFlags      z_zlibCompileFlags
+#  define zlibVersion           z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+#  define Byte                  z_Byte
+#  define Bytef                 z_Bytef
+#  define alloc_func            z_alloc_func
+#  define charf                 z_charf
+#  define free_func             z_free_func
+#  ifndef Z_SOLO
+#    define gzFile                z_gzFile
+#  endif
+#  define gz_header             z_gz_header
+#  define gz_headerp            z_gz_headerp
+#  define in_func               z_in_func
+#  define intf                  z_intf
+#  define out_func              z_out_func
+#  define uInt                  z_uInt
+#  define uIntf                 z_uIntf
+#  define uLong                 z_uLong
+#  define uLongf                z_uLongf
+#  define voidp                 z_voidp
+#  define voidpc                z_voidpc
+#  define voidpf                z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+#  define gz_header_s           z_gz_header_s
+#  define internal_state        z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+#  define z_const const
+#else
+#  define z_const
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+#  if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#    define Z_ARG(args)  args
+#  else
+#    define Z_ARG(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+#  include <limits.h>
+#  if (UINT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned
+#  elif (ULONG_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned long
+#  elif (USHRT_MAX == 0xffffffffUL)
+#    define Z_U4 unsigned short
+#  endif
+#endif
+
+#ifdef Z_U4
+   typedef Z_U4 z_crc_t;
+#else
+   typedef unsigned long z_crc_t;
+#endif
+
+#if 1    /* was set to #if 1 by ./configure */
+#  define Z_HAVE_UNISTD_H
+#endif
+
+#if 1    /* was set to #if 1 by ./configure */
+#  define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+#  ifndef Z_SOLO
+#    include <sys/types.h>      /* for off_t */
+#  endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+#    include <stdarg.h>         /* for va_list */
+#  endif
+#endif
+
+#ifdef _WIN32
+#  ifndef Z_SOLO
+#    include <stddef.h>         /* for wchar_t */
+#  endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+#  undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+#  define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+#  if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+#    include <unistd.h>         /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+#    ifdef VMS
+#      include <unixio.h>       /* for off_t */
+#    endif
+#    ifndef z_off_t
+#      define z_off_t off_t
+#    endif
+#  endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+#  define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+#  define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+#  define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+#  define z_off64_t off64_t
+#else
+#  if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+#    define z_off64_t __int64
+#  else
+#    define z_off64_t z_off_t
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+  #pragma map(deflateInit_,"DEIN")
+  #pragma map(deflateInit2_,"DEIN2")
+  #pragma map(deflateEnd,"DEEND")
+  #pragma map(deflateBound,"DEBND")
+  #pragma map(inflateInit_,"ININ")
+  #pragma map(inflateInit2_,"ININ2")
+  #pragma map(inflateEnd,"INEND")
+  #pragma map(inflateSync,"INSY")
+  #pragma map(inflateSetDictionary,"INSEDI")
+  #pragma map(compressBound,"CMBND")
+  #pragma map(inflate_table,"INTABL")
+  #pragma map(inflate_fast,"INFA")
+  #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/frontend/switch/zlib.h b/frontend/switch/zlib.h
new file mode 100644 (file)
index 0000000..3e0c767
--- /dev/null
@@ -0,0 +1,1768 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.8, April 28th, 2013
+
+  Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+  (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.8"
+#define ZLIB_VERNUM 0x1280
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 8
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+    The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed data.
+  This version of the library supports only one compression method (deflation)
+  but other algorithms will be added later and will have the same stream
+  interface.
+
+    Compression can be done in a single step if the buffers are large enough,
+  or can be done by repeated calls of the compression function.  In the latter
+  case, the application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+    The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+    The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+    This library can optionally read and write gzip streams in memory as well.
+
+    The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+    The library does not install any signal handler.  The decoder checks
+  the consistency of the compressed data, so the library should never crash
+  even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    z_const Bytef *next_in;     /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total number of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total number of bytes output so far */
+
+    z_const char *msg;  /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+     The application must update next_in and avail_in when avail_in has dropped
+   to zero.  It must update next_out and avail_out when avail_out has dropped
+   to zero.  The application must initialize zalloc, zfree and opaque before
+   calling the init function.  All other fields are set by the compression
+   library and must not be updated by the application.
+
+     The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree.  This can be useful for custom
+   memory management.  The compression library attaches no meaning to the
+   opaque value.
+
+     zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+     On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this if
+   the symbol MAXSEG_64K is defined (see zconf.h).  WARNING: On MSDOS, pointers
+   returned by zalloc for objects of exactly 65536 bytes *must* have their
+   offset normalized to zero.  The default allocation function provided by this
+   library ensures this (see zutil.c).  To reduce memory requirements and avoid
+   any allocation of 64K objects, at the expense of compression ratio, compile
+   the library with -DMAX_WBITS=14 (see zconf.h).
+
+     The fields total_in and total_out can be used for statistics or progress
+   reports.  After compression, total_in holds the total size of the
+   uncompressed data and may be saved for use in the decompressor (particularly
+   if the decompressor wants to decompress everything in a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+#define Z_TREES         6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is not
+   compatible with the zlib.h header file used by the application.  This check
+   is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression.  The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+   allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at all
+   (the input data is simply copied a block at a time).  Z_DEFAULT_COMPRESSION
+   requests a default compromise between speed and compression (currently
+   equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if level is not a valid compression level, or
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).  msg is set to null
+   if there is no error message.  deflateInit does not perform any compression:
+   this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows.  deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).  Some
+    output may be provided even if flush is not set.
+
+    Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating avail_in or avail_out accordingly; avail_out should
+  never be zero before the call.  The application can consume the compressed
+  output when it wants, for example when the output buffer is full (avail_out
+  == 0), or after each call of deflate().  If deflate returns Z_OK and with
+  zero avail_out, it must be called again after making room in the output
+  buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumulate before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far.  (In
+  particular avail_in is zero after the call if enough output space has been
+  provided before the call.) Flushing may degrade compression for some
+  compression algorithms and so it should be used only when necessary.  This
+  completes the current deflate block and follows it with an empty stored block
+  that is three bits plus filler bits to the next byte, followed by four bytes
+  (00 00 ff ff).
+
+    If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+  output buffer, but the output is not aligned to a byte boundary.  All of the
+  input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+  This completes the current deflate block and follows it with an empty fixed
+  codes block that is 10 bits long.  This assures that enough bytes are output
+  in order for the decompressor to finish the block before the empty fixed code
+  block.
+
+    If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+  for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+  seven bits of the current block are held to be written as the next byte after
+  the next deflate block is completed.  In this case, the decompressor may not
+  be provided enough bits at this point in order to complete decompression of
+  the data provided so far to the compressor.  It may need to wait for the next
+  block to be emitted.  This is for advanced applications that need to control
+  the emission of deflate blocks.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired.  Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out).  In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there was
+  enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error.  After
+  deflate has returned Z_STREAM_END, the only possible operations on the stream
+  are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step.  In this case, avail_out must be at least the
+  value returned by deflateBound (see below).  Then deflate is guaranteed to
+  return Z_STREAM_END.  If not enough output space is provided, deflate will
+  not return Z_STREAM_END, and it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT).  In doubt, the data is considered
+  binary.  This field is only for information purposes and does not affect the
+  compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero).  Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded).  In the error case, msg
+   may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression.  The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller.  If next_in is not Z_NULL and avail_in is large enough (the
+   exact value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit() does not process any header information -- that is deferred
+   until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full.  It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows.  inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly.  If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing will
+    resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there is
+    no more input data or no more space in the output buffer (see below about
+    the flush parameter).
+
+    Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming more
+  output, and updating the next_* and avail_* values accordingly.  The
+  application can consume the uncompressed output when it wants, for example
+  when the output buffer is full (avail_out == 0), or after each call of
+  inflate().  If inflate returns Z_OK and with zero avail_out, it must be
+  called again after making room in the output buffer because there might be
+  more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+  Z_BLOCK, or Z_TREES.  Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer.  Z_BLOCK requests that inflate()
+  stop if and when it gets to the next deflate block boundary.  When decoding
+  the zlib or gzip format, this will cause inflate() to return immediately
+  after the header and before the first block.  When doing a raw inflate,
+  inflate() will go ahead and process the first block, and will return when it
+  gets to the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64 if
+  inflate() is currently decoding the last block in the deflate stream, plus
+  128 if inflate() returned immediately after decoding an end-of-block code or
+  decoding the complete header up to just before the first byte of the deflate
+  stream.  The end-of-block will not be indicated until all of the uncompressed
+  data from that block has been written to strm->next_out.  The number of
+  unused bits may in general be greater than seven, except when bit 7 of
+  data_type is set, in which case the number of unused bits will be less than
+  eight.  data_type is set as noted here every time inflate() returns for all
+  flush options, and so can be used to determine the amount of currently
+  consumed input in bits.
+
+    The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+  end of each deflate block header is reached, before any actual data in that
+  block is decoded.  This allows the caller to determine the length of the
+  deflate block header for later use in random access within a deflate block.
+  256 is added to the value of strm->data_type when inflate() returns
+  immediately after reaching the end of the deflate block header.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error.  However if all decompression is to be performed in a single step (a
+  single call of inflate), the parameter flush should be set to Z_FINISH.  In
+  this case all pending input is processed and all pending output is flushed;
+  avail_out must be large enough to hold all of the uncompressed data for the
+  operation to complete.  (The size of the uncompressed data may have been
+  saved by the compressor for this purpose.) The use of Z_FINISH is not
+  required to perform an inflation in one step.  However it may be used to
+  inform inflate that a faster approach can be used for the single inflate()
+  call.  Z_FINISH also informs inflate to not maintain a sliding window if the
+  stream completes, which reduces inflate's memory footprint.  If the stream
+  does not complete, either because not all of the stream is provided or not
+  enough output space is provided, then a sliding window will be allocated and
+  inflate() can be called again to continue the operation as if Z_NO_FLUSH had
+  been used.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call.  So the effects of the flush parameter in this implementation are
+  on the return value of inflate() as noted below, when inflate() returns early
+  when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
+  memory for a sliding window when Z_FINISH is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the Adler-32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below.  At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically, if requested when
+  initializing with inflateInit2().  Any information contained in the gzip
+  header is not retained, so applications that need that information should
+  instead use raw inflate, see inflateInit2() below, or inflateBack() and
+  perform their own processing of the gzip header and trailer.  When processing
+  gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
+  producted so far.  The CRC-32 is checked against the gzip trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used.  Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing.  If Z_DATA_ERROR is returned, the application may
+  then call inflateSync() to look for a good compression block if a partial
+  recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any pending
+   output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent.  In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options.  The
+   fields next_in, zalloc, zfree and opaque must be initialized before by the
+   caller.
+
+     The method parameter is the compression method.  It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library.  Larger values of this parameter result in better
+   compression at the expense of memory usage.  The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
+   determines the window size.  deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding.  Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper.  The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero), no
+   header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state.  memLevel=1 uses minimum memory but is
+   slow and reduces compression ratio; memLevel=9 uses maximum memory for
+   optimal speed.  The default value is 8.  See zconf.h for total memory usage
+   as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm.  Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding).  Filtered data consists mostly of small values with a somewhat
+   random distribution.  In this case, the compression algorithm is tuned to
+   compress them better.  The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
+   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
+   strategy parameter only affects the compression ratio but not the
+   correctness of the compressed output even if it is not set appropriately.
+   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+   decoder for special applications.
+
+     deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+   method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+   incompatible with the version assumed by the caller (ZLIB_VERSION).  msg is
+   set to null if there is no error message.  deflateInit2 does not perform any
+   compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output.  When using the zlib format, this
+   function must be called immediately after deflateInit, deflateInit2 or
+   deflateReset, and before any call of deflate.  When doing raw deflate, this
+   function must be called either before any call of deflate, or immediately
+   after the completion of a deflate block, i.e. after all input has been
+   consumed and all output has been delivered when using any of the flush
+   options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH.  The
+   compressor and decompressor must use exactly the same dictionary (see
+   inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary.  Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size
+   provided in deflateInit or deflateInit2.  Thus the strings most likely to be
+   useful should be put at the end of the dictionary, not at the front.  In
+   addition, the current implementation of deflate will use at most the window
+   size minus 262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor.  (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if not at a block boundary for raw deflate).  deflateSetDictionary does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter.  The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and can
+   consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.  The
+   stream will keep the same compression level and any other attributes that
+   may have been set by deflateInit2.
+
+     deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different strategy.
+   If the compression level is changed, the input available so far is
+   compressed with the old level (and may be flushed); the new level will take
+   effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to be
+   compressed and flushed.  In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+   strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit() or
+   deflateInit2(), and after deflateSetHeader(), if used.  This would be used
+   to allocate an output buffer for deflation in a single pass, and so would be
+   called before deflate().  If that first deflate() call is provided the
+   sourceLen input bytes, an output buffer allocated to the size returned by
+   deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
+   to return Z_STREAM_END.  Note that it is possible for the compressed size to
+   be larger than the value returned by deflateBound() if flush options other
+   than Z_FINISH or Z_NO_FLUSH are used.
+*/
+
+ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
+                                       unsigned *pending,
+                                       int *bits));
+/*
+     deflatePending() returns the number of bytes and bits of output that have
+   been generated, but not yet provided in the available output.  The bytes not
+   provided would be due to the available output space having being consumed.
+   The number of bits of output not provided are between 0 and 7, where they
+   await more bits to join them in order to fill out a full byte.  If pending
+   or bits are Z_NULL, then those values are not set.
+
+     deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+ */
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+   is that this function is used to start off the deflate output with the bits
+   leftover from a previous deflate stream when appending to it.  As such, this
+   function can only be used for raw deflate, and must be used before the first
+   deflate() call after a deflateInit2() or deflateReset().  bits must be less
+   than or equal to 16, and that many of the least significant bits of value
+   will be inserted in the output.
+
+     deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
+   room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+     If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+     deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter.  The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library.  The default value is 15 if inflateInit is used
+   instead.  windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used.  If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be zero to request that inflate use the window size in
+   the zlib header of the compressed stream.
+
+     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
+   determines the window size.  inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream.  This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values.  If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is.  Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding.  Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
+   crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+   invalid, such as a null pointer to the structure.  msg is set to null if
+   there is no error message.  inflateInit2 does not perform any decompression
+   apart from possibly reading the zlib header if present: actual decompression
+   will be done by inflate().  (So next_in and avail_in may be modified, but
+   next_out and avail_out are unused and unchanged.) The current implementation
+   of inflateInit2() does not process any header information -- that is
+   deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence.  This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT.  The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called at any
+   time to set the dictionary.  If the provided dictionary is smaller than the
+   window and there is already data in the window, then the provided dictionary
+   will amend what's there.  The application must insure that the dictionary
+   that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (e.g.  dictionary being Z_NULL) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value).  inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
+                                             Bytef *dictionary,
+                                             uInt  *dictLength));
+/*
+     Returns the sliding dictionary being maintained by inflate.  dictLength is
+   set to the number of bytes in the dictionary, and that many bytes are copied
+   to dictionary.  dictionary must have enough space, where 32768 bytes is
+   always enough.  If inflateGetDictionary() is called with dictionary equal to
+   Z_NULL, then only the dictionary length is returned, and nothing is copied.
+   Similary, if dictLength is Z_NULL, then it is not set.
+
+     inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
+   stream state is inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+     Skips invalid compressed data until a possible full flush point (see above
+   for the description of deflate with Z_FULL_FLUSH) can be found, or until all
+   available input is skipped.  No output is provided.
+
+     inflateSync searches for a 00 00 FF FF pattern in the compressed data.
+   All full flush points have this pattern, but not all occurrences of this
+   pattern are full flush points.
+
+     inflateSync returns Z_OK if a possible full flush point has been found,
+   Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
+   has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
+   In the success case, the application may save the current current value of
+   total_in which indicates where valid compressed data was found.  In the
+   error case, the application may repeatedly call inflateSync, providing more
+   input each time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being Z_NULL).  msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.  The
+   stream will keep attributes that may have been set by inflateInit2.
+
+     inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+                                      int windowBits));
+/*
+     This function is the same as inflateReset, but it also permits changing
+   the wrap and window size requests.  The windowBits parameter is interpreted
+   the same as it is for inflateInit2.
+
+     inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+   the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+   that this function is used to start inflating at a bit position in the
+   middle of a byte.  The provided bits will be used before any bytes are used
+   from next_in.  This function should only be used with raw inflate, and
+   should be used before the first inflate() call after inflateInit2() or
+   inflateReset().  bits must be less than or equal to 16, and that many of the
+   least significant bits of value will be inserted in the input.
+
+     If bits is negative, then the input stream bit buffer is emptied.  Then
+   inflatePrime() can be called again to put bits in the buffer.  This is used
+   to clear out bits leftover after feeding inflate a block description prior
+   to feeding inflate codes.
+
+     inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+     This function returns two values, one in the lower 16 bits of the return
+   value, and the other in the remaining upper bits, obtained by shifting the
+   return value down 16 bits.  If the upper value is -1 and the lower value is
+   zero, then inflate() is currently decoding information outside of a block.
+   If the upper value is -1 and the lower value is non-zero, then inflate is in
+   the middle of a stored block, with the lower value equaling the number of
+   bytes from the input remaining to copy.  If the upper value is not -1, then
+   it is the number of bits back from the current bit position in the input of
+   the code (literal or length/distance pair) currently being processed.  In
+   that case the lower value is the number of bytes already emitted for that
+   code.
+
+     A code is being processed if inflate is waiting for more input to complete
+   decoding of the code, or if it has completed decoding but is waiting for
+   more output space to write the literal or match data.
+
+     inflateMark() is used to mark locations in the input data for random
+   access, which may be at bit positions, and to note those cases where the
+   output of a code may span boundaries of random access blocks.  The current
+   location in the input stream can be determined from avail_in and data_type
+   as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+     inflateMark returns the value noted above or -1 << 16 if the provided
+   source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+     inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK or Z_TREES can be
+   used to force inflate() to return immediately after header processing is
+   complete and before any actual data is decompressed.
+
+     The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When any
+   of extra, name, or comment are not Z_NULL and the respective field is not
+   present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+     If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+     inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the parameters are invalid, Z_MEM_ERROR if the internal state could not be
+   allocated, or Z_VERSION_ERROR if the version of the library does not match
+   the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *,
+                                z_const unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is potentially more efficient than
+   inflate() for file i/o applications, in that it avoids copying between the
+   output and the sliding window by simply making the window itself the output
+   buffer.  inflate() can be faster on modern CPUs when used with large
+   buffers.  inflateBack() trusts the application to not change the output
+   buffer passed by the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free the
+   allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects only
+   the raw deflate stream to decompress.  This is different from the normal
+   behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 ..  strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+   in the deflate stream (in which case strm->msg is set to indicate the nature
+   of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+   In the case of Z_BUF_ERROR, an input or output error can be distinguished
+   using strm->next_in which will be Z_NULL only if in() returned an error.  If
+   strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+   non-zero.  (in() will always be called before out(), so strm->next_in is
+   assured to be defined if out() returns non-zero.) Note that inflateBack()
+   cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+#ifndef Z_SOLO
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the basic
+   stream-oriented functions.  To simplify the interface, some default options
+   are assumed (compression level and memory usage, standard memory allocation
+   functions).  The source code of these utility functions can be modified if
+   you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer.  The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer.  Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen).  Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before a
+   compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer.  Upon entry, destLen is the total size
+   of the destination buffer, which must be large enough to hold the entire
+   uncompressed data.  (The size of the uncompressed data must have been saved
+   previously by the compressor and transmitted to the decompressor by some
+   mechanism outside the scope of this compression library.) Upon exit, destLen
+   is the actual size of the uncompressed buffer.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
+   the case where there is not enough room, uncompress() will fill the output
+   buffer with the uncompressed data up to that point.
+*/
+
+                        /* gzip file access functions */
+
+/*
+     This library supports reading and writing files in gzip (.gz) format with
+   an interface similar to that of stdio, using the functions that start with
+   "gz".  The gzip format is different from the zlib format.  gzip is a gzip
+   wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef struct gzFile_s *gzFile;    /* semi-opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
+   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+   for fixed code compression as in "wb9F".  (See the description of
+   deflateInit2 for more information about the strategy parameter.)  'T' will
+   request transparent writing or appending with no compression and not using
+   the gzip format.
+
+     "a" can be used instead of "w" to request that the gzip stream that will
+   be written be appended to the file.  "+" will result in an error, since
+   reading and writing to the same gzip file is not supported.  The addition of
+   "x" when writing will create the file exclusively, which fails if the file
+   already exists.  On systems that support it, the addition of "e" when
+   reading or writing will set the flag to close the file on an execve() call.
+
+     These functions, as well as gzip, will read and decode a sequence of gzip
+   streams in a file.  The append function of gzopen() can be used to create
+   such a file.  (Also see gzflush() for another way to do this.)  When
+   appending, gzopen does not test whether the file begins with a gzip stream,
+   nor does it look for the end of the gzip streams to begin appending.  gzopen
+   will simply append a gzip stream to the existing file.
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.  When
+   reading, this will be detected automatically by looking for the magic two-
+   byte gzip header.
+
+     gzopen returns NULL if the file could not be opened, if there was
+   insufficient memory to allocate the gzFile state, or if an invalid mode was
+   specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+   errno can be checked to determine if the reason gzopen failed was that the
+   file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
+   are obtained from calls like open, dup, creat, pipe or fileno (if the file
+   has been previously opened with fopen).  The mode parameter is as in gzopen.
+
+     The next call of gzclose on the returned gzFile will also close the file
+   descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+   fd.  If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+   mode);.  The duplicated descriptor should be saved to avoid a leak, since
+   gzdopen does not close fd if it fails.  If you are using fileno() to get the
+   file descriptor from a FILE *, then you will have to use dup() to avoid
+   double-close()ing the file descriptor.  Both gzclose() and fclose() will
+   close the associated file descriptor, so they need to have different file
+   descriptors.
+
+     gzdopen returns NULL if there was insufficient memory to allocate the
+   gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+   provided, or '+' was provided), or if fd is -1.  The file descriptor is not
+   used until the next gz* read, write, seek, or close operation, so gzdopen
+   will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+     Set the internal buffer size used by this library's functions.  The
+   default buffer size is 8192 bytes.  This function must be called after
+   gzopen() or gzdopen(), and before any other calls that read or write the
+   file.  The buffer memory allocation is always deferred to the first read or
+   write.  Two buffers are allocated, either both of the specified size when
+   writing, or one of the specified size and the other twice that size when
+   reading.  A larger buffer size of, for example, 64K or 128K bytes will
+   noticeably increase the speed of decompression (reading).
+
+     The new buffer size also affects the maximum length for gzprintf().
+
+     gzbuffer() returns 0 on success, or -1 on failure, such as being called
+   too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy.  See the description
+   of deflateInit2 for the meaning of these parameters.
+
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.  If
+   the input file is not in gzip format, gzread copies the given number of
+   bytes into the buffer directly from the file.
+
+     After reaching the end of a gzip stream in the input, gzread will continue
+   to read, looking for another gzip stream.  Any number of gzip streams may be
+   concatenated in the input file, and will all be decompressed by gzread().
+   If something other than a gzip stream is encountered after a gzip stream,
+   that remaining trailing garbage is ignored (and no error is returned).
+
+     gzread can be used to read a gzip file that is being concurrently written.
+   Upon reaching the end of the input, gzread will return with the available
+   data.  If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
+   gzclearerr can be used to clear the end of file indicator in order to permit
+   gzread to be tried again.  Z_OK indicates that a gzip stream was completed
+   on the last gzread.  Z_BUF_ERROR indicates that the input file ended in the
+   middle of a gzip stream.  Note that gzread does not return -1 in the event
+   of an incomplete gzip stream.  This error is deferred until gzclose(), which
+   will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
+   stream.  Alternatively, gzerror can be used before gzclose to detect this
+   case.
+
+     gzread returns the number of uncompressed bytes actually read, less than
+   len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+                                voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes written or 0 in case of
+   error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the arguments to the compressed file under
+   control of the format string, as in fprintf.  gzprintf returns the number of
+   uncompressed bytes actually written, or 0 in case of error.  The number of
+   uncompressed bytes written is limited to 8191, or one less than the buffer
+   size given to gzbuffer().  The caller should assure that this limit is not
+   exceeded.  If it is exceeded, then gzprintf() will return an error (0) with
+   nothing written.  In this case, there may also be a buffer overflow with
+   unpredictable consequences, which is possible only if zlib was compiled with
+   the insecure functions sprintf() or vsprintf() because the secure snprintf()
+   or vsnprintf() functions were not available.  This can be determined using
+   zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+     Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+
+     gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+     Reads bytes from the compressed file until len-1 characters are read, or a
+   newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  If any characters are read or if len == 1, the
+   string is terminated with a null character.  If no characters are read due
+   to an end-of-file or len < 1, then the buffer is left untouched.
+
+     gzgets returns buf which is a null-terminated string, or it returns NULL
+   for end-of-file or in case of error.  If there was an error, the contents at
+   buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+     Writes c, converted to an unsigned char, into the compressed file.  gzputc
+   returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+     Reads one byte from the compressed file.  gzgetc returns this byte or -1
+   in case of end of file or error.  This is implemented as a macro for speed.
+   As such, it does not do all of the checking the other functions do.  I.e.
+   it does not check to see if file is NULL, nor whether the structure file
+   points to has been clobbered or not.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+     Push one character back onto the stream to be read as the first character
+   on the next read.  At least one character of push-back is allowed.
+   gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
+   fail if c is -1, and may fail if a character has been pushed but not read
+   yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
+   output buffer size of pushed characters is allowed.  (See gzbuffer above.)
+   The pushed character will be discarded if the stream is repositioned with
+   gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file.  The parameter flush
+   is as in the deflate() function.  The return value is the zlib error number
+   (see function gzerror below).  gzflush is only permitted when writing.
+
+     If the flush parameter is Z_FINISH, the remaining data is written and the
+   gzip stream is completed in the output.  If gzwrite() is called again, a new
+   gzip stream will be started in the output.  gzread() is able to read such
+   concatented gzip streams.
+
+     gzflush should be called only when strictly necessary because it will
+   degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+                                   z_off_t offset, int whence));
+
+     Sets the starting position for the next gzread or gzwrite on the given
+   compressed file.  The offset represents a number of bytes in the
+   uncompressed data stream.  The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow.  If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+     gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+
+     Returns the starting position for the next gzread or gzwrite on the given
+   compressed file.  This position represents a number of bytes in the
+   uncompressed data stream, and is zero when starting, even if appending or
+   reading a gzip stream from the middle of a file using gzdopen().
+
+     gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+     Returns the current offset in the file being read or written.  This offset
+   includes the count of bytes that precede the gzip stream, for example when
+   appending or when using gzdopen() for reading.  When reading, the offset
+   does not include as yet unused buffered input.  This information can be used
+   for a progress indicator.  On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns true (1) if the end-of-file indicator has been set while reading,
+   false (0) otherwise.  Note that the end-of-file indicator is set only if the
+   read tried to go past the end of the input, but came up short.  Therefore,
+   just like feof(), gzeof() may return false even if there is no more data to
+   read, in the event that the last read request was for the exact number of
+   bytes remaining in the input file.  This will happen if the input file size
+   is an exact multiple of the buffer size.
+
+     If gzeof() returns true, then the read functions will return no more data,
+   unless the end-of-file indicator is reset by gzclearerr() and the input file
+   has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns true (1) if file is being copied directly while reading, or false
+   (0) if file is a gzip stream being decompressed.
+
+     If the input file is empty, gzdirect() will return true, since the input
+   does not contain a gzip stream.
+
+     If gzdirect() is used immediately after gzopen() or gzdopen() it will
+   cause buffers to be allocated to allow reading the file to determine if it
+   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
+   gzdirect().
+
+     When writing, gzdirect() returns true (1) if transparent writing was
+   requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
+   gzdirect() is not needed when writing.  Transparent writing must be
+   explicitly requested, so the application already knows the answer.  When
+   linking statically, using gzdirect() will include all of the zlib code for
+   gzip file reading and decompression, which may not be desired.)
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file and
+   deallocates the (de)compression state.  Note that once file is closed, you
+   cannot call gzerror with file, since its structures have been deallocated.
+   gzclose must not be called more than once on the same file, just as free
+   must not be called more than once on the same allocation.
+
+     gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+   file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
+   last read ended in the middle of a gzip stream, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+     Same as gzclose(), but gzclose_r() is only for use when reading, and
+   gzclose_w() is only for use when writing or appending.  The advantage to
+   using these instead of gzclose() is that they avoid linking in zlib
+   compression or decompression code that is not used when only reading or only
+   writing respectively.  If gzclose() is used, then both compression and
+   decompression code will be included the application when linking to a static
+   zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the given
+   compressed file.  errnum is set to zlib error number.  If an error occurred
+   in the file system and not in the compression library, errnum is set to
+   Z_ERRNO and the application may consult errno to get the exact error code.
+
+     The application must not modify the returned string.  Future calls to
+   this function may invalidate the previously returned string.  If file is
+   closed, then the string previously returned by gzerror will no longer be
+   available.
+
+     gzerror() should be used to distinguish errors from end-of-file for those
+   functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file.  This is analogous to the
+   clearerr() function in stdio.  This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+#endif /* !Z_SOLO */
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the compression
+   library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum.  If buf is Z_NULL, this function returns the
+   required initial value for the checksum.
+
+     An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster.
+
+   Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.  Note
+   that the z_off_t type (like off_t) is a signed integer.  If len2 is
+   negative, the result has no meaning or utility.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32.  If buf is Z_NULL, this function returns the required
+   initial value for the crc.  Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+                      (int)sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+                      ZLIB_VERSION, (int)sizeof(z_stream))
+
+#ifndef Z_SOLO
+
+/* gzgetc() macro and its supporting function and exposed data structure.  Note
+ * that the real internal state is much larger than the exposed structure.
+ * This abbreviated structure exposes just enough for the gzgetc() macro.  The
+ * user should not mess with these exposed elements, since their names or
+ * behavior could change in the future, perhaps even capriciously.  They can
+ * only be used by the gzgetc() macro.  You have been warned.
+ */
+struct gzFile_s {
+    unsigned have;
+    unsigned char *next;
+    z_off64_t pos;
+};
+ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));  /* backward compatibility */
+#ifdef Z_PREFIX_SET
+#  undef z_gzgetc
+#  define z_gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#else
+#  define gzgetc(g) \
+          ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#endif
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#ifdef Z_LARGE64
+   ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+   ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+   ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+   ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+   ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
+#  ifdef Z_PREFIX_SET
+#    define z_gzopen z_gzopen64
+#    define z_gzseek z_gzseek64
+#    define z_gztell z_gztell64
+#    define z_gzoffset z_gzoffset64
+#    define z_adler32_combine z_adler32_combine64
+#    define z_crc32_combine z_crc32_combine64
+#  else
+#    define gzopen gzopen64
+#    define gzseek gzseek64
+#    define gztell gztell64
+#    define gzoffset gzoffset64
+#    define adler32_combine adler32_combine64
+#    define crc32_combine crc32_combine64
+#  endif
+#  ifndef Z_LARGE64
+     ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+     ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+     ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+     ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+     ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+     ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#  endif
+#else
+   ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+   ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+   ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+   ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+#else /* Z_SOLO */
+
+   ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+   ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+
+#endif /* !Z_SOLO */
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table    OF((void));
+ZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));
+ZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));
+ZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));
+#if defined(_WIN32) && !defined(Z_SOLO)
+ZEXTERN gzFile         ZEXPORT gzopen_w OF((const wchar_t *path,
+                                            const char *mode));
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+#  ifndef Z_SOLO
+ZEXTERN int            ZEXPORTVA gzvprintf Z_ARG((gzFile file,
+                                                  const char *format,
+                                                  va_list va));
+#  endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/frontend/vita/retro_inline.h b/frontend/vita/retro_inline.h
new file mode 100644 (file)
index 0000000..8535d84
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright  (C) 2010-2015 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_inline.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_INLINE_H
+#define __LIBRETRO_SDK_INLINE_H
+
+#ifndef INLINE
+
+#if !defined(__cplusplus) && defined(_WIN32)
+#define INLINE _inline
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
+#define INLINE inline
+#elif defined(__GNUC__)
+#define INLINE __inline__
+#else
+#define INLINE
+#endif
+
+#endif
+#endif
diff --git a/frontend/vita/sys/mman.h b/frontend/vita/sys/mman.h
new file mode 100644 (file)
index 0000000..89da513
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef MMAN_H
+#define MMAN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stdlib.h"
+#include "stdio.h"
+
+#define PROT_READ       0b001
+#define PROT_WRITE      0b010
+#define PROT_EXEC       0b100
+#define MAP_PRIVATE     2
+#define MAP_ANONYMOUS   0x20
+
+#define MAP_FAILED      ((void *)-1)
+
+static inline void* mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+   (void)prot;
+   (void)flags;
+   (void)fd;
+   (void)offset;
+
+   int block, ret;
+
+   block = sceKernelAllocMemBlockForVM("code", len);
+   if(block<=0){
+     sceClibPrintf("could not alloc mem block @0x%08X 0x%08X \n", block, len);
+     exit(1);
+   }
+
+   // get base address
+   ret = sceKernelGetMemBlockBase(block, &addr);
+   if (ret < 0)
+   {
+     sceClibPrintf("could get address @0x%08X 0x%08X  \n", block, addr);
+     exit(1);
+   }
+
+
+   if(!addr)
+      return MAP_FAILED;
+
+   return addr;
+}
+
+static inline int mprotect(void *addr, size_t len, int prot)
+{
+   (void)addr;
+   (void)len;
+   (void)prot;
+   return 0;
+}
+
+static inline int munmap(void *addr, size_t len)
+{
+  int uid = sceKernelFindMemBlockByAddr(addr, len);
+
+  return sceKernelFreeMemBlock(uid);
+
+}
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // MMAN_H
diff --git a/frontend/warm b/frontend/warm
deleted file mode 160000 (submodule)
index a6f015d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit a6f015da3b10b82a476250793645c071340decbc
index ce2f3ea..340cc2f 100644 (file)
@@ -1,2 +1,7 @@
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
 #define MAXPATHLEN 256
-#define PACKAGE_VERSION "1.9"
+#define PCSX_VERSION "1.9"
+
+#endif /* __CONFIG_H__ */
index 9ddd500..c956b41 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef __PCNT_H__
+#define __PCNT_H__
 
 enum pcounters {
        PCNT_ALL,
@@ -130,3 +132,5 @@ void pcnt_gte_end(int op);
 #define pcnt_print(fps)
 
 #endif
+
+#endif /* __PCNT_H__ */
index 9986654..545cfca 100644 (file)
@@ -153,6 +153,8 @@ typedef struct
 
 
 
+// No controller
+#define PSE_PAD_TYPE_NONE                      0
 // MOUSE SCPH-1030
 #define PSE_PAD_TYPE_MOUSE                     1
 // NEGCON - 16 button analog controller SLPH-00001
@@ -191,9 +193,15 @@ typedef struct
 
 typedef struct
 {
-       // controler type - fill it withe predefined values above
+       // controller type - fill it withe predefined values above
        unsigned char controllerType;
 
+       //0 : no multitap between psx and pad
+       //1 : multitap between psx and pad on port 1
+       //2 : multitap between psx and pad on port 2
+       int portMultitap;
+       int requestPadIndex;
+
        // status of buttons - every controller fills this field
        unsigned short buttonStatus;
 
@@ -207,8 +215,13 @@ typedef struct
 
        unsigned char Vib[2];
        unsigned char VibF[2];
-
+       
+       //configuration mode Request 0x43
+       int configMode;
        unsigned char reserved[87];
+       
+       //Lightgun values 
+       int absoluteX,absoluteY;
 
 } PadDataS;
 
index 72c6738..644e2af 100644 (file)
 LOCAL_PATH := $(call my-dir)
 
-include $(CLEAR_VARS)
-
-APP_DIR := ../../src
-
-ifneq ($(TARGET_ARCH_ABI),armeabi-v7a)
-   NO_NEON_BUILD := 1
-else
-   NO_NEON_BUILD := $(NO_NEON)
-endif
-
-ifeq ($(NO_NEON_BUILD)$(TARGET_ARCH_ABI),1armeabi-v7a)
-   LOCAL_MODULE    := retro-noneon
-else
-   LOCAL_MODULE    := retro
-endif
-
-ifeq ($(TARGET_ARCH),arm)
-   LOCAL_ARM_MODE := arm
-
-   LOCAL_CFLAGS += -DANDROID_ARM
-
-   LOCAL_SRC_FILES += ../libpcsxcore/gte_arm.S
+$(shell cd "$(LOCAL_PATH)" && ((git describe || echo) | sed -e 's/.*/#define REV "\0"/' > ../frontend/revision.h_))
+$(shell cd "$(LOCAL_PATH)" && (diff -q ../frontend/revision.h_ ../frontend/revision.h > /dev/null 2>&1 || cp ../frontend/revision.h_ ../frontend/revision.h))
+$(shell cd "$(LOCAL_PATH)" && (rm ../frontend/revision.h_))
 
-   # dynarec
-   LOCAL_SRC_FILES += ../libpcsxcore/new_dynarec/new_dynarec.c ../libpcsxcore/new_dynarec/linkage_arm.S ../libpcsxcore/new_dynarec/emu_if.c ../libpcsxcore/new_dynarec/pcsxmem.c
+HAVE_CHD ?= 1
+USE_LIBRETRO_VFS ?= 0
+
+ROOT_DIR     := $(LOCAL_PATH)/..
+CORE_DIR     := $(ROOT_DIR)/libpcsxcore
+SPU_DIR      := $(ROOT_DIR)/plugins/dfsound
+GPU_DIR      := $(ROOT_DIR)/plugins/gpulib
+CDR_DIR      := $(ROOT_DIR)/plugins/cdrcimg
+INPUT_DIR    := $(ROOT_DIR)/plugins/dfinput
+FRONTEND_DIR := $(ROOT_DIR)/frontend
+NEON_DIR     := $(ROOT_DIR)/plugins/gpu_neon
+UNAI_DIR     := $(ROOT_DIR)/plugins/gpu_unai
+DYNAREC_DIR  := $(ROOT_DIR)/libpcsxcore/new_dynarec
+DEPS_DIR     := $(ROOT_DIR)/deps
+LIBRETRO_COMMON := $(ROOT_DIR)/libretro-common
+EXTRA_INCLUDES :=
+
+# core
+SOURCES_C := $(CORE_DIR)/cdriso.c \
+             $(CORE_DIR)/cdrom.c \
+             $(CORE_DIR)/cheat.c \
+             $(CORE_DIR)/decode_xa.c \
+             $(CORE_DIR)/mdec.c \
+             $(CORE_DIR)/misc.c \
+             $(CORE_DIR)/plugins.c \
+             $(CORE_DIR)/ppf.c \
+             $(CORE_DIR)/psxbios.c \
+             $(CORE_DIR)/psxcommon.c \
+             $(CORE_DIR)/psxcounters.c \
+             $(CORE_DIR)/psxdma.c \
+             $(CORE_DIR)/psxhle.c \
+             $(CORE_DIR)/psxhw.c \
+             $(CORE_DIR)/psxinterpreter.c \
+             $(CORE_DIR)/psxmem.c \
+             $(CORE_DIR)/r3000a.c \
+             $(CORE_DIR)/sio.c \
+             $(CORE_DIR)/spu.c \
+             $(CORE_DIR)/gte.c \
+             $(CORE_DIR)/gte_nf.c \
+             $(CORE_DIR)/gte_divider.c
 
-   # spu
-   LOCAL_SRC_FILES += ../plugins/dfsound/arm_utils.S
+# spu
+SOURCES_C += $(SPU_DIR)/dma.c \
+             $(SPU_DIR)/freeze.c \
+             $(SPU_DIR)/registers.c \
+             $(SPU_DIR)/spu.c \
+             $(SPU_DIR)/out.c \
+             $(SPU_DIR)/nullsnd.c
 
-   # misc
+# gpu
+SOURCES_C += $(GPU_DIR)/gpu.c \
+             $(GPU_DIR)/vout_pl.c
 
-   ifeq ($(NO_NEON_BUILD),1)
-      # gpu
-      LOCAL_CFLAGS += -DREARMED
-      LOCAL_SRC_FILES += ../plugins/gpu_unai/gpulib_if.cpp ../plugins/gpu_unai/gpu_arm.s
-      LOCAL_SRC_FILES += ../frontend/cspace_arm.S
-   else
-      LOCAL_ARM_NEON := true
-      LOCAL_CFLAGS += -DNEON_BUILD -DTEXTURE_CACHE_4BPP -DTEXTURE_CACHE_8BPP
-      LOCAL_SRC_FILES += ../libpcsxcore/gte_neon.S ../frontend/cspace_neon.S
+# cdrcimg
+SOURCES_C += $(CDR_DIR)/cdrcimg.c
 
-      # gpu
-      LOCAL_SRC_FILES += ../plugins/gpu_neon/psx_gpu_if.c ../plugins/gpu_neon/psx_gpu/psx_gpu_arm_neon.S
-   endif
+# dfinput
+SOURCES_C += $(INPUT_DIR)/main.c \
+             $(INPUT_DIR)/pad.c \
+             $(INPUT_DIR)/guncon.c
+
+# frontend
+SOURCES_C += $(FRONTEND_DIR)/main.c \
+             $(FRONTEND_DIR)/plugin.c \
+             $(FRONTEND_DIR)/cspace.c \
+             $(FRONTEND_DIR)/libretro.c
+
+# libchdr
+SOURCES_C += \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/Alloc.c \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/Bra86.c \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/BraIA64.c \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/CpuArch.c \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/Delta.c \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/LzFind.c \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/Lzma86Dec.c \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/LzmaDec.c \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/LzmaEnc.c \
+             $(DEPS_DIR)/libchdr/deps/lzma-19.00/src/Sort.c \
+             $(DEPS_DIR)/libchdr/src/libchdr_bitstream.c \
+             $(DEPS_DIR)/libchdr/src/libchdr_cdrom.c \
+             $(DEPS_DIR)/libchdr/src/libchdr_chd.c \
+             $(DEPS_DIR)/libchdr/src/libchdr_flac.c \
+             $(DEPS_DIR)/libchdr/src/libchdr_huffman.c
+SOURCES_ASM :=
+
+COREFLAGS := -ffast-math -funroll-loops -DHAVE_LIBRETRO -DNO_FRONTEND -DFRONTEND_SUPPORTS_RGB565 -DANDROID -DREARMED
+COREFLAGS += -DHAVE_CHD -D_7ZIP_ST
+
+ifeq ($(USE_LIBRETRO_VFS),1)
+SOURCES_C += \
+             $(LIBRETRO_COMMON)/compat/compat_posix_string.c \
+             $(LIBRETRO_COMMON)/compat/fopen_utf8.c \
+             $(LIBRETRO_COMMON)/encodings/compat_strl.c \
+             $(LIBRETRO_COMMON)/encodings/encoding_utf.c \
+             $(LIBRETRO_COMMON)/file/file_path.c \
+             $(LIBRETRO_COMMON)/streams/file_stream.c \
+             $(LIBRETRO_COMMON)/streams/file_stream_transforms.c \
+             $(LIBRETRO_COMMON)/string/stdstring.c \
+             $(LIBRETRO_COMMON)/time/rtime.c \
+             $(LIBRETRO_COMMON)/vfs/vfs_implementation.c
+COREFLAGS += -DUSE_LIBRETRO_VFS
 endif
 
-ifeq ($(TARGET_ARCH),x86)
-   LOCAL_CFLAGS += -DANDROID_X86
+HAVE_ARI64=0
+HAVE_LIGHTREC=0
+ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
+  HAVE_ARI64=1
+else ifeq ($(TARGET_ARCH_ABI),armeabi)
+  HAVE_ARI64=1
+else ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
+  HAVE_LIGHTREC=1
+else ifeq ($(TARGET_ARCH_ABI),x86_64)
+  HAVE_LIGHTREC=1
+else ifeq ($(TARGET_ARCH_ABI),x86)
+  HAVE_LIGHTREC=1
+else
+  COREFLAGS   += -DDRC_DISABLE
 endif
 
-ifeq ($(TARGET_ARCH),mips)
-   LOCAL_CFLAGS += -DANDROID_MIPS -D__mips__ -D__MIPSEL__
+ifeq ($(HAVE_ARI64),1)
+  COREFLAGS   += -DNEW_DYNAREC
+  SOURCES_ASM += $(CORE_DIR)/gte_arm.S \
+                 $(SPU_DIR)/arm_utils.S \
+                 $(DYNAREC_DIR)/arm/linkage_arm.S
+  SOURCES_C   += $(DYNAREC_DIR)/new_dynarec.c \
+                 $(DYNAREC_DIR)/backends/psx/pcsxmem.c
 endif
 
-ifneq ($(TARGET_ARCH),arm)
-   # gpu
-   LOCAL_CFLAGS += -DREARMED
-   LOCAL_SRC_FILES += ../plugins/gpu_unai/gpulib_if.cpp
+ifeq ($(HAVE_LIGHTREC),1)
+  COREFLAGS   += -DLIGHTREC -DLIGHTREC_STATIC
+  EXTRA_INCLUDES += $(DEPS_DIR)/lightning/include \
+                                                 $(DEPS_DIR)/lightrec
+  SOURCES_C   += $(DEPS_DIR)/lightrec/blockcache.c \
+                                         $(DEPS_DIR)/lightrec/disassembler.c \
+                                         $(DEPS_DIR)/lightrec/emitter.c \
+                                         $(DEPS_DIR)/lightrec/interpreter.c \
+                                         $(DEPS_DIR)/lightrec/lightrec.c \
+                                         $(DEPS_DIR)/lightrec/memmanager.c \
+                                         $(DEPS_DIR)/lightrec/optimizer.c \
+                                         $(DEPS_DIR)/lightrec/regcache.c \
+                                         $(DEPS_DIR)/lightrec/recompiler.c \
+                                         $(DEPS_DIR)/lightrec/reaper.c
+  SOURCES_C   += $(DEPS_DIR)/lightning/lib/jit_disasm.c \
+                                         $(DEPS_DIR)/lightning/lib/jit_memory.c \
+                                         $(DEPS_DIR)/lightning/lib/jit_names.c \
+                                         $(DEPS_DIR)/lightning/lib/jit_note.c \
+                                         $(DEPS_DIR)/lightning/lib/jit_print.c \
+                                         $(DEPS_DIR)/lightning/lib/jit_size.c \
+                                         $(DEPS_DIR)/lightning/lib/lightning.c
+  SOURCES_C   += $(CORE_DIR)/lightrec/plugin.c
 endif
 
-$(shell cd "$(LOCAL_PATH)" && ((git describe || echo) | sed -e 's/.*/#define REV "\0"/' > ../frontend/revision.h_))
-$(shell cd "$(LOCAL_PATH)" && (diff -q ../frontend/revision.h_ ../frontend/revision.h > /dev/null 2>&1 || cp ../frontend/revision.h_ ../frontend/revision.h))
-$(shell cd "$(LOCAL_PATH)" && (rm ../frontend/revision.h_))
-
-LOCAL_SRC_FILES += ../libpcsxcore/cdriso.c ../libpcsxcore/cdrom.c ../libpcsxcore/cheat.c ../libpcsxcore/debug.c \
-   ../libpcsxcore/decode_xa.c ../libpcsxcore/disr3000a.c ../libpcsxcore/mdec.c \
-   ../libpcsxcore/misc.c ../libpcsxcore/plugins.c ../libpcsxcore/ppf.c ../libpcsxcore/psxbios.c \
-   ../libpcsxcore/psxcommon.c ../libpcsxcore/psxcounters.c ../libpcsxcore/psxdma.c ../libpcsxcore/psxhle.c \
-   ../libpcsxcore/psxhw.c ../libpcsxcore/psxinterpreter.c ../libpcsxcore/psxmem.c ../libpcsxcore/r3000a.c \
-   ../libpcsxcore/sio.c ../libpcsxcore/socket.c ../libpcsxcore/spu.c
-LOCAL_SRC_FILES += ../libpcsxcore/gte.c ../libpcsxcore/gte_nf.c ../libpcsxcore/gte_divider.c
 
-# spu
-LOCAL_SRC_FILES += ../plugins/dfsound/dma.c ../plugins/dfsound/freeze.c \
-   ../plugins/dfsound/registers.c ../plugins/dfsound/spu.c \
-   ../plugins/dfsound/out.c ../plugins/dfsound/nullsnd.c
-
-# builtin gpu
-LOCAL_SRC_FILES += ../plugins/gpulib/gpu.c ../plugins/gpulib/vout_pl.c
-
-# cdrcimg
-LOCAL_SRC_FILES += ../plugins/cdrcimg/cdrcimg.c
-
-# dfinput
-LOCAL_SRC_FILES += ../plugins/dfinput/main.c ../plugins/dfinput/pad.c ../plugins/dfinput/guncon.c
-
-# misc
-LOCAL_SRC_FILES += ../frontend/main.c ../frontend/plugin.c ../frontend/cspace.c
+ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
+  COREFLAGS   += -DNEON_BUILD -DTEXTURE_CACHE_4BPP -DTEXTURE_CACHE_8BPP -DGPU_NEON
+  SOURCES_ASM += $(CORE_DIR)/gte_neon.S \
+                 $(NEON_DIR)/psx_gpu/psx_gpu_arm_neon.S \
+                 $(FRONTEND_DIR)/cspace_neon.S
+  SOURCES_C   += $(NEON_DIR)/psx_gpu_if.c
+  SOURCES_C   += $(DYNAREC_DIR)/backends/psx/emu_if.c
+else ifeq ($(TARGET_ARCH_ABI),armeabi)
+  COREFLAGS += -DUSE_GPULIB=1 -DGPU_UNAI
+  SOURCES_ASM += $(UNAI_DIR)/gpu_arm.S \
+                 $(FRONTEND_DIR)/cspace_arm.S
+  SOURCES_C += $(UNAI_DIR)/gpulib_if.cpp
+else
+  COREFLAGS += -DUSE_GPULIB=1 -DGPU_UNAI
+  SOURCES_C += $(UNAI_DIR)/gpulib_if.cpp
+endif
 
-# libretro
-LOCAL_SRC_FILES += ../frontend/libretro.c
+GIT_VERSION := " $(shell git rev-parse --short HEAD || echo unknown)"
+ifneq ($(GIT_VERSION)," unknown")
+  COREFLAGS += -DGIT_VERSION=\"$(GIT_VERSION)\"
+endif
 
-LOCAL_CFLAGS += -O3 -ffast-math -funroll-loops -DNDEBUG -D_FILE_OFFSET_BITS=64 -DHAVE_LIBRETRO -DNO_FRONTEND -DFRONTEND_SUPPORTS_RGB565
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/../include
-LOCAL_LDLIBS := -lz -llog
+include $(CLEAR_VARS)
+LOCAL_MODULE        := retro
+LOCAL_SRC_FILES     := $(SOURCES_C) $(SOURCES_ASM)
+LOCAL_CFLAGS        := $(COREFLAGS)
+LOCAL_C_INCLUDES    := $(ROOT_DIR)/include
+LOCAL_C_INCLUDES    += $(DEPS_DIR)/crypto $(DEPS_DIR)/libchdr/deps/lzma-19.00/include $(DEPS_DIR)/libchdr/include $(DEPS_DIR)/libchdr/include/libchdr
+LOCAL_C_INCLUDES    += $(LIBRETRO_COMMON)/include
+LOCAL_C_INCLUDES    += $(EXTRA_INCLUDES)
+LOCAL_LDFLAGS       := -Wl,-version-script=$(FRONTEND_DIR)/link.T
+LOCAL_LDLIBS        := -lz -llog
+LOCAL_ARM_MODE      := arm
+
+ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
+  LOCAL_ARM_NEON  := true
+endif
 
 include $(BUILD_SHARED_LIBRARY)
index f05229c..a252a72 100644 (file)
@@ -1 +1 @@
-APP_ABI := armeabi armeabi-v7a
+APP_ABI := all
index dca64fa..ee23421 100644 (file)
 #include "cdriso.h"
 #include "ppf.h"
 
+#include <errno.h>
+#include <zlib.h>
+#ifdef HAVE_CHD
+#include <chd.h>
+#endif
+
 #ifdef _WIN32
 #define WIN32_LEAN_AND_MEAN
 #include <process.h>
 #include <windows.h>
 #define strcasecmp _stricmp
-#define usleep(x) Sleep((x) / 1000)
+#define usleep(x) (Sleep((x) / 1000))
 #else
 #include <pthread.h>
 #include <sys/time.h>
 #include <unistd.h>
 #endif
-#include <errno.h>
-#include <zlib.h>
+
+#ifdef USE_LIBRETRO_VFS
+#include <streams/file_stream_transforms.h>
+#undef fseeko
+#undef ftello
+#define ftello rftell
+#define fseeko rfseek
+#endif
 
 #define OFF_T_MSB ((off_t)1 << (sizeof(off_t) * 8 - 1))
 
@@ -92,6 +104,17 @@ static struct {
        unsigned int sector_in_blk;
 } *compr_img;
 
+#ifdef HAVE_CHD
+static struct {
+       unsigned char (*buffer)[CD_FRAMESIZE_RAW + SUB_FRAMESIZE];
+       chd_file* chd;
+       const chd_header* header;
+       unsigned int sectors_per_hunk;
+       unsigned int current_hunk;
+       unsigned int sector_in_hunk;
+} *chd_img;
+#endif
+
 int (*cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector);
 
 char* CALLBACK CDR__getDriveLetter(void);
@@ -225,7 +248,9 @@ static void *playthread(void *param)
                        do {
                                ret = SPU_playCDDAchannel((short *)sndbuffer, s);
                                if (ret == 0x7761)
+            {
                                        usleep(6 * 1000);
+            }
                        } while (ret == 0x7761 && playing); // rearmed_wait
                }
 
@@ -236,7 +261,9 @@ static void *playthread(void *param)
                        // HACK: stop feeding data while emu is paused
                        extern int stop;
                        while (stop && playing)
+         {
                                usleep(10000);
+         }
 
                        now = GetTickCount();
                        osleep = t - now;
@@ -333,11 +360,12 @@ static int parsetoc(const char *isofile) {
                        }
                }
                // check if it's really a TOC named as a .cue
-               fgets(linebuf, sizeof(linebuf), fi);
-               token = strtok(linebuf, " ");
-               if (token && strncmp(token, "CD", 2) != 0 && strcmp(token, "CATALOG") != 0) {
-                       fclose(fi);
-                       return -1;
+               if (fgets(linebuf, sizeof(linebuf), fi) != NULL) {
+                       token = strtok(linebuf, " ");
+                       if (token && strncmp(token, "CD", 2) != 0 && strcmp(token, "CATALOG") != 0) {
+                               fclose(fi);
+                               return -1;
+                       }
                }
                fseek(fi, 0, SEEK_SET);
        }
@@ -458,7 +486,10 @@ static int parsecue(const char *isofile) {
        strncpy(cuename, isofile, sizeof(cuename));
        cuename[MAXPATHLEN - 1] = '\0';
        if (strlen(cuename) >= 4) {
-               strcpy(cuename + strlen(cuename) - 4, ".cue");
+               // If 'isofile' is a '.cd<X>' file, use it as a .cue file
+               //  and don't try to search the additional .cue file
+               if (strncasecmp(cuename + strlen(cuename) - 4, ".cd", 3) != 0 )
+                       strcpy(cuename + strlen(cuename) - 4, ".cue");
        }
        else {
                return -1;
@@ -560,20 +591,15 @@ static int parsecue(const char *isofile) {
                        if (t != 1)
                                sscanf(linebuf, " FILE %255s", tmpb);
 
-                       // absolute path?
-                       ti[numtracks + 1].handle = fopen(tmpb, "rb");
-                       if (ti[numtracks + 1].handle == NULL) {
-                               // relative to .cue?
-                               tmp = strrchr(tmpb, '\\');
-                               if (tmp == NULL)
-                                       tmp = strrchr(tmpb, '/');
-                               if (tmp != NULL)
-                                       tmp++;
-                               else
-                                       tmp = tmpb;
-                               strncpy(incue_fname, tmp, incue_max_len);
-                               ti[numtracks + 1].handle = fopen(filepath, "rb");
-                       }
+                       tmp = strrchr(tmpb, '\\');
+                       if (tmp == NULL)
+                               tmp = strrchr(tmpb, '/');
+                       if (tmp != NULL)
+                               tmp++;
+                       else
+                               tmp = tmpb;
+                       strncpy(incue_fname, tmp, incue_max_len);
+                       ti[numtracks + 1].handle = fopen(filepath, "rb");
 
                        // update global offset if this is not first file in this .cue
                        if (numtracks + 1 > 1) {
@@ -590,9 +616,9 @@ static int parsecue(const char *isofile) {
                        file_len = ftell(ti[numtracks + 1].handle) / 2352;
 
                        if (numtracks == 0 && strlen(isofile) >= 4 &&
-                               strcmp(isofile + strlen(isofile) - 4, ".cue") == 0)
-                       {
-                               // user selected .cue as image file, use it's data track instead
+                               (strcmp(isofile + strlen(isofile) - 4, ".cue") == 0 ||
+                               strncasecmp(isofile + strlen(isofile) - 4, ".cd", 3) == 0)) {
+                               // user selected .cue/.cdX as image file, use it's data track instead
                                fclose(cdHandle);
                                cdHandle = fopen(filepath, "rb");
                        }
@@ -601,6 +627,10 @@ static int parsecue(const char *isofile) {
 
        fclose(fi);
 
+       // if there are no tracks detected, then it's not a cue file
+       if (!numtracks)
+               return -1;
+
        return 0;
 }
 
@@ -690,7 +720,8 @@ static int parsemds(const char *isofile) {
        memset(&ti, 0, sizeof(ti));
 
        // check if it's a valid mds file
-       fread(&i, 1, sizeof(unsigned int), fi);
+       if (fread(&i, 1, sizeof(i), fi) != sizeof(i))
+               goto fail_io;
        i = SWAP32(i);
        if (i != 0x4944454D) {
                // not an valid mds file
@@ -700,19 +731,22 @@ static int parsemds(const char *isofile) {
 
        // get offset to session block
        fseek(fi, 0x50, SEEK_SET);
-       fread(&offset, 1, sizeof(unsigned int), fi);
+       if (fread(&offset, 1, sizeof(offset), fi) != sizeof(offset))
+               goto fail_io;
        offset = SWAP32(offset);
 
        // get total number of tracks
        offset += 14;
        fseek(fi, offset, SEEK_SET);
-       fread(&s, 1, sizeof(unsigned short), fi);
+       if (fread(&s, 1, sizeof(s), fi) != sizeof(s))
+               goto fail_io;
        s = SWAP16(s);
        numtracks = s;
 
        // get offset to track blocks
        fseek(fi, 4, SEEK_CUR);
-       fread(&offset, 1, sizeof(unsigned int), fi);
+       if (fread(&offset, 1, sizeof(offset), fi) != sizeof(offset))
+               goto fail_io;
        offset = SWAP32(offset);
 
        // skip lead-in data
@@ -741,32 +775,41 @@ static int parsemds(const char *isofile) {
                ti[i].start[1] = fgetc(fi);
                ti[i].start[2] = fgetc(fi);
 
-               fread(&extra_offset, 1, sizeof(unsigned int), fi);
+               if (fread(&extra_offset, 1, sizeof(extra_offset), fi) != sizeof(extra_offset))
+                       goto fail_io;
                extra_offset = SWAP32(extra_offset);
 
                // get track start offset (in .mdf)
                fseek(fi, offset + 0x28, SEEK_SET);
-               fread(&l, 1, sizeof(unsigned int), fi);
+               if (fread(&l, 1, sizeof(l), fi) != sizeof(l))
+                       goto fail_io;
                l = SWAP32(l);
                ti[i].start_offset = l;
 
                // get pregap
                fseek(fi, extra_offset, SEEK_SET);
-               fread(&l, 1, sizeof(unsigned int), fi);
+               if (fread(&l, 1, sizeof(l), fi) != sizeof(l))
+                       goto fail_io;
                l = SWAP32(l);
                if (l != 0 && i > 1)
                        pregapOffset = msf2sec(ti[i].start);
 
                // get the track length
-               fread(&l, 1, sizeof(unsigned int), fi);
+               if (fread(&l, 1, sizeof(l), fi) != sizeof(l))
+                       goto fail_io;
                l = SWAP32(l);
                sec2msf(l, ti[i].length);
 
                offset += 0x50;
        }
-
        fclose(fi);
        return 0;
+fail_io:
+#ifndef NDEBUG
+       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+       fclose(fi);
+       return -1;
 }
 
 static int handlepbp(const char *isofile) {
@@ -817,7 +860,8 @@ static int handlepbp(const char *isofile) {
        }
 
        psisoimg_offs = pbp_hdr.psar_offs;
-       fread(psar_sig, 1, sizeof(psar_sig), cdHandle);
+       if (fread(psar_sig, 1, sizeof(psar_sig), cdHandle) != sizeof(psar_sig))
+               goto fail_io;
        psar_sig[10] = 0;
        if (strcmp(psar_sig, "PSTITLEIMG") == 0) {
                // multidisk image?
@@ -853,7 +897,8 @@ static int handlepbp(const char *isofile) {
                        goto fail_io;
                }
 
-               fread(psar_sig, 1, sizeof(psar_sig), cdHandle);
+               if (fread(psar_sig, 1, sizeof(psar_sig), cdHandle) != sizeof(psar_sig))
+                       goto fail_io;
                psar_sig[10] = 0;
        }
 
@@ -871,15 +916,18 @@ static int handlepbp(const char *isofile) {
 
        // first 3 entries are special
        fseek(cdHandle, sizeof(toc_entry), SEEK_CUR);
-       fread(&toc_entry, 1, sizeof(toc_entry), cdHandle);
+       if (fread(&toc_entry, 1, sizeof(toc_entry), cdHandle) != sizeof(toc_entry))
+               goto fail_io;
        numtracks = btoi(toc_entry.index1[0]);
 
-       fread(&toc_entry, 1, sizeof(toc_entry), cdHandle);
+       if (fread(&toc_entry, 1, sizeof(toc_entry), cdHandle) != sizeof(toc_entry))
+               goto fail_io;
        cd_length = btoi(toc_entry.index1[0]) * 60 * 75 +
                btoi(toc_entry.index1[1]) * 75 + btoi(toc_entry.index1[2]);
 
        for (i = 1; i <= numtracks; i++) {
-               fread(&toc_entry, 1, sizeof(toc_entry), cdHandle);
+               if (fread(&toc_entry, 1, sizeof(toc_entry), cdHandle) != sizeof(toc_entry))
+                       goto fail_io;
 
                ti[i].type = (toc_entry.type == 1) ? CDDA : DATA;
 
@@ -937,7 +985,14 @@ static int handlepbp(const char *isofile) {
 fail_index:
        free(compr_img->index_table);
        compr_img->index_table = NULL;
+       goto done;
+
 fail_io:
+#ifndef NDEBUG
+       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+
+done:
        if (compr_img != NULL) {
                free(compr_img);
                compr_img = NULL;
@@ -1029,6 +1084,86 @@ fail_io:
        return -1;
 }
 
+#ifdef HAVE_CHD
+static int handlechd(const char *isofile) {
+       chd_img = calloc(1, sizeof(*chd_img));
+       if (chd_img == NULL)
+               goto fail_io;
+
+       if(chd_open(isofile, CHD_OPEN_READ, NULL, &chd_img->chd) != CHDERR_NONE)
+               goto fail_io;
+
+       if (Config.CHD_Precache && (chd_precache(chd_img->chd) != CHDERR_NONE))
+               goto fail_io;
+
+   chd_img->header = chd_get_header(chd_img->chd);
+
+   chd_img->buffer = malloc(chd_img->header->hunkbytes);
+   if (chd_img->buffer == NULL)
+               goto fail_io;
+
+   chd_img->sectors_per_hunk = chd_img->header->hunkbytes / (CD_FRAMESIZE_RAW + SUB_FRAMESIZE);
+   chd_img->current_hunk = (unsigned int)-1;
+
+   cddaBigEndian = TRUE;
+
+       numtracks = 0;
+       int frame_offset = 0;
+       int file_offset = 0;
+       memset(ti, 0, sizeof(ti));
+
+   while (1)
+   {
+      struct {
+         char type[64];
+         char subtype[32];
+         char pgtype[32];
+         char pgsub[32];
+         uint32_t track;
+         uint32_t frames;
+         uint32_t pregap;
+         uint32_t postgap;
+      } md = {};
+      char meta[256];
+      uint32_t meta_size = 0;
+
+      if (chd_get_metadata(chd_img->chd, CDROM_TRACK_METADATA2_TAG, numtracks, meta, sizeof(meta), &meta_size, NULL, NULL) == CHDERR_NONE)
+         sscanf(meta, CDROM_TRACK_METADATA2_FORMAT, &md.track, md.type, md.subtype, &md.frames, &md.pregap, md.pgtype, md.pgsub, &md.postgap);
+      else if (chd_get_metadata(chd_img->chd, CDROM_TRACK_METADATA_TAG, numtracks, meta, sizeof(meta), &meta_size, NULL, NULL) == CHDERR_NONE)
+         sscanf(meta, CDROM_TRACK_METADATA_FORMAT, &md.track, md.type, md.subtype, &md.frames);
+      else
+         break;
+
+               if(md.track == 1)
+                       md.pregap = 150;
+               else
+                       sec2msf(msf2sec(ti[md.track-1].length) + md.pregap, ti[md.track-1].length);
+
+               ti[md.track].type = !strncmp(md.type, "AUDIO", 5) ? CDDA : DATA;
+
+               sec2msf(frame_offset + md.pregap, ti[md.track].start);
+               sec2msf(md.frames, ti[md.track].length);
+
+               ti[md.track].start_offset = file_offset;
+
+               frame_offset += md.pregap + md.frames + md.postgap;
+               file_offset += md.frames + md.postgap;
+               numtracks++;
+       }
+
+       if (numtracks)
+               return 0;
+
+fail_io:
+       if (chd_img != NULL) {
+               free(chd_img->buffer);
+               free(chd_img);
+               chd_img = NULL;
+       }
+       return -1;
+}
+#endif
+
 // this function tries to get the .sub file of the given .img
 static int opensubfile(const char *isoname) {
        char            subname[MAXPATHLEN];
@@ -1052,13 +1187,18 @@ static int opensubfile(const char *isoname) {
 }
 
 static int opensbifile(const char *isoname) {
-       char            sbiname[MAXPATHLEN];
+       char            sbiname[MAXPATHLEN], disknum[MAXPATHLEN] = "0";
        int             s;
 
        strncpy(sbiname, isoname, sizeof(sbiname));
        sbiname[MAXPATHLEN - 1] = '\0';
        if (strlen(sbiname) >= 4) {
-               strcpy(sbiname + strlen(sbiname) - 4, ".sbi");
+               if (cdrIsoMultidiskCount > 1) {
+                       sprintf(disknum, "_%i.sbi", cdrIsoMultidiskSelect + 1);
+                       strcpy(sbiname + strlen(sbiname) - 4, disknum);
+               }
+               else
+                       strcpy(sbiname + strlen(sbiname) - 4, ".sbi");
        }
        else {
                return -1;
@@ -1070,6 +1210,199 @@ static int opensbifile(const char *isoname) {
        return LoadSBI(sbiname, s);
 }
 
+#ifdef _WIN32
+static void readThreadStop() {}
+static void readThreadStart() {}
+#else
+static pthread_t read_thread_id;
+
+static pthread_cond_t read_thread_msg_avail;
+static pthread_cond_t read_thread_msg_done;
+static pthread_mutex_t read_thread_msg_lock;
+
+static pthread_cond_t sectorbuffer_cond;
+static pthread_mutex_t sectorbuffer_lock;
+
+static boolean read_thread_running = FALSE;
+static int read_thread_sector_start = -1;
+static int read_thread_sector_end = -1;
+
+typedef struct {
+  int sector;
+  long ret;
+  unsigned char data[CD_FRAMESIZE_RAW];
+} SectorBufferEntry;
+
+#define SECTOR_BUFFER_SIZE 4096
+
+static SectorBufferEntry *sectorbuffer;
+static size_t sectorbuffer_index;
+
+int (*sync_cdimg_read_func)(FILE *f, unsigned int base, void *dest, int sector);
+unsigned char *(*sync_CDR_getBuffer)(void);
+
+static unsigned char * CALLBACK ISOgetBuffer_async(void);
+static int cdread_async(FILE *f, unsigned int base, void *dest, int sector);
+
+static void *readThreadMain(void *param) {
+  int max_sector = -1;
+  int requested_sector_start = -1;
+  int requested_sector_end = -1;
+  int last_read_sector = -1;
+  int index = 0;
+
+  int ra_sector = -1;
+  int max_ra = 128;
+  int initial_ra = 1;
+  int speedmult_ra = 4;
+
+  int ra_count = 0;
+  int how_far_ahead = 0;
+
+  unsigned char tmpdata[CD_FRAMESIZE_RAW];
+  long ret;
+
+  max_sector = msf2sec(ti[numtracks].start) + msf2sec(ti[numtracks].length);
+
+  while(1) {
+    pthread_mutex_lock(&read_thread_msg_lock);
+
+    // If we don't have readahead and we don't have a sector request, wait for one.
+    // If we still have readahead to go, don't block, just keep going.
+    // And if we ever have a sector request pending, acknowledge and reset it.
+
+    if (!ra_count) {
+      if (read_thread_sector_start == -1 && read_thread_running) {
+        pthread_cond_wait(&read_thread_msg_avail, &read_thread_msg_lock);
+      }
+    }
+
+    if (read_thread_sector_start != -1) {
+      requested_sector_start = read_thread_sector_start;
+      requested_sector_end = read_thread_sector_end;
+      read_thread_sector_start = -1;
+      read_thread_sector_end = -1;
+      pthread_cond_signal(&read_thread_msg_done);
+    }
+
+    pthread_mutex_unlock(&read_thread_msg_lock);
+
+    if (!read_thread_running)
+      break;
+
+    // Readahead code, based on the implementation in mednafen psx's cdromif.cpp
+    if (requested_sector_start != -1) {
+      if (last_read_sector != -1 && last_read_sector == (requested_sector_start - 1)) {
+        how_far_ahead = ra_sector - requested_sector_end;
+
+        if(how_far_ahead <= max_ra)
+          ra_count = (max_ra - how_far_ahead + 1 ? max_ra - how_far_ahead + 1 : speedmult_ra);
+        else
+          ra_count++;
+      } else if (requested_sector_end != last_read_sector) {
+        ra_sector = requested_sector_end;
+        ra_count = initial_ra;
+      }
+
+      last_read_sector = requested_sector_end;
+    }
+
+    index = ra_sector % SECTOR_BUFFER_SIZE;
+
+    // check for end of CD
+    if (ra_count && ra_sector >= max_sector) {
+      ra_count = 0;
+      pthread_mutex_lock(&sectorbuffer_lock);
+      sectorbuffer[index].ret = -1;
+      sectorbuffer[index].sector = ra_sector;
+      pthread_cond_signal(&sectorbuffer_cond);
+      pthread_mutex_unlock(&sectorbuffer_lock);
+    }
+
+    if (ra_count) {
+      pthread_mutex_lock(&sectorbuffer_lock);
+      if (sectorbuffer[index].sector != ra_sector) {
+        pthread_mutex_unlock(&sectorbuffer_lock);
+
+        ret = sync_cdimg_read_func(cdHandle, 0, tmpdata, ra_sector);
+
+        pthread_mutex_lock(&sectorbuffer_lock);
+        sectorbuffer[index].ret = ret;
+        sectorbuffer[index].sector = ra_sector;
+        memcpy(sectorbuffer[index].data, tmpdata, CD_FRAMESIZE_RAW);
+      }
+      pthread_cond_signal(&sectorbuffer_cond);
+      pthread_mutex_unlock(&sectorbuffer_lock);
+
+      ra_sector++;
+      ra_count--;
+    }
+  }
+
+  return NULL;
+}
+
+static void readThreadStop() {
+  if (read_thread_running == TRUE) {
+    read_thread_running = FALSE;
+    pthread_cond_signal(&read_thread_msg_avail);
+    pthread_join(read_thread_id, NULL);
+  }
+
+  pthread_cond_destroy(&read_thread_msg_done);
+  pthread_cond_destroy(&read_thread_msg_avail);
+  pthread_mutex_destroy(&read_thread_msg_lock);
+
+  pthread_cond_destroy(&sectorbuffer_cond);
+  pthread_mutex_destroy(&sectorbuffer_lock);
+
+  CDR_getBuffer = sync_CDR_getBuffer;
+  cdimg_read_func = sync_cdimg_read_func;
+
+  free(sectorbuffer);
+  sectorbuffer = NULL;
+}
+
+static void readThreadStart() {
+  SysPrintf("Starting async CD thread\n");
+
+  if (read_thread_running == TRUE)
+    return;
+
+  read_thread_running = TRUE;
+  read_thread_sector_start = -1;
+  read_thread_sector_end = -1;
+  sectorbuffer_index = 0;
+
+  sectorbuffer = calloc(SECTOR_BUFFER_SIZE, sizeof(SectorBufferEntry));
+  if(!sectorbuffer)
+    goto error;
+
+  sectorbuffer[0].sector = -1; // Otherwise we might think we've already fetched sector 0!
+
+  sync_CDR_getBuffer = CDR_getBuffer;
+  CDR_getBuffer = ISOgetBuffer_async;
+  sync_cdimg_read_func = cdimg_read_func;
+  cdimg_read_func = cdread_async;
+
+  if (pthread_cond_init(&read_thread_msg_avail, NULL) ||
+      pthread_cond_init(&read_thread_msg_done, NULL) ||
+      pthread_mutex_init(&read_thread_msg_lock, NULL) ||
+      pthread_cond_init(&sectorbuffer_cond, NULL) ||
+      pthread_mutex_init(&sectorbuffer_lock, NULL) ||
+      pthread_create(&read_thread_id, NULL, readThreadMain, NULL))
+    goto error;
+
+  return;
+
+ error:
+  SysPrintf("Error starting async CD thread\n");
+  SysPrintf("Falling back to sync\n");
+
+  readThreadStop();
+}
+#endif
+
 static int cdread_normal(FILE *f, unsigned int base, void *dest, int sector)
 {
        fseek(f, base + sector * CD_FRAMESIZE_RAW, SEEK_SET);
@@ -1082,10 +1415,18 @@ static int cdread_sub_mixed(FILE *f, unsigned int base, void *dest, int sector)
 
        fseek(f, base + sector * (CD_FRAMESIZE_RAW + SUB_FRAMESIZE), SEEK_SET);
        ret = fread(dest, 1, CD_FRAMESIZE_RAW, f);
-       fread(subbuffer, 1, SUB_FRAMESIZE, f);
+       if (fread(subbuffer, 1, SUB_FRAMESIZE, f) != SUB_FRAMESIZE)
+               goto fail_io;
 
        if (subChanRaw) DecodeRawSubData();
+       goto done;
 
+fail_io:
+#ifndef NDEBUG
+       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+
+done:
        return ret;
 }
 
@@ -1190,6 +1531,29 @@ finish:
        return CD_FRAMESIZE_RAW;
 }
 
+#ifdef HAVE_CHD
+static int cdread_chd(FILE *f, unsigned int base, void *dest, int sector)
+{
+       int hunk;
+
+       if (base)
+               sector += base;
+
+       hunk = sector / chd_img->sectors_per_hunk;
+       chd_img->sector_in_hunk = sector % chd_img->sectors_per_hunk;
+
+       if (hunk != chd_img->current_hunk)
+       {
+               chd_read(chd_img->chd, hunk, chd_img->buffer);
+               chd_img->current_hunk = hunk;
+       }
+
+       if (dest != cdbuffer) // copy avoid HACK
+               memcpy(dest, chd_img->buffer[chd_img->sector_in_hunk],
+                       CD_FRAMESIZE_RAW);
+       return CD_FRAMESIZE_RAW;
+}
+#endif
 static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector)
 {
        int ret;
@@ -1205,10 +1569,75 @@ static int cdread_2048(FILE *f, unsigned int base, void *dest, int sector)
        return ret;
 }
 
+#ifndef _WIN32
+
+static int cdread_async(FILE *f, unsigned int base, void *dest, int sector) {
+  boolean found = FALSE;
+  int i = sector % SECTOR_BUFFER_SIZE;
+  long ret;
+
+  if (f != cdHandle || base != 0 || dest != cdbuffer) {
+    // Async reads are only supported for cdbuffer, so call the sync
+    // function directly.
+    return sync_cdimg_read_func(f, base, dest, sector);
+  }
+
+  pthread_mutex_lock(&read_thread_msg_lock);
+
+  // Only wait if we're not trying to read the next sector and
+  // sector_start is set (meaning the last request hasn't been
+  // processed yet)
+  while(read_thread_sector_start != -1 && read_thread_sector_end + 1 != sector) {
+    pthread_cond_wait(&read_thread_msg_done, &read_thread_msg_lock);
+  }
+
+  if (read_thread_sector_start == -1)
+    read_thread_sector_start = sector;
+
+  read_thread_sector_end = sector;
+  pthread_cond_signal(&read_thread_msg_avail);
+  pthread_mutex_unlock(&read_thread_msg_lock);
+
+  do {
+    pthread_mutex_lock(&sectorbuffer_lock);
+    if (sectorbuffer[i].sector == sector) {
+      sectorbuffer_index = i;
+      ret = sectorbuffer[i].ret;
+      found = TRUE;
+    }
+
+    if (!found) {
+      pthread_cond_wait(&sectorbuffer_cond, &sectorbuffer_lock);
+    }
+    pthread_mutex_unlock(&sectorbuffer_lock);
+  } while (!found);
+
+  return ret;
+}
+
+#endif
+
 static unsigned char * CALLBACK ISOgetBuffer_compr(void) {
        return compr_img->buff_raw[compr_img->sector_in_blk] + 12;
 }
 
+#ifdef HAVE_CHD
+static unsigned char * CALLBACK ISOgetBuffer_chd(void) {
+       return chd_img->buffer[chd_img->sector_in_hunk] + 12;
+}
+#endif
+
+#ifndef _WIN32
+static unsigned char * CALLBACK ISOgetBuffer_async(void) {
+  unsigned char *buffer;
+  pthread_mutex_lock(&sectorbuffer_lock);
+  buffer = sectorbuffer[sectorbuffer_index].data;
+  pthread_mutex_unlock(&sectorbuffer_lock);
+  return buffer + 12;
+}
+
+#endif
+
 static unsigned char * CALLBACK ISOgetBuffer(void) {
        return cdbuffer + 12;
 }
@@ -1230,6 +1659,7 @@ static long CALLBACK ISOopen(void) {
        boolean isMode1ISO = FALSE;
        char alt_bin_filename[MAXPATHLEN];
        const char *bin_filename;
+       char image_str[1024] = {0};
 
        if (cdHandle != NULL) {
                return 0; // it's already open
@@ -1242,7 +1672,7 @@ static long CALLBACK ISOopen(void) {
                return -1;
        }
 
-       SysPrintf(_("Loaded CD Image: %s"), GetIsoFile());
+       sprintf(image_str, "Loaded CD Image: %s", GetIsoFile());
 
        cddaBigEndian = FALSE;
        subChanMixed = FALSE;
@@ -1255,33 +1685,40 @@ static long CALLBACK ISOopen(void) {
        cdimg_read_func = cdread_normal;
 
        if (parsetoc(GetIsoFile()) == 0) {
-               SysPrintf("[+toc]");
+               strcat(image_str, "[+toc]");
        }
        else if (parseccd(GetIsoFile()) == 0) {
-               SysPrintf("[+ccd]");
+               strcat(image_str, "[+ccd]");
        }
        else if (parsemds(GetIsoFile()) == 0) {
-               SysPrintf("[+mds]");
+               strcat(image_str, "[+mds]");
        }
        else if (parsecue(GetIsoFile()) == 0) {
-               SysPrintf("[+cue]");
+               strcat(image_str, "[+cue]");
        }
        if (handlepbp(GetIsoFile()) == 0) {
-               SysPrintf("[pbp]");
+               strcat(image_str, "[+pbp]");
                CDR_getBuffer = ISOgetBuffer_compr;
                cdimg_read_func = cdread_compressed;
        }
        else if (handlecbin(GetIsoFile()) == 0) {
-               SysPrintf("[cbin]");
+               strcat(image_str, "[+cbin]");
                CDR_getBuffer = ISOgetBuffer_compr;
                cdimg_read_func = cdread_compressed;
        }
+#ifdef HAVE_CHD
+       else if (handlechd(GetIsoFile()) == 0) {
+               strcat(image_str, "[+chd]");
+               CDR_getBuffer = ISOgetBuffer_chd;
+               cdimg_read_func = cdread_chd;
+       }
+#endif
 
        if (!subChanMixed && opensubfile(GetIsoFile()) == 0) {
-               SysPrintf("[+sub]");
+               strcat(image_str, "[+sub]");
        }
        if (opensbifile(GetIsoFile()) == 0) {
-               SysPrintf("[+sbi]");
+               strcat(image_str, "[+sbi]");
        }
 
        fseeko(cdHandle, 0, SEEK_END);
@@ -1317,15 +1754,20 @@ static long CALLBACK ISOopen(void) {
        if (ftello(cdHandle) % 2048 == 0) {
                unsigned int modeTest = 0;
                fseek(cdHandle, 0, SEEK_SET);
-               fread(&modeTest, 4, 1, cdHandle);
+               if (fread(&modeTest, sizeof(modeTest), 1, cdHandle) != sizeof(modeTest)) {
+#ifndef NDEBUG
+                       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+                       return -1;
+               }
                if (SWAP32(modeTest) != 0xffffff00) {
-                       SysPrintf("[2048]");
+                       strcat(image_str, "[2048]");
                        isMode1ISO = TRUE;
                }
        }
        fseek(cdHandle, 0, SEEK_SET);
 
-       SysPrintf(".\n");
+       SysPrintf("%s.\n", image_str);
 
        PrintTracks();
 
@@ -1341,6 +1783,9 @@ static long CALLBACK ISOopen(void) {
        cdda_cur_sector = 0;
        cdda_file_offset = 0;
 
+  if (Config.AsyncCD) {
+    readThreadStart();
+  }
        return 0;
 }
 
@@ -1364,6 +1809,15 @@ static long CALLBACK ISOclose(void) {
                compr_img = NULL;
        }
 
+#ifdef HAVE_CHD
+       if (chd_img != NULL) {
+               chd_close(chd_img->chd);
+               free(chd_img->buffer);
+               free(chd_img);
+               chd_img = NULL;
+       }
+#endif
+
        for (i = 1; i <= numtracks; i++) {
                if (ti[i].handle != NULL) {
                        fclose(ti[i].handle);
@@ -1377,6 +1831,10 @@ static long CALLBACK ISOclose(void) {
        memset(cdbuffer, 0, sizeof(cdbuffer));
        CDR_getBuffer = ISOgetBuffer;
 
+       if (Config.AsyncCD) {
+               readThreadStop();
+       }
+
        return 0;
 }
 
@@ -1480,7 +1938,9 @@ static long CALLBACK ISOreadTrack(unsigned char *time) {
 
        if (subHandle != NULL) {
                fseek(subHandle, sector * SUB_FRAMESIZE, SEEK_SET);
-               fread(subbuffer, 1, SUB_FRAMESIZE, subHandle);
+               if (fread(subbuffer, 1, SUB_FRAMESIZE, subHandle) != SUB_FRAMESIZE)
+                       /* Faulty subchannel data shouldn't cause a read failure */
+                       return 0;
 
                if (subChanRaw) DecodeRawSubData();
        }
index a725efa..47d45cd 100644 (file)
@@ -496,6 +496,7 @@ void cdrPlayInterrupt()
                if (cdr.SetlocPending) {
                        memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
                        cdr.SetlocPending = 0;
+                       cdr.m_locationChanged = TRUE;
                }
                Find_CurTrack(cdr.SetSectorPlay);
                ReadTrack(cdr.SetSectorPlay);
@@ -527,7 +528,15 @@ void cdrPlayInterrupt()
                }
        }
 
-       CDRMISC_INT(cdReadTime);
+       if (cdr.m_locationChanged)
+       {
+               CDRMISC_INT(cdReadTime * 30);
+               cdr.m_locationChanged = FALSE;
+       }
+       else
+       {
+               CDRMISC_INT(cdReadTime);
+       }
 
        // update for CdlGetlocP/autopause
        generate_subq(cdr.SetSectorPlay);
@@ -589,6 +598,7 @@ void cdrInterrupt() {
                        if (cdr.SetlocPending) {
                                memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
                                cdr.SetlocPending = 0;
+                               cdr.m_locationChanged = TRUE;
                        }
 
                        // BIOS CD Player
@@ -878,7 +888,8 @@ void cdrInterrupt() {
                        }
                        cdr.Result[0] |= (cdr.Result[1] >> 4) & 0x08;
 
-                       strncpy((char *)&cdr.Result[4], "PCSX", 4);
+                       /* This adds the string "PCSX" in Playstation bios boot screen */
+                       memcpy((char *)&cdr.Result[4], "PCSX", 4);
                        cdr.Stat = Complete;
                        break;
 
@@ -914,6 +925,7 @@ void cdrInterrupt() {
                                if(seekTime > 1000000) seekTime = 1000000;
                                memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
                                cdr.SetlocPending = 0;
+                               cdr.m_locationChanged = TRUE;
                        }
                        Find_CurTrack(cdr.SetSectorPlay);
 
@@ -1130,7 +1142,13 @@ void cdrReadInterrupt() {
 
        cdr.Readed = 0;
 
-       CDREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime);
+       uint32_t delay = (cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime;
+       if (cdr.m_locationChanged) {
+               CDREAD_INT(delay * 30);
+               cdr.m_locationChanged = FALSE;
+       } else {
+               CDREAD_INT(delay);
+       }
 
        /*
        Croc 2: $40 - only FORM1 (*)
@@ -1468,6 +1486,8 @@ void cdrReset() {
        cdr.DriveState = DRIVESTATE_STANDBY;
        cdr.StatP = STATUS_ROTATING;
        pTransfer = cdr.Transfer;
+       cdr.SetlocPending = 0;
+       cdr.m_locationChanged = FALSE;
 
        // BIOS player - default values
        cdr.AttenuatorLeftToLeft = 0x80;
index 543c619..a37f6ba 100644 (file)
@@ -59,7 +59,8 @@ typedef struct {
                unsigned char Absolute[3];
        } subq;
        unsigned char TrackChanged;
-       unsigned char pad1[3];
+       boolean m_locationChanged;
+       unsigned char pad1[2];
        unsigned int  freeze_ver;
 
        unsigned char Prev[4];
index 763dc45..4ba7f57 100644 (file)
@@ -445,7 +445,7 @@ static void ProcessCommands() {
             sprintf(reply, "200 %s\r\n", arguments == NULL ? "OK" : arguments);
             break;
         case 0x101:
-            sprintf(reply, "201 %s\r\n", PACKAGE_VERSION);
+            sprintf(reply, "201 %s\r\n", PCSX_VERSION);
             break;
         case 0x102:
             sprintf(reply, "202 1.0\r\n");
index 23667c1..ceb60dc 100644 (file)
@@ -73,17 +73,17 @@ typedef char* (*TdisR3000AF)(u32 code, u32 pc);
 #define _Branch_  (pc + 4 + ((short)_Im_ * 4))
 #define _OfB_     _Im_, _nRs_
 
-#define dName(i)       sprintf(ostr, "%s %-7s,", ostr, i)
-#define dGPR(i)                sprintf(ostr, "%s %8.8x (%s),", ostr, psxRegs.GPR.r[i], disRNameGPR[i])
-#define dCP0(i)                sprintf(ostr, "%s %8.8x (%s),", ostr, psxRegs.CP0.r[i], disRNameCP0[i])
-#define dHI()          sprintf(ostr, "%s %8.8x (%s),", ostr, psxRegs.GPR.n.hi, "hi")
-#define dLO()          sprintf(ostr, "%s %8.8x (%s),", ostr, psxRegs.GPR.n.lo, "lo")
-#define dImm()         sprintf(ostr, "%s %4.4x (%d),", ostr, _Im_, _Im_)
-#define dTarget()      sprintf(ostr, "%s %8.8x,", ostr, _Target_)
-#define dSa()          sprintf(ostr, "%s %2.2x (%d),", ostr, _Sa_, _Sa_)
-#define dOfB()         sprintf(ostr, "%s %4.4x (%8.8x (%s)),", ostr, _Im_, psxRegs.GPR.r[_Rs_], disRNameGPR[_Rs_])
-#define dOffset()      sprintf(ostr, "%s %8.8x,", ostr, _Branch_)
-#define dCode()                sprintf(ostr, "%s %8.8x,", ostr, (code >> 6) & 0xffffff)
+#define dName(i)       snprintf(ostr, sizeof(ostr), "%s %-7s,", ostr, i)
+#define dGPR(i)                snprintf(ostr, sizeof(ostr), "%s %8.8x (%s),", ostr, psxRegs.GPR.r[i], disRNameGPR[i])
+#define dCP0(i)                snprintf(ostr, sizeof(ostr), "%s %8.8x (%s),", ostr, psxRegs.CP0.r[i], disRNameCP0[i])
+#define dHI()          snprintf(ostr, sizeof(ostr), "%s %8.8x (%s),", ostr, psxRegs.GPR.n.hi, "hi")
+#define dLO()          snprintf(ostr, sizeof(ostr), "%s %8.8x (%s),", ostr, psxRegs.GPR.n.lo, "lo")
+#define dImm()         snprintf(ostr, sizeof(ostr), "%s %4.4x (%d),", ostr, _Im_, _Im_)
+#define dTarget()      snprintf(ostr, sizeof(ostr), "%s %8.8x,", ostr, _Target_)
+#define dSa()          snprintf(ostr, sizeof(ostr), "%s %2.2x (%d),", ostr, _Sa_, _Sa_)
+#define dOfB()         snprintf(ostr, sizeof(ostr), "%s %4.4x (%8.8x (%s)),", ostr, _Im_, psxRegs.GPR.r[_Rs_], disRNameGPR[_Rs_])
+#define dOffset()      snprintf(ostr, sizeof(ostr), "%s %8.8x,", ostr, _Branch_)
+#define dCode()                snprintf(ostr, sizeof(ostr), "%s %8.8x,", ostr, (code >> 6) & 0xffffff)
 
 /*********************************************************
 * Arithmetic with immediate operand                      *
index 63a5572..98a22a0 100644 (file)
@@ -21,6 +21,9 @@
  *    that GPU plugin doesn't.
  */
 
+#ifndef __GPU_H__
+#define __GPU_H__
+
 #define PSXGPU_LCF     (1<<31)
 #define PSXGPU_nBUSY   (1<<26)
 #define PSXGPU_ILACE   (1<<22)
@@ -38,3 +41,5 @@
        HW_GPU_STATUS &= PSXGPU_TIMING_BITS; \
        HW_GPU_STATUS |= GPU_readStatus() & ~PSXGPU_TIMING_BITS; \
 }
+
+#endif /* __GPU_H__ */
index 77dff1b..3ae216f 100644 (file)
 #define gteBFC (((s32 *)regs->CP2C.r)[23])
 #define gteOFX (((s32 *)regs->CP2C.r)[24])
 #define gteOFY (((s32 *)regs->CP2C.r)[25])
-#define gteH   (regs->CP2C.p[26].sw.l)
+// senquack - gteH register is u16, not s16, and used in GTE that way.
+//  HOWEVER when read back by CPU using CFC2, it will be incorrectly
+//  sign-extended by bug in original hardware, according to Nocash docs
+//  GTE section 'Screen Offset and Distance'. The emulator does this
+//  sign extension when it is loaded to GTE by CTC2.
+//#define gteH   (regs->CP2C.p[26].sw.l)
+#define gteH   (regs->CP2C.p[26].w.l)
 #define gteDQA (regs->CP2C.p[27].sw.l)
 #define gteDQB (((s32 *)regs->CP2C.r)[28])
 #define gteZSF3 (regs->CP2C.p[29].sw.l)
@@ -254,11 +260,21 @@ static inline u32 limE_(psxCP2Regs *regs, u32 result) {
 #define A3U(x) (x)
 #endif
 
+//senquack - n param should be unsigned (will be 'gteH' reg which is u16)
+#ifdef GTE_USE_NATIVE_DIVIDE
+INLINE u32 DIVIDE(u16 n, u16 d) {
+       if (n < d * 2) {
+               return ((u32)n << 16) / d;
+       }
+       return 0xffffffff;
+}
+#else
 #include "gte_divider.h"
+#endif // GTE_USE_NATIVE_DIVIDE
 
 #ifndef FLAGLESS
 
-static inline u32 MFC2(int reg) {
+u32 MFC2(int reg) {
        psxCP2Regs *regs = &psxRegs.CP2;
        switch (reg) {
                case 1:
@@ -293,7 +309,7 @@ static inline u32 MFC2(int reg) {
        return psxRegs.CP2D.r[reg];
 }
 
-static inline void MTC2(u32 value, int reg) {
+void MTC2(u32 value, int reg) {
        psxCP2Regs *regs = &psxRegs.CP2;
        switch (reg) {
                case 15:
@@ -339,7 +355,7 @@ static inline void MTC2(u32 value, int reg) {
        }
 }
 
-static inline void CTC2(u32 value, int reg) {
+void CTC2(u32 value, int reg) {
        switch (reg) {
                case 4:
                case 12:
index 7646226..8bc6988 100644 (file)
@@ -67,6 +67,10 @@ extern "C" {
 
 struct psxCP2Regs;
 
+u32 MFC2(int reg);
+void MTC2(u32 value, int reg);
+void CTC2(u32 value, int reg);
+
 void gteMFC2();
 void gteCFC2();
 void gteMTC2();
index 6b240db..0288944 100644 (file)
@@ -15,6 +15,9 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses>.
  */
 
+#ifndef __GTE_ARM_H__
+#define __GTE_ARM_H__
+
 void gteRTPS_nf_arm(void *cp2_regs, int opcode);
 void gteRTPT_nf_arm(void *cp2_regs, int opcode);
 void gteNCLIP_arm(void *cp2_regs, int opcode);
@@ -28,3 +31,5 @@ void gteMACtoIR_lm0(void *cp2_regs);
 void gteMACtoIR_lm1(void *cp2_regs);
 void gteMACtoIR_lm0_nf(void *cp2_regs);
 void gteMACtoIR_lm1_nf(void *cp2_regs);
+
+#endif /* __GTE_ARM_H__ */
index 0c98826..765b971 100644 (file)
@@ -15,4 +15,9 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses>.
  */
 
-u32 DIVIDE(s16 n, u16 d);
+#ifndef __GTE_DIVIDER_H__
+#define __GTE_DIVIDER_H__
+
+u32 DIVIDE(u16 n, u16 d);
+
+#endif /* __GTE_DIVIDER_H__ */
index 7d97ff3..60065f8 100644 (file)
@@ -1,12 +1,12 @@
 /*
- * (C) Gražvydas "notaz" Ignotas, 2011
+ * (C) Gra\9evydas "notaz" Ignotas, 2011
  *
  * This work is licensed under the terms of GNU GPL version 2 or later.
  * See the COPYING file in the top-level directory.
  */
 
 #include "arm_features.h"
-#include "new_dynarec/linkage_offsets.h"
+#include "new_dynarec/arm/linkage_offsets.h"
 
 .syntax unified
 .text
index 2fd9e4d..f371640 100644 (file)
@@ -15,6 +15,9 @@
  *  along with this program; if not, see <http://www.gnu.org/licenses>.
  */
 
+#ifndef __GTE_NEON_H__
+#define __GTE_NEON_H__
+
 void gteRTPS_neon(void *cp2_regs, int opcode);
 void gteRTPT_neon(void *cp2_regs, int opcode);
 
@@ -23,3 +26,5 @@ void gteMVMVA_part_neon(void *cp2_regs, int opcode);
 
 // after NEON call only, does not do gteIR
 void gteMACtoIR_flags_neon(void *cp2_regs, int lm);
+
+#endif /* __GTE_NEON_H__ */
diff --git a/libpcsxcore/lightrec/plugin.c b/libpcsxcore/lightrec/plugin.c
new file mode 100644 (file)
index 0000000..05d1735
--- /dev/null
@@ -0,0 +1,600 @@
+#include <lightrec.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "../cdrom.h"
+#include "../gpu.h"
+#include "../gte.h"
+#include "../mdec.h"
+#include "../psxdma.h"
+#include "../psxhw.h"
+#include "../psxmem.h"
+#include "../r3000a.h"
+
+#include "../frontend/main.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
+
+#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#      define LE32TOH(x)       __builtin_bswap32(x)
+#      define HTOLE32(x)       __builtin_bswap32(x)
+#      define LE16TOH(x)       __builtin_bswap16(x)
+#      define HTOLE16(x)       __builtin_bswap16(x)
+#else
+#      define LE32TOH(x)       (x)
+#      define HTOLE32(x)       (x)
+#      define LE16TOH(x)       (x)
+#      define HTOLE16(x)       (x)
+#endif
+
+#ifdef __GNUC__
+#      define likely(x)       __builtin_expect(!!(x),1)
+#      define unlikely(x)     __builtin_expect(!!(x),0)
+#else
+#      define likely(x)       (x)
+#      define unlikely(x)     (x)
+#endif
+
+static struct lightrec_state *lightrec_state;
+
+static char *name = "retroarch.exe";
+
+static bool use_lightrec_interpreter;
+static bool use_pcsx_interpreter;
+static bool lightrec_debug;
+static bool lightrec_very_debug;
+static u32 lightrec_begin_cycles;
+
+int stop;
+u32 cycle_multiplier;
+int new_dynarec_hacks;
+
+/* Unused for now */
+u32 event_cycles[PSXINT_COUNT];
+u32 next_interupt;
+
+void new_dyna_before_save() {}
+void new_dyna_after_save() {}
+void new_dyna_freeze(void *f, int i) {}
+
+enum my_cp2_opcodes {
+       OP_CP2_RTPS             = 0x01,
+       OP_CP2_NCLIP            = 0x06,
+       OP_CP2_OP               = 0x0c,
+       OP_CP2_DPCS             = 0x10,
+       OP_CP2_INTPL            = 0x11,
+       OP_CP2_MVMVA            = 0x12,
+       OP_CP2_NCDS             = 0x13,
+       OP_CP2_CDP              = 0x14,
+       OP_CP2_NCDT             = 0x16,
+       OP_CP2_NCCS             = 0x1b,
+       OP_CP2_CC               = 0x1c,
+       OP_CP2_NCS              = 0x1e,
+       OP_CP2_NCT              = 0x20,
+       OP_CP2_SQR              = 0x28,
+       OP_CP2_DCPL             = 0x29,
+       OP_CP2_DPCT             = 0x2a,
+       OP_CP2_AVSZ3            = 0x2d,
+       OP_CP2_AVSZ4            = 0x2e,
+       OP_CP2_RTPT             = 0x30,
+       OP_CP2_GPF              = 0x3d,
+       OP_CP2_GPL              = 0x3e,
+       OP_CP2_NCCT             = 0x3f,
+};
+
+static void (*cp2_ops[])(struct psxCP2Regs *) = {
+       [OP_CP2_RTPS] = gteRTPS,
+       [OP_CP2_RTPS] = gteRTPS,
+       [OP_CP2_NCLIP] = gteNCLIP,
+       [OP_CP2_OP] = gteOP,
+       [OP_CP2_DPCS] = gteDPCS,
+       [OP_CP2_INTPL] = gteINTPL,
+       [OP_CP2_MVMVA] = gteMVMVA,
+       [OP_CP2_NCDS] = gteNCDS,
+       [OP_CP2_CDP] = gteCDP,
+       [OP_CP2_NCDT] = gteNCDT,
+       [OP_CP2_NCCS] = gteNCCS,
+       [OP_CP2_CC] = gteCC,
+       [OP_CP2_NCS] = gteNCS,
+       [OP_CP2_NCT] = gteNCT,
+       [OP_CP2_SQR] = gteSQR,
+       [OP_CP2_DCPL] = gteDCPL,
+       [OP_CP2_DPCT] = gteDPCT,
+       [OP_CP2_AVSZ3] = gteAVSZ3,
+       [OP_CP2_AVSZ4] = gteAVSZ4,
+       [OP_CP2_RTPT] = gteRTPT,
+       [OP_CP2_GPF] = gteGPF,
+       [OP_CP2_GPL] = gteGPL,
+       [OP_CP2_NCCT] = gteNCCT,
+};
+
+static char cache_buf[64 * 1024];
+
+static u32 cop0_mfc(struct lightrec_state *state, u32 op, u8 reg)
+{
+       return psxRegs.CP0.r[reg];
+}
+
+static u32 cop2_mfc_cfc(struct lightrec_state *state, u8 reg, bool cfc)
+{
+       if (cfc)
+               return psxRegs.CP2C.r[reg];
+       else
+               return MFC2(reg);
+}
+
+static u32 cop2_mfc(struct lightrec_state *state, u32 op, u8 reg)
+{
+       return cop2_mfc_cfc(state, reg, false);
+}
+
+static u32 cop2_cfc(struct lightrec_state *state, u32 op, u8 reg)
+{
+       return cop2_mfc_cfc(state, reg, true);
+}
+
+static void cop0_mtc_ctc(struct lightrec_state *state,
+                        u8 reg, u32 value, bool ctc)
+{
+       switch (reg) {
+       case 1:
+       case 4:
+       case 8:
+       case 14:
+       case 15:
+               /* Those registers are read-only */
+               break;
+       case 12: /* Status */
+               if ((psxRegs.CP0.n.Status & ~value) & (1 << 16)) {
+                       memcpy(psxM, cache_buf, sizeof(cache_buf));
+                       lightrec_invalidate_all(state);
+               } else if ((~psxRegs.CP0.n.Status & value) & (1 << 16)) {
+                       memcpy(cache_buf, psxM, sizeof(cache_buf));
+               }
+
+               psxRegs.CP0.n.Status = value;
+               lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
+               break;
+       case 13: /* Cause */
+               psxRegs.CP0.n.Cause &= ~0x0300;
+               psxRegs.CP0.n.Cause |= value & 0x0300;
+               lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
+               break;
+       default:
+               psxRegs.CP0.r[reg] = value;
+               break;
+       }
+}
+
+static void cop2_mtc_ctc(struct lightrec_state *state,
+                        u8 reg, u32 value, bool ctc)
+{
+       if (ctc)
+               CTC2(value, reg);
+       else
+               MTC2(value, reg);
+}
+
+static void cop0_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
+{
+       cop0_mtc_ctc(state, reg, value, false);
+}
+
+static void cop0_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
+{
+       cop0_mtc_ctc(state, reg, value, true);
+}
+
+static void cop2_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
+{
+       cop2_mtc_ctc(state, reg, value, false);
+}
+
+static void cop2_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
+{
+       cop2_mtc_ctc(state, reg, value, true);
+}
+
+static void cop0_op(struct lightrec_state *state, u32 func)
+{
+       fprintf(stderr, "Invalid access to COP0\n");
+}
+
+static void cop2_op(struct lightrec_state *state, u32 func)
+{
+       psxRegs.code = func;
+
+       if (unlikely(!cp2_ops[func & 0x3f]))
+               fprintf(stderr, "Invalid CP2 function %u\n", func);
+       else
+               cp2_ops[func & 0x3f](&psxRegs.CP2);
+}
+
+static void hw_write_byte(struct lightrec_state *state,
+                         u32 op, void *host, u32 mem, u8 val)
+{
+       psxRegs.cycle = lightrec_current_cycle_count(state);
+
+       psxHwWrite8(mem, val);
+       lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
+
+       lightrec_reset_cycle_count(state, psxRegs.cycle);
+}
+
+static void hw_write_half(struct lightrec_state *state,
+                         u32 op, void *host, u32 mem, u16 val)
+{
+       psxRegs.cycle = lightrec_current_cycle_count(state);
+
+       psxHwWrite16(mem, val);
+       lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
+
+       lightrec_reset_cycle_count(state, psxRegs.cycle);
+}
+
+static void hw_write_word(struct lightrec_state *state,
+                         u32 op, void *host, u32 mem, u32 val)
+{
+       psxRegs.cycle = lightrec_current_cycle_count(state);
+
+       psxHwWrite32(mem, val);
+       lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
+
+       lightrec_reset_cycle_count(state, psxRegs.cycle);
+}
+
+static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem)
+{
+       u8 val;
+
+       psxRegs.cycle = lightrec_current_cycle_count(state);
+
+       lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
+       val = psxHwRead8(mem);
+       lightrec_reset_cycle_count(state, psxRegs.cycle);
+
+       return val;
+}
+
+static u16 hw_read_half(struct lightrec_state *state,
+                       u32 op, void *host, u32 mem)
+{
+       u16 val;
+
+       psxRegs.cycle = lightrec_current_cycle_count(state);
+
+       lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
+       val = psxHwRead16(mem);
+       lightrec_reset_cycle_count(state, psxRegs.cycle);
+
+       return val;
+}
+
+static u32 hw_read_word(struct lightrec_state *state,
+                       u32 op, void *host, u32 mem)
+{
+       u32 val;
+
+       psxRegs.cycle = lightrec_current_cycle_count(state);
+
+       lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
+       val = psxHwRead32(mem);
+       lightrec_reset_cycle_count(state, psxRegs.cycle);
+
+       return val;
+}
+
+static struct lightrec_mem_map_ops hw_regs_ops = {
+       .sb = hw_write_byte,
+       .sh = hw_write_half,
+       .sw = hw_write_word,
+       .lb = hw_read_byte,
+       .lh = hw_read_half,
+       .lw = hw_read_word,
+};
+
+static u32 cache_ctrl;
+
+static void cache_ctrl_write_word(struct lightrec_state *state,
+                                 u32 op, void *host, u32 mem, u32 val)
+{
+       cache_ctrl = val;
+}
+
+static u32 cache_ctrl_read_word(struct lightrec_state *state,
+                               u32 op, void *host, u32 mem)
+{
+       return cache_ctrl;
+}
+
+static struct lightrec_mem_map_ops cache_ctrl_ops = {
+       .sw = cache_ctrl_write_word,
+       .lw = cache_ctrl_read_word,
+};
+
+static struct lightrec_mem_map lightrec_map[] = {
+       [PSX_MAP_KERNEL_USER_RAM] = {
+               /* Kernel and user memory */
+               .pc = 0x00000000,
+               .length = 0x200000,
+       },
+       [PSX_MAP_BIOS] = {
+               /* BIOS */
+               .pc = 0x1fc00000,
+               .length = 0x80000,
+       },
+       [PSX_MAP_SCRATCH_PAD] = {
+               /* Scratch pad */
+               .pc = 0x1f800000,
+               .length = 0x400,
+       },
+       [PSX_MAP_PARALLEL_PORT] = {
+               /* Parallel port */
+               .pc = 0x1f000000,
+               .length = 0x10000,
+       },
+       [PSX_MAP_HW_REGISTERS] = {
+               /* Hardware registers */
+               .pc = 0x1f801000,
+               .length = 0x2000,
+               .ops = &hw_regs_ops,
+       },
+       [PSX_MAP_CACHE_CONTROL] = {
+               /* Cache control */
+               .pc = 0x5ffe0130,
+               .length = 4,
+               .ops = &cache_ctrl_ops,
+       },
+
+       /* Mirrors of the kernel/user memory */
+       [PSX_MAP_MIRROR1] = {
+               .pc = 0x00200000,
+               .length = 0x200000,
+               .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
+       },
+       [PSX_MAP_MIRROR2] = {
+               .pc = 0x00400000,
+               .length = 0x200000,
+               .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
+       },
+       [PSX_MAP_MIRROR3] = {
+               .pc = 0x00600000,
+               .length = 0x200000,
+               .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
+       },
+};
+
+static const struct lightrec_ops lightrec_ops = {
+       .cop0_ops = {
+               .mfc = cop0_mfc,
+               .cfc = cop0_mfc,
+               .mtc = cop0_mtc,
+               .ctc = cop0_ctc,
+               .op = cop0_op,
+       },
+       .cop2_ops = {
+               .mfc = cop2_mfc,
+               .cfc = cop2_cfc,
+               .mtc = cop2_mtc,
+               .ctc = cop2_ctc,
+               .op = cop2_op,
+       },
+};
+
+static int lightrec_plugin_init(void)
+{
+       lightrec_map[PSX_MAP_KERNEL_USER_RAM].address = psxM;
+       lightrec_map[PSX_MAP_BIOS].address = psxR;
+       lightrec_map[PSX_MAP_SCRATCH_PAD].address = psxH;
+       lightrec_map[PSX_MAP_PARALLEL_PORT].address = psxP;
+
+       lightrec_debug = !!getenv("LIGHTREC_DEBUG");
+       lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG");
+       use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER");
+       if (getenv("LIGHTREC_BEGIN_CYCLES"))
+         lightrec_begin_cycles = (unsigned int) strtol(
+                                 getenv("LIGHTREC_BEGIN_CYCLES"), NULL, 0);
+
+       lightrec_state = lightrec_init(name,
+                       lightrec_map, ARRAY_SIZE(lightrec_map),
+                       &lightrec_ops);
+
+       // fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
+       //              (uintptr_t) psxM,
+       //              (uintptr_t) psxP,
+       //              (uintptr_t) psxR,
+       //              (uintptr_t) psxH);
+
+#ifndef _WIN32
+       signal(SIGPIPE, exit);
+#endif
+       return 0;
+}
+
+static u32 hash_calculate_le(const void *buffer, u32 count)
+{
+       unsigned int i;
+       u32 *data = (u32 *) buffer;
+       u32 hash = 0xffffffff;
+
+       count /= 4;
+       for(i = 0; i < count; ++i) {
+               hash += LE32TOH(data[i]);
+               hash += (hash << 10);
+               hash ^= (hash >> 6);
+       }
+
+       hash += (hash << 3);
+       hash ^= (hash >> 11);
+       hash += (hash << 15);
+       return hash;
+}
+
+static u32 hash_calculate(const void *buffer, u32 count)
+{
+       unsigned int i;
+       u32 *data = (u32 *) buffer;
+       u32 hash = 0xffffffff;
+
+       count /= 4;
+       for(i = 0; i < count; ++i) {
+               hash += data[i];
+               hash += (hash << 10);
+               hash ^= (hash >> 6);
+       }
+
+       hash += (hash << 3);
+       hash ^= (hash >> 11);
+       hash += (hash << 15);
+       return hash;
+}
+
+static const char * const mips_regs[] = {
+       "zero",
+       "at",
+       "v0", "v1",
+       "a0", "a1", "a2", "a3",
+       "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
+       "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+       "t8", "t9",
+       "k0", "k1",
+       "gp", "sp", "fp", "ra",
+       "lo", "hi",
+};
+
+static void print_for_big_ass_debugger(void)
+{
+       unsigned int i;
+
+       printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc);
+
+       if (lightrec_very_debug)
+               printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x",
+                               hash_calculate_le(psxM, 0x200000),
+                               hash_calculate_le(psxH, 0x400),
+                               hash_calculate_le(psxH + 0x1000, 0x2000));
+
+       printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x",
+                       hash_calculate(&psxRegs.CP0.r,
+                               sizeof(psxRegs.CP0.r)),
+                       hash_calculate(&psxRegs.CP2D.r,
+                               sizeof(psxRegs.CP2D.r)),
+                       hash_calculate(&psxRegs.CP2C.r,
+                               sizeof(psxRegs.CP2C.r)),
+                       psxRegs.interrupt,
+                       hash_calculate(psxRegs.intCycle,
+                               sizeof(psxRegs.intCycle)),
+                       LE32TOH(HW_GPU_STATUS));
+
+       if (lightrec_very_debug)
+               for (i = 0; i < 34; i++)
+                       printf(" %s 0x%08x", mips_regs[i], psxRegs.GPR.r[i]);
+       else
+               printf(" GPR 0x%08x", hash_calculate(&psxRegs.GPR.r,
+                                       sizeof(psxRegs.GPR.r)));
+       printf("\n");
+}
+
+
+extern void intExecuteBlock();
+
+static u32 old_cycle_counter;
+
+static void lightrec_plugin_execute_block(void)
+{
+       u32 old_pc = psxRegs.pc;
+       u32 flags;
+
+       if (use_pcsx_interpreter) {
+               intExecuteBlock();
+       } else {
+               lightrec_reset_cycle_count(lightrec_state, psxRegs.cycle);
+               lightrec_restore_registers(lightrec_state, psxRegs.GPR.r);
+
+               if (use_lightrec_interpreter)
+                       psxRegs.pc = lightrec_run_interpreter(lightrec_state,
+                                                             psxRegs.pc);
+               else
+                       psxRegs.pc = lightrec_execute_one(lightrec_state,
+                                                         psxRegs.pc);
+
+               psxRegs.cycle = lightrec_current_cycle_count(lightrec_state);
+
+               lightrec_dump_registers(lightrec_state, psxRegs.GPR.r);
+               flags = lightrec_exit_flags(lightrec_state);
+
+               if (flags & LIGHTREC_EXIT_SEGFAULT) {
+                       fprintf(stderr, "Exiting at cycle 0x%08x\n",
+                               psxRegs.cycle);
+                       exit(1);
+               }
+
+               if (flags & LIGHTREC_EXIT_SYSCALL)
+                       psxException(0x20, 0);
+       }
+
+       psxBranchTest();
+
+       if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles
+                       && psxRegs.pc != old_pc)
+               print_for_big_ass_debugger();
+
+       if ((psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x300) &&
+                       (psxRegs.CP0.n.Status & 0x1)) {
+               /* Handle software interrupts */
+               psxRegs.CP0.n.Cause &= ~0x7c;
+               psxException(psxRegs.CP0.n.Cause, 0);
+       }
+
+       if ((psxRegs.cycle & ~0xfffffff) != old_cycle_counter) {
+               SysDLog("RAM usage: Lightrec %u KiB, IR %u KiB, CODE %u KiB, "
+                      "MIPS %u KiB, TOTAL %u KiB, avg. IPI %f\n",
+                      lightrec_get_mem_usage(MEM_FOR_LIGHTREC) / 1024,
+                      lightrec_get_mem_usage(MEM_FOR_IR) / 1024,
+                      lightrec_get_mem_usage(MEM_FOR_CODE) / 1024,
+                      lightrec_get_mem_usage(MEM_FOR_MIPS_CODE) / 1024,
+                      lightrec_get_total_mem_usage() / 1024,
+                      lightrec_get_average_ipi());
+               old_cycle_counter = psxRegs.cycle & ~0xfffffff;
+       }
+}
+
+static void lightrec_plugin_execute(void)
+{
+       extern int stop;
+
+       while (!stop)
+               lightrec_plugin_execute_block();
+}
+
+static void lightrec_plugin_clear(u32 addr, u32 size)
+{
+       if (addr == 0 && size == UINT32_MAX)
+               lightrec_invalidate_all(lightrec_state);
+       else
+               /* size * 4: PCSX uses DMA units */
+               lightrec_invalidate(lightrec_state, addr, size * 4);
+}
+
+static void lightrec_plugin_shutdown(void)
+{
+       lightrec_destroy(lightrec_state);
+}
+
+static void lightrec_plugin_reset(void)
+{
+       lightrec_plugin_shutdown();
+       lightrec_plugin_init();
+}
+
+R3000Acpu psxRec =
+{
+       lightrec_plugin_init,
+       lightrec_plugin_reset,
+       lightrec_plugin_execute,
+       lightrec_plugin_execute_block,
+       lightrec_plugin_clear,
+       lightrec_plugin_shutdown,
+};
index 58170cf..553b90d 100644 (file)
@@ -73,7 +73,7 @@ void mmssdd( char *b, char *p )
 
        m = ((m / 10) << 4) | m % 10;
        s = ((s / 10) << 4) | s % 10;
-       d = ((d / 10) << 4) | d % 10;   
+       d = ((d / 10) << 4) | d % 10;
 
        p[0] = m;
        p[1] = s;
@@ -180,7 +180,7 @@ int LoadCdrom() {
        // is just below, do it here
        fake_bios_gpu_setup();
 
-       if (!Config.HLE) {
+       if (!Config.HLE && !Config.SlowBoot) {
                // skip BIOS logos
                psxRegs.pc = psxRegs.GPR.n.ra;
                return 0;
@@ -191,7 +191,7 @@ int LoadCdrom() {
        READTRACK();
 
        // skip head and sub, and go to the root directory record
-       dir = (struct iso_directory_record*) &buf[12+156]; 
+       dir = (struct iso_directory_record*) &buf[12+156];
 
        mmssdd(dir->extent, (char*)time);
 
@@ -236,7 +236,7 @@ int LoadCdrom() {
 
        psxRegs.pc = SWAP32(tmpHead.pc0);
        psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
-       psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); 
+       psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
        if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
 
        tmpHead.t_size = SWAP32(tmpHead.t_size);
@@ -275,7 +275,7 @@ int LoadCdromFile(const char *filename, EXE_HEADER *head) {
        READTRACK();
 
        // skip head and sub, and go to the root directory record
-       dir = (struct iso_directory_record *)&buf[12 + 156]; 
+       dir = (struct iso_directory_record *)&buf[12 + 156];
 
        mmssdd(dir->extent, (char*)time);
 
@@ -329,7 +329,7 @@ int CheckCdrom() {
        strncpy(CdromLabel, buf + 52, 32);
 
        // skip head and sub, and go to the root directory record
-       dir = (struct iso_directory_record *)&buf[12 + 156]; 
+       dir = (struct iso_directory_record *)&buf[12 + 156];
 
        mmssdd(dir->extent, (char *)time);
 
@@ -357,6 +357,14 @@ int CheckCdrom() {
                                        return -1;
                        }
                }
+               /* Workaround for Wild Arms EU/US which has non-standard string causing incorrect region detection */
+               if (exename[0] == 'E' && exename[1] == 'X' && exename[2] == 'E' && exename[3] == '\\') {
+                       size_t offset = 4;
+                       size_t i, len = strlen(exename) - offset;
+                       for (i = 0; i < len; i++)
+                               exename[i] = exename[i + offset];
+                       exename[i] = '\0';
+               }
        } else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) {
                strcpy(exename, "PSX.EXE;1");
                strcpy(CdromId, "SLUS99999");
@@ -384,7 +392,7 @@ int CheckCdrom() {
        }
 
        if (CdromLabel[0] == ' ') {
-               strncpy(CdromLabel, CdromId, 9);
+               memcpy(CdromLabel, CdromId, 9);
        }
        SysPrintf(_("CD-ROM Label: %.32s\n"), CdromLabel);
        SysPrintf(_("CD-ROM ID: %.9s\n"), CdromId);
@@ -403,7 +411,9 @@ static int PSXGetFileType(FILE *f) {
 
        current = ftell(f);
        fseek(f, 0L, SEEK_SET);
-       fread(mybuf, 2048, 1, f);
+       if (fread(&mybuf, sizeof(mybuf), 1, f) != sizeof(mybuf))
+               goto io_fail;
+       
        fseek(f, current, SEEK_SET);
 
        exe_hdr = (EXE_HEADER *)mybuf;
@@ -418,6 +428,12 @@ static int PSXGetFileType(FILE *f) {
                return COFF_EXE;
 
        return INVALID_EXE;
+
+io_fail:
+#ifndef NDEBUG
+       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+       return INVALID_EXE;
 }
 
 // temporary pandora workaround..
@@ -426,7 +442,7 @@ size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
 {
        void *tmp;
        size_t ret = 0;
-       
+
        tmp = malloc(size * nmemb);
        if (tmp) {
                ret = fread(tmp, size, nmemb, stream);
@@ -445,8 +461,8 @@ int Load(const char *ExePath) {
        u32 section_address, section_size;
        void *mem;
 
-       strncpy(CdromId, "SLUS99999", 9);
-       strncpy(CdromLabel, "SLUS_999.99", 11);
+       strcpy(CdromId, "SLUS99999");
+       strcpy(CdromLabel, "SLUS_999.99");
 
        tmpFile = fopen(ExePath, "rb");
        if (tmpFile == NULL) {
@@ -456,19 +472,19 @@ int Load(const char *ExePath) {
                type = PSXGetFileType(tmpFile);
                switch (type) {
                        case PSX_EXE:
-                               fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
+                               if (fread(&tmpHead, sizeof(EXE_HEADER), 1, tmpFile) != sizeof(EXE_HEADER))
+                                       goto fail_io;
                                section_address = SWAP32(tmpHead.t_addr);
                                section_size = SWAP32(tmpHead.t_size);
                                mem = PSXM(section_address);
                                if (mem != NULL) {
-                                       fseek(tmpFile, 0x800, SEEK_SET);                
+                                       fseek(tmpFile, 0x800, SEEK_SET);
                                        fread_to_ram(mem, section_size, 1, tmpFile);
                                        psxCpu->Clear(section_address, section_size / 4);
                                }
-                               fclose(tmpFile);
                                psxRegs.pc = SWAP32(tmpHead.pc0);
                                psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
-                               psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr); 
+                               psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
                                if (psxRegs.GPR.n.sp == 0)
                                        psxRegs.GPR.n.sp = 0x801fff00;
                                retval = 0;
@@ -476,11 +492,14 @@ int Load(const char *ExePath) {
                        case CPE_EXE:
                                fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
                                do {
-                                       fread(&opcode, 1, 1, tmpFile);
+                                       if (fread(&opcode, sizeof(opcode), 1, tmpFile) != sizeof(opcode))
+                                               goto fail_io;
                                        switch (opcode) {
                                                case 1: /* Section loading */
-                                                       fread(&section_address, 4, 1, tmpFile);
-                                                       fread(&section_size, 4, 1, tmpFile);
+                                                       if (fread(&section_address, sizeof(section_address), 1, tmpFile) != sizeof(section_address))
+                                                               goto fail_io;
+                                                       if (fread(&section_size, sizeof(section_size), 1, tmpFile) != sizeof(section_size))
+                                                               goto fail_io;
                                                        section_address = SWAPu32(section_address);
                                                        section_size = SWAPu32(section_size);
 #ifdef EMU_LOG
@@ -494,7 +513,8 @@ int Load(const char *ExePath) {
                                                        break;
                                                case 3: /* register loading (PC only?) */
                                                        fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
-                                                       fread(&psxRegs.pc, 4, 1, tmpFile);
+                                                       if (fread(&psxRegs.pc, sizeof(psxRegs.pc), 1, tmpFile) != sizeof(psxRegs.pc))
+                                                               goto fail_io;
                                                        psxRegs.pc = SWAPu32(psxRegs.pc);
                                                        break;
                                                case 0: /* End of file */
@@ -523,7 +543,15 @@ int Load(const char *ExePath) {
                CdromLabel[0] = '\0';
        }
 
+       fclose(tmpFile);
        return retval;
+
+fail_io:
+#ifndef NDEBUG
+       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+       fclose(tmpFile);
+       return -1;
 }
 
 // STATES
@@ -557,7 +585,7 @@ struct PcsxSaveFuncs SaveFuncs = {
        zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
 };
 
-static const char PcsxHeader[32] = "STv4 PCSX v" PACKAGE_VERSION;
+static const char PcsxHeader[32] = "STv4 PCSX v" PCSX_VERSION;
 
 // Savestate Versioning!
 // If you make changes to the savestate version, please increment the value below.
@@ -649,6 +677,11 @@ int LoadState(const char *file) {
        if (Config.HLE)
                psxBiosInit();
 
+#if defined(LIGHTREC)
+       if (Config.Cpu != CPU_INTERPRETER)
+               psxCpu->Clear(0, UINT32_MAX); //clear all
+       else
+#endif
        psxCpu->Reset();
        SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
 
@@ -742,7 +775,7 @@ int RecvPcsxInfo() {
        NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
        if (tmp != Config.Cpu) {
                psxCpu->Shutdown();
-#ifdef PSXREC
+#if defined(NEW_DYNAREC) || defined(LIGHTREC)
                if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
                else psxCpu = &psxRec;
 #else
similarity index 99%
rename from libpcsxcore/new_dynarec/assem_arm.c
rename to libpcsxcore/new_dynarec/arm/assem_arm.c
index 21640f8..db1d2af 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
-#include "../gte.h"
+#include "../../gte.h"
 #define FLAGLESS
-#include "../gte.h"
+#include "../../gte.h"
 #undef FLAGLESS
-#include "../gte_arm.h"
-#include "../gte_neon.h"
+#include "../../gte_arm.h"
+#include "../../gte_neon.h"
 #include "pcnt.h"
 #include "arm_features.h"
 
@@ -2518,8 +2518,8 @@ static void mov_loadtype_adj(int type,int rs,int rt)
   }
 }
 
-#include "pcsxmem.h"
-#include "pcsxmem_inline.c"
+#include "../backends/psx/pcsxmem.h"
+#include "../backends/psx/pcsxmem_inline.c"
 
 static void do_readstub(int n)
 {
similarity index 95%
rename from libpcsxcore/new_dynarec/assem_arm.h
rename to libpcsxcore/new_dynarec/arm/assem_arm.h
index bb6114c..1dcc55f 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __ASSEM_ARM_H__
+#define __ASSEM_ARM_H__
+
 #define HOST_REGS 13
 #define HOST_CCREG 10
 #define HOST_BTREG 8
@@ -55,3 +58,5 @@ extern char *invc_ptr;
   extern char translation_cache[1 << TARGET_SIZE_2];
   #define BASE_ADDR (u_int)translation_cache
 #endif
+
+#endif /* __ASSEM_ARM_H__ */
similarity index 99%
rename from libpcsxcore/new_dynarec/linkage_arm.S
rename to libpcsxcore/new_dynarec/arm/linkage_arm.S
index d32dc0b..269eb99 100644 (file)
@@ -20,7 +20,7 @@
  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 #include "arm_features.h"
-#include "new_dynarec_config.h"
+#include "../new_dynarec_config.h"
 #include "linkage_offsets.h"
 
 
similarity index 94%
rename from libpcsxcore/new_dynarec/linkage_offsets.h
rename to libpcsxcore/new_dynarec/arm/linkage_offsets.h
index f7e1911..c7abff0 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef __LINKAGE_OFFSETS_H__
+#define __LINKAGE_OFFSETS_H__
 
 #define LO_next_interupt       64
 #define LO_cycle_count         (LO_next_interupt + 4)
@@ -39,3 +41,5 @@
 #define LO_FCR31               (LO_align0)
 
 #define LO_cop2_to_scratch_buf (LO_scratch_buf_ptr - LO_reg_cop2d)
+
+#endif /* __LINKAGE_OFFSETS_H__ */
similarity index 98%
rename from libpcsxcore/new_dynarec/emu_if.c
rename to libpcsxcore/new_dynarec/backends/psx/emu_if.c
index 22db5d1..2a090a0 100644 (file)
@@ -9,15 +9,19 @@
 
 #include "emu_if.h"
 #include "pcsxmem.h"
-#include "../psxhle.h"
-#include "../r3000a.h"
-#include "../cdrom.h"
-#include "../psxdma.h"
-#include "../mdec.h"
-#include "../gte_arm.h"
-#include "../gte_neon.h"
+#include "../../../psxhle.h"
+#include "../../../r3000a.h"
+#include "../../../cdrom.h"
+#include "../../../psxdma.h"
+#include "../../../mdec.h"
+#include "../../../gte_arm.h"
+#include "../../../gte_neon.h"
+
+#include "../../../gte.h"
+
 #define FLAGLESS
-#include "../gte.h"
+#include "../../../gte.h"
+#undef  FLAGLESS
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
 
@@ -331,6 +335,7 @@ static int ari64_init()
 #ifdef DRC_DBG
        memcpy(gte_handlers_nf, gte_handlers, sizeof(gte_handlers_nf));
 #endif
+   
        psxH_ptr = psxH;
        zeromem_ptr = zero_mem;
        scratch_buf_ptr = scratch_buf;
@@ -431,7 +436,7 @@ void do_insn_cmp() {}
 #ifdef DRC_DISABLE
 unsigned int address;
 int pending_exception, stop;
-unsigned int next_interupt;
+u32 next_interupt;
 int new_dynarec_did_compile;
 int cycle_multiplier;
 int new_dynarec_hacks;
similarity index 94%
rename from libpcsxcore/new_dynarec/emu_if.h
rename to libpcsxcore/new_dynarec/backends/psx/emu_if.h
index 3980490..323764c 100644 (file)
@@ -1,5 +1,8 @@
-#include "new_dynarec.h"
-#include "../r3000a.h"
+#ifndef __EMU_IF_H__
+#define __EMU_IF_H__
+
+#include "../../new_dynarec.h"
+#include "../../../r3000a.h"
 
 extern char invalid_code[0x100000];
 
@@ -89,7 +92,7 @@ extern void *scratch_buf_ptr;
 extern u32 inv_code_start, inv_code_end;
 
 /* cycles/irqs */
-extern unsigned int next_interupt;
+extern u32 next_interupt;
 extern int pending_exception;
 
 /* called by drc */
@@ -106,3 +109,5 @@ extern void SysPrintf(const char *fmt, ...);
 #else
 #define rdram ((u_int)psxM)
 #endif
+
+#endif /* __EMU_IF_H__ */
similarity index 99%
rename from libpcsxcore/new_dynarec/pcsxmem.c
rename to libpcsxcore/new_dynarec/backends/psx/pcsxmem.c
index 9376ff4..647981e 100644 (file)
@@ -6,11 +6,11 @@
  */
 
 #include <stdio.h>
-#include "../psxhw.h"
-#include "../cdrom.h"
-#include "../mdec.h"
-#include "../gpu.h"
-#include "../psxmem_map.h"
+#include "../../../psxhw.h"
+#include "../../../cdrom.h"
+#include "../../../mdec.h"
+#include "../../../gpu.h"
+#include "../../../psxmem_map.h"
 #include "emu_if.h"
 #include "pcsxmem.h"
 
similarity index 76%
rename from libpcsxcore/new_dynarec/pcsxmem.h
rename to libpcsxcore/new_dynarec/backends/psx/pcsxmem.h
index 72892a8..9d292a6 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef __PCSXMEM_H__
+#define __PCSXMEM_H__
 
 extern u8 zero_mem[0x1000];
 
@@ -7,3 +9,5 @@ void new_dyna_pcsx_mem_load_state(void);
 void new_dyna_pcsx_mem_shutdown(void);
 
 int pcsxmem_is_handler_dynamic(unsigned int addr);
+
+#endif /* __PCSXMEM_H__ */
index cd63d2b..bb6ff0b 100644 (file)
 #ifdef VITA
 #include <psp2/kernel/sysmem.h>
 static int sceBlock;
+int getVMBlock();
 #endif
 
 #include "new_dynarec_config.h"
-#include "emu_if.h" //emulator interface
+#include "backends/psx/emu_if.h" //emulator interface
 
 //#define DISASM
 //#define assem_debug printf
@@ -44,13 +45,17 @@ static int sceBlock;
 #define inv_debug(...)
 
 #ifdef __i386__
-#include "assem_x86.h"
+#include "x86/assem_x86.h"
 #endif
 #ifdef __x86_64__
-#include "assem_x64.h"
+#include "x64/assem_x64.h"
 #endif
 #ifdef __arm__
-#include "assem_arm.h"
+#include "arm/assem_arm.h"
+#endif
+
+#ifdef VITA
+int _newlib_vm_size_user = 1 << TARGET_SIZE_2;
 #endif
 
 #define MAXBLOCK 4096
@@ -361,14 +366,16 @@ static u_int get_vpage(u_int vaddr)
 // This is called from the recompiled JR/JALR instructions
 void *get_addr(u_int vaddr)
 {
-  u_int page=get_page(vaddr);
-  u_int vpage=get_vpage(vaddr);
-  struct ll_entry *head;
+  struct ll_entry *head = NULL;
+  u_int page            = get_page(vaddr);
+  u_int vpage           = get_vpage(vaddr);
   //printf("TRACE: count=%d next=%d (get_addr %x,page %d)\n",Count,next_interupt,vaddr,page);
   head=jump_in[page];
-  while(head!=NULL) {
-    if(head->vaddr==vaddr) {
-  //printf("TRACE: count=%d next=%d (get_addr match %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
+  while(head!=NULL)
+  {
+    if(head->vaddr==vaddr)
+    {
+      //printf("TRACE: count=%d next=%d (get_addr match %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
       u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
       ht_bin[3]=ht_bin[1];
       ht_bin[2]=ht_bin[0];
@@ -379,39 +386,47 @@ void *get_addr(u_int vaddr)
     head=head->next;
   }
   head=jump_dirty[vpage];
-  while(head!=NULL) {
-    if(head->vaddr==vaddr) {
+  while(head!=NULL)
+  {
+    if(head->vaddr==vaddr)
+    {
       //printf("TRACE: count=%d next=%d (get_addr match dirty %x: %x)\n",Count,next_interupt,vaddr,(int)head->addr);
       // Don't restore blocks which are about to expire from the cache
       if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
-      if(verify_dirty(head->addr)) {
-        //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]);
-        invalid_code[vaddr>>12]=0;
-        inv_code_start=inv_code_end=~0;
-        if(vpage<2048) {
-          restore_candidate[vpage>>3]|=1<<(vpage&7);
-        }
-        else restore_candidate[page>>3]|=1<<(page&7);
-        u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
-        if(ht_bin[0]==vaddr) {
-          ht_bin[1]=(u_int)head->addr; // Replace existing entry
-        }
-        else
+        if(verify_dirty(head->addr))
         {
-          ht_bin[3]=ht_bin[1];
-          ht_bin[2]=ht_bin[0];
-          ht_bin[1]=(int)head->addr;
-          ht_bin[0]=vaddr;
+          //printf("restore candidate: %x (%d) d=%d\n",vaddr,page,invalid_code[vaddr>>12]);
+          invalid_code[vaddr>>12]=0;
+          inv_code_start=inv_code_end=~0;
+          if(vpage<2048)
+          {
+            restore_candidate[vpage>>3]|=1<<(vpage&7);
+          }
+          else
+          {
+            restore_candidate[page>>3]|=1<<(page&7);
+          }
+          u_int *ht_bin=hash_table[((vaddr>>16)^vaddr)&0xFFFF];
+
+          if(ht_bin[0]==vaddr)
+            ht_bin[1]=(u_int)head->addr; // Replace existing entry
+          else
+          {
+            ht_bin[3]=ht_bin[1];
+            ht_bin[2]=ht_bin[0];
+            ht_bin[1]=(int)head->addr;
+            ht_bin[0]=vaddr;
+          }
+          return head->addr;
         }
-        return head->addr;
-      }
     }
     head=head->next;
   }
   //printf("TRACE: count=%d next=%d (get_addr no-match %x)\n",Count,next_interupt,vaddr);
   int r=new_recompile_block(vaddr);
-  if(r==0) return get_addr(vaddr);
-  // Execute in unmapped page, generate pagefault execption
+  if(r==0)
+    return get_addr(vaddr);
+  // Execute in unmapped page, generate pagefault exception
   Status|=2;
   Cause=(vaddr<<31)|0x8;
   EPC=(vaddr&1)?vaddr-5:vaddr;
@@ -420,6 +435,7 @@ void *get_addr(u_int vaddr)
   EntryHi=BadVAddr&0xFFFFE000;
   return get_addr_ht(0x80000000);
 }
+
 // Look up address in hash table first
 void *get_addr_ht(u_int vaddr)
 {
@@ -763,13 +779,13 @@ void alloc_all(struct regstat *cur,int i)
 }
 
 #ifdef __i386__
-#include "assem_x86.c"
+#include "x86/assem_x86.c"
 #endif
 #ifdef __x86_64__
-#include "assem_x64.c"
+#include "x64/assem_x64.c"
 #endif
 #ifdef __arm__
-#include "assem_arm.c"
+#include "arm/assem_arm.c"
 #endif
 
 // Add virtual address mapping to linked list
@@ -943,23 +959,26 @@ static void invalidate_block_range(u_int block, u_int first, u_int last)
   assert(first+5>page); // NB: this assumes MAXBLOCK<=4096 (4 pages)
   assert(last<page+5);
   // Invalidate the adjacent pages if a block crosses a 4K boundary
-  while(first<page) {
+  while(first<page)
+  {
     invalidate_page(first);
     first++;
   }
-  for(first=page+1;first<last;first++) {
+  for(first=page+1;first<last;first++)
+  {
     invalidate_page(first);
   }
-  #ifdef __arm__
-    do_clear_cache();
-  #endif
+
+#ifdef __arm__
+  do_clear_cache();
+#endif
 
   // Don't trap writes
   invalid_code[block]=1;
 
-  #ifdef USE_MINI_HT
+#ifdef USE_MINI_HT
   memset(mini_ht,-1,sizeof(mini_ht));
-  #endif
+#endif
 }
 
 void invalidate_block(u_int block)
@@ -967,19 +986,22 @@ void invalidate_block(u_int block)
   u_int page=get_page(block<<12);
   u_int vpage=get_vpage(block<<12);
   inv_debug("INVALIDATE: %x (%d)\n",block<<12,page);
-  //inv_debug("invalid_code[block]=%d\n",invalid_code[block]);
   u_int first,last;
   first=last=page;
   struct ll_entry *head;
   head=jump_dirty[vpage];
   //printf("page=%d vpage=%d\n",page,vpage);
-  while(head!=NULL) {
+  while(head!=NULL)
+  {
     u_int start,end;
-    if(vpage>2047||(head->vaddr>>12)==block) { // Ignore vaddr hash collision
+    if(vpage>2047||(head->vaddr>>12)==block)
+    { // Ignore vaddr hash collision
       get_bounds((int)head->addr,&start,&end);
       //printf("start: %x end: %x\n",start,end);
-      if(page<2048&&start>=(u_int)rdram&&end<(u_int)rdram+RAM_SIZE) {
-        if(((start-(u_int)rdram)>>12)<=page&&((end-1-(u_int)rdram)>>12)>=page) {
+      if(page<2048&&start>=(u_int)rdram&&end<(u_int)rdram+RAM_SIZE)
+      {
+        if(((start-(u_int)rdram)>>12)<=page&&((end-1-(u_int)rdram)>>12)>=page)
+        {
           if((((start-(u_int)rdram)>>12)&2047)<first) first=((start-(u_int)rdram)>>12)&2047;
           if((((end-1-(u_int)rdram)>>12)&2047)>last) last=((end-1-(u_int)rdram)>>12)&2047;
         }
@@ -1050,19 +1072,23 @@ void invalidate_addr(u_int addr)
 
 // This is called when loading a save state.
 // Anything could have changed, so invalidate everything.
-void invalidate_all_pages()
+void invalidate_all_pages(void)
 {
   u_int page;
   for(page=0;page<4096;page++)
     invalidate_page(page);
   for(page=0;page<1048576;page++)
-    if(!invalid_code[page]) {
+  {
+    if(!invalid_code[page])
+    {
       restore_candidate[(page&2047)>>3]|=1<<(page&7);
       restore_candidate[((page&2047)>>3)+256]|=1<<(page&7);
     }
-  #ifdef USE_MINI_HT
+  }
+
+#ifdef USE_MINI_HT
   memset(mini_ht,-1,sizeof(mini_ht));
-  #endif
+#endif
 }
 
 // Add an entry to jump_out after making a link
@@ -1087,37 +1113,48 @@ void clean_blocks(u_int page)
   struct ll_entry *head;
   inv_debug("INV: clean_blocks page=%d\n",page);
   head=jump_dirty[page];
-  while(head!=NULL) {
-    if(!invalid_code[head->vaddr>>12]) {
+  while(head!=NULL)
+  {
+    if(!invalid_code[head->vaddr>>12])
+    {
       // Don't restore blocks which are about to expire from the cache
-      if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) {
+      if((((u_int)head->addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
+      {
         u_int start,end;
-        if(verify_dirty(head->addr)) {
+        if(verify_dirty(head->addr))
+        {
           //printf("Possibly Restore %x (%x)\n",head->vaddr, (int)head->addr);
           u_int i;
           u_int inv=0;
           get_bounds((int)head->addr,&start,&end);
-          if(start-(u_int)rdram<RAM_SIZE) {
-            for(i=(start-(u_int)rdram+0x80000000)>>12;i<=(end-1-(u_int)rdram+0x80000000)>>12;i++) {
+          if(start-(u_int)rdram<RAM_SIZE)
+          {
+            for(i=(start-(u_int)rdram+0x80000000)>>12;i<=(end-1-(u_int)rdram+0x80000000)>>12;i++)
+            {
               inv|=invalid_code[i];
             }
           }
-          else if((signed int)head->vaddr>=(signed int)0x80000000+RAM_SIZE) {
+          else if((signed int)head->vaddr>=(signed int)0x80000000+RAM_SIZE)
+          {
             inv=1;
           }
-          if(!inv) {
+          if(!inv)
+          {
             void * clean_addr=(void *)get_clean_addr((int)head->addr);
-            if((((u_int)clean_addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2))) {
+            if((((u_int)clean_addr-(u_int)out)<<(32-TARGET_SIZE_2))>0x60000000+(MAX_OUTPUT_BLOCK_SIZE<<(32-TARGET_SIZE_2)))
+            {
               u_int ppage=page;
               inv_debug("INV: Restored %x (%x/%x)\n",head->vaddr, (int)head->addr, (int)clean_addr);
               //printf("page=%x, addr=%x\n",page,head->vaddr);
               //assert(head->vaddr>>12==(page|0x80000));
               ll_add_flags(jump_in+ppage,head->vaddr,head->reg_sv_flags,clean_addr);
               u_int *ht_bin=hash_table[((head->vaddr>>16)^head->vaddr)&0xFFFF];
-              if(ht_bin[0]==head->vaddr) {
+              if(ht_bin[0]==head->vaddr)
+              {
                 ht_bin[1]=(u_int)clean_addr; // Replace existing entry
               }
-              if(ht_bin[2]==head->vaddr) {
+              if(ht_bin[2]==head->vaddr)
+              {
                 ht_bin[3]=(u_int)clean_addr; // Replace existing entry
               }
             }
@@ -1129,15 +1166,17 @@ void clean_blocks(u_int page)
   }
 }
 
-
-void mov_alloc(struct regstat *current,int i)
+static void mov_alloc(struct regstat *current,int i)
 {
   // Note: Don't need to actually alloc the source registers
-  if((~current->is32>>rs1[i])&1) {
+  if((~current->is32>>rs1[i])&1)
+  {
     //alloc_reg64(current,i,rs1[i]);
     alloc_reg64(current,i,rt1[i]);
     current->is32&=~(1LL<<rt1[i]);
-  } else {
+  }
+  else
+  {
     //alloc_reg(current,i,rs1[i]);
     alloc_reg(current,i,rt1[i]);
     current->is32|=(1LL<<rt1[i]);
@@ -1695,7 +1734,8 @@ void syscall_alloc(struct regstat *current,int i)
 
 void delayslot_alloc(struct regstat *current,int i)
 {
-  switch(itype[i]) {
+  switch(itype[i])
+  {
     case UJUMP:
     case CJUMP:
     case SJUMP:
@@ -1845,7 +1885,8 @@ void wb_register(signed char r,signed char regmap[],uint64_t dirty,uint64_t is32
   }
 }
 
-int mchecksum()
+#if 0
+static int mchecksum(void)
 {
   //if(!tracedebug) return 0;
   int i;
@@ -1858,7 +1899,8 @@ int mchecksum()
   }
   return sum;
 }
-int rchecksum()
+
+static int rchecksum(void)
 {
   int i;
   int sum=0;
@@ -1866,7 +1908,8 @@ int rchecksum()
     sum^=((u_int *)reg)[i];
   return sum;
 }
-void rlist()
+
+static void rlist(void)
 {
   int i;
   printf("TRACE: ");
@@ -1875,12 +1918,12 @@ void rlist()
   printf("\n");
 }
 
-void enabletrace()
+static void enabletrace(void)
 {
   tracedebug=1;
 }
 
-void memdebug(int i)
+static void memdebug(int i)
 {
   //printf("TRACE: count=%d next=%d (checksum %x) lo=%8x%8x\n",Count,next_interupt,mchecksum(),(int)(reg[LOREG]>>32),(int)reg[LOREG]);
   //printf("TRACE: count=%d next=%d (rchecksum %x)\n",Count,next_interupt,rchecksum());
@@ -1905,6 +1948,7 @@ void memdebug(int i)
   }
   //printf("TRACE: %x\n",(&i)[-1]);
 }
+#endif
 
 void alu_assemble(int i,struct regstat *i_regs)
 {
@@ -7016,7 +7060,7 @@ static int new_dynarec_test(void)
 
 // clear the state completely, instead of just marking
 // things invalid like invalidate_all_pages() does
-void new_dynarec_clear_full()
+void new_dynarec_clear_full(void)
 {
   int n;
   out=(u_char *)BASE_ADDR;
@@ -7037,45 +7081,57 @@ void new_dynarec_clear_full()
   for(n=0;n<4096;n++) ll_clear(jump_dirty+n);
 }
 
-void new_dynarec_init()
+void new_dynarec_init(void)
 {
   SysPrintf("Init new dynarec\n");
 
+#ifdef _3DS
+  check_rosalina();
+#endif
+
   // allocate/prepare a buffer for translation cache
   // see assem_arm.h for some explanation
 #if   defined(BASE_ADDR_FIXED)
   if (mmap (translation_cache, 1 << TARGET_SIZE_2,
-            PROT_READ | PROT_WRITE | PROT_EXEC,
-            MAP_PRIVATE | MAP_ANONYMOUS,
-            -1, 0) != translation_cache) {
+        PROT_READ | PROT_WRITE | PROT_EXEC,
+        MAP_PRIVATE | MAP_ANONYMOUS,
+        -1, 0) != translation_cache)
+  {
     SysPrintf("mmap() failed: %s\n", strerror(errno));
     SysPrintf("disable BASE_ADDR_FIXED and recompile\n");
     abort();
   }
 #elif defined(BASE_ADDR_DYNAMIC)
-  #ifdef VITA
-  sceBlock = sceKernelAllocMemBlockForVM("code", 1 << TARGET_SIZE_2);
+#ifdef VITA
+  sceBlock = getVMBlock();//sceKernelAllocMemBlockForVM("code", 1 << TARGET_SIZE_2);
   if (sceBlock < 0)
     SysPrintf("sceKernelAllocMemBlockForVM failed\n");
   int ret = sceKernelGetMemBlockBase(sceBlock, (void **)&translation_cache);
   if (ret < 0)
     SysPrintf("sceKernelGetMemBlockBase failed\n");
-  #else
+    
+  sceKernelOpenVMDomain();
+  sceClibPrintf("translation_cache = 0x%08X \n ", translation_cache);
+#elif defined(_MSC_VER)
+  base_addr = VirtualAlloc(NULL, 1<<TARGET_SIZE_2, MEM_COMMIT | MEM_RESERVE,
+      PAGE_EXECUTE_READWRITE);
+#else
   translation_cache = mmap (NULL, 1 << TARGET_SIZE_2,
-            PROT_READ | PROT_WRITE | PROT_EXEC,
-            MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+      PROT_READ | PROT_WRITE | PROT_EXEC,
+      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
   if (translation_cache == MAP_FAILED) {
     SysPrintf("mmap() failed: %s\n", strerror(errno));
     abort();
   }
-  #endif
+#endif
 #else
-  #ifndef NO_WRITE_EXEC
+#ifndef NO_WRITE_EXEC
   // not all systems allow execute in data segment by default
   if (mprotect((void *)BASE_ADDR, 1<<TARGET_SIZE_2, PROT_READ | PROT_WRITE | PROT_EXEC) != 0)
     SysPrintf("mprotect() failed: %s\n", strerror(errno));
-  #endif
 #endif
+#endif
+
   out=(u_char *)BASE_ADDR;
   cycle_multiplier=200;
   new_dynarec_clear_full();
@@ -7092,24 +7148,28 @@ void new_dynarec_init()
     SysPrintf("warning: RAM is not directly mapped, performance will suffer\n");
 }
 
-void new_dynarec_cleanup()
+void new_dynarec_cleanup(void)
 {
   int n;
 #if defined(BASE_ADDR_FIXED) || defined(BASE_ADDR_DYNAMIC)
-  #ifdef VITA
-  sceKernelFreeMemBlock(sceBlock);
-  sceBlock = -1;
-  #else
+#ifndef VITA
+#if defined(_MSC_VER)
+  VirtualFree(base_addr, 0, MEM_RELEASE);
+#else
   if (munmap ((void *)BASE_ADDR, 1<<TARGET_SIZE_2) < 0)
     SysPrintf("munmap() failed\n");
-  #endif
 #endif
-  for(n=0;n<4096;n++) ll_clear(jump_in+n);
-  for(n=0;n<4096;n++) ll_clear(jump_out+n);
-  for(n=0;n<4096;n++) ll_clear(jump_dirty+n);
-  #ifdef ROM_COPY
+#endif
+#endif
+  for(n=0;n<4096;n++)
+    ll_clear(jump_in+n);
+  for(n=0;n<4096;n++)
+    ll_clear(jump_out+n);
+  for(n=0;n<4096;n++)
+    ll_clear(jump_dirty+n);
+#ifdef ROM_COPY
   if (munmap (ROM_COPY, 67108864) < 0) {SysPrintf("munmap() failed\n");}
-  #endif
+#endif
 }
 
 static u_int *get_source_start(u_int addr, u_int *limit)
index ddc84a5..8c89051 100644 (file)
@@ -1,4 +1,7 @@
-#define NEW_DYNAREC 1
+#ifndef __NEW_DYNAREC_H__
+#define __NEW_DYNAREC_H__
+
+/* #define NEW_DYNAREC 1 */
 
 extern int pcaddr;
 extern int pending_exception;
@@ -11,12 +14,14 @@ extern int cycle_multiplier; // 100 for 1.0
 #define NDHACK_GTE_NO_FLAGS    (1<<2)
 extern int new_dynarec_hacks;
 
-void new_dynarec_init();
-void new_dynarec_cleanup();
-void new_dynarec_clear_full();
-void new_dyna_start();
+void new_dynarec_init(void);
+void new_dynarec_cleanup(void);
+void new_dynarec_clear_full(void);
+void new_dyna_start(void);
 int  new_dynarec_save_blocks(void *save, int size);
 void new_dynarec_load_blocks(const void *save, int size);
 
-void invalidate_all_pages();
+void invalidate_all_pages(void);
 void invalidate_block(unsigned int block);
+
+#endif /* __NEW_DYNAREC_H__ */
index fbd08ac..3b00780 100644 (file)
@@ -1,12 +1,15 @@
-
+#ifndef __NEW_DYNAREC_CONFIG_H__
+#define __NEW_DYNAREC_CONFIG_H__
 
 #define CORTEX_A8_BRANCH_PREDICTION_HACK 1
 #define USE_MINI_HT 1
 //#define REG_PREFETCH 1
 
-#if defined(__MACH__) || defined(VITA)
+#if defined(__MACH__)
 #define NO_WRITE_EXEC 1
 #endif
 #ifdef VITA
 #define BASE_ADDR_DYNAMIC 1
 #endif
+
+#endif /* __NEW_DYNAREC_CONFIG_H__ */
index e6d8a11..a2f8fe2 100644 (file)
-/***************************************************************************\r
- *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *\r
- *                                                                         *\r
- *   This program is free software; you can redistribute it and/or modify  *\r
- *   it under the terms of the GNU General Public License as published by  *\r
- *   the Free Software Foundation; either version 2 of the License, or     *\r
- *   (at your option) any later version.                                   *\r
- *                                                                         *\r
- *   This program is distributed in the hope that it will be useful,       *\r
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *\r
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *\r
- *   GNU General Public License for more details.                          *\r
- *                                                                         *\r
- *   You should have received a copy of the GNU General Public License     *\r
- *   along with this program; if not, write to the                         *\r
- *   Free Software Foundation, Inc.,                                       *\r
- *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *\r
- ***************************************************************************/\r
-\r
-/*\r
-* Plugin library callback/access functions.\r
-*/\r
-\r
-#include "plugins.h"\r
-#include "cdriso.h"\r
-\r
-static char IsoFile[MAXPATHLEN] = "";\r
-static s64 cdOpenCaseTime = 0;\r
-\r
-GPUupdateLace         GPU_updateLace;\r
-GPUinit               GPU_init;\r
-GPUshutdown           GPU_shutdown; \r
-GPUconfigure          GPU_configure;\r
-GPUtest               GPU_test;\r
-GPUabout              GPU_about;\r
-GPUopen               GPU_open;\r
-GPUclose              GPU_close;\r
-GPUreadStatus         GPU_readStatus;\r
-GPUreadData           GPU_readData;\r
-GPUreadDataMem        GPU_readDataMem;\r
-GPUwriteStatus        GPU_writeStatus; \r
-GPUwriteData          GPU_writeData;\r
-GPUwriteDataMem       GPU_writeDataMem;\r
-GPUdmaChain           GPU_dmaChain;\r
-GPUkeypressed         GPU_keypressed;\r
-GPUdisplayText        GPU_displayText;\r
-GPUmakeSnapshot       GPU_makeSnapshot;\r
-GPUfreeze             GPU_freeze;\r
-GPUgetScreenPic       GPU_getScreenPic;\r
-GPUshowScreenPic      GPU_showScreenPic;\r
-GPUclearDynarec       GPU_clearDynarec;\r
-GPUvBlank             GPU_vBlank;\r
-\r
-CDRinit               CDR_init;\r
-CDRshutdown           CDR_shutdown;\r
-CDRopen               CDR_open;\r
-CDRclose              CDR_close; \r
-CDRtest               CDR_test;\r
-CDRgetTN              CDR_getTN;\r
-CDRgetTD              CDR_getTD;\r
-CDRreadTrack          CDR_readTrack;\r
-CDRgetBuffer          CDR_getBuffer;\r
-CDRplay               CDR_play;\r
-CDRstop               CDR_stop;\r
-CDRgetStatus          CDR_getStatus;\r
-CDRgetDriveLetter     CDR_getDriveLetter;\r
-CDRgetBufferSub       CDR_getBufferSub;\r
-CDRconfigure          CDR_configure;\r
-CDRabout              CDR_about;\r
-CDRsetfilename        CDR_setfilename;\r
-CDRreadCDDA           CDR_readCDDA;\r
-CDRgetTE              CDR_getTE;\r
-\r
-SPUconfigure          SPU_configure;\r
-SPUabout              SPU_about;\r
-SPUinit               SPU_init;\r
-SPUshutdown           SPU_shutdown;\r
-SPUtest               SPU_test;\r
-SPUopen               SPU_open;\r
-SPUclose              SPU_close;\r
-SPUplaySample         SPU_playSample;\r
-SPUwriteRegister      SPU_writeRegister;\r
-SPUreadRegister       SPU_readRegister;\r
-SPUwriteDMA           SPU_writeDMA;\r
-SPUreadDMA            SPU_readDMA;\r
-SPUwriteDMAMem        SPU_writeDMAMem;\r
-SPUreadDMAMem         SPU_readDMAMem;\r
-SPUplayADPCMchannel   SPU_playADPCMchannel;\r
-SPUfreeze             SPU_freeze;\r
-SPUregisterCallback   SPU_registerCallback;\r
-SPUregisterScheduleCb SPU_registerScheduleCb;\r
-SPUasync              SPU_async;\r
-SPUplayCDDAchannel    SPU_playCDDAchannel;\r
-\r
-PADconfigure          PAD1_configure;\r
-PADabout              PAD1_about;\r
-PADinit               PAD1_init;\r
-PADshutdown           PAD1_shutdown;\r
-PADtest               PAD1_test;\r
-PADopen               PAD1_open;\r
-PADclose              PAD1_close;\r
-PADquery              PAD1_query;\r
-PADreadPort1          PAD1_readPort1;\r
-PADkeypressed         PAD1_keypressed;\r
-PADstartPoll          PAD1_startPoll;\r
-PADpoll               PAD1_poll;\r
-PADsetSensitive       PAD1_setSensitive;\r
-\r
-PADconfigure          PAD2_configure;\r
-PADabout              PAD2_about;\r
-PADinit               PAD2_init;\r
-PADshutdown           PAD2_shutdown;\r
-PADtest               PAD2_test;\r
-PADopen               PAD2_open;\r
-PADclose              PAD2_close;\r
-PADquery              PAD2_query;\r
-PADreadPort2          PAD2_readPort2;\r
-PADkeypressed         PAD2_keypressed;\r
-PADstartPoll          PAD2_startPoll;\r
-PADpoll               PAD2_poll;\r
-PADsetSensitive       PAD2_setSensitive;\r
-\r
-NETinit               NET_init;\r
-NETshutdown           NET_shutdown;\r
-NETopen               NET_open;\r
-NETclose              NET_close; \r
-NETtest               NET_test;\r
-NETconfigure          NET_configure;\r
-NETabout              NET_about;\r
-NETpause              NET_pause;\r
-NETresume             NET_resume;\r
-NETqueryPlayer        NET_queryPlayer;\r
-NETsendData           NET_sendData;\r
-NETrecvData           NET_recvData;\r
-NETsendPadData        NET_sendPadData;\r
-NETrecvPadData        NET_recvPadData;\r
-NETsetInfo            NET_setInfo;\r
-NETkeypressed         NET_keypressed;\r
-\r
-#ifdef ENABLE_SIO1API\r
-\r
-SIO1init              SIO1_init;\r
-SIO1shutdown          SIO1_shutdown;\r
-SIO1open              SIO1_open;\r
-SIO1close             SIO1_close; \r
-SIO1test              SIO1_test;\r
-SIO1configure         SIO1_configure;\r
-SIO1about             SIO1_about;\r
-SIO1pause             SIO1_pause;\r
-SIO1resume            SIO1_resume;\r
-SIO1keypressed        SIO1_keypressed;\r
-SIO1writeData8        SIO1_writeData8;\r
-SIO1writeData16       SIO1_writeData16;\r
-SIO1writeData32       SIO1_writeData32;\r
-SIO1writeStat16       SIO1_writeStat16;\r
-SIO1writeStat32       SIO1_writeStat32;\r
-SIO1writeMode16       SIO1_writeMode16;\r
-SIO1writeMode32       SIO1_writeMode32;\r
-SIO1writeCtrl16       SIO1_writeCtrl16;\r
-SIO1writeCtrl32       SIO1_writeCtrl32;\r
-SIO1writeBaud16       SIO1_writeBaud16;\r
-SIO1writeBaud32       SIO1_writeBaud32;\r
-SIO1readData8         SIO1_readData8;\r
-SIO1readData16        SIO1_readData16;\r
-SIO1readData32        SIO1_readData32;\r
-SIO1readStat16        SIO1_readStat16;\r
-SIO1readStat32        SIO1_readStat32;\r
-SIO1readMode16        SIO1_readMode16;\r
-SIO1readMode32        SIO1_readMode32;\r
-SIO1readCtrl16        SIO1_readCtrl16;\r
-SIO1readCtrl32        SIO1_readCtrl32;\r
-SIO1readBaud16        SIO1_readBaud16;\r
-SIO1readBaud32        SIO1_readBaud32;\r
-SIO1registerCallback  SIO1_registerCallback;\r
-\r
-#endif\r
-\r
-static const char *err;\r
-\r
-#define CheckErr(func) { \\r
-       err = SysLibError(); \\r
-       if (err != NULL) { SysMessage(_("Error loading %s: %s"), func, err); return -1; } \\r
-}\r
-\r
-#define LoadSym(dest, src, name, checkerr) { \\r
-       dest = (src)SysLoadSym(drv, name); \\r
-       if (checkerr) { CheckErr(name); } else SysLibError(); \\r
-}\r
-\r
-void *hGPUDriver = NULL;\r
-\r
-void CALLBACK GPU__displayText(char *pText) {\r
-       SysPrintf("%s\n", pText);\r
-}\r
-\r
-long CALLBACK GPU__configure(void) { return 0; }\r
-long CALLBACK GPU__test(void) { return 0; }\r
-void CALLBACK GPU__about(void) {}\r
-void CALLBACK GPU__makeSnapshot(void) {}\r
-void CALLBACK GPU__keypressed(int key) {}\r
-long CALLBACK GPU__getScreenPic(unsigned char *pMem) { return -1; }\r
-long CALLBACK GPU__showScreenPic(unsigned char *pMem) { return -1; }\r
-void CALLBACK GPU__clearDynarec(void (CALLBACK *callback)(void)) {}\r
-void CALLBACK GPU__vBlank(int val) {}\r
-\r
-#define LoadGpuSym1(dest, name) \\r
-       LoadSym(GPU_##dest, GPU##dest, name, TRUE);\r
-\r
-#define LoadGpuSym0(dest, name) \\r
-       LoadSym(GPU_##dest, GPU##dest, name, FALSE); \\r
-       if (GPU_##dest == NULL) GPU_##dest = (GPU##dest) GPU__##dest;\r
-\r
-#define LoadGpuSymN(dest, name) \\r
-       LoadSym(GPU_##dest, GPU##dest, name, FALSE);\r
-\r
-static int LoadGPUplugin(const char *GPUdll) {\r
-       void *drv;\r
-\r
-       hGPUDriver = SysLoadLibrary(GPUdll);\r
-       if (hGPUDriver == NULL) { \r
-               GPU_configure = NULL;\r
-               SysMessage (_("Could not load GPU plugin %s!"), GPUdll); return -1; \r
-       }\r
-       drv = hGPUDriver;\r
-       LoadGpuSym1(init, "GPUinit");\r
-       LoadGpuSym1(shutdown, "GPUshutdown");\r
-       LoadGpuSym1(open, "GPUopen");\r
-       LoadGpuSym1(close, "GPUclose");\r
-       LoadGpuSym1(readData, "GPUreadData");\r
-       LoadGpuSym1(readDataMem, "GPUreadDataMem");\r
-       LoadGpuSym1(readStatus, "GPUreadStatus");\r
-       LoadGpuSym1(writeData, "GPUwriteData");\r
-       LoadGpuSym1(writeDataMem, "GPUwriteDataMem");\r
-       LoadGpuSym1(writeStatus, "GPUwriteStatus");\r
-       LoadGpuSym1(dmaChain, "GPUdmaChain");\r
-       LoadGpuSym1(updateLace, "GPUupdateLace");\r
-       LoadGpuSym0(keypressed, "GPUkeypressed");\r
-       LoadGpuSym0(displayText, "GPUdisplayText");\r
-       LoadGpuSym0(makeSnapshot, "GPUmakeSnapshot");\r
-       LoadGpuSym1(freeze, "GPUfreeze");\r
-       LoadGpuSym0(getScreenPic, "GPUgetScreenPic");\r
-       LoadGpuSym0(showScreenPic, "GPUshowScreenPic");\r
-       LoadGpuSym0(clearDynarec, "GPUclearDynarec");\r
-    LoadGpuSym0(vBlank, "GPUvBlank");\r
-       LoadGpuSym0(configure, "GPUconfigure");\r
-       LoadGpuSym0(test, "GPUtest");\r
-       LoadGpuSym0(about, "GPUabout");\r
-\r
-       return 0;\r
-}\r
-\r
-void *hCDRDriver = NULL;\r
-\r
-long CALLBACK CDR__play(unsigned char *sector) { return 0; }\r
-long CALLBACK CDR__stop(void) { return 0; }\r
-\r
-long CALLBACK CDR__getStatus(struct CdrStat *stat) {\r
-       if (cdOpenCaseTime < 0 || cdOpenCaseTime > (s64)time(NULL))\r
-               stat->Status = 0x10;\r
-       else\r
-               stat->Status = 0;\r
-\r
-       return 0;\r
-}\r
-\r
-char* CALLBACK CDR__getDriveLetter(void) { return NULL; }\r
-long CALLBACK CDR__configure(void) { return 0; }\r
-long CALLBACK CDR__test(void) { return 0; }\r
-void CALLBACK CDR__about(void) {}\r
-long CALLBACK CDR__setfilename(char*filename) { return 0; }\r
-\r
-#define LoadCdrSym1(dest, name) \\r
-       LoadSym(CDR_##dest, CDR##dest, name, TRUE);\r
-\r
-#define LoadCdrSym0(dest, name) \\r
-       LoadSym(CDR_##dest, CDR##dest, name, FALSE); \\r
-       if (CDR_##dest == NULL) CDR_##dest = (CDR##dest) CDR__##dest;\r
-\r
-#define LoadCdrSymN(dest, name) \\r
-       LoadSym(CDR_##dest, CDR##dest, name, FALSE);\r
-\r
-static int LoadCDRplugin(const char *CDRdll) {\r
-       void *drv;\r
-\r
-       if (CDRdll == NULL) {\r
-               cdrIsoInit();\r
-               return 0;\r
-       }\r
-\r
-       hCDRDriver = SysLoadLibrary(CDRdll);\r
-       if (hCDRDriver == NULL) {\r
-               CDR_configure = NULL;\r
-               SysMessage (_("Could not load CD-ROM plugin %s!"), CDRdll);  return -1;\r
-       }\r
-       drv = hCDRDriver;\r
-       LoadCdrSym1(init, "CDRinit");\r
-       LoadCdrSym1(shutdown, "CDRshutdown");\r
-       LoadCdrSym1(open, "CDRopen");\r
-       LoadCdrSym1(close, "CDRclose");\r
-       LoadCdrSym1(getTN, "CDRgetTN");\r
-       LoadCdrSym1(getTD, "CDRgetTD");\r
-       LoadCdrSym1(readTrack, "CDRreadTrack");\r
-       LoadCdrSym1(getBuffer, "CDRgetBuffer");\r
-       LoadCdrSym1(getBufferSub, "CDRgetBufferSub");\r
-       LoadCdrSym0(play, "CDRplay");\r
-       LoadCdrSym0(stop, "CDRstop");\r
-       LoadCdrSym0(getStatus, "CDRgetStatus");\r
-       LoadCdrSym0(getDriveLetter, "CDRgetDriveLetter");\r
-       LoadCdrSym0(configure, "CDRconfigure");\r
-       LoadCdrSym0(test, "CDRtest");\r
-       LoadCdrSym0(about, "CDRabout");\r
-       LoadCdrSym0(setfilename, "CDRsetfilename");\r
-       LoadCdrSymN(readCDDA, "CDRreadCDDA");\r
-       LoadCdrSymN(getTE, "CDRgetTE");\r
-\r
-       return 0;\r
-}\r
-\r
-void *hSPUDriver = NULL;\r
-\r
-long CALLBACK SPU__configure(void) { return 0; }\r
-void CALLBACK SPU__about(void) {}\r
-long CALLBACK SPU__test(void) { return 0; }\r
-void CALLBACK SPU__registerScheduleCb(void (CALLBACK *cb)(unsigned int)) {}\r
-\r
-#define LoadSpuSym1(dest, name) \\r
-       LoadSym(SPU_##dest, SPU##dest, name, TRUE);\r
-\r
-#define LoadSpuSym0(dest, name) \\r
-       LoadSym(SPU_##dest, SPU##dest, name, FALSE); \\r
-       if (SPU_##dest == NULL) SPU_##dest = (SPU##dest) SPU__##dest;\r
-\r
-#define LoadSpuSymN(dest, name) \\r
-       LoadSym(SPU_##dest, SPU##dest, name, FALSE);\r
-\r
-static int LoadSPUplugin(const char *SPUdll) {\r
-       void *drv;\r
-\r
-       hSPUDriver = SysLoadLibrary(SPUdll);\r
-       if (hSPUDriver == NULL) {\r
-               SPU_configure = NULL;\r
-               SysMessage (_("Could not load SPU plugin %s!"), SPUdll); return -1;\r
-       }\r
-       drv = hSPUDriver;\r
-       LoadSpuSym1(init, "SPUinit");\r
-       LoadSpuSym1(shutdown, "SPUshutdown");\r
-       LoadSpuSym1(open, "SPUopen");\r
-       LoadSpuSym1(close, "SPUclose");\r
-       LoadSpuSym0(configure, "SPUconfigure");\r
-       LoadSpuSym0(about, "SPUabout");\r
-       LoadSpuSym0(test, "SPUtest");\r
-       LoadSpuSym1(writeRegister, "SPUwriteRegister");\r
-       LoadSpuSym1(readRegister, "SPUreadRegister");           \r
-       LoadSpuSym1(writeDMA, "SPUwriteDMA");\r
-       LoadSpuSym1(readDMA, "SPUreadDMA");\r
-       LoadSpuSym1(writeDMAMem, "SPUwriteDMAMem");\r
-       LoadSpuSym1(readDMAMem, "SPUreadDMAMem");\r
-       LoadSpuSym1(playADPCMchannel, "SPUplayADPCMchannel");\r
-       LoadSpuSym1(freeze, "SPUfreeze");\r
-       LoadSpuSym1(registerCallback, "SPUregisterCallback");\r
-       LoadSpuSym0(registerScheduleCb, "SPUregisterScheduleCb");\r
-       LoadSpuSymN(async, "SPUasync");\r
-       LoadSpuSymN(playCDDAchannel, "SPUplayCDDAchannel");\r
-\r
-       return 0;\r
-}\r
-\r
-void *hPAD1Driver = NULL;\r
-void *hPAD2Driver = NULL;\r
-\r
-static unsigned char buf[256];\r
-unsigned char stdpar[10] = { 0x00, 0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };\r
-unsigned char mousepar[8] = { 0x00, 0x12, 0x5a, 0xff, 0xff, 0xff, 0xff };\r
-unsigned char analogpar[9] = { 0x00, 0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };\r
-\r
-static int bufcount, bufc;\r
-\r
-PadDataS padd1, padd2;\r
-\r
-unsigned char _PADstartPoll(PadDataS *pad) {\r
-    bufc = 0;\r
-\r
-    switch (pad->controllerType) {\r
-        case PSE_PAD_TYPE_MOUSE:\r
-            mousepar[3] = pad->buttonStatus & 0xff;\r
-            mousepar[4] = pad->buttonStatus >> 8;\r
-            mousepar[5] = pad->moveX;\r
-            mousepar[6] = pad->moveY;\r
-\r
-            memcpy(buf, mousepar, 7);\r
-            bufcount = 6;\r
-            break;\r
-        case PSE_PAD_TYPE_NEGCON: // npc101/npc104(slph00001/slph00069)\r
-            analogpar[1] = 0x23;\r
-            analogpar[3] = pad->buttonStatus & 0xff;\r
-            analogpar[4] = pad->buttonStatus >> 8;\r
-            analogpar[5] = pad->rightJoyX;\r
-            analogpar[6] = pad->rightJoyY;\r
-            analogpar[7] = pad->leftJoyX;\r
-            analogpar[8] = pad->leftJoyY;\r
-\r
-            memcpy(buf, analogpar, 9);\r
-            bufcount = 8;\r
-            break;\r
-        case PSE_PAD_TYPE_ANALOGPAD: // scph1150\r
-            analogpar[1] = 0x73;\r
-            analogpar[3] = pad->buttonStatus & 0xff;\r
-            analogpar[4] = pad->buttonStatus >> 8;\r
-            analogpar[5] = pad->rightJoyX;\r
-            analogpar[6] = pad->rightJoyY;\r
-            analogpar[7] = pad->leftJoyX;\r
-            analogpar[8] = pad->leftJoyY;\r
-\r
-            memcpy(buf, analogpar, 9);\r
-            bufcount = 8;\r
-            break;\r
-        case PSE_PAD_TYPE_ANALOGJOY: // scph1110\r
-            analogpar[1] = 0x53;\r
-            analogpar[3] = pad->buttonStatus & 0xff;\r
-            analogpar[4] = pad->buttonStatus >> 8;\r
-            analogpar[5] = pad->rightJoyX;\r
-            analogpar[6] = pad->rightJoyY;\r
-            analogpar[7] = pad->leftJoyX;\r
-            analogpar[8] = pad->leftJoyY;\r
-\r
-            memcpy(buf, analogpar, 9);\r
-            bufcount = 8;\r
-            break;\r
-        case PSE_PAD_TYPE_STANDARD:\r
-        default:\r
-            stdpar[3] = pad->buttonStatus & 0xff;\r
-            stdpar[4] = pad->buttonStatus >> 8;\r
-\r
-            memcpy(buf, stdpar, 5);\r
-            bufcount = 4;\r
-    }\r
-\r
-    return buf[bufc++];\r
-}\r
-\r
-unsigned char _PADpoll(unsigned char value) {\r
-    if (bufc > bufcount) return 0;\r
-    return buf[bufc++];\r
-}\r
-\r
-unsigned char CALLBACK PAD1__startPoll(int pad) {\r
-    PadDataS padd;\r
-\r
-    PAD1_readPort1(&padd);\r
-\r
-    return _PADstartPoll(&padd);\r
-}\r
-\r
-unsigned char CALLBACK PAD1__poll(unsigned char value) {\r
-    return _PADpoll(value);\r
-}\r
-\r
-long CALLBACK PAD1__configure(void) { return 0; }\r
-void CALLBACK PAD1__about(void) {}\r
-long CALLBACK PAD1__test(void) { return 0; }\r
-long CALLBACK PAD1__query(void) { return 3; }\r
-long CALLBACK PAD1__keypressed() { return 0; }\r
-\r
-#define LoadPad1Sym1(dest, name) \\r
-       LoadSym(PAD1_##dest, PAD##dest, name, TRUE);\r
-\r
-#define LoadPad1SymN(dest, name) \\r
-       LoadSym(PAD1_##dest, PAD##dest, name, FALSE);\r
-\r
-#define LoadPad1Sym0(dest, name) \\r
-       LoadSym(PAD1_##dest, PAD##dest, name, FALSE); \\r
-       if (PAD1_##dest == NULL) PAD1_##dest = (PAD##dest) PAD1__##dest;\r
-\r
-static int LoadPAD1plugin(const char *PAD1dll) {\r
-       void *drv;\r
-\r
-       hPAD1Driver = SysLoadLibrary(PAD1dll);\r
-       if (hPAD1Driver == NULL) {\r
-               PAD1_configure = NULL;\r
-               SysMessage (_("Could not load Controller 1 plugin %s!"), PAD1dll); return -1;\r
-       }\r
-       drv = hPAD1Driver;\r
-       LoadPad1Sym1(init, "PADinit");\r
-       LoadPad1Sym1(shutdown, "PADshutdown");\r
-       LoadPad1Sym1(open, "PADopen");\r
-       LoadPad1Sym1(close, "PADclose");\r
-       LoadPad1Sym0(query, "PADquery");\r
-       LoadPad1Sym1(readPort1, "PADreadPort1");\r
-       LoadPad1Sym0(configure, "PADconfigure");\r
-       LoadPad1Sym0(test, "PADtest");\r
-       LoadPad1Sym0(about, "PADabout");\r
-       LoadPad1Sym0(keypressed, "PADkeypressed");\r
-       LoadPad1Sym0(startPoll, "PADstartPoll");\r
-       LoadPad1Sym0(poll, "PADpoll");\r
-       LoadPad1SymN(setSensitive, "PADsetSensitive");\r
-\r
-       return 0;\r
-}\r
-\r
-unsigned char CALLBACK PAD2__startPoll(int pad) {\r
-       PadDataS padd;\r
-\r
-       PAD2_readPort2(&padd);\r
-    \r
-       return _PADstartPoll(&padd);\r
-}\r
-\r
-unsigned char CALLBACK PAD2__poll(unsigned char value) {\r
-       return _PADpoll(value);\r
-}\r
-\r
-long CALLBACK PAD2__configure(void) { return 0; }\r
-void CALLBACK PAD2__about(void) {}\r
-long CALLBACK PAD2__test(void) { return 0; }\r
-long CALLBACK PAD2__query(void) { return PSE_PAD_USE_PORT1 | PSE_PAD_USE_PORT2; }\r
-long CALLBACK PAD2__keypressed() { return 0; }\r
-\r
-#define LoadPad2Sym1(dest, name) \\r
-       LoadSym(PAD2_##dest, PAD##dest, name, TRUE);\r
-\r
-#define LoadPad2Sym0(dest, name) \\r
-       LoadSym(PAD2_##dest, PAD##dest, name, FALSE); \\r
-       if (PAD2_##dest == NULL) PAD2_##dest = (PAD##dest) PAD2__##dest;\r
-\r
-#define LoadPad2SymN(dest, name) \\r
-       LoadSym(PAD2_##dest, PAD##dest, name, FALSE);\r
-\r
-static int LoadPAD2plugin(const char *PAD2dll) {\r
-       void *drv;\r
-\r
-       hPAD2Driver = SysLoadLibrary(PAD2dll);\r
-       if (hPAD2Driver == NULL) {\r
-               PAD2_configure = NULL;\r
-               SysMessage (_("Could not load Controller 2 plugin %s!"), PAD2dll); return -1;\r
-       }\r
-       drv = hPAD2Driver;\r
-       LoadPad2Sym1(init, "PADinit");\r
-       LoadPad2Sym1(shutdown, "PADshutdown");\r
-       LoadPad2Sym1(open, "PADopen");\r
-       LoadPad2Sym1(close, "PADclose");\r
-       LoadPad2Sym0(query, "PADquery");\r
-       LoadPad2Sym1(readPort2, "PADreadPort2");\r
-       LoadPad2Sym0(configure, "PADconfigure");\r
-       LoadPad2Sym0(test, "PADtest");\r
-       LoadPad2Sym0(about, "PADabout");\r
-       LoadPad2Sym0(keypressed, "PADkeypressed");\r
-       LoadPad2Sym0(startPoll, "PADstartPoll");\r
-       LoadPad2Sym0(poll, "PADpoll");\r
-       LoadPad2SymN(setSensitive, "PADsetSensitive");\r
-\r
-       return 0;\r
-}\r
-\r
-void *hNETDriver = NULL;\r
-\r
-void CALLBACK NET__setInfo(netInfo *info) {}\r
-void CALLBACK NET__keypressed(int key) {}\r
-long CALLBACK NET__configure(void) { return 0; }\r
-long CALLBACK NET__test(void) { return 0; }\r
-void CALLBACK NET__about(void) {}\r
-\r
-#define LoadNetSym1(dest, name) \\r
-       LoadSym(NET_##dest, NET##dest, name, TRUE);\r
-\r
-#define LoadNetSymN(dest, name) \\r
-       LoadSym(NET_##dest, NET##dest, name, FALSE);\r
-\r
-#define LoadNetSym0(dest, name) \\r
-       LoadSym(NET_##dest, NET##dest, name, FALSE); \\r
-       if (NET_##dest == NULL) NET_##dest = (NET##dest) NET__##dest;\r
-\r
-static int LoadNETplugin(const char *NETdll) {\r
-       void *drv;\r
-\r
-       hNETDriver = SysLoadLibrary(NETdll);\r
-       if (hNETDriver == NULL) {\r
-               SysMessage (_("Could not load NetPlay plugin %s!"), NETdll); return -1;\r
-       }\r
-       drv = hNETDriver;\r
-       LoadNetSym1(init, "NETinit");\r
-       LoadNetSym1(shutdown, "NETshutdown");\r
-       LoadNetSym1(open, "NETopen");\r
-       LoadNetSym1(close, "NETclose");\r
-       LoadNetSymN(sendData, "NETsendData");\r
-       LoadNetSymN(recvData, "NETrecvData");\r
-       LoadNetSym1(sendPadData, "NETsendPadData");\r
-       LoadNetSym1(recvPadData, "NETrecvPadData");\r
-       LoadNetSym1(queryPlayer, "NETqueryPlayer");\r
-       LoadNetSym1(pause, "NETpause");\r
-       LoadNetSym1(resume, "NETresume");\r
-       LoadNetSym0(setInfo, "NETsetInfo");\r
-       LoadNetSym0(keypressed, "NETkeypressed");\r
-       LoadNetSym0(configure, "NETconfigure");\r
-       LoadNetSym0(test, "NETtest");\r
-       LoadNetSym0(about, "NETabout");\r
-\r
-       return 0;\r
-}\r
-\r
-#ifdef ENABLE_SIO1API\r
-\r
-void *hSIO1Driver = NULL;\r
-\r
-long CALLBACK SIO1__init(void) { return 0; }\r
-long CALLBACK SIO1__shutdown(void) { return 0; }\r
-long CALLBACK SIO1__open(void) { return 0; }\r
-long CALLBACK SIO1__close(void) { return 0; }\r
-long CALLBACK SIO1__configure(void) { return 0; }\r
-long CALLBACK SIO1__test(void) { return 0; }\r
-void CALLBACK SIO1__about(void) {}\r
-void CALLBACK SIO1__pause(void) {}\r
-void CALLBACK SIO1__resume(void) {}\r
-long CALLBACK SIO1__keypressed(int key) { return 0; }\r
-void CALLBACK SIO1__writeData8(unsigned char val) {}\r
-void CALLBACK SIO1__writeData16(unsigned short val) {}\r
-void CALLBACK SIO1__writeData32(unsigned long val) {}\r
-void CALLBACK SIO1__writeStat16(unsigned short val) {}\r
-void CALLBACK SIO1__writeStat32(unsigned long val) {}\r
-void CALLBACK SIO1__writeMode16(unsigned short val) {}\r
-void CALLBACK SIO1__writeMode32(unsigned long val) {}\r
-void CALLBACK SIO1__writeCtrl16(unsigned short val) {}\r
-void CALLBACK SIO1__writeCtrl32(unsigned long val) {}\r
-void CALLBACK SIO1__writeBaud16(unsigned short val) {}\r
-void CALLBACK SIO1__writeBaud32(unsigned long val) {}\r
-unsigned char CALLBACK SIO1__readData8(void) { return 0; }\r
-unsigned short CALLBACK SIO1__readData16(void) { return 0; }\r
-unsigned long CALLBACK SIO1__readData32(void) { return 0; }\r
-unsigned short CALLBACK SIO1__readStat16(void) { return 0; }\r
-unsigned long CALLBACK SIO1__readStat32(void) { return 0; }\r
-unsigned short CALLBACK SIO1__readMode16(void) { return 0; }\r
-unsigned long CALLBACK SIO1__readMode32(void) { return 0; }\r
-unsigned short CALLBACK SIO1__readCtrl16(void) { return 0; }\r
-unsigned long CALLBACK SIO1__readCtrl32(void) { return 0; }\r
-unsigned short CALLBACK SIO1__readBaud16(void) { return 0; }\r
-unsigned long CALLBACK SIO1__readBaud32(void) { return 0; }\r
-void CALLBACK SIO1__registerCallback(void (CALLBACK *callback)(void)) {};\r
-\r
-void CALLBACK SIO1irq(void) {\r
-    psxHu32ref(0x1070) |= SWAPu32(0x100);\r
-}\r
-\r
-#define LoadSio1Sym1(dest, name) \\r
-    LoadSym(SIO1_##dest, SIO1##dest, name, TRUE);\r
-\r
-#define LoadSio1SymN(dest, name) \\r
-    LoadSym(SIO1_##dest, SIO1##dest, name, FALSE);\r
-\r
-#define LoadSio1Sym0(dest, name) \\r
-    LoadSym(SIO1_##dest, SIO1##dest, name, FALSE); \\r
-    if (SIO1_##dest == NULL) SIO1_##dest = (SIO1##dest) SIO1__##dest;\r
-\r
-static int LoadSIO1plugin(const char *SIO1dll) {\r
-    void *drv;\r
-\r
-    hSIO1Driver = SysLoadLibrary(SIO1dll);\r
-    if (hSIO1Driver == NULL) {\r
-        SysMessage (_("Could not load SIO1 plugin %s!"), SIO1dll); return -1;\r
-    }\r
-    drv = hSIO1Driver;\r
-\r
-    LoadSio1Sym0(init, "SIO1init");\r
-    LoadSio1Sym0(shutdown, "SIO1shutdown");\r
-    LoadSio1Sym0(open, "SIO1open");\r
-    LoadSio1Sym0(close, "SIO1close");\r
-    LoadSio1Sym0(pause, "SIO1pause");\r
-    LoadSio1Sym0(resume, "SIO1resume");\r
-    LoadSio1Sym0(keypressed, "SIO1keypressed");\r
-    LoadSio1Sym0(configure, "SIO1configure");\r
-    LoadSio1Sym0(test, "SIO1test");\r
-    LoadSio1Sym0(about, "SIO1about");\r
-    LoadSio1Sym0(writeData8, "SIO1writeData8");\r
-    LoadSio1Sym0(writeData16, "SIO1writeData16");\r
-    LoadSio1Sym0(writeData32, "SIO1writeData32");\r
-    LoadSio1Sym0(writeStat16, "SIO1writeStat16");\r
-    LoadSio1Sym0(writeStat32, "SIO1writeStat32");\r
-    LoadSio1Sym0(writeMode16, "SIO1writeMode16");\r
-    LoadSio1Sym0(writeMode32, "SIO1writeMode32");\r
-    LoadSio1Sym0(writeCtrl16, "SIO1writeCtrl16");\r
-    LoadSio1Sym0(writeCtrl32, "SIO1writeCtrl32");\r
-    LoadSio1Sym0(writeBaud16, "SIO1writeBaud16");\r
-    LoadSio1Sym0(writeBaud32, "SIO1writeBaud32");\r
-    LoadSio1Sym0(readData16, "SIO1readData16");\r
-    LoadSio1Sym0(readData32, "SIO1readData32");\r
-    LoadSio1Sym0(readStat16, "SIO1readStat16");\r
-    LoadSio1Sym0(readStat32, "SIO1readStat32");\r
-    LoadSio1Sym0(readMode16, "SIO1readMode16");\r
-    LoadSio1Sym0(readMode32, "SIO1readMode32");\r
-    LoadSio1Sym0(readCtrl16, "SIO1readCtrl16");\r
-    LoadSio1Sym0(readCtrl32, "SIO1readCtrl32");\r
-    LoadSio1Sym0(readBaud16, "SIO1readBaud16");\r
-    LoadSio1Sym0(readBaud32, "SIO1readBaud32");\r
-    LoadSio1Sym0(registerCallback, "SIO1registerCallback");\r
-\r
-    return 0;\r
-}\r
-\r
-#endif\r
-\r
-void CALLBACK clearDynarec(void) {\r
-       psxCpu->Reset();\r
-}\r
-\r
-int LoadPlugins() {\r
-       int ret;\r
-       char Plugin[MAXPATHLEN];\r
-\r
-       ReleasePlugins();\r
-       SysLibError();\r
-\r
-       if (UsingIso()) {\r
-               LoadCDRplugin(NULL);\r
-       } else {\r
-               sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Cdr);\r
-               if (LoadCDRplugin(Plugin) == -1) return -1;\r
-       }\r
-\r
-       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Gpu);\r
-       if (LoadGPUplugin(Plugin) == -1) return -1;\r
-\r
-       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Spu);\r
-       if (LoadSPUplugin(Plugin) == -1) return -1;\r
-\r
-       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Pad1);\r
-       if (LoadPAD1plugin(Plugin) == -1) return -1;\r
-\r
-       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Pad2);\r
-       if (LoadPAD2plugin(Plugin) == -1) return -1;\r
-\r
-       if (strcmp("Disabled", Config.Net) == 0 || strcmp("", Config.Net) == 0)\r
-               Config.UseNet = FALSE;\r
-       else {\r
-               Config.UseNet = TRUE;\r
-               sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Net);\r
-               if (LoadNETplugin(Plugin) == -1) Config.UseNet = FALSE;\r
-       }\r
-\r
-#ifdef ENABLE_SIO1API\r
-       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Sio1);\r
-       if (LoadSIO1plugin(Plugin) == -1) return -1;\r
-#endif\r
-\r
-       ret = CDR_init();\r
-       if (ret < 0) { SysMessage (_("Error initializing CD-ROM plugin: %d"), ret); return -1; }\r
-       ret = GPU_init();\r
-       if (ret < 0) { SysMessage (_("Error initializing GPU plugin: %d"), ret); return -1; }\r
-       ret = SPU_init();\r
-       if (ret < 0) { SysMessage (_("Error initializing SPU plugin: %d"), ret); return -1; }\r
-       ret = PAD1_init(1);\r
-       if (ret < 0) { SysMessage (_("Error initializing Controller 1 plugin: %d"), ret); return -1; }\r
-       ret = PAD2_init(2);\r
-       if (ret < 0) { SysMessage (_("Error initializing Controller 2 plugin: %d"), ret); return -1; }\r
-\r
-       if (Config.UseNet) {\r
-               ret = NET_init();\r
-               if (ret < 0) { SysMessage (_("Error initializing NetPlay plugin: %d"), ret); return -1; }\r
-       }\r
-\r
-#ifdef ENABLE_SIO1API\r
-       ret = SIO1_init();\r
-       if (ret < 0) { SysMessage (_("Error initializing SIO1 plugin: %d"), ret); return -1; }\r
-#endif\r
-\r
-       SysPrintf(_("Plugins loaded.\n"));\r
-       return 0;\r
-}\r
-\r
-void ReleasePlugins() {\r
-       if (Config.UseNet) {\r
-               int ret = NET_close();\r
-               if (ret < 0) Config.UseNet = FALSE;\r
-       }\r
-       NetOpened = FALSE;\r
-\r
-       if (hCDRDriver != NULL || cdrIsoActive()) CDR_shutdown();\r
-       if (hGPUDriver != NULL) GPU_shutdown();\r
-       if (hSPUDriver != NULL) SPU_shutdown();\r
-       if (hPAD1Driver != NULL) PAD1_shutdown();\r
-       if (hPAD2Driver != NULL) PAD2_shutdown();\r
-\r
-       if (Config.UseNet && hNETDriver != NULL) NET_shutdown(); \r
-\r
-       if (hCDRDriver != NULL) SysCloseLibrary(hCDRDriver); hCDRDriver = NULL;\r
-       if (hGPUDriver != NULL) SysCloseLibrary(hGPUDriver); hGPUDriver = NULL;\r
-       if (hSPUDriver != NULL) SysCloseLibrary(hSPUDriver); hSPUDriver = NULL;\r
-       if (hPAD1Driver != NULL) SysCloseLibrary(hPAD1Driver); hPAD1Driver = NULL;\r
-       if (hPAD2Driver != NULL) SysCloseLibrary(hPAD2Driver); hPAD2Driver = NULL;\r
-\r
-       if (Config.UseNet && hNETDriver != NULL) {\r
-               SysCloseLibrary(hNETDriver); hNETDriver = NULL;\r
-       }\r
-\r
-#ifdef ENABLE_SIO1API\r
-       if (hSIO1Driver != NULL) {\r
-               SIO1_shutdown();\r
-               SysCloseLibrary(hSIO1Driver);\r
-               hSIO1Driver = NULL;\r
-       }\r
-#endif\r
-}\r
-\r
-// for CD swap\r
-int ReloadCdromPlugin()\r
-{\r
-       if (hCDRDriver != NULL || cdrIsoActive()) CDR_shutdown();\r
-       if (hCDRDriver != NULL) SysCloseLibrary(hCDRDriver); hCDRDriver = NULL;\r
-\r
-       if (UsingIso()) {\r
-               LoadCDRplugin(NULL);\r
-       } else {\r
-               char Plugin[MAXPATHLEN];\r
-               sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Cdr);\r
-               if (LoadCDRplugin(Plugin) == -1) return -1;\r
-       }\r
-\r
-       return CDR_init();\r
-}\r
-\r
-void SetIsoFile(const char *filename) {\r
-       if (filename == NULL) {\r
-               IsoFile[0] = '\0';\r
-               return;\r
-       }\r
-       strncpy(IsoFile, filename, MAXPATHLEN);\r
-}\r
-\r
-const char *GetIsoFile(void) {\r
-       return IsoFile;\r
-}\r
-\r
-boolean UsingIso(void) {\r
-       return (IsoFile[0] != '\0');\r
-}\r
-\r
-void SetCdOpenCaseTime(s64 time) {\r
-       cdOpenCaseTime = time;\r
-}\r
+/***************************************************************************
+ *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
+ ***************************************************************************/
+
+/*
+* Plugin library callback/access functions.
+*/
+
+#include "plugins.h"
+#include "cdriso.h"
+#include "../plugins/dfinput/externals.h"
+
+static char IsoFile[MAXPATHLEN] = "";
+static s64 cdOpenCaseTime = 0;
+
+GPUupdateLace         GPU_updateLace;
+GPUinit               GPU_init;
+GPUshutdown           GPU_shutdown;
+GPUconfigure          GPU_configure;
+GPUtest               GPU_test;
+GPUabout              GPU_about;
+GPUopen               GPU_open;
+GPUclose              GPU_close;
+GPUreadStatus         GPU_readStatus;
+GPUreadData           GPU_readData;
+GPUreadDataMem        GPU_readDataMem;
+GPUwriteStatus        GPU_writeStatus;
+GPUwriteData          GPU_writeData;
+GPUwriteDataMem       GPU_writeDataMem;
+GPUdmaChain           GPU_dmaChain;
+GPUkeypressed         GPU_keypressed;
+GPUdisplayText        GPU_displayText;
+GPUmakeSnapshot       GPU_makeSnapshot;
+GPUfreeze             GPU_freeze;
+GPUgetScreenPic       GPU_getScreenPic;
+GPUshowScreenPic      GPU_showScreenPic;
+GPUclearDynarec       GPU_clearDynarec;
+GPUvBlank             GPU_vBlank;
+
+CDRinit               CDR_init;
+CDRshutdown           CDR_shutdown;
+CDRopen               CDR_open;
+CDRclose              CDR_close;
+CDRtest               CDR_test;
+CDRgetTN              CDR_getTN;
+CDRgetTD              CDR_getTD;
+CDRreadTrack          CDR_readTrack;
+CDRgetBuffer          CDR_getBuffer;
+CDRplay               CDR_play;
+CDRstop               CDR_stop;
+CDRgetStatus          CDR_getStatus;
+CDRgetDriveLetter     CDR_getDriveLetter;
+CDRgetBufferSub       CDR_getBufferSub;
+CDRconfigure          CDR_configure;
+CDRabout              CDR_about;
+CDRsetfilename        CDR_setfilename;
+CDRreadCDDA           CDR_readCDDA;
+CDRgetTE              CDR_getTE;
+
+SPUconfigure          SPU_configure;
+SPUabout              SPU_about;
+SPUinit               SPU_init;
+SPUshutdown           SPU_shutdown;
+SPUtest               SPU_test;
+SPUopen               SPU_open;
+SPUclose              SPU_close;
+SPUplaySample         SPU_playSample;
+SPUwriteRegister      SPU_writeRegister;
+SPUreadRegister       SPU_readRegister;
+SPUwriteDMA           SPU_writeDMA;
+SPUreadDMA            SPU_readDMA;
+SPUwriteDMAMem        SPU_writeDMAMem;
+SPUreadDMAMem         SPU_readDMAMem;
+SPUplayADPCMchannel   SPU_playADPCMchannel;
+SPUfreeze             SPU_freeze;
+SPUregisterCallback   SPU_registerCallback;
+SPUregisterScheduleCb SPU_registerScheduleCb;
+SPUasync              SPU_async;
+SPUplayCDDAchannel    SPU_playCDDAchannel;
+
+PADconfigure          PAD1_configure;
+PADabout              PAD1_about;
+PADinit               PAD1_init;
+PADshutdown           PAD1_shutdown;
+PADtest               PAD1_test;
+PADopen               PAD1_open;
+PADclose              PAD1_close;
+PADquery              PAD1_query;
+PADreadPort1          PAD1_readPort1;
+PADkeypressed         PAD1_keypressed;
+PADstartPoll          PAD1_startPoll;
+PADpoll               PAD1_poll;
+PADsetSensitive       PAD1_setSensitive;
+
+PADconfigure          PAD2_configure;
+PADabout              PAD2_about;
+PADinit               PAD2_init;
+PADshutdown           PAD2_shutdown;
+PADtest               PAD2_test;
+PADopen               PAD2_open;
+PADclose              PAD2_close;
+PADquery              PAD2_query;
+PADreadPort2          PAD2_readPort2;
+PADkeypressed         PAD2_keypressed;
+PADstartPoll          PAD2_startPoll;
+PADpoll               PAD2_poll;
+PADsetSensitive       PAD2_setSensitive;
+
+NETinit               NET_init;
+NETshutdown           NET_shutdown;
+NETopen               NET_open;
+NETclose              NET_close;
+NETtest               NET_test;
+NETconfigure          NET_configure;
+NETabout              NET_about;
+NETpause              NET_pause;
+NETresume             NET_resume;
+NETqueryPlayer        NET_queryPlayer;
+NETsendData           NET_sendData;
+NETrecvData           NET_recvData;
+NETsendPadData        NET_sendPadData;
+NETrecvPadData        NET_recvPadData;
+NETsetInfo            NET_setInfo;
+NETkeypressed         NET_keypressed;
+
+#ifdef ENABLE_SIO1API
+
+SIO1init              SIO1_init;
+SIO1shutdown          SIO1_shutdown;
+SIO1open              SIO1_open;
+SIO1close             SIO1_close;
+SIO1test              SIO1_test;
+SIO1configure         SIO1_configure;
+SIO1about             SIO1_about;
+SIO1pause             SIO1_pause;
+SIO1resume            SIO1_resume;
+SIO1keypressed        SIO1_keypressed;
+SIO1writeData8        SIO1_writeData8;
+SIO1writeData16       SIO1_writeData16;
+SIO1writeData32       SIO1_writeData32;
+SIO1writeStat16       SIO1_writeStat16;
+SIO1writeStat32       SIO1_writeStat32;
+SIO1writeMode16       SIO1_writeMode16;
+SIO1writeMode32       SIO1_writeMode32;
+SIO1writeCtrl16       SIO1_writeCtrl16;
+SIO1writeCtrl32       SIO1_writeCtrl32;
+SIO1writeBaud16       SIO1_writeBaud16;
+SIO1writeBaud32       SIO1_writeBaud32;
+SIO1readData8         SIO1_readData8;
+SIO1readData16        SIO1_readData16;
+SIO1readData32        SIO1_readData32;
+SIO1readStat16        SIO1_readStat16;
+SIO1readStat32        SIO1_readStat32;
+SIO1readMode16        SIO1_readMode16;
+SIO1readMode32        SIO1_readMode32;
+SIO1readCtrl16        SIO1_readCtrl16;
+SIO1readCtrl32        SIO1_readCtrl32;
+SIO1readBaud16        SIO1_readBaud16;
+SIO1readBaud32        SIO1_readBaud32;
+SIO1registerCallback  SIO1_registerCallback;
+
+#endif
+
+static const char *err;
+
+#define CheckErr(func) { \
+       err = SysLibError(); \
+       if (err != NULL) { SysMessage(_("Error loading %s: %s"), func, err); return -1; } \
+}
+
+#define LoadSym(dest, src, name, checkerr) { \
+       dest = (src)SysLoadSym(drv, name); \
+       if (checkerr) { CheckErr(name); } else SysLibError(); \
+}
+
+void *hGPUDriver = NULL;
+
+void CALLBACK GPU__displayText(char *pText) {
+       SysPrintf("%s\n", pText);
+}
+
+long CALLBACK GPU__configure(void) { return 0; }
+long CALLBACK GPU__test(void) { return 0; }
+void CALLBACK GPU__about(void) {}
+void CALLBACK GPU__makeSnapshot(void) {}
+void CALLBACK GPU__keypressed(int key) {}
+long CALLBACK GPU__getScreenPic(unsigned char *pMem) { return -1; }
+long CALLBACK GPU__showScreenPic(unsigned char *pMem) { return -1; }
+void CALLBACK GPU__clearDynarec(void (CALLBACK *callback)(void)) {}
+void CALLBACK GPU__vBlank(int val) {}
+
+#define LoadGpuSym1(dest, name) \
+       LoadSym(GPU_##dest, GPU##dest, name, TRUE);
+
+#define LoadGpuSym0(dest, name) \
+       LoadSym(GPU_##dest, GPU##dest, name, FALSE); \
+       if (GPU_##dest == NULL) GPU_##dest = (GPU##dest) GPU__##dest;
+
+#define LoadGpuSymN(dest, name) \
+       LoadSym(GPU_##dest, GPU##dest, name, FALSE);
+
+static int LoadGPUplugin(const char *GPUdll) {
+       void *drv;
+
+       hGPUDriver = SysLoadLibrary(GPUdll);
+       if (hGPUDriver == NULL) {
+               GPU_configure = NULL;
+               SysMessage (_("Could not load GPU plugin %s!"), GPUdll); return -1;
+       }
+       drv = hGPUDriver;
+       LoadGpuSym1(init, "GPUinit");
+       LoadGpuSym1(shutdown, "GPUshutdown");
+       LoadGpuSym1(open, "GPUopen");
+       LoadGpuSym1(close, "GPUclose");
+       LoadGpuSym1(readData, "GPUreadData");
+       LoadGpuSym1(readDataMem, "GPUreadDataMem");
+       LoadGpuSym1(readStatus, "GPUreadStatus");
+       LoadGpuSym1(writeData, "GPUwriteData");
+       LoadGpuSym1(writeDataMem, "GPUwriteDataMem");
+       LoadGpuSym1(writeStatus, "GPUwriteStatus");
+       LoadGpuSym1(dmaChain, "GPUdmaChain");
+       LoadGpuSym1(updateLace, "GPUupdateLace");
+       LoadGpuSym0(keypressed, "GPUkeypressed");
+       LoadGpuSym0(displayText, "GPUdisplayText");
+       LoadGpuSym0(makeSnapshot, "GPUmakeSnapshot");
+       LoadGpuSym1(freeze, "GPUfreeze");
+       LoadGpuSym0(getScreenPic, "GPUgetScreenPic");
+       LoadGpuSym0(showScreenPic, "GPUshowScreenPic");
+       LoadGpuSym0(clearDynarec, "GPUclearDynarec");
+       LoadGpuSym0(vBlank, "GPUvBlank");
+       LoadGpuSym0(configure, "GPUconfigure");
+       LoadGpuSym0(test, "GPUtest");
+       LoadGpuSym0(about, "GPUabout");
+
+       return 0;
+}
+
+void *hCDRDriver = NULL;
+
+long CALLBACK CDR__play(unsigned char *sector) { return 0; }
+long CALLBACK CDR__stop(void) { return 0; }
+
+long CALLBACK CDR__getStatus(struct CdrStat *stat) {
+       if (cdOpenCaseTime < 0 || cdOpenCaseTime > (s64)time(NULL))
+               stat->Status = 0x10;
+       else
+               stat->Status = 0;
+
+       return 0;
+}
+
+char* CALLBACK CDR__getDriveLetter(void) { return NULL; }
+long CALLBACK CDR__configure(void) { return 0; }
+long CALLBACK CDR__test(void) { return 0; }
+void CALLBACK CDR__about(void) {}
+long CALLBACK CDR__setfilename(char*filename) { return 0; }
+
+#define LoadCdrSym1(dest, name) \
+       LoadSym(CDR_##dest, CDR##dest, name, TRUE);
+
+#define LoadCdrSym0(dest, name) \
+       LoadSym(CDR_##dest, CDR##dest, name, FALSE); \
+       if (CDR_##dest == NULL) CDR_##dest = (CDR##dest) CDR__##dest;
+
+#define LoadCdrSymN(dest, name) \
+       LoadSym(CDR_##dest, CDR##dest, name, FALSE);
+
+static int LoadCDRplugin(const char *CDRdll) {
+       void *drv;
+
+       if (CDRdll == NULL) {
+               cdrIsoInit();
+               return 0;
+       }
+
+       hCDRDriver = SysLoadLibrary(CDRdll);
+       if (hCDRDriver == NULL) {
+               CDR_configure = NULL;
+               SysMessage (_("Could not load CD-ROM plugin %s!"), CDRdll);  return -1;
+       }
+       drv = hCDRDriver;
+       LoadCdrSym1(init, "CDRinit");
+       LoadCdrSym1(shutdown, "CDRshutdown");
+       LoadCdrSym1(open, "CDRopen");
+       LoadCdrSym1(close, "CDRclose");
+       LoadCdrSym1(getTN, "CDRgetTN");
+       LoadCdrSym1(getTD, "CDRgetTD");
+       LoadCdrSym1(readTrack, "CDRreadTrack");
+       LoadCdrSym1(getBuffer, "CDRgetBuffer");
+       LoadCdrSym1(getBufferSub, "CDRgetBufferSub");
+       LoadCdrSym0(play, "CDRplay");
+       LoadCdrSym0(stop, "CDRstop");
+       LoadCdrSym0(getStatus, "CDRgetStatus");
+       LoadCdrSym0(getDriveLetter, "CDRgetDriveLetter");
+       LoadCdrSym0(configure, "CDRconfigure");
+       LoadCdrSym0(test, "CDRtest");
+       LoadCdrSym0(about, "CDRabout");
+       LoadCdrSym0(setfilename, "CDRsetfilename");
+       LoadCdrSymN(readCDDA, "CDRreadCDDA");
+       LoadCdrSymN(getTE, "CDRgetTE");
+
+       return 0;
+}
+
+void *hSPUDriver = NULL;
+
+long CALLBACK SPU__configure(void) { return 0; }
+void CALLBACK SPU__about(void) {}
+long CALLBACK SPU__test(void) { return 0; }
+void CALLBACK SPU__registerScheduleCb(void (CALLBACK *cb)(unsigned int)) {}
+
+#define LoadSpuSym1(dest, name) \
+       LoadSym(SPU_##dest, SPU##dest, name, TRUE);
+
+#define LoadSpuSym0(dest, name) \
+       LoadSym(SPU_##dest, SPU##dest, name, FALSE); \
+       if (SPU_##dest == NULL) SPU_##dest = (SPU##dest) SPU__##dest;
+
+#define LoadSpuSymN(dest, name) \
+       LoadSym(SPU_##dest, SPU##dest, name, FALSE);
+
+static int LoadSPUplugin(const char *SPUdll) {
+       void *drv;
+
+       hSPUDriver = SysLoadLibrary(SPUdll);
+       if (hSPUDriver == NULL) {
+               SPU_configure = NULL;
+               SysMessage (_("Could not load SPU plugin %s!"), SPUdll); return -1;
+       }
+       drv = hSPUDriver;
+       LoadSpuSym1(init, "SPUinit");
+       LoadSpuSym1(shutdown, "SPUshutdown");
+       LoadSpuSym1(open, "SPUopen");
+       LoadSpuSym1(close, "SPUclose");
+       LoadSpuSym0(configure, "SPUconfigure");
+       LoadSpuSym0(about, "SPUabout");
+       LoadSpuSym0(test, "SPUtest");
+       LoadSpuSym1(writeRegister, "SPUwriteRegister");
+       LoadSpuSym1(readRegister, "SPUreadRegister");
+       LoadSpuSym1(writeDMA, "SPUwriteDMA");
+       LoadSpuSym1(readDMA, "SPUreadDMA");
+       LoadSpuSym1(writeDMAMem, "SPUwriteDMAMem");
+       LoadSpuSym1(readDMAMem, "SPUreadDMAMem");
+       LoadSpuSym1(playADPCMchannel, "SPUplayADPCMchannel");
+       LoadSpuSym1(freeze, "SPUfreeze");
+       LoadSpuSym1(registerCallback, "SPUregisterCallback");
+       LoadSpuSym0(registerScheduleCb, "SPUregisterScheduleCb");
+       LoadSpuSymN(async, "SPUasync");
+       LoadSpuSymN(playCDDAchannel, "SPUplayCDDAchannel");
+
+       return 0;
+}
+
+extern int in_type[8];
+
+void *hPAD1Driver = NULL;
+void *hPAD2Driver = NULL;
+
+static int multitap1 = -1;
+static int multitap2 = -1;
+//Pad information, keystate, mode, config mode, vibration
+static PadDataS pad[8];
+
+static int reqPos, respSize, req;
+static int ledStateReq44[8];
+static int PadMode[8]; /* 0 : digital 1: analog */
+
+static unsigned char buf[256];
+static unsigned char bufMulti[34] = { 0x80, 0x5a,
+                                                                       0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                                                       0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                                                       0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                                                       0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+unsigned char stdpar[8] = { 0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+unsigned char multitappar[34] = { 0x80, 0x5a,
+                                                                       0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                                                       0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                                                       0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                                                       0x41, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+//response for request 44, 45, 46, 47, 4C, 4D
+static unsigned char resp45[8]    = {0xF3, 0x5A, 0x01, 0x02, 0x00, 0x02, 0x01, 0x00};
+static unsigned char resp46_00[8] = {0xF3, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A};
+static unsigned char resp46_01[8] = {0xF3, 0x5A, 0x00, 0x00, 0x01, 0x01, 0x01, 0x14};
+static unsigned char resp47[8]    = {0xF3, 0x5A, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00};
+static unsigned char resp4C_00[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00};
+static unsigned char resp4C_01[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00};
+static unsigned char resp4D[8]    = {0xF3, 0x5A, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF};
+
+//fixed reponse of request number 41, 48, 49, 4A, 4B, 4E, 4F
+static unsigned char resp40[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static unsigned char resp41[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static unsigned char resp43[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static unsigned char resp44[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static unsigned char resp49[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static unsigned char resp4A[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static unsigned char resp4B[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static unsigned char resp4E[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static unsigned char resp4F[8] = {0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+// Resquest of psx core
+enum {
+       // REQUEST
+       // first call of this request for the pad, the pad is configured as an digital pad.
+       // 0x0X, 0x42, 0x0Y, 0xZZ, 0xAA, 0x00, 0x00, 0x00, 0x00
+       // X pad number (used for the multitap, first request response 0x00, 0x80, 0x5A, (8 bytes pad A), (8 bytes pad B), (8 bytes pad C), (8 bytes pad D)
+       // Y if 1 : psx request the full length response for the multitap, 3 bytes header and 4 block of 8 bytes per pad
+       // Y if 0 : psx request a pad key state
+       // ZZ rumble small motor 00-> OFF, 01 -> ON
+       // AA rumble large motor speed 0x00 -> 0xFF
+       // RESPONSE
+       // header 3 Bytes
+       // 0x00
+       // PadId -> 0x41 for digital pas, 0x73 for analog pad
+       // 0x5A mode has not change (no press on analog button on the center of pad), 0x00 the analog button have been pressed and the mode switch
+       // 6 Bytes for keystates
+       CMD_READ_DATA_AND_VIBRATE = 0x42,
+
+       // REQUEST
+       // Header
+       // 0x0N, 0x43, 0x00, XX, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       // XX = 00 -> Normal mode : Seconde bytes of response = padId
+       // XX = 01 -> Configuration mode : Seconde bytes of response = 0xF3
+       // RESPONSE
+       // enter in config mode example :
+       // req : 01 43 00 01 00 00 00 00 00 00
+       // res : 00 41 5A buttons state, analog states
+       // exit config mode :
+       // req : 01 43 00 00 00 00 00 00 00 00
+       // res : 00 F3 5A buttons state, analog states
+       CMD_CONFIG_MODE = 0x43,
+
+       // Set led State
+       // REQUEST
+       // 0x0N, 0x44, 0x00, VAL, SEL, 0x00, 0x00, 0x00, 0x00
+       // If sel = 2 then
+       // VAL = 00 -> OFF
+       // VAL = 01 -> ON
+       // RESPONSE
+       // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       CMD_SET_MODE_AND_LOCK = 0x44,
+
+       // Get Analog Led state
+       // REQUEST
+       // 0x0N, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       // RESPONSE
+       // 0x00, 0xF3, 0x5A, 0x01, 0x02, VAL, 0x02, 0x01, 0x00
+       // VAL = 00 Led OFF
+       // VAL = 01 Led ON
+       CMD_QUERY_MODEL_AND_MODE = 0x45,
+
+       //Get Variable A
+       // REQUEST
+       // 0x0N, 0x46, 0x00, 0xXX, 0x00, 0x00, 0x00, 0x00, 0x00
+       // RESPONSE
+       // XX=00
+       // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A
+       // XX=01
+       // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x01, 0x01, 0x01, 0x14
+       CMD_QUERY_ACT = 0x46,
+
+       // REQUEST
+       // 0x0N, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       // RESPONSE
+       // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00
+       CMD_QUERY_COMB = 0x47,
+
+       // REQUEST
+       // 0x0N, 0x4C, 0x00, 0xXX, 0x00, 0x00, 0x00, 0x00, 0x00
+       // RESPONSE
+       // XX = 0
+       // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00
+       // XX = 1
+       // 0x00, 0xF3, 0x5A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00
+       CMD_QUERY_MODE = 0x4C,
+
+       // REQUEST
+       // 0x0N, 0x4D, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
+       // RESPONSE
+       // 0x00, 0xF3, 0x5A, old value or
+       // AA = 01 unlock large motor (and swap VAL1 and VAL2)
+       // BB = 01 unlock large motor (default)
+       // CC, DD, EE, FF = all FF -> unlock small motor
+       //
+       // default repsonse for analog pad with 2 motor : 0x00 0xF3 0x5A 0x00 0x01 0xFF 0xFF 0xFF 0xFF
+       //
+       CMD_VIBRATION_TOGGLE = 0x4D,
+       REQ40 = 0x40,
+       REQ41 = 0x41,
+       REQ49 = 0x49,
+       REQ4A = 0x4A,
+       REQ4B = 0x4B,
+       REQ4E = 0x4E,
+       REQ4F = 0x4F
+};
+
+
+
+
+//NO MULTITAP
+
+void initBufForRequest(int padIndex, char value){
+       switch (value){
+               //Pad keystate already in buffer
+               //case CMD_READ_DATA_AND_VIBRATE :
+               //      break;
+               case CMD_CONFIG_MODE :
+                       if (pad[padIndex].configMode == 1) {
+                               memcpy(buf, resp43, 8);
+                               break;
+                       }
+                       //else, not in config mode, pad keystate return (already in the buffer)
+                       break;
+               case CMD_SET_MODE_AND_LOCK :
+                       memcpy(buf, resp44, 8);
+                       break;
+               case CMD_QUERY_MODEL_AND_MODE :
+                       memcpy(buf, resp45, 8);
+                       buf[4] = PadMode[padIndex];
+                       break;
+               case CMD_QUERY_ACT :
+                       memcpy(buf, resp46_00, 8);
+                       break;
+               case CMD_QUERY_COMB :
+                       memcpy(buf, resp47, 8);
+                       break;
+               case CMD_QUERY_MODE :
+                       memcpy(buf, resp4C_00, 8);
+                       break;
+               case CMD_VIBRATION_TOGGLE :
+                       memcpy(buf, resp4D, 8);
+                       break;
+               case REQ40 :
+                       memcpy(buf, resp40, 8);
+                       break;
+               case REQ41 :
+                       memcpy(buf, resp41, 8);
+                       break;
+               case REQ49 :
+                       memcpy(buf, resp49, 8);
+                       break;
+               case REQ4A :
+                       memcpy(buf, resp4A, 8);
+                       break;
+               case REQ4B :
+                       memcpy(buf, resp4B, 8);
+                       break;
+               case REQ4E :
+                       memcpy(buf, resp4E, 8);
+                       break;
+               case REQ4F :
+                       memcpy(buf, resp4F, 8);
+                       break;
+       }
+}
+
+
+
+
+void reqIndex2Treatment(int padIndex, char value){
+       switch (req){
+               case CMD_CONFIG_MODE :
+                       //0x43
+                       if (value == 0) {
+                               pad[padIndex].configMode = 0;
+                       } else {
+                               pad[padIndex].configMode = 1;
+                       }
+                       break;
+               case CMD_SET_MODE_AND_LOCK :
+                       //0x44 store the led state for change mode if the next value = 0x02
+                       //0x01 analog ON
+                       //0x00 analog OFF
+                       ledStateReq44[padIndex] = value;
+                       PadMode[padIndex] = value;
+                       break;
+               case CMD_QUERY_ACT :
+                       //0x46
+                       if (value == 1) {
+                               memcpy(buf, resp46_01, 8);
+                       }
+                       break;
+               case CMD_QUERY_MODE :
+                       if (value == 1) {
+                               memcpy(buf, resp4C_01, 8);
+                       }
+                       break;
+               case CMD_VIBRATION_TOGGLE :
+                       //0x4D
+                       memcpy(buf, resp4D, 8);
+                       break;
+               case CMD_READ_DATA_AND_VIBRATE:
+                       //mem the vibration value for small motor;
+                       pad[padIndex].Vib[0] = value;
+                       break;
+       }
+}
+
+void vibrate(int padIndex){
+       if (pad[padIndex].Vib[0] != pad[padIndex].VibF[0] || pad[padIndex].Vib[1] != pad[padIndex].VibF[1]) {
+               //value is different update Value and call libretro for vibration
+               pad[padIndex].VibF[0] = pad[padIndex].Vib[0];
+               pad[padIndex].VibF[1] = pad[padIndex].Vib[1];
+               plat_trigger_vibrate(padIndex, pad[padIndex].VibF[0], pad[padIndex].VibF[1]);
+               //printf("vibration pad %i", padIndex);
+       }
+}
+
+
+
+
+//Build response for 0x42 request Pad in port
+void _PADstartPoll(PadDataS *pad) {
+       switch (pad->controllerType) {
+               case PSE_PAD_TYPE_MOUSE:
+                       stdpar[0] = 0x12;
+                       stdpar[1] = 0x5a;
+                       stdpar[2] = pad->buttonStatus & 0xff;
+                       stdpar[3] = pad->buttonStatus >> 8;
+                       stdpar[4] = pad->moveX;
+                       stdpar[5] = pad->moveY;
+                       memcpy(buf, stdpar, 6);
+                       respSize = 6;
+                       break;
+               case PSE_PAD_TYPE_NEGCON: // npc101/npc104(slph00001/slph00069)
+                       stdpar[0] = 0x23;
+                       stdpar[1] = 0x5a;
+                       stdpar[2] = pad->buttonStatus & 0xff;
+                       stdpar[3] = pad->buttonStatus >> 8;
+                       stdpar[4] = pad->rightJoyX;
+                       stdpar[5] = pad->rightJoyY;
+                       stdpar[6] = pad->leftJoyX;
+                       stdpar[7] = pad->leftJoyY;
+                       memcpy(buf, stdpar, 8);
+                       respSize = 8;
+                       break;
+       case PSE_PAD_TYPE_GUNCON: // GUNCON - gun controller SLPH-00034 from Namco
+                       stdpar[0] = 0x63;
+                       stdpar[1] = 0x5a;
+                       stdpar[2] = pad->buttonStatus & 0xff;
+                       stdpar[3] = pad->buttonStatus >> 8;
+
+                       //This code assumes an X resolution of 256 and a Y resolution of 240
+                       int xres = 256;
+                       int yres = 240;
+
+                       //The code wants an input range for x and y of 0-1023 we passed in -32767 -> 32767
+                       int absX = (pad->absoluteX / 64) + 512;
+                       int absY = (pad->absoluteY / 64) + 512;
+
+                       //Keep within limits
+                       if (absX > 1023) absX = 1023;
+                       if (absX < 0) absX = 0;
+                       if (absY > 1023) absY = 1023;
+                       if (absY < 0) absY = 0;
+
+                       stdpar[4] = 0x5a - (xres - 256) / 3 + (((xres - 256) / 3 + 356) * absX >> 10);
+                       stdpar[5] = (0x5a - (xres - 256) / 3 + (((xres - 256) / 3 + 356) * absX >> 10)) >> 8;
+                       stdpar[6] = 0x20 + (yres * absY >> 10);
+                       stdpar[7] = (0x20 + (yres * absY >> 10)) >> 8;
+
+                       //Offscreen - Point at the side of the screen so PSX thinks you are pointing offscreen
+                       //Required as a mouse can't be offscreen
+                       //Coordinates X=0001h, Y=000Ah indicates "no light"
+                       //This will mean you cannot shoot the very each of the screen
+                       //ToDo read offscreen range from settings if useful to change
+                       int OffscreenRange = 2;
+                       if (absX < (OffscreenRange) || absX > (1023 - OffscreenRange) || absY < (OffscreenRange) || absY > (1023 - OffscreenRange)) {
+                               stdpar[4] = 0x01;
+                               stdpar[5] = 0x00;
+                               stdpar[6] = 0x0A;
+                               stdpar[7] = 0x00;
+                       }
+
+                       memcpy(buf, stdpar, 8);
+                       respSize = 8;
+                       break;
+               case PSE_PAD_TYPE_ANALOGPAD: // scph1150
+                       stdpar[0] = 0x73;
+                       stdpar[1] = 0x5a;
+                       stdpar[2] = pad->buttonStatus & 0xff;
+                       stdpar[3] = pad->buttonStatus >> 8;
+                       stdpar[4] = pad->rightJoyX;
+                       stdpar[5] = pad->rightJoyY;
+                       stdpar[6] = pad->leftJoyX;
+                       stdpar[7] = pad->leftJoyY;
+                       memcpy(buf, stdpar, 8);
+                       respSize = 8;
+                       break;
+               case PSE_PAD_TYPE_ANALOGJOY: // scph1110
+                       stdpar[0] = 0x53;
+                       stdpar[1] = 0x5a;
+                       stdpar[2] = pad->buttonStatus & 0xff;
+                       stdpar[3] = pad->buttonStatus >> 8;
+                       stdpar[4] = pad->rightJoyX;
+                       stdpar[5] = pad->rightJoyY;
+                       stdpar[6] = pad->leftJoyX;
+                       stdpar[7] = pad->leftJoyY;
+                       memcpy(buf, stdpar, 8);
+                       respSize = 8;
+                       break;
+               case PSE_PAD_TYPE_STANDARD:
+                       stdpar[0] = 0x41;
+                       stdpar[1] = 0x5a;
+                       stdpar[2] = pad->buttonStatus & 0xff;
+                       stdpar[3] = pad->buttonStatus >> 8;
+                       //avoid analog value in multitap mode if change pad type in game.
+                       stdpar[4] = 0xff;
+                       stdpar[5] = 0xff;
+                       stdpar[6] = 0xff;
+                       stdpar[7] = 0xff;
+                       memcpy(buf, stdpar, 8);
+                       respSize = 8;
+                       break;
+               default:
+                       stdpar[0] = 0xff;
+                       stdpar[1] = 0xff;
+                       stdpar[2] = 0xff;
+                       stdpar[3] = 0xff;
+                       stdpar[4] = 0xff;
+                       stdpar[5] = 0xff;
+                       stdpar[6] = 0xff;
+                       stdpar[7] = 0xff;
+                       memcpy(buf, stdpar, 8);
+                       respSize = 8;
+                       break;
+       }
+}
+
+
+//Build response for 0x42 request Multitap in port
+//Response header for multitap : 0x80, 0x5A, (Pad information port 1-2A), (Pad information port 1-2B), (Pad information port 1-2C), (Pad information port 1-2D)
+void _PADstartPollMultitap(PadDataS* padd) {
+       int i, offset;
+       for(i = 0; i < 4; i++) {
+               offset = 2 + (i * 8);
+       _PADstartPoll(&padd[i]);
+       memcpy(multitappar+offset, stdpar, 8);
+       }
+       memcpy(bufMulti, multitappar, 34);
+       respSize = 34;
+}
+
+
+unsigned char _PADpoll(int port, unsigned char value) {
+       if (reqPos == 0) {
+               //mem the request number
+               req = value;
+
+               // Don't enable Analog/Vibration for a standard pad
+               if (in_type[port] == PSE_PAD_TYPE_STANDARD ||
+                       in_type[port] == PSE_PAD_TYPE_NEGCON) {
+                       ; // Pad keystate already in buffer
+               }
+               else
+               {
+                       //copy the default value of request response in buffer instead of the keystate
+                       initBufForRequest(port, value);
+               }
+       }
+
+       //if no new request the pad return 0xff, for signaling connected
+       if (reqPos >= respSize) return 0xff;
+
+       switch(reqPos){
+               case 2:
+                       reqIndex2Treatment(port, value);
+               break;
+               case 3:
+                       switch(req) {
+                               case CMD_SET_MODE_AND_LOCK :
+                                       //change mode on pad
+                               break;
+                               case CMD_READ_DATA_AND_VIBRATE:
+                               //mem the vibration value for Large motor;
+                               pad[port].Vib[1] = value;
+
+                               if (in_type[port] == PSE_PAD_TYPE_STANDARD &&
+                                       in_type[port] == PSE_PAD_TYPE_NEGCON)
+                                       break;
+
+                               //vibration
+                               vibrate(port);
+                               break;
+                       }
+               break;
+       }
+       return buf[reqPos++];
+}
+
+
+unsigned char _PADpollMultitap(int port, unsigned char value) {
+       if (reqPos >= respSize) return 0xff;
+       return bufMulti[reqPos++];
+}
+
+
+// refresh the button state on port 1.
+// int pad is not needed.
+unsigned char CALLBACK PAD1__startPoll(int pad) {
+       reqPos = 0;
+       // first call the pad provide if a multitap is connected between the psx and himself
+       if (multitap1 == -1) {
+               PadDataS padd;
+               padd.requestPadIndex = 0;
+               PAD1_readPort1(&padd);
+               multitap1 = padd.portMultitap;
+       }
+       // just one pad is on port 1 : NO MULTITAP
+       if (multitap1 == 0) {
+               PadDataS padd;
+               padd.requestPadIndex = 0;
+               PAD1_readPort1(&padd);
+               _PADstartPoll(&padd);
+       } else {
+               // a multitap is plugged : refresh all pad.
+               int i;
+               PadDataS padd[4];
+               for(i = 0; i < 4; i++) {
+                       padd[i].requestPadIndex = i;
+                       PAD1_readPort1(&padd[i]);
+               }
+               _PADstartPollMultitap(padd);
+       }
+       //printf("\npad 1 : ");
+       return 0x00;
+}
+
+unsigned char CALLBACK PAD1__poll(unsigned char value) {
+       char tmp;
+       if (multitap1 == 1) {
+               tmp = _PADpollMultitap(0, value);
+       } else {
+               tmp = _PADpoll(0, value);
+       }
+       //printf("%2x:%2x, ",value,tmp);
+       return tmp;
+
+}
+
+
+long CALLBACK PAD1__configure(void) { return 0; }
+void CALLBACK PAD1__about(void) {}
+long CALLBACK PAD1__test(void) { return 0; }
+long CALLBACK PAD1__query(void) { return 3; }
+long CALLBACK PAD1__keypressed() { return 0; }
+
+#define LoadPad1Sym1(dest, name) \
+       LoadSym(PAD1_##dest, PAD##dest, name, TRUE);
+
+#define LoadPad1SymN(dest, name) \
+       LoadSym(PAD1_##dest, PAD##dest, name, FALSE);
+
+#define LoadPad1Sym0(dest, name) \
+       LoadSym(PAD1_##dest, PAD##dest, name, FALSE); \
+       if (PAD1_##dest == NULL) PAD1_##dest = (PAD##dest) PAD1__##dest;
+
+static int LoadPAD1plugin(const char *PAD1dll) {
+       void *drv;
+
+       hPAD1Driver = SysLoadLibrary(PAD1dll);
+       if (hPAD1Driver == NULL) {
+               PAD1_configure = NULL;
+               SysMessage (_("Could not load Controller 1 plugin %s!"), PAD1dll); return -1;
+       }
+       drv = hPAD1Driver;
+       LoadPad1Sym1(init, "PADinit");
+       LoadPad1Sym1(shutdown, "PADshutdown");
+       LoadPad1Sym1(open, "PADopen");
+       LoadPad1Sym1(close, "PADclose");
+       LoadPad1Sym0(query, "PADquery");
+       LoadPad1Sym1(readPort1, "PADreadPort1");
+       LoadPad1Sym0(configure, "PADconfigure");
+       LoadPad1Sym0(test, "PADtest");
+       LoadPad1Sym0(about, "PADabout");
+       LoadPad1Sym0(keypressed, "PADkeypressed");
+       LoadPad1Sym0(startPoll, "PADstartPoll");
+       LoadPad1Sym0(poll, "PADpoll");
+       LoadPad1SymN(setSensitive, "PADsetSensitive");
+
+       return 0;
+}
+
+unsigned char CALLBACK PAD2__startPoll(int pad) {
+       int pad_index;
+
+       reqPos = 0;
+       if (multitap1 == 0 && (multitap2 == 0 || multitap2 == 2)) {
+               pad_index = 1;
+       } else if(multitap1 == 1 && (multitap2 == 0 || multitap2 == 2)) {
+               pad_index = 4;
+       } else {
+               pad_index = 0;
+       }
+
+       //first call the pad provide if a multitap is connected between the psx and himself
+       if (multitap2 == -1) {
+               PadDataS padd;
+               padd.requestPadIndex = pad_index;
+               PAD2_readPort2(&padd);
+               multitap2 = padd.portMultitap;
+       }
+
+       // just one pad is on port 1 : NO MULTITAP
+       if (multitap2 == 0) {
+               PadDataS padd;
+               padd.requestPadIndex = pad_index;
+               PAD2_readPort2(&padd);
+               _PADstartPoll(&padd);
+       } else {
+               // a multitap is plugged : refresh all pad.
+               int i;
+               PadDataS padd[4];
+               for(i = 0; i < 4; i++) {
+                       padd[i].requestPadIndex = i+pad_index;
+                       PAD2_readPort2(&padd[i]);
+               }
+               _PADstartPollMultitap(padd);
+       }
+       //printf("\npad 2 : ");
+       return 0x00;
+}
+
+unsigned char CALLBACK PAD2__poll(unsigned char value) {
+       char tmp;
+       if (multitap2 == 2) {
+               tmp = _PADpollMultitap(1, value);
+       } else {
+               tmp = _PADpoll(1, value);
+       }
+       //printf("%2x:%2x, ",value,tmp);
+       return tmp;
+}
+
+long CALLBACK PAD2__configure(void) { return 0; }
+void CALLBACK PAD2__about(void) {}
+long CALLBACK PAD2__test(void) { return 0; }
+long CALLBACK PAD2__query(void) { return PSE_PAD_USE_PORT1 | PSE_PAD_USE_PORT2; }
+long CALLBACK PAD2__keypressed() { return 0; }
+
+#define LoadPad2Sym1(dest, name) \
+       LoadSym(PAD2_##dest, PAD##dest, name, TRUE);
+
+#define LoadPad2Sym0(dest, name) \
+       LoadSym(PAD2_##dest, PAD##dest, name, FALSE); \
+       if (PAD2_##dest == NULL) PAD2_##dest = (PAD##dest) PAD2__##dest;
+
+#define LoadPad2SymN(dest, name) \
+       LoadSym(PAD2_##dest, PAD##dest, name, FALSE);
+
+static int LoadPAD2plugin(const char *PAD2dll) {
+       void *drv;
+
+       hPAD2Driver = SysLoadLibrary(PAD2dll);
+       if (hPAD2Driver == NULL) {
+               PAD2_configure = NULL;
+               SysMessage (_("Could not load Controller 2 plugin %s!"), PAD2dll); return -1;
+       }
+       drv = hPAD2Driver;
+       LoadPad2Sym1(init, "PADinit");
+       LoadPad2Sym1(shutdown, "PADshutdown");
+       LoadPad2Sym1(open, "PADopen");
+       LoadPad2Sym1(close, "PADclose");
+       LoadPad2Sym0(query, "PADquery");
+       LoadPad2Sym1(readPort2, "PADreadPort2");
+       LoadPad2Sym0(configure, "PADconfigure");
+       LoadPad2Sym0(test, "PADtest");
+       LoadPad2Sym0(about, "PADabout");
+       LoadPad2Sym0(keypressed, "PADkeypressed");
+       LoadPad2Sym0(startPoll, "PADstartPoll");
+       LoadPad2Sym0(poll, "PADpoll");
+       LoadPad2SymN(setSensitive, "PADsetSensitive");
+
+       return 0;
+}
+
+void *hNETDriver = NULL;
+
+void CALLBACK NET__setInfo(netInfo *info) {}
+void CALLBACK NET__keypressed(int key) {}
+long CALLBACK NET__configure(void) { return 0; }
+long CALLBACK NET__test(void) { return 0; }
+void CALLBACK NET__about(void) {}
+
+#define LoadNetSym1(dest, name) \
+       LoadSym(NET_##dest, NET##dest, name, TRUE);
+
+#define LoadNetSymN(dest, name) \
+       LoadSym(NET_##dest, NET##dest, name, FALSE);
+
+#define LoadNetSym0(dest, name) \
+       LoadSym(NET_##dest, NET##dest, name, FALSE); \
+       if (NET_##dest == NULL) NET_##dest = (NET##dest) NET__##dest;
+
+static int LoadNETplugin(const char *NETdll) {
+       void *drv;
+
+       hNETDriver = SysLoadLibrary(NETdll);
+       if (hNETDriver == NULL) {
+               SysMessage (_("Could not load NetPlay plugin %s!"), NETdll); return -1;
+       }
+       drv = hNETDriver;
+       LoadNetSym1(init, "NETinit");
+       LoadNetSym1(shutdown, "NETshutdown");
+       LoadNetSym1(open, "NETopen");
+       LoadNetSym1(close, "NETclose");
+       LoadNetSymN(sendData, "NETsendData");
+       LoadNetSymN(recvData, "NETrecvData");
+       LoadNetSym1(sendPadData, "NETsendPadData");
+       LoadNetSym1(recvPadData, "NETrecvPadData");
+       LoadNetSym1(queryPlayer, "NETqueryPlayer");
+       LoadNetSym1(pause, "NETpause");
+       LoadNetSym1(resume, "NETresume");
+       LoadNetSym0(setInfo, "NETsetInfo");
+       LoadNetSym0(keypressed, "NETkeypressed");
+       LoadNetSym0(configure, "NETconfigure");
+       LoadNetSym0(test, "NETtest");
+       LoadNetSym0(about, "NETabout");
+
+       return 0;
+}
+
+#ifdef ENABLE_SIO1API
+
+void *hSIO1Driver = NULL;
+
+long CALLBACK SIO1__init(void) { return 0; }
+long CALLBACK SIO1__shutdown(void) { return 0; }
+long CALLBACK SIO1__open(void) { return 0; }
+long CALLBACK SIO1__close(void) { return 0; }
+long CALLBACK SIO1__configure(void) { return 0; }
+long CALLBACK SIO1__test(void) { return 0; }
+void CALLBACK SIO1__about(void) {}
+void CALLBACK SIO1__pause(void) {}
+void CALLBACK SIO1__resume(void) {}
+long CALLBACK SIO1__keypressed(int key) { return 0; }
+void CALLBACK SIO1__writeData8(unsigned char val) {}
+void CALLBACK SIO1__writeData16(unsigned short val) {}
+void CALLBACK SIO1__writeData32(unsigned long val) {}
+void CALLBACK SIO1__writeStat16(unsigned short val) {}
+void CALLBACK SIO1__writeStat32(unsigned long val) {}
+void CALLBACK SIO1__writeMode16(unsigned short val) {}
+void CALLBACK SIO1__writeMode32(unsigned long val) {}
+void CALLBACK SIO1__writeCtrl16(unsigned short val) {}
+void CALLBACK SIO1__writeCtrl32(unsigned long val) {}
+void CALLBACK SIO1__writeBaud16(unsigned short val) {}
+void CALLBACK SIO1__writeBaud32(unsigned long val) {}
+unsigned char CALLBACK SIO1__readData8(void) { return 0; }
+unsigned short CALLBACK SIO1__readData16(void) { return 0; }
+unsigned long CALLBACK SIO1__readData32(void) { return 0; }
+unsigned short CALLBACK SIO1__readStat16(void) { return 0; }
+unsigned long CALLBACK SIO1__readStat32(void) { return 0; }
+unsigned short CALLBACK SIO1__readMode16(void) { return 0; }
+unsigned long CALLBACK SIO1__readMode32(void) { return 0; }
+unsigned short CALLBACK SIO1__readCtrl16(void) { return 0; }
+unsigned long CALLBACK SIO1__readCtrl32(void) { return 0; }
+unsigned short CALLBACK SIO1__readBaud16(void) { return 0; }
+unsigned long CALLBACK SIO1__readBaud32(void) { return 0; }
+void CALLBACK SIO1__registerCallback(void (CALLBACK *callback)(void)) {};
+
+void CALLBACK SIO1irq(void) {
+       psxHu32ref(0x1070) |= SWAPu32(0x100);
+}
+
+#define LoadSio1Sym1(dest, name) \
+       LoadSym(SIO1_##dest, SIO1##dest, name, TRUE);
+
+#define LoadSio1SymN(dest, name) \
+       LoadSym(SIO1_##dest, SIO1##dest, name, FALSE);
+
+#define LoadSio1Sym0(dest, name) \
+       LoadSym(SIO1_##dest, SIO1##dest, name, FALSE); \
+       if (SIO1_##dest == NULL) SIO1_##dest = (SIO1##dest) SIO1__##dest;
+
+static int LoadSIO1plugin(const char *SIO1dll) {
+       void *drv;
+
+       hSIO1Driver = SysLoadLibrary(SIO1dll);
+       if (hSIO1Driver == NULL) {
+               SysMessage (_("Could not load SIO1 plugin %s!"), SIO1dll); return -1;
+       }
+       drv = hSIO1Driver;
+
+       LoadSio1Sym0(init, "SIO1init");
+       LoadSio1Sym0(shutdown, "SIO1shutdown");
+       LoadSio1Sym0(open, "SIO1open");
+       LoadSio1Sym0(close, "SIO1close");
+       LoadSio1Sym0(pause, "SIO1pause");
+       LoadSio1Sym0(resume, "SIO1resume");
+       LoadSio1Sym0(keypressed, "SIO1keypressed");
+       LoadSio1Sym0(configure, "SIO1configure");
+       LoadSio1Sym0(test, "SIO1test");
+       LoadSio1Sym0(about, "SIO1about");
+       LoadSio1Sym0(writeData8, "SIO1writeData8");
+       LoadSio1Sym0(writeData16, "SIO1writeData16");
+       LoadSio1Sym0(writeData32, "SIO1writeData32");
+       LoadSio1Sym0(writeStat16, "SIO1writeStat16");
+       LoadSio1Sym0(writeStat32, "SIO1writeStat32");
+       LoadSio1Sym0(writeMode16, "SIO1writeMode16");
+       LoadSio1Sym0(writeMode32, "SIO1writeMode32");
+       LoadSio1Sym0(writeCtrl16, "SIO1writeCtrl16");
+       LoadSio1Sym0(writeCtrl32, "SIO1writeCtrl32");
+       LoadSio1Sym0(writeBaud16, "SIO1writeBaud16");
+       LoadSio1Sym0(writeBaud32, "SIO1writeBaud32");
+       LoadSio1Sym0(readData16, "SIO1readData16");
+       LoadSio1Sym0(readData32, "SIO1readData32");
+       LoadSio1Sym0(readStat16, "SIO1readStat16");
+       LoadSio1Sym0(readStat32, "SIO1readStat32");
+       LoadSio1Sym0(readMode16, "SIO1readMode16");
+       LoadSio1Sym0(readMode32, "SIO1readMode32");
+       LoadSio1Sym0(readCtrl16, "SIO1readCtrl16");
+       LoadSio1Sym0(readCtrl32, "SIO1readCtrl32");
+       LoadSio1Sym0(readBaud16, "SIO1readBaud16");
+       LoadSio1Sym0(readBaud32, "SIO1readBaud32");
+       LoadSio1Sym0(registerCallback, "SIO1registerCallback");
+
+       return 0;
+}
+
+#endif
+
+void CALLBACK clearDynarec(void) {
+       psxCpu->Reset();
+}
+
+int LoadPlugins() {
+       int ret;
+       char Plugin[MAXPATHLEN * 2];
+
+       ReleasePlugins();
+       SysLibError();
+
+       if (UsingIso()) {
+               LoadCDRplugin(NULL);
+       } else {
+               sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Cdr);
+               if (LoadCDRplugin(Plugin) == -1) return -1;
+       }
+
+       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Gpu);
+       if (LoadGPUplugin(Plugin) == -1) return -1;
+
+       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Spu);
+       if (LoadSPUplugin(Plugin) == -1) return -1;
+
+       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Pad1);
+       if (LoadPAD1plugin(Plugin) == -1) return -1;
+
+       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Pad2);
+       if (LoadPAD2plugin(Plugin) == -1) return -1;
+
+       if (strcmp("Disabled", Config.Net) == 0 || strcmp("", Config.Net) == 0)
+               Config.UseNet = FALSE;
+       else {
+               Config.UseNet = TRUE;
+               sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Net);
+               if (LoadNETplugin(Plugin) == -1) Config.UseNet = FALSE;
+       }
+
+#ifdef ENABLE_SIO1API
+       sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Sio1);
+       if (LoadSIO1plugin(Plugin) == -1) return -1;
+#endif
+
+       ret = CDR_init();
+       if (ret < 0) { SysMessage (_("Error initializing CD-ROM plugin: %d"), ret); return -1; }
+       ret = GPU_init();
+       if (ret < 0) { SysMessage (_("Error initializing GPU plugin: %d"), ret); return -1; }
+       ret = SPU_init();
+       if (ret < 0) { SysMessage (_("Error initializing SPU plugin: %d"), ret); return -1; }
+       ret = PAD1_init(1);
+       if (ret < 0) { SysMessage (_("Error initializing Controller 1 plugin: %d"), ret); return -1; }
+       ret = PAD2_init(2);
+       if (ret < 0) { SysMessage (_("Error initializing Controller 2 plugin: %d"), ret); return -1; }
+
+       if (Config.UseNet) {
+               ret = NET_init();
+               if (ret < 0) { SysMessage (_("Error initializing NetPlay plugin: %d"), ret); return -1; }
+       }
+
+#ifdef ENABLE_SIO1API
+       ret = SIO1_init();
+       if (ret < 0) { SysMessage (_("Error initializing SIO1 plugin: %d"), ret); return -1; }
+#endif
+
+       SysPrintf(_("Plugins loaded.\n"));
+       return 0;
+}
+
+void ReleasePlugins() {
+       if (Config.UseNet) {
+               int ret = NET_close();
+               if (ret < 0) Config.UseNet = FALSE;
+       }
+       NetOpened = FALSE;
+
+       if (hCDRDriver != NULL || cdrIsoActive()) CDR_shutdown();
+       if (hGPUDriver != NULL) GPU_shutdown();
+       if (hSPUDriver != NULL) SPU_shutdown();
+       if (hPAD1Driver != NULL) PAD1_shutdown();
+       if (hPAD2Driver != NULL) PAD2_shutdown();
+
+       if (Config.UseNet && hNETDriver != NULL) NET_shutdown();
+
+       if (hCDRDriver != NULL) { SysCloseLibrary(hCDRDriver); hCDRDriver = NULL; }
+       if (hGPUDriver != NULL) { SysCloseLibrary(hGPUDriver); hGPUDriver = NULL; }
+       if (hSPUDriver != NULL) { SysCloseLibrary(hSPUDriver); hSPUDriver = NULL; }
+       if (hPAD1Driver != NULL) { SysCloseLibrary(hPAD1Driver); hPAD1Driver = NULL; }
+       if (hPAD2Driver != NULL) { SysCloseLibrary(hPAD2Driver); hPAD2Driver = NULL; }
+
+       if (Config.UseNet && hNETDriver != NULL) {
+               SysCloseLibrary(hNETDriver); hNETDriver = NULL;
+       }
+
+#ifdef ENABLE_SIO1API
+       if (hSIO1Driver != NULL) {
+               SIO1_shutdown();
+               SysCloseLibrary(hSIO1Driver);
+               hSIO1Driver = NULL;
+       }
+#endif
+}
+
+// for CD swap
+int ReloadCdromPlugin()
+{
+       if (hCDRDriver != NULL || cdrIsoActive()) CDR_shutdown();
+       if (hCDRDriver != NULL) { SysCloseLibrary(hCDRDriver); hCDRDriver = NULL; }
+
+       if (UsingIso()) {
+               LoadCDRplugin(NULL);
+       } else {
+               char Plugin[MAXPATHLEN * 2];
+               sprintf(Plugin, "%s/%s", Config.PluginsDir, Config.Cdr);
+               if (LoadCDRplugin(Plugin) == -1) return -1;
+       }
+
+       return CDR_init();
+}
+
+void SetIsoFile(const char *filename) {
+       if (filename == NULL) {
+               IsoFile[0] = '\0';
+               return;
+       }
+       strncpy(IsoFile, filename, MAXPATHLEN - 1);
+}
+
+const char *GetIsoFile(void) {
+       return IsoFile;
+}
+
+boolean UsingIso(void) {
+       return (IsoFile[0] != '\0');
+}
+
+void SetCdOpenCaseTime(s64 time) {
+       cdOpenCaseTime = time;
+}
index edebdd0..a76b153 100644 (file)
@@ -183,7 +183,7 @@ void BuildPPFCache() {
        char                    method, undo = 0, blockcheck = 0;
        int                             dizlen, dizyn;
        unsigned char   ppfmem[512];
-       char                    szPPF[MAXPATHLEN];
+       char                    szPPF[MAXPATHLEN * 2];
        int                             count, seekpos, pos;
        u32                             anz; // use 32-bit to avoid stupid overflows
        s32                             ladr, off, anx;
@@ -212,7 +212,8 @@ void BuildPPFCache() {
        if (ppffile == NULL) return;
 
        memset(buffer, 0, 5);
-       fread(buffer, 3, 1, ppffile);
+       if (fread(buffer, 3, 1, ppffile) != 3)
+               goto fail_io;
 
        if (strcmp(buffer, "PPF") != 0) {
                SysPrintf(_("Invalid PPF patch: %s.\n"), szPPF);
@@ -235,12 +236,14 @@ void BuildPPFCache() {
                        fseek(ppffile, -8, SEEK_END);
 
                        memset(buffer, 0, 5);
-                       fread(buffer, 4, 1, ppffile);
+                       if (fread(buffer, 4, 1, ppffile) != 4)
+                               goto fail_io;
 
                        if (strcmp(".DIZ", buffer) != 0) {
                                dizyn = 0;
                        } else {
-                               fread(&dizlen, 4, 1, ppffile);
+                               if (fread(&dizlen, 4, 1, ppffile) != 4)
+                                       goto fail_io;
                                dizlen = SWAP32(dizlen);
                                dizyn = 1;
                        }
@@ -266,12 +269,15 @@ void BuildPPFCache() {
 
                        fseek(ppffile, -6, SEEK_END);
                        memset(buffer, 0, 5);
-                       fread(buffer, 4, 1, ppffile);
+                       if (fread(buffer, 4, 1, ppffile) != 4)
+                               goto fail_io;
                        dizlen = 0;
 
                        if (strcmp(".DIZ", buffer) == 0) {
                                fseek(ppffile, -2, SEEK_END);
-                               fread(&dizlen, 2, 1, ppffile);
+                               // TODO: Endian/size unsafe?
+                               if (fread(&dizlen, 2, 1, ppffile) != 2)
+                                       goto fail_io;
                                dizlen = SWAP32(dizlen);
                                dizlen += 36;
                        }
@@ -298,13 +304,19 @@ void BuildPPFCache() {
        // now do the data reading
        do {                                                
                fseek(ppffile, seekpos, SEEK_SET);
-               fread(&pos, 4, 1, ppffile);
+               if (fread(&pos, sizeof(pos), 1, ppffile) != sizeof(pos))
+                       goto fail_io;
                pos = SWAP32(pos);
 
-               if (method == 2) fread(buffer, 4, 1, ppffile); // skip 4 bytes on ppf3 (no int64 support here)
+               if (method == 2) {
+                       // skip 4 bytes on ppf3 (no int64 support here)
+                       if (fread(buffer, 4, 1, ppffile) != 4)
+                               goto fail_io;
+               }
 
                anz = fgetc(ppffile);
-               fread(ppfmem, anz, 1, ppffile);   
+               if (fread(ppfmem, anz, 1, ppffile) != anz)
+                       goto fail_io;
 
                ladr = pos / CD_FRAMESIZE_RAW;
                off = pos % CD_FRAMESIZE_RAW;
@@ -331,6 +343,12 @@ void BuildPPFCache() {
        FillPPFCache(); // build address array
 
        SysPrintf(_("Loaded PPF %d.0 patch: %s.\n"), method + 1, szPPF);
+
+fail_io:
+#ifndef NDEBUG
+       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+       fclose(ppffile);
 }
 
 // redump.org SBI files, slightly different handling from PCSX-Reloaded
@@ -353,12 +371,15 @@ int LoadSBI(const char *fname, int sector_count) {
        }
 
        // 4-byte SBI header
-       fread(buffer, 1, 4, sbihandle);
+       if (fread(buffer, 1, 4, sbihandle) != 4)
+               goto fail_io;
+
        while (1) {
                s = fread(sbitime, 1, 3, sbihandle);
                if (s != 3)
-                       break;
-               fread(&t, 1, 1, sbihandle);
+                       goto fail_io;
+               if (fread(&t, sizeof(t), 1, sbihandle) != sizeof(t))
+                       goto fail_io;
                switch (t) {
                default:
                case 1:
@@ -379,8 +400,14 @@ int LoadSBI(const char *fname, int sector_count) {
        }
 
        fclose(sbihandle);
-
        return 0;
+
+fail_io:
+#ifndef NDEBUG
+       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+       fclose(sbihandle);
+       return -1;
 }
 
 void UnloadSBI(void) {
index ecd4264..6016f7e 100644 (file)
@@ -1,6 +1,6 @@
 /***************************************************************************
  *   Copyright (C) 2019 Ryan Schultz, PCSX-df Team, PCSX team, gameblabla, *
- *      dmitrysmagin, senquack                                                                                            *
+ *   dmitrysmagin, senquack                                                *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
@@ -18,7 +18,7 @@
  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
  ***************************************************************************/
 
-/* Gameblabla 2018-2019 : 
+/* Gameblabla 2018-2019 :
  * Numerous changes to bios calls as well as improvements in order to conform to nocash's findings
  * for the PSX bios calls. Thanks senquack for helping out with some of the changes
  * and helping to spot issues and refine my patches.
@@ -33,6 +33,7 @@
 #include "psxbios.h"
 #include "psxhw.h"
 #include "gpu.h"
+#include "sio.h"
 #include <zlib.h>
 
 #undef SysPrintf
@@ -217,7 +218,7 @@ typedef struct {
        u32 func;
 } TCB;
 
-typedef struct {                   
+typedef struct {
        u32 _pc0;
        u32 gp0;
        u32 t_addr;
@@ -255,7 +256,7 @@ static int pad_buf1len, pad_buf2len;
 static int pad_stopped = 0;
 
 static u32 regs[35];
-static EvCB *Event;
+static EvCB *EventCB;
 static EvCB *HwEV; // 0xf0
 static EvCB *EvEV; // 0xf1
 static EvCB *RcEV; // 0xf2
@@ -267,10 +268,10 @@ static u32 *heap_addr = NULL;
 static u32 *heap_end = NULL;
 static u32 SysIntRP[8];
 static int CardState = -1;
-static TCB Thread[8];
+static TCB ThreadCB[8];
 static int CurThread = 0;
 static FileDesc FDesc[32];
-static u32 card_active_chan;
+static u32 card_active_chan = 0;
 
 boolean hleSoftCall = FALSE;
 
@@ -299,12 +300,12 @@ static inline void softCall2(u32 pc) {
 }
 
 static inline void DeliverEvent(u32 ev, u32 spec) {
-       if (Event[ev][spec].status != EvStACTIVE) return;
+       if (EventCB[ev][spec].status != EvStACTIVE) return;
 
-//     Event[ev][spec].status = EvStALREADY;
-       if (Event[ev][spec].mode == EvMdINTR) {
-               softCall2(Event[ev][spec].fhandler);
-       } else Event[ev][spec].status = EvStALREADY;
+//     EventCB[ev][spec].status = EvStALREADY;
+       if (EventCB[ev][spec].mode == EvMdINTR) {
+               softCall2(EventCB[ev][spec].fhandler);
+       } else EventCB[ev][spec].status = EvStALREADY;
 }
 
 static unsigned interrupt_r26=0x8004E8B0;
@@ -696,7 +697,7 @@ void psxBios_index() { // 0x1c
                pc0 = ra;
                return;
        }
-       
+
        do {
                if (*p == a1) {
                        v0 = a0 + (p - (char *)Ra0);
@@ -925,7 +926,7 @@ void psxBios_memcmp() { // 0x2d
 
 void psxBios_memchr() { // 0x2e
        char *p = (char *)Ra0;
-       
+
        if (a0 == 0 || a2 > 0x7FFFFFFF)
        {
                pc0 = ra;
@@ -1424,7 +1425,7 @@ void psxBios_GPU_dw() { // 0x46
        } while(--size);
 
        pc0 = ra;
-}  
+}
 
 void psxBios_mem2vram() { // 0x47
        int size;
@@ -1464,8 +1465,8 @@ void psxBios_GPU_cwb() { // 0x4a
 
        pc0 = ra;
 }
-   
-void psxBios_GPU_SendPackets() { //4b: 
+
+void psxBios_GPU_SendPackets() { //4b:
        GPU_writeStatus(0x04000002);
        psxHwWrite32(0x1f8010f4,0);
        psxHwWrite32(0x1f8010f0,psxHwRead32(0x1f8010f0)|0x800);
@@ -1500,7 +1501,7 @@ void psxBios_LoadExec() { // 51
 #endif
        s_addr = a1; s_size = a2;
 
-       a1 = 0xf000;    
+       a1 = 0xf000;
        psxBios_Load();
 
        header->S_addr = s_addr;
@@ -1555,7 +1556,7 @@ void psxBios_SetMem() { // 9f
                        psxHu32ref(0x1060) = SWAP32(new | 0x300);
                        psxMu32ref(0x060) = a0;
                        SysPrintf("Change effective memory : %d MBytes\n",a0);
-       
+
                default:
                        SysPrintf("Effective memory must be 2/8 MBytes\n");
                break;
@@ -1575,16 +1576,16 @@ void psxBios__card_info() { // ab
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s: %x\n", biosA0n[0xab], a0);
 #endif
-       u32 ret;
+       u32 ret, port;
        card_active_chan = a0;
-
-       switch (card_active_chan) 
-       {
-       case 0x00: case 0x01: case 0x02: case 0x03:
-               ret = Config.Mcd1[0] ? 0x2 : 0x8;
-               break;
-       case 0x10: case 0x11: case 0x12: case 0x13:
-               ret = Config.Mcd2[0] ? 0x2 : 0x8;
+       port = card_active_chan >> 4;
+
+       switch (port) {
+       case 0x0:
+       case 0x1:
+               ret = 0x2;
+               if (McdDisable[port & 1])
+                       ret = 0x8;
                break;
        default:
 #ifdef PSXBIOS_LOG
@@ -1593,8 +1594,12 @@ void psxBios__card_info() { // ab
                ret = 0x11;
                break;
        }
-       
-       DeliverEvent(0x11, 0x2); // 0xf4000001, 0x0004
+
+       if (McdDisable[0] && McdDisable[1])
+               ret = 0x8;
+
+       DeliverEvent(0x11, 0x2); // 0xf0000011, 0x0004
+//     DeliverEvent(0x81, 0x2); // 0xf4000001, 0x0004
        DeliverEvent(0x81, ret); // 0xf4000001, 0x0004
        v0 = 1; pc0 = ra;
 }
@@ -1683,14 +1688,14 @@ void psxBios_ResetRCnt() { // 06
 }
 
 
-/* gets ev for use with Event */
+/* gets ev for use with EventCB */
 #define GetEv() \
        ev = (a0 >> 24) & 0xf; \
        if (ev == 0xf) ev = 0x5; \
        ev*= 32; \
        ev+= a0&0x1f;
 
-/* gets spec for use with Event */
+/* gets spec for use with EventCB */
 #define GetSpec() \
        spec = 0; \
        switch (a1) { \
@@ -1728,9 +1733,9 @@ void psxBios_OpenEvent() { // 08
        PSXBIOS_LOG("psxBios_%s %x,%x (class:%x, spec:%x, mode:%x, func:%x)\n", biosB0n[0x08], ev, spec, a0, a1, a2, a3);
 #endif
 
-       Event[ev][spec].status = EvStWAIT;
-       Event[ev][spec].mode = a2;
-       Event[ev][spec].fhandler = a3;
+       EventCB[ev][spec].status = EvStWAIT;
+       EventCB[ev][spec].mode = a2;
+       EventCB[ev][spec].fhandler = a3;
 
        v0 = ev | (spec << 8);
        pc0 = ra;
@@ -1746,7 +1751,7 @@ void psxBios_CloseEvent() { // 09
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x09], ev, spec);
 #endif
 
-       Event[ev][spec].status = EvStUNUSED;
+       EventCB[ev][spec].status = EvStUNUSED;
 
        v0 = 1; pc0 = ra;
 }
@@ -1759,17 +1764,17 @@ void psxBios_WaitEvent() { // 0a
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0a], ev, spec);
 #endif
-       if (Event[ev][spec].status == EvStUNUSED)
+       if (EventCB[ev][spec].status == EvStUNUSED)
        {
                v0 = 0;
-               pc0 = ra;       
+               pc0 = ra;
                return;
        }
 
-       if (Event[ev][spec].status == EvStALREADY) 
+       if (EventCB[ev][spec].status == EvStALREADY)
        {
                /* Callback events (mode=EvMdINTR) do never set the ready flag (and thus WaitEvent would hang forever). */
-               if (!(Event[ev][spec].mode == EvMdINTR)) Event[ev][spec].status = EvStACTIVE;
+               if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE;
                v0 = 1;
                pc0 = ra;
                return;
@@ -1785,12 +1790,12 @@ void psxBios_TestEvent() { // 0b
        ev   = a0 & 0xff;
        spec = (a0 >> 8) & 0xff;
 
-       if (Event[ev][spec].status == EvStALREADY) 
+       if (EventCB[ev][spec].status == EvStALREADY)
        {
-               if (!(Event[ev][spec].mode == EvMdINTR)) Event[ev][spec].status = EvStACTIVE;
+               if (!(EventCB[ev][spec].mode == EvMdINTR)) EventCB[ev][spec].status = EvStACTIVE;
                v0 = 1;
-       } 
-       else 
+       }
+       else
        {
                v0 = 0;
        }
@@ -1812,7 +1817,7 @@ void psxBios_EnableEvent() { // 0c
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0c], ev, spec);
 #endif
 
-       Event[ev][spec].status = EvStACTIVE;
+       EventCB[ev][spec].status = EvStACTIVE;
 
        v0 = 1; pc0 = ra;
 }
@@ -1827,7 +1832,7 @@ void psxBios_DisableEvent() { // 0d
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x0d], ev, spec);
 #endif
 
-       Event[ev][spec].status = EvStWAIT;
+       EventCB[ev][spec].status = EvStWAIT;
 
        v0 = 1; pc0 = ra;
 }
@@ -1841,7 +1846,7 @@ void psxBios_OpenTh() { // 0e
 
        for (th=1; th<8; th++)
        {
-               if (Thread[th].status == 0) break;
+               if (ThreadCB[th].status == 0) break;
 
        }
        if (th == 8) {
@@ -1858,10 +1863,10 @@ void psxBios_OpenTh() { // 0e
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x0e], th);
 #endif
 
-       Thread[th].status = 1;
-       Thread[th].func    = a0;
-       Thread[th].reg[29] = a1;
-       Thread[th].reg[28] = a2;
+       ThreadCB[th].status = 1;
+       ThreadCB[th].func    = a0;
+       ThreadCB[th].reg[29] = a1;
+       ThreadCB[th].reg[28] = a2;
 
        v0 = th; pc0 = ra;
 }
@@ -1878,8 +1883,8 @@ void psxBios_CloseTh() { // 0f
 #endif
        /* The return value is always 1 (even if the handle was already closed). */
        v0 = 1;
-       if (Thread[th].status != 0) {
-               Thread[th].status = 0;
+       if (ThreadCB[th].status != 0) {
+               ThreadCB[th].status = 0;
        }
 
        pc0 = ra;
@@ -1897,18 +1902,18 @@ void psxBios_ChangeTh() { // 10
 #endif
        /* The return value is always 1. */
        v0 = 1;
-       if (Thread[th].status == 0 || CurThread == th) {
+       if (ThreadCB[th].status == 0 || CurThread == th) {
                pc0 = ra;
        } else {
-               if (Thread[CurThread].status == 2) {
-                       Thread[CurThread].status = 1;
-                       Thread[CurThread].func = ra;
-                       memcpy(Thread[CurThread].reg, psxRegs.GPR.r, 32*4);
+               if (ThreadCB[CurThread].status == 2) {
+                       ThreadCB[CurThread].status = 1;
+                       ThreadCB[CurThread].func = ra;
+                       memcpy(ThreadCB[CurThread].reg, psxRegs.GPR.r, 32*4);
                }
 
-               memcpy(psxRegs.GPR.r, Thread[th].reg, 32*4);
-               pc0 = Thread[th].func;
-               Thread[th].status = 2;
+               memcpy(psxRegs.GPR.r, ThreadCB[th].reg, 32*4);
+               pc0 = ThreadCB[th].func;
+               ThreadCB[th].status = 2;
                CurThread = th;
        }
 }
@@ -2012,26 +2017,27 @@ void psxBios_UnDeliverEvent() { // 0x20
        PSXBIOS_LOG("psxBios_%s %x,%x\n", biosB0n[0x20], ev, spec);
 #endif
 
-       if (Event[ev][spec].status == EvStALREADY &&
-               Event[ev][spec].mode == EvMdNOINTR)
-               Event[ev][spec].status = EvStACTIVE;
+       if (EventCB[ev][spec].status == EvStALREADY &&
+               EventCB[ev][spec].mode == EvMdNOINTR)
+               EventCB[ev][spec].status = EvStACTIVE;
 
        pc0 = ra;
 }
 
 char ffile[64], *pfile;
 int nfile;
-static void buopen(int mcd, u8 *ptr, u8 *cfg)
+
+static void buopen(int mcd, char *ptr, char *cfg)
 {
        int i;
-       u8 *fptr = ptr;
+       char *mcd_data = ptr;
 
        strcpy(FDesc[1 + mcd].name, Ra0+5);
        FDesc[1 + mcd].offset = 0;
        FDesc[1 + mcd].mode   = a1;
 
        for (i=1; i<16; i++) {
-               fptr += 128;
+               const char *fptr = mcd_data + 128 * i;
                if ((*fptr & 0xF0) != 0x50) continue;
                if (strcmp(FDesc[1 + mcd].name, fptr+0xa)) continue;
                FDesc[1 + mcd].mcfile = i;
@@ -2040,12 +2046,11 @@ static void buopen(int mcd, u8 *ptr, u8 *cfg)
                break;
        }
        if (a1 & 0x200 && v0 == -1) { /* FCREAT */
-               fptr = ptr;
                for (i=1; i<16; i++) {
                        int j, xor, nblk = a1 >> 16;
-                       u8 *pptr, *fptr2;
+                       char *pptr, *fptr2;
+                       char *fptr = mcd_data + 128 * i;
 
-                       fptr += 128;
                        if ((*fptr & 0xF0) != 0xa0) continue;
 
                        FDesc[1 + mcd].mcfile = i;
@@ -2060,7 +2065,7 @@ static void buopen(int mcd, u8 *ptr, u8 *cfg)
                                int k;
                                for(i++; i<16; i++) {
                                        fptr2 += 128;
-                                       
+
                                        memset(fptr2, 0, 128);
                                        fptr2[0] = j < nblk ? 0x52 : 0x53;
                                        pptr[8] = i - 1;
@@ -2090,8 +2095,6 @@ static void buopen(int mcd, u8 *ptr, u8 *cfg)
  */
 
 void psxBios_open() { // 0x32
-       int i;
-       char *ptr;
        void *pa0 = Ra0;
 
 #ifdef PSXBIOS_LOG
@@ -2160,7 +2163,7 @@ void psxBios_read() { // 0x34
                        case 3: buread(pa1, 2, a2); break;
                }
        }
-               
+
        pc0 = ra;
 }
 
@@ -2226,7 +2229,7 @@ void psxBios_puts() { // 3e/3f
 
 /* To avoid any issues with different behaviour when using the libc's own strlen instead.
  * We want to mimic the PSX's behaviour in this case for bufile. */
-static size_t strlen_internal(char* p) 
+static size_t strlen_internal(char* p)
 {
        size_t size_of_array = 0;
        while (*p++) size_of_array++;
@@ -2267,7 +2270,7 @@ static size_t strlen_internal(char* p)
 /*
  *     struct DIRENTRY* firstfile(char *name,struct DIRENTRY *dir);
  */
+
 void psxBios_firstfile() { // 42
        struct DIRENTRY *dir = (struct DIRENTRY *)Ra1;
        void *pa0 = Ra0;
@@ -2524,7 +2527,7 @@ void psxBios__new_card() { // 0x50
 
 /* According to a user, this allows Final Fantasy Tactics to save/load properly */
 void psxBios__get_error(void) // 55
-{ 
+{
        v0 = 0;
        pc0 = ra;
 }
@@ -2600,7 +2603,7 @@ void psxBios__card_chan() { // 0x58
 void psxBios_ChangeClearPad() { // 5b
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("psxBios_%s: %x\n", biosB0n[0x5b], a0);
-#endif 
+#endif
 
        pc0 = ra;
 }
@@ -2668,11 +2671,11 @@ void psxBios_ChangeClearRCnt() { // 0a
        pc0 = ra;
 }
 
-void psxBios_dummy() { 
+void psxBios_dummy() {
 #ifdef PSXBIOS_LOG
        PSXBIOS_LOG("unk %x call: %x\n", pc0 & 0x1fffff, t1);
 #endif
-       pc0 = ra; 
+       pc0 = ra;
 }
 
 void (*biosA0[256])();
@@ -2683,7 +2686,7 @@ void (*biosC0[256])();
 
 void psxBiosInit() {
        u32 base, size;
-       u32 *ptr; 
+       u32 *ptr;
        int i;
        uLongf len;
 
@@ -2766,7 +2769,7 @@ void psxBiosInit() {
        biosA0[0x39] = psxBios_InitHeap;
        //biosA0[0x3a] = psxBios__exit;
        biosA0[0x3b] = psxBios_getchar;
-       biosA0[0x3c] = psxBios_putchar; 
+       biosA0[0x3c] = psxBios_putchar;
        //biosA0[0x3d] = psxBios_gets;
        //biosA0[0x40] = psxBios_sys_a0_40;
        //biosA0[0x41] = psxBios_LoadTest;
@@ -2782,7 +2785,7 @@ void psxBiosInit() {
        biosA0[0x4b] = psxBios_GPU_SendPackets;
        biosA0[0x4c] = psxBios_sys_a0_4c;
        biosA0[0x4d] = psxBios_GPU_GetGPUStatus;
-       //biosA0[0x4e] = psxBios_GPU_sync;      
+       //biosA0[0x4e] = psxBios_GPU_sync;
        //biosA0[0x4f] = psxBios_sys_a0_4f;
        //biosA0[0x50] = psxBios_sys_a0_50;
        biosA0[0x51] = psxBios_LoadExec;
@@ -2834,10 +2837,10 @@ void psxBiosInit() {
        //biosA0[0x7f] = psxBios_sys_a0_7f;
        //biosA0[0x80] = psxBios_sys_a0_80;
        //biosA0[0x81] = psxBios_sys_a0_81;
-       //biosA0[0x82] = psxBios_sys_a0_82;             
+       //biosA0[0x82] = psxBios_sys_a0_82;
        //biosA0[0x83] = psxBios_sys_a0_83;
        //biosA0[0x84] = psxBios_sys_a0_84;
-       //biosA0[0x85] = psxBios__96_CdStop;    
+       //biosA0[0x85] = psxBios__96_CdStop;
        //biosA0[0x86] = psxBios_sys_a0_86;
        //biosA0[0x87] = psxBios_sys_a0_87;
        //biosA0[0x88] = psxBios_sys_a0_88;
@@ -2989,7 +2992,7 @@ void psxBiosInit() {
        //biosC0[0x07] = psxBios_InstallExeptionHandler;
        //biosC0[0x08] = psxBios_SysInitMemory;
        //biosC0[0x09] = psxBios_SysInitKMem;
-       biosC0[0x0a] = psxBios_ChangeClearRCnt; 
+       biosC0[0x0a] = psxBios_ChangeClearRCnt;
        //biosC0[0x0b] = psxBios_SystemError;
        //biosC0[0x0c] = psxBios_InitDefInt;
        //biosC0[0x0d] = psxBios_sys_c0_0d;
@@ -3012,14 +3015,14 @@ void psxBiosInit() {
 /**/
        base = 0x1000;
        size = sizeof(EvCB) * 32;
-       Event = (void *)&psxR[base]; base += size * 6;
-       memset(Event, 0, size * 6);
-       HwEV = Event;
-       EvEV = Event + 32;
-       RcEV = Event + 32 * 2;
-       UeEV = Event + 32 * 3;
-       SwEV = Event + 32 * 4;
-       ThEV = Event + 32 * 5;
+       EventCB = (void *)&psxR[base]; base += size * 6;
+       memset(EventCB, 0, size * 6);
+       HwEV = EventCB;
+       EvEV = EventCB + 32;
+       RcEV = EventCB + 32 * 2;
+       UeEV = EventCB + 32 * 3;
+       SwEV = EventCB + 32 * 4;
+       ThEV = EventCB + 32 * 5;
 
        ptr = (u32 *)&psxM[0x0874]; // b0 table
        ptr[0] = SWAPu32(0x4c54 - 0x884);
@@ -3028,8 +3031,8 @@ void psxBiosInit() {
        ptr[6] = SWAPu32(0xc80);
 
        memset(SysIntRP, 0, sizeof(SysIntRP));
-       memset(Thread, 0, sizeof(Thread));
-       Thread[0].status = 2; // main thread
+       memset(ThreadCB, 0, sizeof(ThreadCB));
+       ThreadCB[0].status = 2; // main thread
 
        pad_stopped = 1;
        jmp_int = NULL;
@@ -3057,7 +3060,7 @@ void psxBiosInit() {
 */
        // opcode HLE
        psxRu32ref(0x0000) = SWAPu32((0x3b << 26) | 4);
-       /* Whatever this does, it actually breaks CTR, even without the uninitiliazed memory patch. 
+       /* Whatever this does, it actually breaks CTR, even without the uninitiliazed memory patch.
        Normally games shouldn't read from address 0 yet they do. See explanation below in details. */
        //psxMu32ref(0x0000) = SWAPu32((0x3b << 26) | 0);
        psxMu32ref(0x00a0) = SWAPu32((0x3b << 26) | 1);
@@ -3085,14 +3088,14 @@ void psxBiosInit() {
        psxHu32ref(0x1060) = SWAPu32(0x00000b88);
 
        hleSoftCall = FALSE;
-       
+
        /*      Some games like R-Types, CTR, Fade to Black read from adress 0x00000000 due to uninitialized pointers.
                See Garbage Area at Address 00000000h in Nocash PSX Specfications for more information.
                Here are some examples of games not working with this fix in place :
                R-type won't get past the Irem logo if not implemented.
                Crash Team Racing will softlock after the Sony logo.
        */
-       
+
        psxMu32ref(0x0000) = SWAPu32(0x00000003);
        /*
        But overwritten by 00000003h after soon.
@@ -3273,7 +3276,7 @@ void psxBiosException() {
                                        break;
 
                                case 2: // ExitCritical - enable irq's
-                                       psxRegs.CP0.n.Status |= 0x404; 
+                                       psxRegs.CP0.n.Status |= 0x404;
                                        break;
                                /* Normally this should cover SYS(00h, SYS(04h but they don't do anything relevant so... */
                                default:
@@ -3332,7 +3335,7 @@ void psxBiosFreeze(int Mode) {
        bfreezes(regs);
        bfreezes(SysIntRP);
        bfreezel(&CardState);
-       bfreezes(Thread);
+       bfreezes(ThreadCB);
        bfreezel(&CurThread);
        bfreezes(FDesc);
        bfreezel(&card_active_chan);
index 9f5444e..708d984 100644 (file)
@@ -40,7 +40,9 @@ extern "C" {
 #include <math.h>
 #include <time.h>
 #include <ctype.h>
+#ifndef __SWITCH__
 #include <sys/types.h>
+#endif
 #include <assert.h>
 
 // Define types
@@ -118,7 +120,10 @@ typedef struct {
        boolean Mdec;
        boolean PsxAuto;
        boolean Cdda;
+       boolean AsyncCD;
+       boolean CHD_Precache; /* loads disk image into memory, works with CHD only. */
        boolean HLE;
+       boolean SlowBoot;
        boolean Debug;
        boolean PsxOut;
        boolean SpuIrq;
index 35823da..db0b1ec 100644 (file)
@@ -64,11 +64,15 @@ static const u32 HSyncTotal[]     = { 263, 313 };
 #define VBlankStart 240
 
 #define VERBOSE_LEVEL 0
+#if VERBOSE_LEVEL > 0
 static const s32 VerboseLevel     = VERBOSE_LEVEL;
+#endif
 
 /******************************************************************************/
 
+#ifndef NEW_DYNAREC
 Rcnt rcnts[ CounterQuantity ];
+#endif
 
 u32 hSyncCount = 0;
 u32 frame_counter = 0;
@@ -494,7 +498,7 @@ s32 psxRcntFreeze( void *f, s32 Mode )
     u32 count;
     s32 i;
 
-    gzfreeze( &rcnts, sizeof(rcnts) );
+    gzfreeze( &rcnts, sizeof(Rcnt) * CounterQuantity );
     gzfreeze( &hSyncCount, sizeof(hSyncCount) );
     gzfreeze( &spuSyncCount, sizeof(spuSyncCount) );
     gzfreeze( &psxNextCounter, sizeof(psxNextCounter) );
index 83362ec..7507192 100644 (file)
 
 #include "psxhle.h"
 
+#if 0
+#define PSXHLE_LOG SysPrintf
+#else
+#define PSXHLE_LOG(...)
+#endif
+
 static void hleDummy() {
        psxRegs.pc = psxRegs.GPR.n.ra;
 
@@ -54,10 +60,10 @@ static void hleC0() {
 }
 
 static void hleBootstrap() { // 0xbfc00000
-       SysPrintf("hleBootstrap\n");
+       PSXHLE_LOG("hleBootstrap\n");
        CheckCdrom();
        LoadCdrom();
-       SysPrintf("CdromLabel: \"%s\": PC = %8.8lx (SP = %8.8lx)\n", CdromLabel, psxRegs.pc, psxRegs.GPR.n.sp);
+       PSXHLE_LOG("CdromLabel: \"%s\": PC = %8.8lx (SP = %8.8lx)\n", CdromLabel, psxRegs.pc, psxRegs.GPR.n.sp);
 }
 
 typedef struct {                   
@@ -77,7 +83,7 @@ typedef struct {
 static void hleExecRet() {
        EXEC *header = (EXEC*)PSXM(psxRegs.GPR.n.s0);
 
-       SysPrintf("ExecRet %x: %x\n", psxRegs.GPR.n.s0, header->ret);
+       PSXHLE_LOG("ExecRet %x: %x\n", psxRegs.GPR.n.s0, header->ret);
 
        psxRegs.GPR.n.ra = header->ret;
        psxRegs.GPR.n.sp = header->_sp;
index cf3de79..e904cee 100644 (file)
@@ -39,6 +39,14 @@ static u32 branchPC;
 #define debugI()
 #endif
 
+#ifndef NDEBUG
+#include "debug.h"
+#else
+void StartDebugger() {}
+void ProcessDebug() {}
+void StopDebugger() {}
+#endif
+
 void execI();
 
 // Subsets
@@ -501,14 +509,20 @@ void psxSLTU()    { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); }       // Rd
 * Format:  OP rs, rt                                     *
 *********************************************************/
 void psxDIV() {
-       if (_i32(_rRt_) != 0) {
-               _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
-               _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
-       }
-       else {
-               _i32(_rLo_) = _i32(_rRs_) >= 0 ? 0xffffffff : 1;
-               _i32(_rHi_) = _i32(_rRs_);
-       }
+    if (!_i32(_rRt_)) {
+        _i32(_rHi_) = _i32(_rRs_);
+        if (_i32(_rRs_) & 0x80000000) {
+            _i32(_rLo_) = 1;
+        } else {
+            _i32(_rLo_) = 0xFFFFFFFF;
+        }
+    } else if (_i32(_rRs_) == 0x80000000 && _i32(_rRt_) == 0xFFFFFFFF) {
+        _i32(_rLo_) = 0x80000000;
+        _i32(_rHi_) = 0;
+    } else {
+        _i32(_rLo_) = _i32(_rRs_) / _i32(_rRt_);
+        _i32(_rHi_) = _i32(_rRs_) % _i32(_rRt_);
+    }
 }
 
 void psxDIVU() {
index a1a641d..2f427ac 100644 (file)
 
 #include "memmap.h"
 
+#ifdef USE_LIBRETRO_VFS
+#include <streams/file_stream_transforms.h>
+#endif
+
 #ifndef MAP_ANONYMOUS
 #define MAP_ANONYMOUS MAP_ANON
 #endif
 
+#ifndef NDEBUG
+#include "debug.h"
+#else
+void DebugCheckBP(u32 address, enum breakpoint_types type) {}
+#endif
+
 void *(*psxMapHook)(unsigned long addr, size_t size, int is_fixed,
                enum psxMapTag tag);
 void (*psxUnmapHook)(void *ptr, size_t size, enum psxMapTag tag);
@@ -42,7 +52,16 @@ void (*psxUnmapHook)(void *ptr, size_t size, enum psxMapTag tag);
 void *psxMap(unsigned long addr, size_t size, int is_fixed,
                enum psxMapTag tag)
 {
+#ifdef LIGHTREC
+#ifdef MAP_FIXED_NOREPLACE
+       int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE;
+#else
+       int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
+#endif
+#else
        int flags = MAP_PRIVATE | MAP_ANONYMOUS;
+#endif
+
        int try_ = 0;
        unsigned long mask;
        void *req, *ret;
@@ -135,7 +154,14 @@ int psxMemInit() {
        memset(psxMemRLUT, 0, 0x10000 * sizeof(void *));
        memset(psxMemWLUT, 0, 0x10000 * sizeof(void *));
 
+#ifdef LIGHTREC
+       psxM = psxMap(0x30000000, 0x00210000, 1, MAP_TAG_RAM);
+       if (psxM == NULL)
+               psxM = psxMap(0x70000000, 0x00210000, 1, MAP_TAG_RAM);
+
+#else
        psxM = psxMap(0x80000000, 0x00210000, 1, MAP_TAG_RAM);
+#endif
 #ifndef RAM_FIXED
        if (psxM == NULL)
                psxM = psxMap(0x77000000, 0x00210000, 0, MAP_TAG_RAM);
@@ -146,8 +172,18 @@ int psxMemInit() {
        }
 
        psxP = &psxM[0x200000];
+#ifdef LIGHTREC
+       psxH = psxMap(0x4f800000, 0x10000, 0, MAP_TAG_OTHER);
+       if (psxH == NULL)
+               psxH = psxMap(0x8f800000, 0x10000, 0, MAP_TAG_OTHER);
+
+       psxR = psxMap(0x4fc00000, 0x80000, 0, MAP_TAG_OTHER);
+       if (psxR == NULL)
+               psxR = psxMap(0x8fc00000, 0x80000, 0, MAP_TAG_OTHER);
+#else
        psxH = psxMap(0x1f800000, 0x10000, 0, MAP_TAG_OTHER);
        psxR = psxMap(0x1fc00000, 0x80000, 0, MAP_TAG_OTHER);
+#endif
 
        if (psxMemRLUT == NULL || psxMemWLUT == NULL || 
            psxR == NULL || psxP == NULL || psxH == NULL) {
@@ -189,6 +225,8 @@ void psxMemReset() {
        memset(psxM, 0, 0x00200000);
        memset(psxP, 0xff, 0x00010000);
 
+       Config.HLE = TRUE;
+
        if (strcmp(Config.Bios, "HLE") != 0) {
                sprintf(bios, "%s/%s", Config.BiosDir, Config.Bios);
                f = fopen(bios, "rb");
@@ -196,13 +234,15 @@ void psxMemReset() {
                if (f == NULL) {
                        SysMessage(_("Could not open BIOS:\"%s\". Enabling HLE Bios!\n"), bios);
                        memset(psxR, 0, 0x80000);
-                       Config.HLE = TRUE;
                } else {
-                       fread(psxR, 1, 0x80000, f);
+                       if (fread(psxR, 1, 0x80000, f) == 0x80000) {
+                               Config.HLE = FALSE;
+                       } else {
+                               SysMessage(_("The selected BIOS:\"%s\" is of wrong size. Enabling HLE Bios!\n"), bios);
+                       }
                        fclose(f);
-                       Config.HLE = FALSE;
                }
-       } else Config.HLE = TRUE;
+       }
 }
 
 void psxMemShutdown() {
index d9fee00..36b4693 100644 (file)
@@ -122,9 +122,11 @@ extern u8 **psxMemRLUT;
 
 #define PSXMu32ref(mem)        (*(u32 *)PSXM(mem))
 
-#if !defined(PSXREC) && (defined(__x86_64__) || defined(__i386__) || defined(__ppc__)) && !defined(NOPSXREC)
+#ifndef PSXREC
+#if defined(NEW_DYNAREC) || defined(LIGHTREC)
 #define PSXREC
 #endif
+#endif
 
 int psxMemInit();
 void psxMemReset();
index 82eb885..0a3e00b 100644 (file)
 #include "gte.h"
 
 R3000Acpu *psxCpu = NULL;
+#ifndef NEW_DYNAREC
 psxRegisters psxRegs;
+#endif
 
 int psxInit() {
-       SysPrintf(_("Running PCSX Version %s (%s).\n"), PACKAGE_VERSION, __DATE__);
+       SysPrintf(_("Running PCSX Version %s (%s).\n"), PCSX_VERSION, __DATE__);
 
-#ifdef PSXREC
+#if defined(NEW_DYNAREC) || defined(LIGHTREC)
        if (Config.Cpu == CPU_INTERPRETER) {
                psxCpu = &psxInt;
        } else psxCpu = &psxRec;
@@ -50,7 +52,7 @@ int psxInit() {
 void psxReset() {
        psxMemReset();
 
-       memset(&psxRegs, 0, sizeof(psxRegs));
+       memset(&psxRegs, 0x00, sizeof(psxRegs));
 
        psxRegs.pc = 0xbfc00000; // Start in bootstrap
 
index b3732d2..8392fd8 100644 (file)
 #include "sio.h"
 #include <sys/stat.h>
 
+#ifdef USE_LIBRETRO_VFS
+#include <streams/file_stream_transforms.h>
+#endif
+
 // Status Flags
 #define TX_RDY         0x0001
 #define RX_RDY         0x0002
@@ -117,6 +121,20 @@ void sioWrite8(unsigned char value) {
                                                        break;
                                        }
                                }
+                               // NegCon - Wipeout 3
+                               if( buf[parp] == 0x23 ) {
+                                       switch (value) {
+                                               // enter config mode
+                                               case 0x43:
+                                                       buf[1] = 0x79;
+                                                       break;
+
+                                               // get status
+                                               case 0x45:
+                                                       buf[1] = 0xf3;
+                                                       break;
+                                       }
+                               }
                        }
                        else padst = 0;
                        return;
@@ -409,6 +427,12 @@ void LoadMcd(int mcd, char *str) {
        }
 
        McdDisable[mcd - 1] = 0;
+#ifdef HAVE_LIBRETRO
+       // memcard1 is handled by libretro
+       if (mcd == 1)
+               return;
+#endif
+
        if (str == NULL || strcmp(str, "none") == 0) {
                McdDisable[mcd - 1] = 1;
                return;
@@ -430,7 +454,12 @@ void LoadMcd(int mcd, char *str) {
                                else if(buf.st_size == MCD_SIZE + 3904)
                                        fseek(f, 3904, SEEK_SET);
                        }
-                       fread(data, 1, MCD_SIZE, f);
+                       if (fread(data, 1, MCD_SIZE, f) != MCD_SIZE) {
+#ifndef NDEBUG
+                               SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+                               memset(data, 0x00, MCD_SIZE);
+                       }
                        fclose(f);
                }
                else
@@ -445,7 +474,12 @@ void LoadMcd(int mcd, char *str) {
                        else if(buf.st_size == MCD_SIZE + 3904)
                                fseek(f, 3904, SEEK_SET);
                }
-               fread(data, 1, MCD_SIZE, f);
+               if (fread(data, 1, MCD_SIZE, f) != MCD_SIZE) {
+#ifndef NDEBUG
+                       SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
+#endif
+                       memset(data, 0x00, MCD_SIZE);
+               }
                fclose(f);
        }
 }
index eff1746..a554c2b 100644 (file)
@@ -34,6 +34,7 @@ extern "C" {
 #define MCD_SIZE       (1024 * 8 * 16)
 
 extern char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE];
+extern char McdDisable[2];
 
 void sioWrite8(unsigned char value);
 void sioWriteStat16(unsigned short value);
index 105d624..0692648 100644 (file)
@@ -21,6 +21,9 @@
 // Converted to binary format by Wei Mingzhi <whistler_wmz@users.sf.net>.
 //
 
+#ifndef __SJISFONT_H__
+#define __SJISFONT_H__
+
 const unsigned char font_8140[] = {
        0x78, 0xda, 0xad, 0x3b, 0x3b, 0x90, 0x1b, 0xc9,
        0x75, 0x3d, 0x9f, 0x05, 0x1a, 0xcb, 0xe1, 0x4e,
@@ -6954,3 +6957,5 @@ const unsigned char font_889f[] = {
        0xeb, 0xe7, 0xa8, 0x89, 0x0a, 0x11, 0xbc, 0xbc,
        0x33, 0xf9, 0xff, 0xe8, 0xc4, 0x21, 0xbf
 };
+
+#endif /* __SJISFONT_H__ */
index 31f82e2..df768e6 100644 (file)
  *  along with this program; if not, see <http://www.gnu.org/licenses>.
  */
 
+#ifdef NO_SOCKET
+
+int StartServer() { return 0;}
+void StopServer() {}
+void GetClient() {}
+void CloseClient() {}
+int HasClient() { return 0;}
+int ReadSocket(char * buffer, int len) { return 0;}
+int RawReadSocket(char * buffer, int len) { return 0;}
+void WriteSocket(char * buffer, int len) {}
+
+void SetsBlock() {}
+void SetsNonblock() {}
+
+#else // NO_SOCKET
+
 #ifdef _WIN32
 #include <winsock2.h>
 #endif
@@ -119,7 +135,7 @@ void GetClient() {
     }
 #endif
 
-    sprintf(hello, "000 PCSX Version %s - Debug console\r\n", PACKAGE_VERSION);
+    sprintf(hello, "000 PCSX Version %s - Debug console\r\n", PCSX_VERSION);
     WriteSocket(hello, strlen(hello));
     ptr = 0;
 }
@@ -252,3 +268,4 @@ void SetsNonblock() {
     fcntl(server_socket, F_SETFL, flags | O_NONBLOCK);
 #endif
 }
+#endif // NO_SOCKET
index c869fdf..cd1814c 100644 (file)
@@ -35,6 +35,7 @@ void SysCloseLibrary(void *lib);              // Closes Library
 void SysUpdate();                                              // Called on VBlank (to update i.e. pads)
 void SysRunGui();                                              // Returns to the Gui
 void SysClose();                                               // Close mem and plugins
+void SysDLog(const char *fmt, ...);            // Prints debug-level logs
 
 #ifdef __cplusplus
 }
diff --git a/libretro-common/compat/compat_posix_string.c b/libretro-common/compat/compat_posix_string.c
new file mode 100644 (file)
index 0000000..6a2f07e
--- /dev/null
@@ -0,0 +1,104 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_posix_string.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <ctype.h>
+
+#include <compat/posix_string.h>
+
+#ifdef _WIN32
+
+#undef strcasecmp
+#undef strdup
+#undef isblank
+#undef strtok_r
+#include <ctype.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <compat/strl.h>
+
+#include <string.h>
+
+int retro_strcasecmp__(const char *a, const char *b)
+{
+   while (*a && *b)
+   {
+      int a_ = tolower(*a);
+      int b_ = tolower(*b);
+
+      if (a_ != b_)
+         return a_ - b_;
+
+      a++;
+      b++;
+   }
+
+   return tolower(*a) - tolower(*b);
+}
+
+char *retro_strdup__(const char *orig)
+{
+   size_t len = strlen(orig) + 1;
+   char *ret  = (char*)malloc(len);
+   if (!ret)
+      return NULL;
+
+   strlcpy(ret, orig, len);
+   return ret;
+}
+
+int retro_isblank__(int c)
+{
+   return (c == ' ') || (c == '\t');
+}
+
+char *retro_strtok_r__(char *str, const char *delim, char **saveptr)
+{
+   char *first = NULL;
+   if (!saveptr || !delim)
+      return NULL;
+
+   if (str)
+      *saveptr = str;
+
+   do
+   {
+      char *ptr = NULL;
+      first = *saveptr;
+      while (*first && strchr(delim, *first))
+         *first++ = '\0';
+
+      if (*first == '\0')
+         return NULL;
+
+      ptr = first + 1;
+
+      while (*ptr && !strchr(delim, *ptr))
+         ptr++;
+
+      *saveptr = ptr + (*ptr ? 1 : 0);
+      *ptr     = '\0';
+   } while (strlen(first) == 0);
+
+   return first;
+}
+
+#endif
diff --git a/libretro-common/compat/compat_strcasestr.c b/libretro-common/compat/compat_strcasestr.c
new file mode 100644 (file)
index 0000000..4129dab
--- /dev/null
@@ -0,0 +1,58 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_strcasestr.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <ctype.h>
+
+#include <compat/strcasestr.h>
+
+/* Pretty much strncasecmp. */
+static int casencmp(const char *a, const char *b, size_t n)
+{
+   size_t i;
+
+   for (i = 0; i < n; i++)
+   {
+      int a_lower = tolower(a[i]);
+      int b_lower = tolower(b[i]);
+      if (a_lower != b_lower)
+         return a_lower - b_lower;
+   }
+
+   return 0;
+}
+
+char *strcasestr_retro__(const char *haystack, const char *needle)
+{
+   size_t i, search_off;
+   size_t hay_len    = strlen(haystack);
+   size_t needle_len = strlen(needle);
+
+   if (needle_len > hay_len)
+      return NULL;
+
+   search_off = hay_len - needle_len;
+   for (i = 0; i <= search_off; i++)
+      if (!casencmp(haystack + i, needle, needle_len))
+         return (char*)haystack + i;
+
+   return NULL;
+}
diff --git a/libretro-common/compat/fopen_utf8.c b/libretro-common/compat/fopen_utf8.c
new file mode 100644 (file)
index 0000000..85abb59
--- /dev/null
@@ -0,0 +1,63 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fopen_utf8.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <compat/fopen_utf8.h>
+#include <encodings/utf.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+#endif
+
+#ifdef _WIN32
+#undef fopen
+
+void *fopen_utf8(const char * filename, const char * mode)
+{
+#if defined(LEGACY_WIN32)
+   FILE             *ret = NULL;
+   char * filename_local = utf8_to_local_string_alloc(filename);
+
+   if (!filename_local)
+      return NULL;
+   ret = fopen(filename_local, mode);
+   if (filename_local)
+      free(filename_local);
+   return ret;
+#else
+   wchar_t * filename_w = utf8_to_utf16_string_alloc(filename);
+   wchar_t * mode_w = utf8_to_utf16_string_alloc(mode);
+   FILE* ret = NULL;
+
+   if (filename_w && mode_w)
+      ret = _wfopen(filename_w, mode_w);
+   if (filename_w)
+      free(filename_w);
+   if (mode_w)
+      free(mode_w);
+   return ret;
+#endif
+}
+#endif
diff --git a/libretro-common/encodings/compat_strl.c b/libretro-common/encodings/compat_strl.c
new file mode 100644 (file)
index 0000000..3172310
--- /dev/null
@@ -0,0 +1,69 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (compat_strl.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <compat/strl.h>
+
+/* Implementation of strlcpy()/strlcat() based on OpenBSD. */
+
+#ifndef __MACH__
+
+size_t strlcpy(char *dest, const char *source, size_t size)
+{
+   size_t src_size = 0;
+   size_t        n = size;
+
+   if (n)
+      while (--n && (*dest++ = *source++)) src_size++;
+
+   if (!n)
+   {
+      if (size) *dest = '\0';
+      while (*source++) src_size++;
+   }
+
+   return src_size;
+}
+
+size_t strlcat(char *dest, const char *source, size_t size)
+{
+   size_t len = strlen(dest);
+
+   dest += len;
+
+   if (len > size)
+      size = 0;
+   else
+      size -= len;
+
+   return len + strlcpy(dest, source, size);
+}
+#endif
+
+char *strldup(const char *s, size_t n)
+{
+   char *dst = (char*)malloc(sizeof(char) * (n + 1));
+   strlcpy(dst, s, n);
+   return dst;
+}
diff --git a/libretro-common/encodings/encoding_utf.c b/libretro-common/encodings/encoding_utf.c
new file mode 100644 (file)
index 0000000..2760824
--- /dev/null
@@ -0,0 +1,512 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (encoding_utf.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <boolean.h>
+#include <compat/strl.h>
+#include <retro_inline.h>
+
+#include <encodings/utf.h>
+
+#if defined(_WIN32) && !defined(_XBOX)
+#include <windows.h>
+#elif defined(_XBOX)
+#include <xtl.h>
+#endif
+
+#define UTF8_WALKBYTE(string) (*((*(string))++))
+
+static unsigned leading_ones(uint8_t c)
+{
+   unsigned ones = 0;
+   while (c & 0x80)
+   {
+      ones++;
+      c <<= 1;
+   }
+
+   return ones;
+}
+
+/* Simple implementation. Assumes the sequence is
+ * properly synchronized and terminated. */
+
+size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
+      const char *in, size_t in_size)
+{
+   unsigned i;
+   size_t ret = 0;
+   while (in_size && out_chars)
+   {
+      unsigned extra, shift;
+      uint32_t c;
+      uint8_t first = *in++;
+      unsigned ones = leading_ones(first);
+
+      if (ones > 6 || ones == 1) /* Invalid or desync. */
+         break;
+
+      extra = ones ? ones - 1 : ones;
+      if (1 + extra > in_size) /* Overflow. */
+         break;
+
+      shift = (extra - 1) * 6;
+      c     = (first & ((1 << (7 - ones)) - 1)) << (6 * extra);
+
+      for (i = 0; i < extra; i++, in++, shift -= 6)
+         c |= (*in & 0x3f) << shift;
+
+      *out++ = c;
+      in_size -= 1 + extra;
+      out_chars--;
+      ret++;
+   }
+
+   return ret;
+}
+
+bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
+     const uint16_t *in, size_t in_size)
+{
+   size_t out_pos            = 0;
+   size_t in_pos             = 0;
+   static const 
+      uint8_t utf8_limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+   for (;;)
+   {
+      unsigned num_adds;
+      uint32_t value;
+
+      if (in_pos == in_size)
+      {
+         *out_chars = out_pos;
+         return true;
+      }
+      value = in[in_pos++];
+      if (value < 0x80)
+      {
+         if (out)
+            out[out_pos] = (char)value;
+         out_pos++;
+         continue;
+      }
+
+      if (value >= 0xD800 && value < 0xE000)
+      {
+         uint32_t c2;
+
+         if (value >= 0xDC00 || in_pos == in_size)
+            break;
+         c2 = in[in_pos++];
+         if (c2 < 0xDC00 || c2 >= 0xE000)
+            break;
+         value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
+      }
+
+      for (num_adds = 1; num_adds < 5; num_adds++)
+         if (value < (((uint32_t)1) << (num_adds * 5 + 6)))
+            break;
+      if (out)
+         out[out_pos] = (char)(utf8_limits[num_adds - 1]
+               + (value >> (6 * num_adds)));
+      out_pos++;
+      do
+      {
+         num_adds--;
+         if (out)
+            out[out_pos] = (char)(0x80
+                  + ((value >> (6 * num_adds)) & 0x3F));
+         out_pos++;
+      }while (num_adds != 0);
+   }
+
+   *out_chars = out_pos;
+   return false;
+}
+
+/* Acts mostly like strlcpy.
+ *
+ * Copies the given number of UTF-8 characters,
+ * but at most d_len bytes.
+ *
+ * Always NULL terminates.
+ * Does not copy half a character.
+ *
+ * Returns number of bytes. 's' is assumed valid UTF-8.
+ * Use only if 'chars' is considerably less than 'd_len'. */
+size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars)
+{
+   const uint8_t *sb     = (const uint8_t*)s;
+   const uint8_t *sb_org = sb;
+
+   if (!s)
+      return 0;
+
+   while (*sb && chars-- > 0)
+   {
+      sb++;
+      while ((*sb & 0xC0) == 0x80)
+         sb++;
+   }
+
+   if ((size_t)(sb - sb_org) > d_len-1 /* NUL */)
+   {
+      sb = sb_org + d_len-1;
+      while ((*sb & 0xC0) == 0x80)
+         sb--;
+   }
+
+   memcpy(d, sb_org, sb-sb_org);
+   d[sb-sb_org] = '\0';
+
+   return sb-sb_org;
+}
+
+const char *utf8skip(const char *str, size_t chars)
+{
+   const uint8_t *strb = (const uint8_t*)str;
+
+   if (!chars)
+      return str;
+
+   do
+   {
+      strb++;
+      while ((*strb & 0xC0)==0x80)
+         strb++;
+      chars--;
+   }while (chars);
+
+   return (const char*)strb;
+}
+
+size_t utf8len(const char *string)
+{
+   size_t ret = 0;
+
+   if (!string)
+      return 0;
+
+   while (*string)
+   {
+      if ((*string & 0xC0) != 0x80)
+         ret++;
+      string++;
+   }
+   return ret;
+}
+
+/* Does not validate the input, returns garbage if it's not UTF-8. */
+uint32_t utf8_walk(const char **string)
+{
+   uint8_t first = UTF8_WALKBYTE(string);
+   uint32_t ret  = 0;
+
+   if (first < 128)
+      return first;
+
+   ret    = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
+   if (first >= 0xE0)
+   {
+      ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
+      if (first >= 0xF0)
+      {
+         ret = (ret << 6) | (UTF8_WALKBYTE(string) & 0x3F);
+         return ret | (first & 7) << 18;
+      }
+      return ret | (first & 15) << 12;
+   }
+
+   return ret | (first & 31) << 6;
+}
+
+static bool utf16_to_char(uint8_t **utf_data,
+      size_t *dest_len, const uint16_t *in)
+{
+   unsigned len    = 0;
+
+   while (in[len] != '\0')
+      len++;
+
+   utf16_conv_utf8(NULL, dest_len, in, len);
+   *dest_len  += 1;
+   *utf_data   = (uint8_t*)malloc(*dest_len);
+   if (*utf_data == 0)
+      return false;
+
+   return utf16_conv_utf8(*utf_data, dest_len, in, len);
+}
+
+bool utf16_to_char_string(const uint16_t *in, char *s, size_t len)
+{
+   size_t     dest_len  = 0;
+   uint8_t *utf16_data  = NULL;
+   bool            ret  = utf16_to_char(&utf16_data, &dest_len, in);
+
+   if (ret)
+   {
+      utf16_data[dest_len] = 0;
+      strlcpy(s, (const char*)utf16_data, len);
+   }
+
+   free(utf16_data);
+   utf16_data = NULL;
+
+   return ret;
+}
+
+#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
+/* Returned pointer MUST be freed by the caller if non-NULL. */
+static char *mb_to_mb_string_alloc(const char *str,
+      enum CodePage cp_in, enum CodePage cp_out)
+{
+   wchar_t *path_buf_wide = NULL;
+   int path_buf_wide_len  = MultiByteToWideChar(cp_in, 0, str, -1, NULL, 0);
+
+   /* Windows 95 will return 0 from these functions with 
+    * a UTF8 codepage set without MSLU.
+    *
+    * From an unknown MSDN version (others omit this info):
+    *   - CP_UTF8 Windows 98/Me, Windows NT 4.0 and later: 
+    *   Translate using UTF-8. When this is set, dwFlags must be zero.
+    *   - Windows 95: Under the Microsoft Layer for Unicode, 
+    *   MultiByteToWideChar also supports CP_UTF7 and CP_UTF8.
+    */
+
+   if (!path_buf_wide_len)
+      return strdup(str);
+
+   path_buf_wide = (wchar_t*)
+      calloc(path_buf_wide_len + sizeof(wchar_t), sizeof(wchar_t));
+
+   if (path_buf_wide)
+   {
+      MultiByteToWideChar(cp_in, 0,
+            str, -1, path_buf_wide, path_buf_wide_len);
+
+      if (*path_buf_wide)
+      {
+         int path_buf_len = WideCharToMultiByte(cp_out, 0,
+               path_buf_wide, -1, NULL, 0, NULL, NULL);
+
+         if (path_buf_len)
+         {
+            char *path_buf = (char*)
+               calloc(path_buf_len + sizeof(char), sizeof(char));
+
+            if (path_buf)
+            {
+               WideCharToMultiByte(cp_out, 0,
+                     path_buf_wide, -1, path_buf,
+                     path_buf_len, NULL, NULL);
+
+               free(path_buf_wide);
+
+               if (*path_buf)
+                  return path_buf;
+
+               free(path_buf);
+               return NULL;
+            }
+         }
+         else
+         {
+            free(path_buf_wide);
+            return strdup(str);
+         }
+      }
+
+      free(path_buf_wide);
+   }
+
+   return NULL;
+}
+#endif
+
+/* Returned pointer MUST be freed by the caller if non-NULL. */
+char* utf8_to_local_string_alloc(const char *str)
+{
+   if (str && *str)
+   {
+#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
+      return mb_to_mb_string_alloc(str, CODEPAGE_UTF8, CODEPAGE_LOCAL);
+#else
+      /* assume string needs no modification if not on Windows */
+      return strdup(str);
+#endif
+   }
+   return NULL;
+}
+
+/* Returned pointer MUST be freed by the caller if non-NULL. */
+char* local_to_utf8_string_alloc(const char *str)
+{
+   if (str && *str)
+   {
+#if defined(_WIN32) && !defined(_XBOX) && !defined(UNICODE)
+      return mb_to_mb_string_alloc(str, CODEPAGE_LOCAL, CODEPAGE_UTF8);
+#else
+      /* assume string needs no modification if not on Windows */
+      return strdup(str);
+#endif
+   }
+   return NULL;
+}
+
+/* Returned pointer MUST be freed by the caller if non-NULL. */
+wchar_t* utf8_to_utf16_string_alloc(const char *str)
+{
+#ifdef _WIN32
+   int len        = 0;
+   int out_len    = 0;
+#else
+   size_t len     = 0;
+   size_t out_len = 0;
+#endif
+   wchar_t *buf   = NULL;
+
+   if (!str || !*str)
+      return NULL;
+
+#ifdef _WIN32
+   len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+
+   if (len)
+   {
+      buf = (wchar_t*)calloc(len, sizeof(wchar_t));
+
+      if (!buf)
+         return NULL;
+
+      out_len = MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, len);
+   }
+   else
+   {
+      /* fallback to ANSI codepage instead */
+      len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+
+      if (len)
+      {
+         buf = (wchar_t*)calloc(len, sizeof(wchar_t));
+
+         if (!buf)
+            return NULL;
+
+         out_len = MultiByteToWideChar(CP_ACP, 0, str, -1, buf, len);
+      }
+   }
+
+   if (out_len < 0)
+   {
+      free(buf);
+      return NULL;
+   }
+#else
+   /* NOTE: For now, assume non-Windows platforms' locale is already UTF-8. */
+   len = mbstowcs(NULL, str, 0) + 1;
+
+   if (len)
+   {
+      buf = (wchar_t*)calloc(len, sizeof(wchar_t));
+
+      if (!buf)
+         return NULL;
+
+      out_len = mbstowcs(buf, str, len);
+   }
+
+   if (out_len == (size_t)-1)
+   {
+      free(buf);
+      return NULL;
+   }
+#endif
+
+   return buf;
+}
+
+/* Returned pointer MUST be freed by the caller if non-NULL. */
+char* utf16_to_utf8_string_alloc(const wchar_t *str)
+{
+#ifdef _WIN32
+   int len        = 0;
+#else
+   size_t len     = 0;
+#endif
+   char *buf      = NULL;
+
+   if (!str || !*str)
+      return NULL;
+
+#ifdef _WIN32
+   {
+      UINT code_page = CP_UTF8;
+      len            = WideCharToMultiByte(code_page,
+            0, str, -1, NULL, 0, NULL, NULL);
+
+      /* fallback to ANSI codepage instead */
+      if (!len)
+      {
+         code_page   = CP_ACP;
+         len         = WideCharToMultiByte(code_page,
+               0, str, -1, NULL, 0, NULL, NULL);
+      }
+
+      buf = (char*)calloc(len, sizeof(char));
+
+      if (!buf)
+         return NULL;
+
+      if (WideCharToMultiByte(code_page,
+            0, str, -1, buf, len, NULL, NULL) < 0)
+      {
+         free(buf);
+         return NULL;
+      }
+   }
+#else
+   /* NOTE: For now, assume non-Windows platforms' 
+    * locale is already UTF-8. */
+   len = wcstombs(NULL, str, 0) + 1;
+
+   if (len)
+   {
+      buf = (char*)calloc(len, sizeof(char));
+
+      if (!buf)
+         return NULL;
+
+      if (wcstombs(buf, str, len) == (size_t)-1)
+      {
+         free(buf);
+         return NULL;
+      }
+   }
+#endif
+
+   return buf;
+}
diff --git a/libretro-common/file/file_path.c b/libretro-common/file/file_path.c
new file mode 100644 (file)
index 0000000..3dd53c9
--- /dev/null
@@ -0,0 +1,1293 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_path.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+
+#include <boolean.h>
+#include <file/file_path.h>
+#include <retro_assert.h>
+#include <string/stdstring.h>
+#include <time/rtime.h>
+
+/* TODO: There are probably some unnecessary things on this huge include list now but I'm too afraid to touch it */
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+#ifdef __HAIKU__
+#include <kernel/image.h>
+#endif
+#ifndef __MACH__
+#include <compat/strl.h>
+#include <compat/posix_string.h>
+#endif
+#include <retro_miscellaneous.h>
+#include <encodings/utf.h>
+
+#if defined(_WIN32)
+#ifdef _MSC_VER
+#define setmode _setmode
+#endif
+#include <sys/stat.h>
+#ifdef _XBOX
+#include <xtl.h>
+#define INVALID_FILE_ATTRIBUTES -1
+#else
+#include <io.h>
+#include <fcntl.h>
+#include <direct.h>
+#include <windows.h>
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
+#endif
+#elif defined(VITA)
+#define SCE_ERROR_ERRNO_EEXIST 0x80010011
+#include <psp2/io/fcntl.h>
+#include <psp2/io/dirent.h>
+#include <psp2/io/stat.h>
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#if defined(PSP)
+#include <pspkernel.h>
+#endif
+
+#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+#include <cell/cell_fs.h>
+#endif
+
+#if defined(VITA)
+#define FIO_S_ISDIR SCE_S_ISDIR
+#endif
+
+#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
+#include <unistd.h> /* stat() is defined here */
+#endif
+
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+#ifdef __WINRT__
+#include <uwp/uwp_func.h>
+#endif
+#endif
+
+/* Assume W-functions do not work below Win2K and Xbox platforms */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+
+#endif
+
+/**
+ * path_get_archive_delim:
+ * @path               : path
+ *
+ * Find delimiter of an archive file. Only the first '#'
+ * after a compression extension is considered.
+ *
+ * Returns: pointer to the delimiter in the path if it contains
+ * a path inside a compressed file, otherwise NULL.
+ */
+const char *path_get_archive_delim(const char *path)
+{
+   const char *last_slash = find_last_slash(path);
+   const char *delim      = NULL;
+   char buf[5];
+
+   buf[0] = '\0';
+
+   if (!last_slash)
+      return NULL;
+
+   /* Find delimiter position */
+   delim = strrchr(last_slash, '#');
+
+   if (!delim)
+      return NULL;
+
+   /* Check whether this is a known archive type
+    * > Note: The code duplication here is
+    *   deliberate, to maximise performance */
+   if (delim - last_slash > 4)
+   {
+      strlcpy(buf, delim - 4, sizeof(buf));
+      buf[4] = '\0';
+
+      string_to_lower(buf);
+
+      /* Check if this is a '.zip', '.apk' or '.7z' file */
+      if (string_is_equal(buf,     ".zip") ||
+          string_is_equal(buf,     ".apk") ||
+          string_is_equal(buf + 1, ".7z"))
+         return delim;
+   }
+   else if (delim - last_slash > 3)
+   {
+      strlcpy(buf, delim - 3, sizeof(buf));
+      buf[3] = '\0';
+
+      string_to_lower(buf);
+
+      /* Check if this is a '.7z' file */
+      if (string_is_equal(buf, ".7z"))
+         return delim;
+   }
+
+   return NULL;
+}
+
+/**
+ * path_get_extension:
+ * @path               : path
+ *
+ * Gets extension of file. Only '.'s
+ * after the last slash are considered.
+ *
+ * Returns: extension part from the path.
+ */
+const char *path_get_extension(const char *path)
+{
+   const char *ext;
+   if (!string_is_empty(path) && ((ext = strrchr(path_basename(path), '.'))))
+      return ext + 1;
+   return "";
+}
+
+/**
+ * path_remove_extension:
+ * @path               : path
+ *
+ * Mutates path by removing its extension. Removes all
+ * text after and including the last '.'.
+ * Only '.'s after the last slash are considered.
+ *
+ * Returns:
+ * 1) If path has an extension, returns path with the
+ *    extension removed.
+ * 2) If there is no extension, returns NULL.
+ * 3) If path is empty or NULL, returns NULL
+ */
+char *path_remove_extension(char *path)
+{
+   char *last = !string_is_empty(path)
+      ? (char*)strrchr(path_basename(path), '.') : NULL;
+   if (!last)
+      return NULL;
+   if (*last)
+      *last = '\0';
+   return path;
+}
+
+/**
+ * path_is_compressed_file:
+ * @path               : path
+ *
+ * Checks if path is a compressed file.
+ *
+ * Returns: true (1) if path is a compressed file, otherwise false (0).
+ **/
+bool path_is_compressed_file(const char* path)
+{
+   const char *ext = path_get_extension(path);
+
+   if (string_is_empty(ext))
+      return false;
+
+   if (string_is_equal_noncase(ext, "zip") ||
+       string_is_equal_noncase(ext, "apk") ||
+       string_is_equal_noncase(ext, "7z"))
+      return true;
+
+   return false;
+}
+
+/**
+ * fill_pathname:
+ * @out_path           : output path
+ * @in_path            : input  path
+ * @replace            : what to replace
+ * @size               : buffer size of output path
+ *
+ * FIXME: Verify
+ *
+ * Replaces filename extension with 'replace' and outputs result to out_path.
+ * The extension here is considered to be the string from the last '.'
+ * to the end.
+ *
+ * Only '.'s after the last slash are considered as extensions.
+ * If no '.' is present, in_path and replace will simply be concatenated.
+ * 'size' is buffer size of 'out_path'.
+ * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =>
+ * out_path = "/foo/bar/baz/boo.asm"
+ * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ""     =>
+ * out_path = "/foo/bar/baz/boo"
+ */
+void fill_pathname(char *out_path, const char *in_path,
+      const char *replace, size_t size)
+{
+   char tmp_path[PATH_MAX_LENGTH];
+   char *tok                      = NULL;
+
+   tmp_path[0] = '\0';
+
+   strlcpy(tmp_path, in_path, sizeof(tmp_path));
+   if ((tok = (char*)strrchr(path_basename(tmp_path), '.')))
+      *tok = '\0';
+
+   fill_pathname_noext(out_path, tmp_path, replace, size);
+}
+
+/**
+ * fill_pathname_noext:
+ * @out_path           : output path
+ * @in_path            : input  path
+ * @replace            : what to replace
+ * @size               : buffer size of output path
+ *
+ * Appends a filename extension 'replace' to 'in_path', and outputs
+ * result in 'out_path'.
+ *
+ * Assumes in_path has no extension. If an extension is still
+ * present in 'in_path', it will be ignored.
+ *
+ */
+size_t fill_pathname_noext(char *out_path, const char *in_path,
+      const char *replace, size_t size)
+{
+   strlcpy(out_path, in_path, size);
+   return strlcat(out_path, replace, size);
+}
+
+char *find_last_slash(const char *str)
+{
+   const char *slash     = strrchr(str, '/');
+#ifdef _WIN32
+   const char *backslash = strrchr(str, '\\');
+
+   if (!slash || (backslash > slash))
+      return (char*)backslash;
+#endif
+   return (char*)slash;
+}
+
+/**
+ * fill_pathname_slash:
+ * @path               : path
+ * @size               : size of path
+ *
+ * Assumes path is a directory. Appends a slash
+ * if not already there.
+ **/
+void fill_pathname_slash(char *path, size_t size)
+{
+   size_t path_len;
+   const char *last_slash = find_last_slash(path);
+
+   if (!last_slash)
+   {
+      strlcat(path, PATH_DEFAULT_SLASH(), size);
+      return;
+   }
+
+   path_len               = strlen(path);
+   /* Try to preserve slash type. */
+   if (last_slash != (path + path_len - 1))
+   {
+      path[path_len]   = last_slash[0];
+      path[path_len+1] = '\0';
+   }
+}
+
+/**
+ * fill_pathname_dir:
+ * @in_dir             : input directory path
+ * @in_basename        : input basename to be appended to @in_dir
+ * @replace            : replacement to be appended to @in_basename
+ * @size               : size of buffer
+ *
+ * Appends basename of 'in_basename', to 'in_dir', along with 'replace'.
+ * Basename of in_basename is the string after the last '/' or '\\',
+ * i.e the filename without directories.
+ *
+ * If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
+ * 'size' is buffer size of 'in_dir'.
+ *
+ * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
+ * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
+ **/
+size_t fill_pathname_dir(char *in_dir, const char *in_basename,
+      const char *replace, size_t size)
+{
+   const char *base = NULL;
+
+   fill_pathname_slash(in_dir, size);
+   base = path_basename(in_basename);
+   strlcat(in_dir, base, size);
+   return strlcat(in_dir, replace, size);
+}
+
+/**
+ * fill_pathname_base:
+ * @out                : output path
+ * @in_path            : input path
+ * @size               : size of output path
+ *
+ * Copies basename of @in_path into @out_path.
+ **/
+size_t fill_pathname_base(char *out, const char *in_path, size_t size)
+{
+   const char     *ptr = path_basename(in_path);
+
+   if (!ptr)
+      ptr = in_path;
+
+   return strlcpy(out, ptr, size);
+}
+
+void fill_pathname_base_noext(char *out,
+      const char *in_path, size_t size)
+{
+   fill_pathname_base(out, in_path, size);
+   path_remove_extension(out);
+}
+
+size_t fill_pathname_base_ext(char *out,
+      const char *in_path, const char *ext,
+      size_t size)
+{
+   fill_pathname_base_noext(out, in_path, size);
+   return strlcat(out, ext, size);
+}
+
+/**
+ * fill_pathname_basedir:
+ * @out_dir            : output directory
+ * @in_path            : input path
+ * @size               : size of output directory
+ *
+ * Copies base directory of @in_path into @out_path.
+ * If in_path is a path without any slashes (relative current directory),
+ * @out_path will get path "./".
+ **/
+void fill_pathname_basedir(char *out_dir,
+      const char *in_path, size_t size)
+{
+   if (out_dir != in_path)
+      strlcpy(out_dir, in_path, size);
+   path_basedir(out_dir);
+}
+
+void fill_pathname_basedir_noext(char *out_dir,
+      const char *in_path, size_t size)
+{
+   fill_pathname_basedir(out_dir, in_path, size);
+   path_remove_extension(out_dir);
+}
+
+/**
+ * fill_pathname_parent_dir_name:
+ * @out_dir            : output directory
+ * @in_dir             : input directory
+ * @size               : size of output directory
+ *
+ * Copies only the parent directory name of @in_dir into @out_dir.
+ * The two buffers must not overlap. Removes trailing '/'.
+ * Returns true on success, false if a slash was not found in the path.
+ **/
+bool fill_pathname_parent_dir_name(char *out_dir,
+      const char *in_dir, size_t size)
+{
+   bool success = false;
+   char *temp   = strdup(in_dir);
+   char *last   = find_last_slash(temp);
+
+   if (last && last[1] == 0)
+   {
+      *last     = '\0';
+      last      = find_last_slash(temp);
+   }
+
+   if (last)
+      *last     = '\0';
+
+   in_dir       = find_last_slash(temp);
+
+   success      = in_dir && in_dir[1];
+
+   if (success)
+      strlcpy(out_dir, in_dir + 1, size);
+
+   free(temp);
+   return success;
+}
+
+/**
+ * fill_pathname_parent_dir:
+ * @out_dir            : output directory
+ * @in_dir             : input directory
+ * @size               : size of output directory
+ *
+ * Copies parent directory of @in_dir into @out_dir.
+ * Assumes @in_dir is a directory. Keeps trailing '/'.
+ * If the path was already at the root directory, @out_dir will be an empty string.
+ **/
+void fill_pathname_parent_dir(char *out_dir,
+      const char *in_dir, size_t size)
+{
+   if (out_dir != in_dir)
+      strlcpy(out_dir, in_dir, size);
+   path_parent_dir(out_dir);
+}
+
+/**
+ * fill_dated_filename:
+ * @out_filename       : output filename
+ * @ext                : extension of output filename
+ * @size               : buffer size of output filename
+ *
+ * Creates a 'dated' filename prefixed by 'RetroArch', and
+ * concatenates extension (@ext) to it.
+ *
+ * E.g.:
+ * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
+ **/
+size_t fill_dated_filename(char *out_filename,
+      const char *ext, size_t size)
+{
+   time_t cur_time = time(NULL);
+   struct tm tm_;
+
+   rtime_localtime(&cur_time, &tm_);
+
+   strftime(out_filename, size,
+         "RetroArch-%m%d-%H%M%S", &tm_);
+   return strlcat(out_filename, ext, size);
+}
+
+/**
+ * fill_str_dated_filename:
+ * @out_filename       : output filename
+ * @in_str             : input string
+ * @ext                : extension of output filename
+ * @size               : buffer size of output filename
+ *
+ * Creates a 'dated' filename prefixed by the string @in_str, and
+ * concatenates extension (@ext) to it.
+ *
+ * E.g.:
+ * out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
+ **/
+void fill_str_dated_filename(char *out_filename,
+      const char *in_str, const char *ext, size_t size)
+{
+   char format[256];
+   struct tm tm_;
+   time_t cur_time = time(NULL);
+
+   format[0]       = '\0';
+
+   rtime_localtime(&cur_time, &tm_);
+
+   if (string_is_empty(ext))
+   {
+      strftime(format, sizeof(format), "-%y%m%d-%H%M%S", &tm_);
+      fill_pathname_noext(out_filename, in_str, format, size);
+   }
+   else
+   {
+      strftime(format, sizeof(format), "-%y%m%d-%H%M%S.", &tm_);
+
+      fill_pathname_join_concat_noext(out_filename,
+            in_str, format, ext,
+            size);
+   }
+}
+
+/**
+ * path_basedir:
+ * @path               : path
+ *
+ * Extracts base directory by mutating path.
+ * Keeps trailing '/'.
+ **/
+void path_basedir(char *path)
+{
+   char *last = NULL;
+
+   if (strlen(path) < 2)
+      return;
+
+   last = find_last_slash(path);
+
+   if (last)
+      last[1] = '\0';
+   else
+      snprintf(path, 3, "." PATH_DEFAULT_SLASH());
+}
+
+/**
+ * path_parent_dir:
+ * @path               : path
+ *
+ * Extracts parent directory by mutating path.
+ * Assumes that path is a directory. Keeps trailing '/'.
+ * If the path was already at the root directory, returns empty string
+ **/
+void path_parent_dir(char *path)
+{
+   size_t len = 0;
+
+   if (!path)
+      return;
+   
+   len = strlen(path);
+
+   if (len && PATH_CHAR_IS_SLASH(path[len - 1]))
+   {
+      bool path_was_absolute = path_is_absolute(path);
+
+      path[len - 1] = '\0';
+
+      if (path_was_absolute && !find_last_slash(path))
+      {
+         /* We removed the only slash from what used to be an absolute path.
+          * On Linux, this goes from "/" to an empty string and everything works fine,
+          * but on Windows, we went from C:\ to C:, which is not a valid path and that later
+          * gets errornously treated as a relative one by path_basedir and returns "./".
+          * What we really wanted is an empty string. */
+         path[0] = '\0';
+         return;
+      }
+   }
+   path_basedir(path);
+}
+
+/**
+ * path_basename:
+ * @path               : path
+ *
+ * Get basename from @path.
+ *
+ * Returns: basename from path.
+ **/
+const char *path_basename(const char *path)
+{
+   /* We cut at the first compression-related hash */
+   const char *delim = path_get_archive_delim(path);
+   if (delim)
+      return delim + 1;
+
+   {
+      /* We cut at the last slash */
+      const char *last  = find_last_slash(path);
+      if (last)
+         return last + 1;
+   }
+
+   return path;
+}
+
+/**
+ * path_is_absolute:
+ * @path               : path
+ *
+ * Checks if @path is an absolute path or a relative path.
+ *
+ * Returns: true if path is absolute, false if path is relative.
+ **/
+bool path_is_absolute(const char *path)
+{
+   if (string_is_empty(path))
+      return false;
+
+   if (path[0] == '/')
+      return true;
+
+#if defined(_WIN32)
+   /* Many roads lead to Rome...
+    * Note: Drive letter can only be 1 character long */
+   if (string_starts_with_size(path,     "\\\\", STRLEN_CONST("\\\\")) ||
+       string_starts_with_size(path + 1, ":/",   STRLEN_CONST(":/"))   ||
+       string_starts_with_size(path + 1, ":\\",  STRLEN_CONST(":\\")))
+      return true;
+#elif defined(__wiiu__) || defined(VITA)
+   {
+      const char *seperator = strchr(path, ':');
+      if (seperator && (seperator[1] == '/'))
+         return true;
+   }
+#endif
+
+   return false;
+}
+
+/**
+ * path_resolve_realpath:
+ * @buf                : input and output buffer for path
+ * @size               : size of buffer
+ * @resolve_symlinks   : whether to resolve symlinks or not
+ *
+ * Resolves use of ".", "..", multiple slashes etc in absolute paths.
+ *
+ * Relative paths are rebased on the current working dir.
+ *
+ * Returns: @buf if successful, NULL otherwise.
+ * Note: Not implemented on consoles
+ * Note: Symlinks are only resolved on Unix-likes
+ * Note: The current working dir might not be what you expect,
+ *       e.g. on Android it is "/"
+ *       Use of fill_pathname_resolve_relative() should be prefered
+ **/
+char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks)
+{
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+   char tmp[PATH_MAX_LENGTH];
+#ifdef _WIN32
+   strlcpy(tmp, buf, sizeof(tmp));
+   if (!_fullpath(buf, tmp, size))
+   {
+      strlcpy(buf, tmp, size);
+      return NULL;
+   }
+   return buf;
+#else
+   size_t t;
+   char *p;
+   const char *next;
+   const char *buf_end;
+
+   if (resolve_symlinks)
+   {
+      strlcpy(tmp, buf, sizeof(tmp));
+
+      /* NOTE: realpath() expects at least PATH_MAX_LENGTH bytes in buf.
+       * Technically, PATH_MAX_LENGTH needn't be defined, but we rely on it anyways.
+       * POSIX 2008 can automatically allocate for you,
+       * but don't rely on that. */
+      if (!realpath(tmp, buf))
+      {
+         strlcpy(buf, tmp, size);
+         return NULL;
+      }
+
+      return buf;
+   }
+
+   t = 0; /* length of output */
+   buf_end = buf + strlen(buf);
+
+   if (!path_is_absolute(buf))
+   {
+      size_t len;
+      /* rebase on working directory */
+      if (!getcwd(tmp, PATH_MAX_LENGTH-1))
+         return NULL;
+
+      len = strlen(tmp);
+      t += len;
+
+      if (tmp[len-1] != '/')
+         tmp[t++] = '/';
+
+      if (string_is_empty(buf))
+         goto end;
+
+      p = buf;
+   }
+   else
+   {
+      /* UNIX paths can start with multiple '/', copy those */
+      for (p = buf; *p == '/'; p++)
+         tmp[t++] = '/';
+   }
+
+   /* p points to just after a slash while 'next' points to the next slash
+    * if there are no slashes, they point relative to where one would be */
+   do
+   {
+      next = strchr(p, '/');
+      if (!next)
+         next = buf_end;
+
+      if ((next - p == 2 && p[0] == '.' && p[1] == '.'))
+      {
+         p += 3;
+
+         /* fail for illegal /.., //.. etc */
+         if (t == 1 || tmp[t-2] == '/')
+            return NULL;
+
+         /* delete previous segment in tmp by adjusting size t
+          * tmp[t-1] == '/', find '/' before that */
+         t = t-2;
+         while (tmp[t] != '/')
+            t--;
+         t++;
+      }
+      else if (next - p == 1 && p[0] == '.')
+         p += 2;
+      else if (next - p == 0)
+         p += 1;
+      else
+      {
+         /* fail when truncating */
+         if (t + next-p+1 > PATH_MAX_LENGTH-1)
+            return NULL;
+
+         while (p <= next)
+            tmp[t++] = *p++;
+      }
+
+   }
+   while (next < buf_end);
+
+end:
+   tmp[t] = '\0';
+   strlcpy(buf, tmp, size);
+   return buf;
+#endif
+#endif
+   return NULL;
+}
+
+/**
+ * path_relative_to:
+ * @out                : buffer to write the relative path to
+ * @path               : path to be expressed relatively
+ * @base               : base directory to start out on
+ * @size               : size of output buffer
+ *
+ * Turns @path into a path relative to @base and writes it to @out.
+ *
+ * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
+ * Both @path and @base are assumed to be absolute paths without "." or "..".
+ *
+ * E.g. path /a/b/e/f.cg with base /a/b/c/d/ turns into ../../e/f.cg
+ **/
+size_t path_relative_to(char *out,
+      const char *path, const char *base, size_t size)
+{
+   size_t i, j;
+   const char *trimmed_path, *trimmed_base;
+
+#ifdef _WIN32
+   /* For different drives, return absolute path */
+   if (strlen(path) >= 2 && strlen(base) >= 2
+         && path[1] == ':' && base[1] == ':'
+         && path[0] != base[0])
+      return strlcpy(out, path, size);
+#endif
+
+   /* Trim common beginning */
+   for (i = 0, j = 0; path[i] && base[i] && path[i] == base[i]; i++)
+      if (path[i] == PATH_DEFAULT_SLASH_C())
+         j = i + 1;
+
+   trimmed_path = path+j;
+   trimmed_base = base+i;
+
+   /* Each segment of base turns into ".." */
+   out[0] = '\0';
+   for (i = 0; trimmed_base[i]; i++)
+      if (trimmed_base[i] == PATH_DEFAULT_SLASH_C())
+         strlcat(out, ".." PATH_DEFAULT_SLASH(), size);
+
+   return strlcat(out, trimmed_path, size);
+}
+
+/**
+ * fill_pathname_resolve_relative:
+ * @out_path           : output path
+ * @in_refpath         : input reference path
+ * @in_path            : input path
+ * @size               : size of @out_path
+ *
+ * Joins basedir of @in_refpath together with @in_path.
+ * If @in_path is an absolute path, out_path = in_path.
+ * E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
+ * out_path = "/foo/bar/foobar.cg".
+ **/
+void fill_pathname_resolve_relative(char *out_path,
+      const char *in_refpath, const char *in_path, size_t size)
+{
+   if (path_is_absolute(in_path))
+   {
+      strlcpy(out_path, in_path, size);
+      return;
+   }
+
+   fill_pathname_basedir(out_path, in_refpath, size);
+   strlcat(out_path, in_path, size);
+   path_resolve_realpath(out_path, size, false);
+}
+
+/**
+ * fill_pathname_join:
+ * @out_path           : output path
+ * @dir                : directory
+ * @path               : path
+ * @size               : size of output path
+ *
+ * Joins a directory (@dir) and path (@path) together.
+ * Makes sure not to get  two consecutive slashes
+ * between directory and path.
+ **/
+size_t fill_pathname_join(char *out_path,
+      const char *dir, const char *path, size_t size)
+{
+   if (out_path != dir)
+      strlcpy(out_path, dir, size);
+
+   if (*out_path)
+      fill_pathname_slash(out_path, size);
+
+   return strlcat(out_path, path, size);
+}
+
+size_t fill_pathname_join_special_ext(char *out_path,
+      const char *dir,  const char *path,
+      const char *last, const char *ext,
+      size_t size)
+{
+   fill_pathname_join(out_path, dir, path, size);
+   if (*out_path)
+      fill_pathname_slash(out_path, size);
+
+   strlcat(out_path, last, size);
+   return strlcat(out_path, ext, size);
+}
+
+size_t fill_pathname_join_concat_noext(char *out_path,
+      const char *dir, const char *path,
+      const char *concat,
+      size_t size)
+{
+   fill_pathname_noext(out_path, dir, path, size);
+   return strlcat(out_path, concat, size);
+}
+
+size_t fill_pathname_join_concat(char *out_path,
+      const char *dir, const char *path,
+      const char *concat,
+      size_t size)
+{
+   fill_pathname_join(out_path, dir, path, size);
+   return strlcat(out_path, concat, size);
+}
+
+void fill_pathname_join_noext(char *out_path,
+      const char *dir, const char *path, size_t size)
+{
+   fill_pathname_join(out_path, dir, path, size);
+   path_remove_extension(out_path);
+}
+
+/**
+ * fill_pathname_join_delim:
+ * @out_path           : output path
+ * @dir                : directory
+ * @path               : path
+ * @delim              : delimiter
+ * @size               : size of output path
+ *
+ * Joins a directory (@dir) and path (@path) together
+ * using the given delimiter (@delim).
+ **/
+size_t fill_pathname_join_delim(char *out_path, const char *dir,
+      const char *path, const char delim, size_t size)
+{
+   size_t copied;
+   /* behavior of strlcpy is undefined if dst and src overlap */
+   if (out_path == dir)
+      copied = strlen(dir);
+   else
+      copied = strlcpy(out_path, dir, size);
+
+   out_path[copied]   = delim;
+   out_path[copied+1] = '\0';
+
+   if (path)
+      copied = strlcat(out_path, path, size);
+   return copied;
+}
+
+size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
+      const char *path, const char delim, const char *concat,
+      size_t size)
+{
+   fill_pathname_join_delim(out_path, dir, path, delim, size);
+   return strlcat(out_path, concat, size);
+}
+
+/**
+ * fill_short_pathname_representation:
+ * @out_rep            : output representation
+ * @in_path            : input path
+ * @size               : size of output representation
+ *
+ * Generates a short representation of path. It should only
+ * be used for displaying the result; the output representation is not
+ * binding in any meaningful way (for a normal path, this is the same as basename)
+ * In case of more complex URLs, this should cut everything except for
+ * the main image file.
+ *
+ * E.g.: "/path/to/game.img" -> game.img
+ *       "/path/to/myarchive.7z#folder/to/game.img" -> game.img
+ */
+size_t fill_short_pathname_representation(char* out_rep,
+      const char *in_path, size_t size)
+{
+   char path_short[PATH_MAX_LENGTH];
+
+   path_short[0] = '\0';
+
+   fill_pathname(path_short, path_basename(in_path), "",
+            sizeof(path_short));
+
+   return strlcpy(out_rep, path_short, size);
+}
+
+void fill_short_pathname_representation_noext(char* out_rep,
+      const char *in_path, size_t size)
+{
+   fill_short_pathname_representation(out_rep, in_path, size);
+   path_remove_extension(out_rep);
+}
+
+void fill_pathname_expand_special(char *out_path,
+      const char *in_path, size_t size)
+{
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+   if (in_path[0] == '~')
+   {
+      char *home_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
+
+      home_dir[0] = '\0';
+
+      fill_pathname_home_dir(home_dir,
+         PATH_MAX_LENGTH * sizeof(char));
+
+      if (*home_dir)
+      {
+         size_t src_size = strlcpy(out_path, home_dir, size);
+         retro_assert(src_size < size);
+
+         out_path  += src_size;
+         size      -= src_size;
+
+         if (!PATH_CHAR_IS_SLASH(out_path[-1]))
+         {
+            src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
+            retro_assert(src_size < size);
+
+            out_path += src_size;
+            size     -= src_size;
+         }
+
+         in_path += 2;
+      }
+
+      free(home_dir);
+   }
+   else if (in_path[0] == ':')
+   {
+      char *application_dir = (char*)malloc(PATH_MAX_LENGTH * sizeof(char));
+
+      application_dir[0]    = '\0';
+
+      fill_pathname_application_dir(application_dir,
+            PATH_MAX_LENGTH * sizeof(char));
+
+      if (*application_dir)
+      {
+         size_t src_size   = strlcpy(out_path, application_dir, size);
+         retro_assert(src_size < size);
+
+         out_path  += src_size;
+         size      -= src_size;
+
+         if (!PATH_CHAR_IS_SLASH(out_path[-1]))
+         {
+            src_size = strlcpy(out_path, PATH_DEFAULT_SLASH(), size);
+            retro_assert(src_size < size);
+
+            out_path += src_size;
+            size     -= src_size;
+         }
+
+         in_path += 2;
+      }
+
+      free(application_dir);
+   }
+#endif
+
+   retro_assert(strlcpy(out_path, in_path, size) < size);
+}
+
+void fill_pathname_abbreviate_special(char *out_path,
+      const char *in_path, size_t size)
+{
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+   unsigned i;
+   const char *candidates[3];
+   const char *notations[3];
+   char application_dir[PATH_MAX_LENGTH];
+   char home_dir[PATH_MAX_LENGTH];
+
+   application_dir[0] = '\0';
+   home_dir[0]        = '\0';
+
+   /* application_dir could be zero-string. Safeguard against this.
+    *
+    * Keep application dir in front of home, moving app dir to a
+    * new location inside home would break otherwise. */
+
+   /* ugly hack - use application_dir pointer
+    * before filling it in. C89 reasons */
+   candidates[0] = application_dir;
+   candidates[1] = home_dir;
+   candidates[2] = NULL;
+
+   notations [0] = ":";
+   notations [1] = "~";
+   notations [2] = NULL;
+
+   fill_pathname_application_dir(application_dir, sizeof(application_dir));
+   fill_pathname_home_dir(home_dir, sizeof(home_dir));
+
+   for (i = 0; candidates[i]; i++)
+   {
+      if (!string_is_empty(candidates[i]) &&
+          string_starts_with(in_path, candidates[i]))
+      {
+         size_t src_size  = strlcpy(out_path, notations[i], size);
+
+         retro_assert(src_size < size);
+
+         out_path        += src_size;
+         size            -= src_size;
+         in_path         += strlen(candidates[i]);
+
+         if (!PATH_CHAR_IS_SLASH(*in_path))
+         {
+            strcpy_literal(out_path, PATH_DEFAULT_SLASH());
+            out_path++;
+            size--;
+         }
+
+         break; /* Don't allow more abbrevs to take place. */
+      }
+   }
+
+#endif
+
+   retro_assert(strlcpy(out_path, in_path, size) < size);
+}
+
+/**
+ * path_basedir:
+ * @path               : path
+ *
+ * Extracts base directory by mutating path.
+ * Keeps trailing '/'.
+ **/
+void path_basedir_wrapper(char *path)
+{
+   char *last = NULL;
+   if (strlen(path) < 2)
+      return;
+
+#ifdef HAVE_COMPRESSION
+   /* We want to find the directory with the archive in basedir. */
+   last = (char*)path_get_archive_delim(path);
+   if (last)
+      *last = '\0';
+#endif
+
+   last = find_last_slash(path);
+
+   if (last)
+      last[1] = '\0';
+   else
+      snprintf(path, 3, "." PATH_DEFAULT_SLASH());
+}
+
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+void fill_pathname_application_path(char *s, size_t len)
+{
+   size_t i;
+#ifdef __APPLE__
+  CFBundleRef bundle = CFBundleGetMainBundle();
+#endif
+#ifdef _WIN32
+   DWORD ret = 0;
+   wchar_t wstr[PATH_MAX_LENGTH] = {0};
+#endif
+#ifdef __HAIKU__
+   image_info info;
+   int32_t cookie = 0;
+#endif
+   (void)i;
+
+   if (!len)
+      return;
+
+#if defined(_WIN32)
+#ifdef LEGACY_WIN32
+   ret    = GetModuleFileNameA(NULL, s, len);
+#else
+   ret    = GetModuleFileNameW(NULL, wstr, ARRAY_SIZE(wstr));
+
+   if (*wstr)
+   {
+      char *str = utf16_to_utf8_string_alloc(wstr);
+
+      if (str)
+      {
+         strlcpy(s, str, len);
+         free(str);
+      }
+   }
+#endif
+   s[ret] = '\0';
+#elif defined(__APPLE__)
+   if (bundle)
+   {
+      CFURLRef bundle_url     = CFBundleCopyBundleURL(bundle);
+      CFStringRef bundle_path = CFURLCopyPath(bundle_url);
+      CFStringGetCString(bundle_path, s, len, kCFStringEncodingUTF8);
+#ifdef HAVE_COCOATOUCH
+      {
+         /* This needs to be done so that the path becomes 
+          * /private/var/... and this
+          * is used consistently throughout for the iOS bundle path */
+         char resolved_bundle_dir_buf[PATH_MAX_LENGTH] = {0};
+         if (realpath(s, resolved_bundle_dir_buf))
+         {
+            strlcpy(s, resolved_bundle_dir_buf, len - 1);
+            strlcat(s, "/", len);
+         }
+      }
+#endif
+
+      CFRelease(bundle_path);
+      CFRelease(bundle_url);
+#ifndef HAVE_COCOATOUCH
+      /* Not sure what this does but it breaks 
+       * stuff for iOS, so skipping */
+      retro_assert(strlcat(s, "nobin", len) < len);
+#endif
+      return;
+   }
+#elif defined(__HAIKU__)
+   while (get_next_image_info(0, &cookie, &info) == B_OK)
+   {
+      if (info.type == B_APP_IMAGE)
+      {
+         strlcpy(s, info.name, len);
+         return;
+      }
+   }
+#elif defined(__QNX__)
+   char *buff = malloc(len);
+
+   if (_cmdname(buff))
+      strlcpy(s, buff, len);
+
+   free(buff);
+#else
+   {
+      pid_t pid;
+      static const char *exts[] = { "exe", "file", "path/a.out" };
+      char link_path[255];
+
+      link_path[0] = *s = '\0';
+      pid       = getpid();
+
+      /* Linux, BSD and Solaris paths. Not standardized. */
+      for (i = 0; i < ARRAY_SIZE(exts); i++)
+      {
+         ssize_t ret;
+
+         snprintf(link_path, sizeof(link_path), "/proc/%u/%s",
+               (unsigned)pid, exts[i]);
+         ret = readlink(link_path, s, len - 1);
+
+         if (ret >= 0)
+         {
+            s[ret] = '\0';
+            return;
+         }
+      }
+   }
+#endif
+}
+
+void fill_pathname_application_dir(char *s, size_t len)
+{
+#ifdef __WINRT__
+   strlcpy(s, uwp_dir_install, len);
+#else
+   fill_pathname_application_path(s, len);
+   path_basedir_wrapper(s);
+#endif
+}
+
+void fill_pathname_home_dir(char *s, size_t len)
+{
+#ifdef __WINRT__
+   const char *home = uwp_dir_data;
+#else
+   const char *home = getenv("HOME");
+#endif
+   if (home)
+      strlcpy(s, home, len);
+   else
+      *s = 0;
+}
+#endif
+
+bool is_path_accessible_using_standard_io(const char *path)
+{
+#ifdef __WINRT__
+   char relative_path_abbrev[PATH_MAX_LENGTH];
+   fill_pathname_abbreviate_special(relative_path_abbrev,
+         path, sizeof(relative_path_abbrev));
+   return (strlen(relative_path_abbrev) >= 2 )
+      &&  (    relative_path_abbrev[0] == ':'
+            || relative_path_abbrev[0] == '~')
+      && PATH_CHAR_IS_SLASH(relative_path_abbrev[1]);
+#else
+   return true;
+#endif
+}
diff --git a/libretro-common/include/boolean.h b/libretro-common/include/boolean.h
new file mode 100644 (file)
index 0000000..9d0d7c1
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (boolean.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_BOOLEAN_H
+#define __LIBRETRO_SDK_BOOLEAN_H
+
+#ifndef __cplusplus
+
+#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
+/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
+#define bool unsigned char
+#define true 1
+#define false 0
+#else
+#include <stdbool.h>
+#endif
+
+#endif
+
+#endif
diff --git a/libretro-common/include/compat/fopen_utf8.h b/libretro-common/include/compat/fopen_utf8.h
new file mode 100644 (file)
index 0000000..97d4404
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (fopen_utf8.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
+#define __LIBRETRO_SDK_COMPAT_FOPEN_UTF8_H
+
+#ifdef _WIN32
+/* Defined to error rather than fopen_utf8, to make it clear to everyone reading the code that not worrying about utf16 is fine */
+/* TODO: enable */
+/* #define fopen (use fopen_utf8 instead) */
+void *fopen_utf8(const char * filename, const char * mode);
+#else
+#define fopen_utf8 fopen
+#endif
+#endif
diff --git a/libretro-common/include/compat/posix_string.h b/libretro-common/include/compat/posix_string.h
new file mode 100644 (file)
index 0000000..47964b2
--- /dev/null
@@ -0,0 +1,60 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (posix_string.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
+#define __LIBRETRO_SDK_COMPAT_POSIX_STRING_H
+
+#include <retro_common_api.h>
+
+#ifdef _MSC_VER
+#include <compat/msvc.h>
+#endif
+
+RETRO_BEGIN_DECLS
+
+#ifdef _WIN32
+#undef strtok_r
+#define strtok_r(str, delim, saveptr) retro_strtok_r__(str, delim, saveptr)
+
+char *strtok_r(char *str, const char *delim, char **saveptr);
+#endif
+
+#ifdef _MSC_VER
+#undef strcasecmp
+#undef strdup
+#define strcasecmp(a, b) retro_strcasecmp__(a, b)
+#define strdup(orig)     retro_strdup__(orig)
+int strcasecmp(const char *a, const char *b);
+char *strdup(const char *orig);
+
+/* isblank is available since MSVC 2013 */
+#if _MSC_VER < 1800
+#undef isblank
+#define isblank(c)       retro_isblank__(c)
+int isblank(int c);
+#endif
+
+#endif
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/include/compat/strcasestr.h b/libretro-common/include/compat/strcasestr.h
new file mode 100644 (file)
index 0000000..227e253
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (strcasestr.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_COMPAT_STRCASESTR_H
+#define __LIBRETRO_SDK_COMPAT_STRCASESTR_H
+
+#include <string.h>
+
+#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
+#include "../../../config.h"
+#endif
+
+#ifndef HAVE_STRCASESTR
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+/* Avoid possible naming collisions during link
+ * since we prefer to use the actual name. */
+#define strcasestr(haystack, needle) strcasestr_retro__(haystack, needle)
+
+char *strcasestr(const char *haystack, const char *needle);
+
+RETRO_END_DECLS
+
+#endif
+
+#endif
diff --git a/libretro-common/include/compat/strl.h b/libretro-common/include/compat/strl.h
new file mode 100644 (file)
index 0000000..5e7a892
--- /dev/null
@@ -0,0 +1,59 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (strl.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_COMPAT_STRL_H
+#define __LIBRETRO_SDK_COMPAT_STRL_H
+
+#include <string.h>
+#include <stddef.h>
+
+#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
+#include "../../../config.h"
+#endif
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+#ifdef __MACH__
+#ifndef HAVE_STRL
+#define HAVE_STRL
+#endif
+#endif
+
+#ifndef HAVE_STRL
+/* Avoid possible naming collisions during link since
+ * we prefer to use the actual name. */
+#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)
+
+#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)
+
+size_t strlcpy(char *dest, const char *source, size_t size);
+size_t strlcat(char *dest, const char *source, size_t size);
+
+#endif
+
+char *strldup(const char *s, size_t n);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/include/encodings/utf.h b/libretro-common/include/encodings/utf.h
new file mode 100644 (file)
index 0000000..bea4e14
--- /dev/null
@@ -0,0 +1,67 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (utf.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _LIBRETRO_ENCODINGS_UTF_H
+#define _LIBRETRO_ENCODINGS_UTF_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <boolean.h>
+
+#include <retro_common_api.h>
+
+RETRO_BEGIN_DECLS
+
+enum CodePage
+{
+   CODEPAGE_LOCAL = 0, /* CP_ACP */
+   CODEPAGE_UTF8  = 65001 /* CP_UTF8 */
+};
+
+size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
+      const char *in, size_t in_size);
+
+bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
+      const uint16_t *in, size_t in_size);
+
+size_t utf8len(const char *string);
+
+size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
+
+const char *utf8skip(const char *str, size_t chars);
+
+uint32_t utf8_walk(const char **string);
+
+bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
+
+char* utf8_to_local_string_alloc(const char *str);
+
+char* local_to_utf8_string_alloc(const char *str);
+
+wchar_t* utf8_to_utf16_string_alloc(const char *str);
+
+char* utf16_to_utf8_string_alloc(const wchar_t *str);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/include/file/file_path.h b/libretro-common/include/file/file_path.h
new file mode 100644 (file)
index 0000000..6f1918d
--- /dev/null
@@ -0,0 +1,531 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_path.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_FILE_PATH_H
+#define __LIBRETRO_SDK_FILE_PATH_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#include <libretro.h>
+#include <retro_common_api.h>
+
+#include <boolean.h>
+
+RETRO_BEGIN_DECLS
+
+#define PATH_REQUIRED_VFS_VERSION 3
+
+void path_vfs_init(const struct retro_vfs_interface_info* vfs_info);
+
+/* Order in this enum is equivalent to negative sort order in filelist
+ *  (i.e. DIRECTORY is on top of PLAIN_FILE) */
+enum
+{
+   RARCH_FILETYPE_UNSET,
+   RARCH_PLAIN_FILE,
+   RARCH_COMPRESSED_FILE_IN_ARCHIVE,
+   RARCH_COMPRESSED_ARCHIVE,
+   RARCH_DIRECTORY,
+   RARCH_FILE_UNSUPPORTED
+};
+
+/**
+ * path_is_compressed_file:
+ * @path               : path
+ *
+ * Checks if path is a compressed file.
+ *
+ * Returns: true (1) if path is a compressed file, otherwise false (0).
+ **/
+bool path_is_compressed_file(const char *path);
+
+/**
+ * path_contains_compressed_file:
+ * @path               : path
+ *
+ * Checks if path contains a compressed file.
+ *
+ * Currently we only check for hash symbol (#) inside the pathname.
+ * If path is ever expanded to a general URI, we should check for that here.
+ *
+ * Example:  Somewhere in the path there might be a compressed file
+ * E.g.: /path/to/file.7z#mygame.img
+ *
+ * Returns: true (1) if path contains compressed file, otherwise false (0).
+ **/
+#define path_contains_compressed_file(path) (path_get_archive_delim((path)) != NULL)
+
+/**
+ * path_get_archive_delim:
+ * @path               : path
+ *
+ * Gets delimiter of an archive file. Only the first '#'
+ * after a compression extension is considered.
+ *
+ * Returns: pointer to the delimiter in the path if it contains
+ * a compressed file, otherwise NULL.
+ */
+const char *path_get_archive_delim(const char *path);
+
+/**
+ * path_get_extension:
+ * @path               : path
+ *
+ * Gets extension of file. Only '.'s
+ * after the last slash are considered.
+ *
+ * Returns: extension part from the path.
+ */
+const char *path_get_extension(const char *path);
+
+/**
+ * path_remove_extension:
+ * @path               : path
+ *
+ * Mutates path by removing its extension. Removes all
+ * text after and including the last '.'.
+ * Only '.'s after the last slash are considered.
+ *
+ * Returns:
+ * 1) If path has an extension, returns path with the
+ *    extension removed.
+ * 2) If there is no extension, returns NULL.
+ * 3) If path is empty or NULL, returns NULL
+ */
+char *path_remove_extension(char *path);
+
+/**
+ * path_basename:
+ * @path               : path
+ *
+ * Get basename from @path.
+ *
+ * Returns: basename from path.
+ **/
+const char *path_basename(const char *path);
+
+/**
+ * path_basedir:
+ * @path               : path
+ *
+ * Extracts base directory by mutating path.
+ * Keeps trailing '/'.
+ **/
+void path_basedir(char *path);
+
+/**
+ * path_parent_dir:
+ * @path               : path
+ *
+ * Extracts parent directory by mutating path.
+ * Assumes that path is a directory. Keeps trailing '/'.
+ * If the path was already at the root directory, returns empty string
+ **/
+void path_parent_dir(char *path);
+
+/**
+ * path_resolve_realpath:
+ * @buf                : input and output buffer for path
+ * @size               : size of buffer
+ * @resolve_symlinks   : whether to resolve symlinks or not
+ *
+ * Resolves use of ".", "..", multiple slashes etc in absolute paths.
+ *
+ * Relative paths are rebased on the current working dir.
+ *
+ * Returns: @buf if successful, NULL otherwise.
+ * Note: Not implemented on consoles
+ * Note: Symlinks are only resolved on Unix-likes
+ * Note: The current working dir might not be what you expect,
+ *       e.g. on Android it is "/"
+ *       Use of fill_pathname_resolve_relative() should be prefered
+ **/
+char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks);
+
+/**
+ * path_relative_to:
+ * @out                : buffer to write the relative path to
+ * @path               : path to be expressed relatively
+ * @base               : relative to this
+ * @size               : size of output buffer
+ *
+ * Turns @path into a path relative to @base and writes it to @out.
+ *
+ * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'.
+ * Both @path and @base are assumed to be absolute paths without "." or "..".
+ *
+ * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp
+ **/
+size_t path_relative_to(char *out, const char *path, const char *base, size_t size);
+
+/**
+ * path_is_absolute:
+ * @path               : path
+ *
+ * Checks if @path is an absolute path or a relative path.
+ *
+ * Returns: true if path is absolute, false if path is relative.
+ **/
+bool path_is_absolute(const char *path);
+
+/**
+ * fill_pathname:
+ * @out_path           : output path
+ * @in_path            : input  path
+ * @replace            : what to replace
+ * @size               : buffer size of output path
+ *
+ * FIXME: Verify
+ *
+ * Replaces filename extension with 'replace' and outputs result to out_path.
+ * The extension here is considered to be the string from the last '.'
+ * to the end.
+ *
+ * Only '.'s after the last slash are considered as extensions.
+ * If no '.' is present, in_path and replace will simply be concatenated.
+ * 'size' is buffer size of 'out_path'.
+ * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" =>
+ * out_path = "/foo/bar/baz/boo.asm"
+ * E.g.: in_path = "/foo/bar/baz/boo.c", replace = ""     =>
+ * out_path = "/foo/bar/baz/boo"
+ */
+void fill_pathname(char *out_path, const char *in_path,
+      const char *replace, size_t size);
+
+/**
+ * fill_dated_filename:
+ * @out_filename       : output filename
+ * @ext                : extension of output filename
+ * @size               : buffer size of output filename
+ *
+ * Creates a 'dated' filename prefixed by 'RetroArch', and
+ * concatenates extension (@ext) to it.
+ *
+ * E.g.:
+ * out_filename = "RetroArch-{month}{day}-{Hours}{Minutes}.{@ext}"
+ **/
+size_t fill_dated_filename(char *out_filename,
+      const char *ext, size_t size);
+
+/**
+ * fill_str_dated_filename:
+ * @out_filename       : output filename
+ * @in_str             : input string
+ * @ext                : extension of output filename
+ * @size               : buffer size of output filename
+ *
+ * Creates a 'dated' filename prefixed by the string @in_str, and
+ * concatenates extension (@ext) to it.
+ *
+ * E.g.:
+ * out_filename = "RetroArch-{year}{month}{day}-{Hour}{Minute}{Second}.{@ext}"
+ **/
+void fill_str_dated_filename(char *out_filename,
+      const char *in_str, const char *ext, size_t size);
+
+/**
+ * fill_pathname_noext:
+ * @out_path           : output path
+ * @in_path            : input  path
+ * @replace            : what to replace
+ * @size               : buffer size of output path
+ *
+ * Appends a filename extension 'replace' to 'in_path', and outputs
+ * result in 'out_path'.
+ *
+ * Assumes in_path has no extension. If an extension is still
+ * present in 'in_path', it will be ignored.
+ *
+ */
+size_t fill_pathname_noext(char *out_path, const char *in_path,
+      const char *replace, size_t size);
+
+/**
+ * find_last_slash:
+ * @str : input path
+ *
+ * Gets a pointer to the last slash in the input path.
+ *
+ * Returns: a pointer to the last slash in the input path.
+ **/
+char *find_last_slash(const char *str);
+
+/**
+ * fill_pathname_dir:
+ * @in_dir             : input directory path
+ * @in_basename        : input basename to be appended to @in_dir
+ * @replace            : replacement to be appended to @in_basename
+ * @size               : size of buffer
+ *
+ * Appends basename of 'in_basename', to 'in_dir', along with 'replace'.
+ * Basename of in_basename is the string after the last '/' or '\\',
+ * i.e the filename without directories.
+ *
+ * If in_basename has no '/' or '\\', the whole 'in_basename' will be used.
+ * 'size' is buffer size of 'in_dir'.
+ *
+ * E.g..: in_dir = "/tmp/some_dir", in_basename = "/some_content/foo.c",
+ * replace = ".asm" => in_dir = "/tmp/some_dir/foo.c.asm"
+ **/
+size_t fill_pathname_dir(char *in_dir, const char *in_basename,
+      const char *replace, size_t size);
+
+/**
+ * fill_pathname_base:
+ * @out                : output path
+ * @in_path            : input path
+ * @size               : size of output path
+ *
+ * Copies basename of @in_path into @out_path.
+ **/
+size_t fill_pathname_base(char *out_path, const char *in_path, size_t size);
+
+void fill_pathname_base_noext(char *out_dir,
+      const char *in_path, size_t size);
+
+size_t fill_pathname_base_ext(char *out,
+      const char *in_path, const char *ext,
+      size_t size);
+
+/**
+ * fill_pathname_basedir:
+ * @out_dir            : output directory
+ * @in_path            : input path
+ * @size               : size of output directory
+ *
+ * Copies base directory of @in_path into @out_path.
+ * If in_path is a path without any slashes (relative current directory),
+ * @out_path will get path "./".
+ **/
+void fill_pathname_basedir(char *out_path, const char *in_path, size_t size);
+
+void fill_pathname_basedir_noext(char *out_dir,
+      const char *in_path, size_t size);
+
+/**
+ * fill_pathname_parent_dir_name:
+ * @out_dir            : output directory
+ * @in_dir             : input directory
+ * @size               : size of output directory
+ *
+ * Copies only the parent directory name of @in_dir into @out_dir.
+ * The two buffers must not overlap. Removes trailing '/'.
+ * Returns true on success, false if a slash was not found in the path.
+ **/
+bool fill_pathname_parent_dir_name(char *out_dir,
+      const char *in_dir, size_t size);
+
+/**
+ * fill_pathname_parent_dir:
+ * @out_dir            : output directory
+ * @in_dir             : input directory
+ * @size               : size of output directory
+ *
+ * Copies parent directory of @in_dir into @out_dir.
+ * Assumes @in_dir is a directory. Keeps trailing '/'.
+ * If the path was already at the root directory, @out_dir will be an empty string.
+ **/
+void fill_pathname_parent_dir(char *out_dir,
+      const char *in_dir, size_t size);
+
+/**
+ * fill_pathname_resolve_relative:
+ * @out_path           : output path
+ * @in_refpath         : input reference path
+ * @in_path            : input path
+ * @size               : size of @out_path
+ *
+ * Joins basedir of @in_refpath together with @in_path.
+ * If @in_path is an absolute path, out_path = in_path.
+ * E.g.: in_refpath = "/foo/bar/baz.a", in_path = "foobar.cg",
+ * out_path = "/foo/bar/foobar.cg".
+ **/
+void fill_pathname_resolve_relative(char *out_path, const char *in_refpath,
+      const char *in_path, size_t size);
+
+/**
+ * fill_pathname_join:
+ * @out_path           : output path
+ * @dir                : directory
+ * @path               : path
+ * @size               : size of output path
+ *
+ * Joins a directory (@dir) and path (@path) together.
+ * Makes sure not to get  two consecutive slashes
+ * between directory and path.
+ **/
+size_t fill_pathname_join(char *out_path, const char *dir,
+      const char *path, size_t size);
+
+size_t fill_pathname_join_special_ext(char *out_path,
+      const char *dir,  const char *path,
+      const char *last, const char *ext,
+      size_t size);
+
+size_t fill_pathname_join_concat_noext(char *out_path,
+      const char *dir, const char *path,
+      const char *concat,
+      size_t size);
+
+size_t fill_pathname_join_concat(char *out_path,
+      const char *dir, const char *path,
+      const char *concat,
+      size_t size);
+
+void fill_pathname_join_noext(char *out_path,
+      const char *dir, const char *path, size_t size);
+
+/**
+ * fill_pathname_join_delim:
+ * @out_path           : output path
+ * @dir                : directory
+ * @path               : path
+ * @delim              : delimiter
+ * @size               : size of output path
+ *
+ * Joins a directory (@dir) and path (@path) together
+ * using the given delimiter (@delim).
+ **/
+size_t fill_pathname_join_delim(char *out_path, const char *dir,
+      const char *path, const char delim, size_t size);
+
+size_t fill_pathname_join_delim_concat(char *out_path, const char *dir,
+      const char *path, const char delim, const char *concat,
+      size_t size);
+
+/**
+ * fill_short_pathname_representation:
+ * @out_rep            : output representation
+ * @in_path            : input path
+ * @size               : size of output representation
+ *
+ * Generates a short representation of path. It should only
+ * be used for displaying the result; the output representation is not
+ * binding in any meaningful way (for a normal path, this is the same as basename)
+ * In case of more complex URLs, this should cut everything except for
+ * the main image file.
+ *
+ * E.g.: "/path/to/game.img" -> game.img
+ *       "/path/to/myarchive.7z#folder/to/game.img" -> game.img
+ */
+size_t fill_short_pathname_representation(char* out_rep,
+      const char *in_path, size_t size);
+
+void fill_short_pathname_representation_noext(char* out_rep,
+      const char *in_path, size_t size);
+
+void fill_pathname_expand_special(char *out_path,
+      const char *in_path, size_t size);
+
+void fill_pathname_abbreviate_special(char *out_path,
+      const char *in_path, size_t size);
+
+/**
+ * path_basedir:
+ * @path               : path
+ *
+ * Extracts base directory by mutating path.
+ * Keeps trailing '/'.
+ **/
+void path_basedir_wrapper(char *path);
+
+/**
+ * path_char_is_slash:
+ * @c                  : character
+ *
+ * Checks if character (@c) is a slash.
+ *
+ * Returns: true (1) if character is a slash, otherwise false (0).
+ */
+#ifdef _WIN32
+#define PATH_CHAR_IS_SLASH(c) (((c) == '/') || ((c) == '\\'))
+#else
+#define PATH_CHAR_IS_SLASH(c) ((c) == '/')
+#endif
+
+/**
+ * path_default_slash and path_default_slash_c:
+ *
+ * Gets the default slash separator.
+ *
+ * Returns: default slash separator.
+ */
+#ifdef _WIN32
+#define PATH_DEFAULT_SLASH() "\\"
+#define PATH_DEFAULT_SLASH_C() '\\'
+#else
+#define PATH_DEFAULT_SLASH() "/"
+#define PATH_DEFAULT_SLASH_C() '/'
+#endif
+
+/**
+ * fill_pathname_slash:
+ * @path               : path
+ * @size               : size of path
+ *
+ * Assumes path is a directory. Appends a slash
+ * if not already there.
+ **/
+void fill_pathname_slash(char *path, size_t size);
+
+#if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL)
+void fill_pathname_application_path(char *buf, size_t size);
+void fill_pathname_application_dir(char *buf, size_t size);
+void fill_pathname_home_dir(char *buf, size_t size);
+#endif
+
+/**
+ * path_mkdir:
+ * @dir                : directory
+ *
+ * Create directory on filesystem.
+ *
+ * Returns: true (1) if directory could be created, otherwise false (0).
+ **/
+bool path_mkdir(const char *dir);
+
+/**
+ * path_is_directory:
+ * @path               : path
+ *
+ * Checks if path is a directory.
+ *
+ * Returns: true (1) if path is a directory, otherwise false (0).
+ */
+bool path_is_directory(const char *path);
+
+bool path_is_character_special(const char *path);
+
+int path_stat(const char *path);
+
+bool path_is_valid(const char *path);
+
+int32_t path_get_size(const char *path);
+
+bool is_path_accessible_using_standard_io(const char *path);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h
new file mode 100644 (file)
index 0000000..8a5da86
--- /dev/null
@@ -0,0 +1,3093 @@
+/* Copyright (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this libretro API header (libretro.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef LIBRETRO_H__
+#define LIBRETRO_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __cplusplus
+#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
+/* Hack applied for MSVC when compiling in C89 mode
+ * as it isn't C99-compliant. */
+#define bool unsigned char
+#define true 1
+#define false 0
+#else
+#include <stdbool.h>
+#endif
+#endif
+
+#ifndef RETRO_CALLCONV
+#  if defined(__GNUC__) && defined(__i386__) && !defined(__x86_64__)
+#    define RETRO_CALLCONV __attribute__((cdecl))
+#  elif defined(_MSC_VER) && defined(_M_X86) && !defined(_M_X64)
+#    define RETRO_CALLCONV __cdecl
+#  else
+#    define RETRO_CALLCONV /* all other platforms only have one calling convention each */
+#  endif
+#endif
+
+#ifndef RETRO_API
+#  if defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+#    ifdef RETRO_IMPORT_SYMBOLS
+#      ifdef __GNUC__
+#        define RETRO_API RETRO_CALLCONV __attribute__((__dllimport__))
+#      else
+#        define RETRO_API RETRO_CALLCONV __declspec(dllimport)
+#      endif
+#    else
+#      ifdef __GNUC__
+#        define RETRO_API RETRO_CALLCONV __attribute__((__dllexport__))
+#      else
+#        define RETRO_API RETRO_CALLCONV __declspec(dllexport)
+#      endif
+#    endif
+#  else
+#      if defined(__GNUC__) && __GNUC__ >= 4
+#        define RETRO_API RETRO_CALLCONV __attribute__((__visibility__("default")))
+#      else
+#        define RETRO_API RETRO_CALLCONV
+#      endif
+#  endif
+#endif
+
+/* Used for checking API/ABI mismatches that can break libretro
+ * implementations.
+ * It is not incremented for compatible changes to the API.
+ */
+#define RETRO_API_VERSION         1
+
+/*
+ * Libretro's fundamental device abstractions.
+ *
+ * Libretro's input system consists of some standardized device types,
+ * such as a joypad (with/without analog), mouse, keyboard, lightgun
+ * and a pointer.
+ *
+ * The functionality of these devices are fixed, and individual cores
+ * map their own concept of a controller to libretro's abstractions.
+ * This makes it possible for frontends to map the abstract types to a
+ * real input device, and not having to worry about binding input
+ * correctly to arbitrary controller layouts.
+ */
+
+#define RETRO_DEVICE_TYPE_SHIFT         8
+#define RETRO_DEVICE_MASK               ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1)
+#define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base)
+
+/* Input disabled. */
+#define RETRO_DEVICE_NONE         0
+
+/* The JOYPAD is called RetroPad. It is essentially a Super Nintendo
+ * controller, but with additional L2/R2/L3/R3 buttons, similar to a
+ * PS1 DualShock. */
+#define RETRO_DEVICE_JOYPAD       1
+
+/* The mouse is a simple mouse, similar to Super Nintendo's mouse.
+ * X and Y coordinates are reported relatively to last poll (poll callback).
+ * It is up to the libretro implementation to keep track of where the mouse
+ * pointer is supposed to be on the screen.
+ * The frontend must make sure not to interfere with its own hardware
+ * mouse pointer.
+ */
+#define RETRO_DEVICE_MOUSE        2
+
+/* KEYBOARD device lets one poll for raw key pressed.
+ * It is poll based, so input callback will return with the current
+ * pressed state.
+ * For event/text based keyboard input, see
+ * RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
+ */
+#define RETRO_DEVICE_KEYBOARD     3
+
+/* LIGHTGUN device is similar to Guncon-2 for PlayStation 2.
+ * It reports X/Y coordinates in screen space (similar to the pointer)
+ * in the range [-0x8000, 0x7fff] in both axes, with zero being center and
+ * -0x8000 being out of bounds.
+ * As well as reporting on/off screen state. It features a trigger,
+ * start/select buttons, auxiliary action buttons and a
+ * directional pad. A forced off-screen shot can be requested for
+ * auto-reloading function in some games.
+ */
+#define RETRO_DEVICE_LIGHTGUN     4
+
+/* The ANALOG device is an extension to JOYPAD (RetroPad).
+ * Similar to DualShock2 it adds two analog sticks and all buttons can
+ * be analog. This is treated as a separate device type as it returns
+ * axis values in the full analog range of [-0x7fff, 0x7fff],
+ * although some devices may return -0x8000.
+ * Positive X axis is right. Positive Y axis is down.
+ * Buttons are returned in the range [0, 0x7fff].
+ * Only use ANALOG type when polling for analog values.
+ */
+#define RETRO_DEVICE_ANALOG       5
+
+/* Abstracts the concept of a pointing mechanism, e.g. touch.
+ * This allows libretro to query in absolute coordinates where on the
+ * screen a mouse (or something similar) is being placed.
+ * For a touch centric device, coordinates reported are the coordinates
+ * of the press.
+ *
+ * Coordinates in X and Y are reported as:
+ * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
+ * and 0x7fff corresponds to the far right/bottom of the screen.
+ * The "screen" is here defined as area that is passed to the frontend and
+ * later displayed on the monitor.
+ *
+ * The frontend is free to scale/resize this screen as it sees fit, however,
+ * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the
+ * game image, etc.
+ *
+ * To check if the pointer coordinates are valid (e.g. a touch display
+ * actually being touched), PRESSED returns 1 or 0.
+ *
+ * If using a mouse on a desktop, PRESSED will usually correspond to the
+ * left mouse button, but this is a frontend decision.
+ * PRESSED will only return 1 if the pointer is inside the game screen.
+ *
+ * For multi-touch, the index variable can be used to successively query
+ * more presses.
+ * If index = 0 returns true for _PRESSED, coordinates can be extracted
+ * with _X, _Y for index = 0. One can then query _PRESSED, _X, _Y with
+ * index = 1, and so on.
+ * Eventually _PRESSED will return false for an index. No further presses
+ * are registered at this point. */
+#define RETRO_DEVICE_POINTER      6
+
+/* Buttons for the RetroPad (JOYPAD).
+ * The placement of these is equivalent to placements on the
+ * Super Nintendo controller.
+ * L2/R2/L3/R3 buttons correspond to the PS1 DualShock.
+ * Also used as id values for RETRO_DEVICE_INDEX_ANALOG_BUTTON */
+#define RETRO_DEVICE_ID_JOYPAD_B        0
+#define RETRO_DEVICE_ID_JOYPAD_Y        1
+#define RETRO_DEVICE_ID_JOYPAD_SELECT   2
+#define RETRO_DEVICE_ID_JOYPAD_START    3
+#define RETRO_DEVICE_ID_JOYPAD_UP       4
+#define RETRO_DEVICE_ID_JOYPAD_DOWN     5
+#define RETRO_DEVICE_ID_JOYPAD_LEFT     6
+#define RETRO_DEVICE_ID_JOYPAD_RIGHT    7
+#define RETRO_DEVICE_ID_JOYPAD_A        8
+#define RETRO_DEVICE_ID_JOYPAD_X        9
+#define RETRO_DEVICE_ID_JOYPAD_L       10
+#define RETRO_DEVICE_ID_JOYPAD_R       11
+#define RETRO_DEVICE_ID_JOYPAD_L2      12
+#define RETRO_DEVICE_ID_JOYPAD_R2      13
+#define RETRO_DEVICE_ID_JOYPAD_L3      14
+#define RETRO_DEVICE_ID_JOYPAD_R3      15
+
+#define RETRO_DEVICE_ID_JOYPAD_MASK    256
+
+/* Index / Id values for ANALOG device. */
+#define RETRO_DEVICE_INDEX_ANALOG_LEFT       0
+#define RETRO_DEVICE_INDEX_ANALOG_RIGHT      1
+#define RETRO_DEVICE_INDEX_ANALOG_BUTTON     2
+#define RETRO_DEVICE_ID_ANALOG_X             0
+#define RETRO_DEVICE_ID_ANALOG_Y             1
+
+/* Id values for MOUSE. */
+#define RETRO_DEVICE_ID_MOUSE_X                0
+#define RETRO_DEVICE_ID_MOUSE_Y                1
+#define RETRO_DEVICE_ID_MOUSE_LEFT             2
+#define RETRO_DEVICE_ID_MOUSE_RIGHT            3
+#define RETRO_DEVICE_ID_MOUSE_WHEELUP          4
+#define RETRO_DEVICE_ID_MOUSE_WHEELDOWN        5
+#define RETRO_DEVICE_ID_MOUSE_MIDDLE           6
+#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP    7
+#define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN  8
+#define RETRO_DEVICE_ID_MOUSE_BUTTON_4         9
+#define RETRO_DEVICE_ID_MOUSE_BUTTON_5         10
+
+/* Id values for LIGHTGUN. */
+#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X        13 /*Absolute Position*/
+#define RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y        14 /*Absolute*/
+#define RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN    15 /*Status Check*/
+#define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER          2
+#define RETRO_DEVICE_ID_LIGHTGUN_RELOAD          16 /*Forced off-screen shot*/
+#define RETRO_DEVICE_ID_LIGHTGUN_AUX_A            3
+#define RETRO_DEVICE_ID_LIGHTGUN_AUX_B            4
+#define RETRO_DEVICE_ID_LIGHTGUN_START            6
+#define RETRO_DEVICE_ID_LIGHTGUN_SELECT           7
+#define RETRO_DEVICE_ID_LIGHTGUN_AUX_C            8
+#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_UP          9
+#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_DOWN       10
+#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_LEFT       11
+#define RETRO_DEVICE_ID_LIGHTGUN_DPAD_RIGHT      12
+/* deprecated */
+#define RETRO_DEVICE_ID_LIGHTGUN_X                0 /*Relative Position*/
+#define RETRO_DEVICE_ID_LIGHTGUN_Y                1 /*Relative*/
+#define RETRO_DEVICE_ID_LIGHTGUN_CURSOR           3 /*Use Aux:A*/
+#define RETRO_DEVICE_ID_LIGHTGUN_TURBO            4 /*Use Aux:B*/
+#define RETRO_DEVICE_ID_LIGHTGUN_PAUSE            5 /*Use Start*/
+
+/* Id values for POINTER. */
+#define RETRO_DEVICE_ID_POINTER_X         0
+#define RETRO_DEVICE_ID_POINTER_Y         1
+#define RETRO_DEVICE_ID_POINTER_PRESSED   2
+#define RETRO_DEVICE_ID_POINTER_COUNT     3
+
+/* Returned from retro_get_region(). */
+#define RETRO_REGION_NTSC  0
+#define RETRO_REGION_PAL   1
+
+/* Id values for LANGUAGE */
+enum retro_language
+{
+   RETRO_LANGUAGE_ENGLISH             = 0,
+   RETRO_LANGUAGE_JAPANESE            = 1,
+   RETRO_LANGUAGE_FRENCH              = 2,
+   RETRO_LANGUAGE_SPANISH             = 3,
+   RETRO_LANGUAGE_GERMAN              = 4,
+   RETRO_LANGUAGE_ITALIAN             = 5,
+   RETRO_LANGUAGE_DUTCH               = 6,
+   RETRO_LANGUAGE_PORTUGUESE_BRAZIL   = 7,
+   RETRO_LANGUAGE_PORTUGUESE_PORTUGAL = 8,
+   RETRO_LANGUAGE_RUSSIAN             = 9,
+   RETRO_LANGUAGE_KOREAN              = 10,
+   RETRO_LANGUAGE_CHINESE_TRADITIONAL = 11,
+   RETRO_LANGUAGE_CHINESE_SIMPLIFIED  = 12,
+   RETRO_LANGUAGE_ESPERANTO           = 13,
+   RETRO_LANGUAGE_POLISH              = 14,
+   RETRO_LANGUAGE_VIETNAMESE          = 15,
+   RETRO_LANGUAGE_ARABIC              = 16,
+   RETRO_LANGUAGE_GREEK               = 17,
+   RETRO_LANGUAGE_TURKISH             = 18,
+   RETRO_LANGUAGE_SLOVAK              = 19,
+   RETRO_LANGUAGE_PERSIAN             = 20,
+   RETRO_LANGUAGE_HEBREW              = 21,
+   RETRO_LANGUAGE_ASTURIAN            = 22,
+   RETRO_LANGUAGE_FINNISH             = 23,
+   RETRO_LANGUAGE_LAST,
+
+   /* Ensure sizeof(enum) == sizeof(int) */
+   RETRO_LANGUAGE_DUMMY          = INT_MAX
+};
+
+/* Passed to retro_get_memory_data/size().
+ * If the memory type doesn't apply to the
+ * implementation NULL/0 can be returned.
+ */
+#define RETRO_MEMORY_MASK        0xff
+
+/* Regular save RAM. This RAM is usually found on a game cartridge,
+ * backed up by a battery.
+ * If save game data is too complex for a single memory buffer,
+ * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment
+ * callback can be used. */
+#define RETRO_MEMORY_SAVE_RAM    0
+
+/* Some games have a built-in clock to keep track of time.
+ * This memory is usually just a couple of bytes to keep track of time.
+ */
+#define RETRO_MEMORY_RTC         1
+
+/* System ram lets a frontend peek into a game systems main RAM. */
+#define RETRO_MEMORY_SYSTEM_RAM  2
+
+/* Video ram lets a frontend peek into a game systems video RAM (VRAM). */
+#define RETRO_MEMORY_VIDEO_RAM   3
+
+/* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */
+enum retro_key
+{
+   RETROK_UNKNOWN        = 0,
+   RETROK_FIRST          = 0,
+   RETROK_BACKSPACE      = 8,
+   RETROK_TAB            = 9,
+   RETROK_CLEAR          = 12,
+   RETROK_RETURN         = 13,
+   RETROK_PAUSE          = 19,
+   RETROK_ESCAPE         = 27,
+   RETROK_SPACE          = 32,
+   RETROK_EXCLAIM        = 33,
+   RETROK_QUOTEDBL       = 34,
+   RETROK_HASH           = 35,
+   RETROK_DOLLAR         = 36,
+   RETROK_AMPERSAND      = 38,
+   RETROK_QUOTE          = 39,
+   RETROK_LEFTPAREN      = 40,
+   RETROK_RIGHTPAREN     = 41,
+   RETROK_ASTERISK       = 42,
+   RETROK_PLUS           = 43,
+   RETROK_COMMA          = 44,
+   RETROK_MINUS          = 45,
+   RETROK_PERIOD         = 46,
+   RETROK_SLASH          = 47,
+   RETROK_0              = 48,
+   RETROK_1              = 49,
+   RETROK_2              = 50,
+   RETROK_3              = 51,
+   RETROK_4              = 52,
+   RETROK_5              = 53,
+   RETROK_6              = 54,
+   RETROK_7              = 55,
+   RETROK_8              = 56,
+   RETROK_9              = 57,
+   RETROK_COLON          = 58,
+   RETROK_SEMICOLON      = 59,
+   RETROK_LESS           = 60,
+   RETROK_EQUALS         = 61,
+   RETROK_GREATER        = 62,
+   RETROK_QUESTION       = 63,
+   RETROK_AT             = 64,
+   RETROK_LEFTBRACKET    = 91,
+   RETROK_BACKSLASH      = 92,
+   RETROK_RIGHTBRACKET   = 93,
+   RETROK_CARET          = 94,
+   RETROK_UNDERSCORE     = 95,
+   RETROK_BACKQUOTE      = 96,
+   RETROK_a              = 97,
+   RETROK_b              = 98,
+   RETROK_c              = 99,
+   RETROK_d              = 100,
+   RETROK_e              = 101,
+   RETROK_f              = 102,
+   RETROK_g              = 103,
+   RETROK_h              = 104,
+   RETROK_i              = 105,
+   RETROK_j              = 106,
+   RETROK_k              = 107,
+   RETROK_l              = 108,
+   RETROK_m              = 109,
+   RETROK_n              = 110,
+   RETROK_o              = 111,
+   RETROK_p              = 112,
+   RETROK_q              = 113,
+   RETROK_r              = 114,
+   RETROK_s              = 115,
+   RETROK_t              = 116,
+   RETROK_u              = 117,
+   RETROK_v              = 118,
+   RETROK_w              = 119,
+   RETROK_x              = 120,
+   RETROK_y              = 121,
+   RETROK_z              = 122,
+   RETROK_LEFTBRACE      = 123,
+   RETROK_BAR            = 124,
+   RETROK_RIGHTBRACE     = 125,
+   RETROK_TILDE          = 126,
+   RETROK_DELETE         = 127,
+
+   RETROK_KP0            = 256,
+   RETROK_KP1            = 257,
+   RETROK_KP2            = 258,
+   RETROK_KP3            = 259,
+   RETROK_KP4            = 260,
+   RETROK_KP5            = 261,
+   RETROK_KP6            = 262,
+   RETROK_KP7            = 263,
+   RETROK_KP8            = 264,
+   RETROK_KP9            = 265,
+   RETROK_KP_PERIOD      = 266,
+   RETROK_KP_DIVIDE      = 267,
+   RETROK_KP_MULTIPLY    = 268,
+   RETROK_KP_MINUS       = 269,
+   RETROK_KP_PLUS        = 270,
+   RETROK_KP_ENTER       = 271,
+   RETROK_KP_EQUALS      = 272,
+
+   RETROK_UP             = 273,
+   RETROK_DOWN           = 274,
+   RETROK_RIGHT          = 275,
+   RETROK_LEFT           = 276,
+   RETROK_INSERT         = 277,
+   RETROK_HOME           = 278,
+   RETROK_END            = 279,
+   RETROK_PAGEUP         = 280,
+   RETROK_PAGEDOWN       = 281,
+
+   RETROK_F1             = 282,
+   RETROK_F2             = 283,
+   RETROK_F3             = 284,
+   RETROK_F4             = 285,
+   RETROK_F5             = 286,
+   RETROK_F6             = 287,
+   RETROK_F7             = 288,
+   RETROK_F8             = 289,
+   RETROK_F9             = 290,
+   RETROK_F10            = 291,
+   RETROK_F11            = 292,
+   RETROK_F12            = 293,
+   RETROK_F13            = 294,
+   RETROK_F14            = 295,
+   RETROK_F15            = 296,
+
+   RETROK_NUMLOCK        = 300,
+   RETROK_CAPSLOCK       = 301,
+   RETROK_SCROLLOCK      = 302,
+   RETROK_RSHIFT         = 303,
+   RETROK_LSHIFT         = 304,
+   RETROK_RCTRL          = 305,
+   RETROK_LCTRL          = 306,
+   RETROK_RALT           = 307,
+   RETROK_LALT           = 308,
+   RETROK_RMETA          = 309,
+   RETROK_LMETA          = 310,
+   RETROK_LSUPER         = 311,
+   RETROK_RSUPER         = 312,
+   RETROK_MODE           = 313,
+   RETROK_COMPOSE        = 314,
+
+   RETROK_HELP           = 315,
+   RETROK_PRINT          = 316,
+   RETROK_SYSREQ         = 317,
+   RETROK_BREAK          = 318,
+   RETROK_MENU           = 319,
+   RETROK_POWER          = 320,
+   RETROK_EURO           = 321,
+   RETROK_UNDO           = 322,
+   RETROK_OEM_102        = 323,
+
+   RETROK_LAST,
+
+   RETROK_DUMMY          = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
+};
+
+enum retro_mod
+{
+   RETROKMOD_NONE       = 0x0000,
+
+   RETROKMOD_SHIFT      = 0x01,
+   RETROKMOD_CTRL       = 0x02,
+   RETROKMOD_ALT        = 0x04,
+   RETROKMOD_META       = 0x08,
+
+   RETROKMOD_NUMLOCK    = 0x10,
+   RETROKMOD_CAPSLOCK   = 0x20,
+   RETROKMOD_SCROLLOCK  = 0x40,
+
+   RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
+};
+
+/* If set, this call is not part of the public libretro API yet. It can
+ * change or be removed at any time. */
+#define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000
+/* Environment callback to be used internally in frontend. */
+#define RETRO_ENVIRONMENT_PRIVATE 0x20000
+
+/* Environment commands. */
+#define RETRO_ENVIRONMENT_SET_ROTATION  1  /* const unsigned * --
+                                            * Sets screen rotation of graphics.
+                                            * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180,
+                                            * 270 degrees counter-clockwise respectively.
+                                            */
+#define RETRO_ENVIRONMENT_GET_OVERSCAN  2  /* bool * --
+                                            * NOTE: As of 2019 this callback is considered deprecated in favor of
+                                            * using core options to manage overscan in a more nuanced, core-specific way.
+                                            *
+                                            * Boolean value whether or not the implementation should use overscan,
+                                            * or crop away overscan.
+                                            */
+#define RETRO_ENVIRONMENT_GET_CAN_DUPE  3  /* bool * --
+                                            * Boolean value whether or not frontend supports frame duping,
+                                            * passing NULL to video frame callback.
+                                            */
+
+                                           /* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES),
+                                            * and reserved to avoid possible ABI clash.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_MESSAGE   6  /* const struct retro_message * --
+                                            * Sets a message to be displayed in implementation-specific manner
+                                            * for a certain amount of 'frames'.
+                                            * Should not be used for trivial messages, which should simply be
+                                            * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
+                                            * fallback, stderr).
+                                            */
+#define RETRO_ENVIRONMENT_SHUTDOWN      7  /* N/A (NULL) --
+                                            * Requests the frontend to shutdown.
+                                            * Should only be used if game has a specific
+                                            * way to shutdown the game from a menu item or similar.
+                                            */
+#define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8
+                                           /* const unsigned * --
+                                            * Gives a hint to the frontend how demanding this implementation
+                                            * is on a system. E.g. reporting a level of 2 means
+                                            * this implementation should run decently on all frontends
+                                            * of level 2 and up.
+                                            *
+                                            * It can be used by the frontend to potentially warn
+                                            * about too demanding implementations.
+                                            *
+                                            * The levels are "floating".
+                                            *
+                                            * This function can be called on a per-game basis,
+                                            * as certain games an implementation can play might be
+                                            * particularly demanding.
+                                            * If called, it should be called in retro_load_game().
+                                            */
+#define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9
+                                           /* const char ** --
+                                            * Returns the "system" directory of the frontend.
+                                            * This directory can be used to store system specific
+                                            * content such as BIOSes, configuration data, etc.
+                                            * The returned value can be NULL.
+                                            * If so, no such directory is defined,
+                                            * and it's up to the implementation to find a suitable directory.
+                                            *
+                                            * NOTE: Some cores used this folder also for "save" data such as
+                                            * memory cards, etc, for lack of a better place to put it.
+                                            * This is now discouraged, and if possible, cores should try to
+                                            * use the new GET_SAVE_DIRECTORY.
+                                            */
+#define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10
+                                           /* const enum retro_pixel_format * --
+                                            * Sets the internal pixel format used by the implementation.
+                                            * The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555.
+                                            * This pixel format however, is deprecated (see enum retro_pixel_format).
+                                            * If the call returns false, the frontend does not support this pixel
+                                            * format.
+                                            *
+                                            * This function should be called inside retro_load_game() or
+                                            * retro_get_system_av_info().
+                                            */
+#define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11
+                                           /* const struct retro_input_descriptor * --
+                                            * Sets an array of retro_input_descriptors.
+                                            * It is up to the frontend to present this in a usable way.
+                                            * The array is terminated by retro_input_descriptor::description
+                                            * being set to NULL.
+                                            * This function can be called at any time, but it is recommended
+                                            * to call it as early as possible.
+                                            */
+#define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12
+                                           /* const struct retro_keyboard_callback * --
+                                            * Sets a callback function used to notify core about keyboard events.
+                                            */
+#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13
+                                           /* const struct retro_disk_control_callback * --
+                                            * Sets an interface which frontend can use to eject and insert
+                                            * disk images.
+                                            * This is used for games which consist of multiple images and
+                                            * must be manually swapped out by the user (e.g. PSX).
+                                            */
+#define RETRO_ENVIRONMENT_SET_HW_RENDER 14
+                                           /* struct retro_hw_render_callback * --
+                                            * Sets an interface to let a libretro core render with
+                                            * hardware acceleration.
+                                            * Should be called in retro_load_game().
+                                            * If successful, libretro cores will be able to render to a
+                                            * frontend-provided framebuffer.
+                                            * The size of this framebuffer will be at least as large as
+                                            * max_width/max_height provided in get_av_info().
+                                            * If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or
+                                            * NULL to retro_video_refresh_t.
+                                            */
+#define RETRO_ENVIRONMENT_GET_VARIABLE 15
+                                           /* struct retro_variable * --
+                                            * Interface to acquire user-defined information from environment
+                                            * that cannot feasibly be supported in a multi-system way.
+                                            * 'key' should be set to a key which has already been set by
+                                            * SET_VARIABLES.
+                                            * 'data' will be set to a value or NULL.
+                                            */
+#define RETRO_ENVIRONMENT_SET_VARIABLES 16
+                                           /* const struct retro_variable * --
+                                            * Allows an implementation to signal the environment
+                                            * which variables it might want to check for later using
+                                            * GET_VARIABLE.
+                                            * This allows the frontend to present these variables to
+                                            * a user dynamically.
+                                            * This should be called the first time as early as
+                                            * possible (ideally in retro_set_environment).
+                                            * Afterward it may be called again for the core to communicate
+                                            * updated options to the frontend, but the number of core
+                                            * options must not change from the number in the initial call.
+                                            *
+                                            * 'data' points to an array of retro_variable structs
+                                            * terminated by a { NULL, NULL } element.
+                                            * retro_variable::key should be namespaced to not collide
+                                            * with other implementations' keys. E.g. A core called
+                                            * 'foo' should use keys named as 'foo_option'.
+                                            * retro_variable::value should contain a human readable
+                                            * description of the key as well as a '|' delimited list
+                                            * of expected values.
+                                            *
+                                            * The number of possible options should be very limited,
+                                            * i.e. it should be feasible to cycle through options
+                                            * without a keyboard.
+                                            *
+                                            * First entry should be treated as a default.
+                                            *
+                                            * Example entry:
+                                            * { "foo_option", "Speed hack coprocessor X; false|true" }
+                                            *
+                                            * Text before first ';' is description. This ';' must be
+                                            * followed by a space, and followed by a list of possible
+                                            * values split up with '|'.
+                                            *
+                                            * Only strings are operated on. The possible values will
+                                            * generally be displayed and stored as-is by the frontend.
+                                            */
+#define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17
+                                           /* bool * --
+                                            * Result is set to true if some variables are updated by
+                                            * frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE.
+                                            * Variables should be queried with GET_VARIABLE.
+                                            */
+#define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18
+                                           /* const bool * --
+                                            * If true, the libretro implementation supports calls to
+                                            * retro_load_game() with NULL as argument.
+                                            * Used by cores which can run without particular game data.
+                                            * This should be called within retro_set_environment() only.
+                                            */
+#define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19
+                                           /* const char ** --
+                                            * Retrieves the absolute path from where this libretro
+                                            * implementation was loaded.
+                                            * NULL is returned if the libretro was loaded statically
+                                            * (i.e. linked statically to frontend), or if the path cannot be
+                                            * determined.
+                                            * Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can
+                                            * be loaded without ugly hacks.
+                                            */
+
+                                           /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK.
+                                            * It was not used by any known core at the time,
+                                            * and was removed from the API. */
+#define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21
+                                           /* const struct retro_frame_time_callback * --
+                                            * Lets the core know how much time has passed since last
+                                            * invocation of retro_run().
+                                            * The frontend can tamper with the timing to fake fast-forward,
+                                            * slow-motion, frame stepping, etc.
+                                            * In this case the delta time will use the reference value
+                                            * in frame_time_callback..
+                                            */
+#define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22
+                                           /* const struct retro_audio_callback * --
+                                            * Sets an interface which is used to notify a libretro core about audio
+                                            * being available for writing.
+                                            * The callback can be called from any thread, so a core using this must
+                                            * have a thread safe audio implementation.
+                                            * It is intended for games where audio and video are completely
+                                            * asynchronous and audio can be generated on the fly.
+                                            * This interface is not recommended for use with emulators which have
+                                            * highly synchronous audio.
+                                            *
+                                            * The callback only notifies about writability; the libretro core still
+                                            * has to call the normal audio callbacks
+                                            * to write audio. The audio callbacks must be called from within the
+                                            * notification callback.
+                                            * The amount of audio data to write is up to the implementation.
+                                            * Generally, the audio callback will be called continously in a loop.
+                                            *
+                                            * Due to thread safety guarantees and lack of sync between audio and
+                                            * video, a frontend  can selectively disallow this interface based on
+                                            * internal configuration. A core using this interface must also
+                                            * implement the "normal" audio interface.
+                                            *
+                                            * A libretro core using SET_AUDIO_CALLBACK should also make use of
+                                            * SET_FRAME_TIME_CALLBACK.
+                                            */
+#define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23
+                                           /* struct retro_rumble_interface * --
+                                            * Gets an interface which is used by a libretro core to set
+                                            * state of rumble motors in controllers.
+                                            * A strong and weak motor is supported, and they can be
+                                            * controlled indepedently.
+                                            * Should be called from either retro_init() or retro_load_game().
+                                            * Should not be called from retro_set_environment().
+                                            * Returns false if rumble functionality is unavailable.
+                                            */
+#define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24
+                                           /* uint64_t * --
+                                            * Gets a bitmask telling which device type are expected to be
+                                            * handled properly in a call to retro_input_state_t.
+                                            * Devices which are not handled or recognized always return
+                                            * 0 in retro_input_state_t.
+                                            * Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG).
+                                            * Should only be called in retro_run().
+                                            */
+#define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_sensor_interface * --
+                                            * Gets access to the sensor interface.
+                                            * The purpose of this interface is to allow
+                                            * setting state related to sensors such as polling rate,
+                                            * enabling/disable it entirely, etc.
+                                            * Reading sensor state is done via the normal
+                                            * input_state_callback API.
+                                            */
+#define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_camera_callback * --
+                                            * Gets an interface to a video camera driver.
+                                            * A libretro core can use this interface to get access to a
+                                            * video camera.
+                                            * New video frames are delivered in a callback in same
+                                            * thread as retro_run().
+                                            *
+                                            * GET_CAMERA_INTERFACE should be called in retro_load_game().
+                                            *
+                                            * Depending on the camera implementation used, camera frames
+                                            * will be delivered as a raw framebuffer,
+                                            * or as an OpenGL texture directly.
+                                            *
+                                            * The core has to tell the frontend here which types of
+                                            * buffers can be handled properly.
+                                            * An OpenGL texture can only be handled when using a
+                                            * libretro GL core (SET_HW_RENDER).
+                                            * It is recommended to use a libretro GL core when
+                                            * using camera interface.
+                                            *
+                                            * The camera is not started automatically. The retrieved start/stop
+                                            * functions must be used to explicitly
+                                            * start and stop the camera driver.
+                                            */
+#define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27
+                                           /* struct retro_log_callback * --
+                                            * Gets an interface for logging. This is useful for
+                                            * logging in a cross-platform way
+                                            * as certain platforms cannot use stderr for logging.
+                                            * It also allows the frontend to
+                                            * show logging information in a more suitable way.
+                                            * If this interface is not used, libretro cores should
+                                            * log to stderr as desired.
+                                            */
+#define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28
+                                           /* struct retro_perf_callback * --
+                                            * Gets an interface for performance counters. This is useful
+                                            * for performance logging in a cross-platform way and for detecting
+                                            * architecture-specific features, such as SIMD support.
+                                            */
+#define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29
+                                           /* struct retro_location_callback * --
+                                            * Gets access to the location interface.
+                                            * The purpose of this interface is to be able to retrieve
+                                            * location-based information from the host device,
+                                            * such as current latitude / longitude.
+                                            */
+#define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30 /* Old name, kept for compatibility. */
+#define RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY 30
+                                           /* const char ** --
+                                            * Returns the "core assets" directory of the frontend.
+                                            * This directory can be used to store specific assets that the
+                                            * core relies upon, such as art assets,
+                                            * input data, etc etc.
+                                            * The returned value can be NULL.
+                                            * If so, no such directory is defined,
+                                            * and it's up to the implementation to find a suitable directory.
+                                            */
+#define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31
+                                           /* const char ** --
+                                            * Returns the "save" directory of the frontend, unless there is no
+                                            * save directory available. The save directory should be used to
+                                            * store SRAM, memory cards, high scores, etc, if the libretro core
+                                            * cannot use the regular memory interface (retro_get_memory_data()).
+                                            *
+                                            * If the frontend cannot designate a save directory, it will return
+                                            * NULL to indicate that the core should attempt to operate without a
+                                            * save directory set.
+                                            *
+                                            * NOTE: early libretro cores used the system directory for save
+                                            * files. Cores that need to be backwards-compatible can still check
+                                            * GET_SYSTEM_DIRECTORY.
+                                            */
+#define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32
+                                           /* const struct retro_system_av_info * --
+                                            * Sets a new av_info structure. This can only be called from
+                                            * within retro_run().
+                                            * This should *only* be used if the core is completely altering the
+                                            * internal resolutions, aspect ratios, timings, sampling rate, etc.
+                                            * Calling this can require a full reinitialization of video/audio
+                                            * drivers in the frontend,
+                                            *
+                                            * so it is important to call it very sparingly, and usually only with
+                                            * the users explicit consent.
+                                            * An eventual driver reinitialize will happen so that video and
+                                            * audio callbacks
+                                            * happening after this call within the same retro_run() call will
+                                            * target the newly initialized driver.
+                                            *
+                                            * This callback makes it possible to support configurable resolutions
+                                            * in games, which can be useful to
+                                            * avoid setting the "worst case" in max_width/max_height.
+                                            *
+                                            * ***HIGHLY RECOMMENDED*** Do not call this callback every time
+                                            * resolution changes in an emulator core if it's
+                                            * expected to be a temporary change, for the reasons of possible
+                                            * driver reinitialization.
+                                            * This call is not a free pass for not trying to provide
+                                            * correct values in retro_get_system_av_info(). If you need to change
+                                            * things like aspect ratio or nominal width/height,
+                                            * use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant
+                                            * of SET_SYSTEM_AV_INFO.
+                                            *
+                                            * If this returns false, the frontend does not acknowledge a
+                                            * changed av_info struct.
+                                            */
+#define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33
+                                           /* const struct retro_get_proc_address_interface * --
+                                            * Allows a libretro core to announce support for the
+                                            * get_proc_address() interface.
+                                            * This interface allows for a standard way to extend libretro where
+                                            * use of environment calls are too indirect,
+                                            * e.g. for cases where the frontend wants to call directly into the core.
+                                            *
+                                            * If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK
+                                            * **MUST** be called from within retro_set_environment().
+                                            */
+#define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34
+                                           /* const struct retro_subsystem_info * --
+                                            * This environment call introduces the concept of libretro "subsystems".
+                                            * A subsystem is a variant of a libretro core which supports
+                                            * different kinds of games.
+                                            * The purpose of this is to support e.g. emulators which might
+                                            * have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo.
+                                            * It can also be used to pick among subsystems in an explicit way
+                                            * if the libretro implementation is a multi-system emulator itself.
+                                            *
+                                            * Loading a game via a subsystem is done with retro_load_game_special(),
+                                            * and this environment call allows a libretro core to expose which
+                                            * subsystems are supported for use with retro_load_game_special().
+                                            * A core passes an array of retro_game_special_info which is terminated
+                                            * with a zeroed out retro_game_special_info struct.
+                                            *
+                                            * If a core wants to use this functionality, SET_SUBSYSTEM_INFO
+                                            * **MUST** be called from within retro_set_environment().
+                                            */
+#define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35
+                                           /* const struct retro_controller_info * --
+                                            * This environment call lets a libretro core tell the frontend
+                                            * which controller subclasses are recognized in calls to
+                                            * retro_set_controller_port_device().
+                                            *
+                                            * Some emulators such as Super Nintendo support multiple lightgun
+                                            * types which must be specifically selected from. It is therefore
+                                            * sometimes necessary for a frontend to be able to tell the core
+                                            * about a special kind of input device which is not specifcally
+                                            * provided by the Libretro API.
+                                            *
+                                            * In order for a frontend to understand the workings of those devices,
+                                            * they must be defined as a specialized subclass of the generic device
+                                            * types already defined in the libretro API.
+                                            *
+                                            * The core must pass an array of const struct retro_controller_info which
+                                            * is terminated with a blanked out struct. Each element of the
+                                            * retro_controller_info struct corresponds to the ascending port index
+                                            * that is passed to retro_set_controller_port_device() when that function
+                                            * is called to indicate to the core that the frontend has changed the
+                                            * active device subclass. SEE ALSO: retro_set_controller_port_device()
+                                            *
+                                            * The ascending input port indexes provided by the core in the struct
+                                            * are generally presented by frontends as ascending User # or Player #,
+                                            * such as Player 1, Player 2, Player 3, etc. Which device subclasses are
+                                            * supported can vary per input port.
+                                            *
+                                            * The first inner element of each entry in the retro_controller_info array
+                                            * is a retro_controller_description struct that specifies the names and
+                                            * codes of all device subclasses that are available for the corresponding
+                                            * User or Player, beginning with the generic Libretro device that the
+                                            * subclasses are derived from. The second inner element of each entry is the
+                                            * total number of subclasses that are listed in the retro_controller_description.
+                                            *
+                                            * NOTE: Even if special device types are set in the libretro core,
+                                            * libretro should only poll input based on the base input device types.
+                                            */
+#define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* const struct retro_memory_map * --
+                                            * This environment call lets a libretro core tell the frontend
+                                            * about the memory maps this core emulates.
+                                            * This can be used to implement, for example, cheats in a core-agnostic way.
+                                            *
+                                            * Should only be used by emulators; it doesn't make much sense for
+                                            * anything else.
+                                            * It is recommended to expose all relevant pointers through
+                                            * retro_get_memory_* as well.
+                                            *
+                                            * Can be called from retro_init and retro_load_game.
+                                            */
+#define RETRO_ENVIRONMENT_SET_GEOMETRY 37
+                                           /* const struct retro_game_geometry * --
+                                            * This environment call is similar to SET_SYSTEM_AV_INFO for changing
+                                            * video parameters, but provides a guarantee that drivers will not be
+                                            * reinitialized.
+                                            * This can only be called from within retro_run().
+                                            *
+                                            * The purpose of this call is to allow a core to alter nominal
+                                            * width/heights as well as aspect ratios on-the-fly, which can be
+                                            * useful for some emulators to change in run-time.
+                                            *
+                                            * max_width/max_height arguments are ignored and cannot be changed
+                                            * with this call as this could potentially require a reinitialization or a
+                                            * non-constant time operation.
+                                            * If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required.
+                                            *
+                                            * A frontend must guarantee that this environment call completes in
+                                            * constant time.
+                                            */
+#define RETRO_ENVIRONMENT_GET_USERNAME 38
+                                           /* const char **
+                                            * Returns the specified username of the frontend, if specified by the user.
+                                            * This username can be used as a nickname for a core that has online facilities
+                                            * or any other mode where personalization of the user is desirable.
+                                            * The returned value can be NULL.
+                                            * If this environ callback is used by a core that requires a valid username,
+                                            * a default username should be specified by the core.
+                                            */
+#define RETRO_ENVIRONMENT_GET_LANGUAGE 39
+                                           /* unsigned * --
+                                            * Returns the specified language of the frontend, if specified by the user.
+                                            * It can be used by the core for localization purposes.
+                                            */
+#define RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER (40 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_framebuffer * --
+                                            * Returns a preallocated framebuffer which the core can use for rendering
+                                            * the frame into when not using SET_HW_RENDER.
+                                            * The framebuffer returned from this call must not be used
+                                            * after the current call to retro_run() returns.
+                                            *
+                                            * The goal of this call is to allow zero-copy behavior where a core
+                                            * can render directly into video memory, avoiding extra bandwidth cost by copying
+                                            * memory from core to video memory.
+                                            *
+                                            * If this call succeeds and the core renders into it,
+                                            * the framebuffer pointer and pitch can be passed to retro_video_refresh_t.
+                                            * If the buffer from GET_CURRENT_SOFTWARE_FRAMEBUFFER is to be used,
+                                            * the core must pass the exact
+                                            * same pointer as returned by GET_CURRENT_SOFTWARE_FRAMEBUFFER;
+                                            * i.e. passing a pointer which is offset from the
+                                            * buffer is undefined. The width, height and pitch parameters
+                                            * must also match exactly to the values obtained from GET_CURRENT_SOFTWARE_FRAMEBUFFER.
+                                            *
+                                            * It is possible for a frontend to return a different pixel format
+                                            * than the one used in SET_PIXEL_FORMAT. This can happen if the frontend
+                                            * needs to perform conversion.
+                                            *
+                                            * It is still valid for a core to render to a different buffer
+                                            * even if GET_CURRENT_SOFTWARE_FRAMEBUFFER succeeds.
+                                            *
+                                            * A frontend must make sure that the pointer obtained from this function is
+                                            * writeable (and readable).
+                                            */
+#define RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE (41 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* const struct retro_hw_render_interface ** --
+                                            * Returns an API specific rendering interface for accessing API specific data.
+                                            * Not all HW rendering APIs support or need this.
+                                            * The contents of the returned pointer is specific to the rendering API
+                                            * being used. See the various headers like libretro_vulkan.h, etc.
+                                            *
+                                            * GET_HW_RENDER_INTERFACE cannot be called before context_reset has been called.
+                                            * Similarly, after context_destroyed callback returns,
+                                            * the contents of the HW_RENDER_INTERFACE are invalidated.
+                                            */
+#define RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS (42 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* const bool * --
+                                            * If true, the libretro implementation supports achievements
+                                            * either via memory descriptors set with RETRO_ENVIRONMENT_SET_MEMORY_MAPS
+                                            * or via retro_get_memory_data/retro_get_memory_size.
+                                            *
+                                            * This must be called before the first call to retro_run.
+                                            */
+#define RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE (43 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* const struct retro_hw_render_context_negotiation_interface * --
+                                            * Sets an interface which lets the libretro core negotiate with frontend how a context is created.
+                                            * The semantics of this interface depends on which API is used in SET_HW_RENDER earlier.
+                                            * This interface will be used when the frontend is trying to create a HW rendering context,
+                                            * so it will be used after SET_HW_RENDER, but before the context_reset callback.
+                                            */
+#define RETRO_ENVIRONMENT_SET_SERIALIZATION_QUIRKS 44
+                                           /* uint64_t * --
+                                            * Sets quirk flags associated with serialization. The frontend will zero any flags it doesn't
+                                            * recognize or support. Should be set in either retro_init or retro_load_game, but not both.
+                                            */
+#define RETRO_ENVIRONMENT_SET_HW_SHARED_CONTEXT (44 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* N/A (null) * --
+                                            * The frontend will try to use a 'shared' hardware context (mostly applicable
+                                            * to OpenGL) when a hardware context is being set up.
+                                            *
+                                            * Returns true if the frontend supports shared hardware contexts and false
+                                            * if the frontend does not support shared hardware contexts.
+                                            *
+                                            * This will do nothing on its own until SET_HW_RENDER env callbacks are
+                                            * being used.
+                                            */
+#define RETRO_ENVIRONMENT_GET_VFS_INTERFACE (45 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_vfs_interface_info * --
+                                            * Gets access to the VFS interface.
+                                            * VFS presence needs to be queried prior to load_game or any
+                                            * get_system/save/other_directory being called to let front end know
+                                            * core supports VFS before it starts handing out paths.
+                                            * It is recomended to do so in retro_set_environment
+                                            */
+#define RETRO_ENVIRONMENT_GET_LED_INTERFACE (46 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_led_interface * --
+                                            * Gets an interface which is used by a libretro core to set
+                                            * state of LEDs.
+                                            */
+#define RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE (47 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* int * --
+                                            * Tells the core if the frontend wants audio or video.
+                                            * If disabled, the frontend will discard the audio or video,
+                                            * so the core may decide to skip generating a frame or generating audio.
+                                            * This is mainly used for increasing performance.
+                                            * Bit 0 (value 1): Enable Video
+                                            * Bit 1 (value 2): Enable Audio
+                                            * Bit 2 (value 4): Use Fast Savestates.
+                                            * Bit 3 (value 8): Hard Disable Audio
+                                            * Other bits are reserved for future use and will default to zero.
+                                            * If video is disabled:
+                                            * * The frontend wants the core to not generate any video,
+                                            *   including presenting frames via hardware acceleration.
+                                            * * The frontend's video frame callback will do nothing.
+                                            * * After running the frame, the video output of the next frame should be
+                                            *   no different than if video was enabled, and saving and loading state
+                                            *   should have no issues.
+                                            * If audio is disabled:
+                                            * * The frontend wants the core to not generate any audio.
+                                            * * The frontend's audio callbacks will do nothing.
+                                            * * After running the frame, the audio output of the next frame should be
+                                            *   no different than if audio was enabled, and saving and loading state
+                                            *   should have no issues.
+                                            * Fast Savestates:
+                                            * * Guaranteed to be created by the same binary that will load them.
+                                            * * Will not be written to or read from the disk.
+                                            * * Suggest that the core assumes loading state will succeed.
+                                            * * Suggest that the core updates its memory buffers in-place if possible.
+                                            * * Suggest that the core skips clearing memory.
+                                            * * Suggest that the core skips resetting the system.
+                                            * * Suggest that the core may skip validation steps.
+                                            * Hard Disable Audio:
+                                            * * Used for a secondary core when running ahead.
+                                            * * Indicates that the frontend will never need audio from the core.
+                                            * * Suggests that the core may stop synthesizing audio, but this should not
+                                            *   compromise emulation accuracy.
+                                            * * Audio output for the next frame does not matter, and the frontend will
+                                            *   never need an accurate audio state in the future.
+                                            * * State will never be saved when using Hard Disable Audio.
+                                            */
+#define RETRO_ENVIRONMENT_GET_MIDI_INTERFACE (48 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                           /* struct retro_midi_interface ** --
+                                            * Returns a MIDI interface that can be used for raw data I/O.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_FASTFORWARDING (49 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                            /* bool * --
+                                            * Boolean value that indicates whether or not the frontend is in
+                                            * fastforwarding mode.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_TARGET_REFRESH_RATE (50 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                            /* float * --
+                                            * Float value that lets us know what target refresh rate
+                                            * is curently in use by the frontend.
+                                            *
+                                            * The core can use the returned value to set an ideal
+                                            * refresh rate/framerate.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_INPUT_BITMASKS (51 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+                                            /* bool * --
+                                            * Boolean value that indicates whether or not the frontend supports
+                                            * input bitmasks being returned by retro_input_state_t. The advantage
+                                            * of this is that retro_input_state_t has to be only called once to
+                                            * grab all button states instead of multiple times.
+                                            *
+                                            * If it returns true, you can pass RETRO_DEVICE_ID_JOYPAD_MASK as 'id'
+                                            * to retro_input_state_t (make sure 'device' is set to RETRO_DEVICE_JOYPAD).
+                                            * It will return a bitmask of all the digital buttons.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION 52
+                                           /* unsigned * --
+                                            * Unsigned value is the API version number of the core options
+                                            * interface supported by the frontend. If callback return false,
+                                            * API version is assumed to be 0.
+                                            *
+                                            * In legacy code, core options are set by passing an array of
+                                            * retro_variable structs to RETRO_ENVIRONMENT_SET_VARIABLES.
+                                            * This may be still be done regardless of the core options
+                                            * interface version.
+                                            *
+                                            * If version is >= 1 however, core options may instead be set by
+                                            * passing an array of retro_core_option_definition structs to
+                                            * RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of
+                                            * retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.
+                                            * This allows the core to additionally set option sublabel information
+                                            * and/or provide localisation support.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS 53
+                                           /* const struct retro_core_option_definition ** --
+                                            * Allows an implementation to signal the environment
+                                            * which variables it might want to check for later using
+                                            * GET_VARIABLE.
+                                            * This allows the frontend to present these variables to
+                                            * a user dynamically.
+                                            * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
+                                            * returns an API version of >= 1.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
+                                            * This should be called the first time as early as
+                                            * possible (ideally in retro_set_environment).
+                                            * Afterwards it may be called again for the core to communicate
+                                            * updated options to the frontend, but the number of core
+                                            * options must not change from the number in the initial call.
+                                            *
+                                            * 'data' points to an array of retro_core_option_definition structs
+                                            * terminated by a { NULL, NULL, NULL, {{0}}, NULL } element.
+                                            * retro_core_option_definition::key should be namespaced to not collide
+                                            * with other implementations' keys. e.g. A core called
+                                            * 'foo' should use keys named as 'foo_option'.
+                                            * retro_core_option_definition::desc should contain a human readable
+                                            * description of the key.
+                                            * retro_core_option_definition::info should contain any additional human
+                                            * readable information text that a typical user may need to
+                                            * understand the functionality of the option.
+                                            * retro_core_option_definition::values is an array of retro_core_option_value
+                                            * structs terminated by a { NULL, NULL } element.
+                                            * > retro_core_option_definition::values[index].value is an expected option
+                                            *   value.
+                                            * > retro_core_option_definition::values[index].label is a human readable
+                                            *   label used when displaying the value on screen. If NULL,
+                                            *   the value itself is used.
+                                            * retro_core_option_definition::default_value is the default core option
+                                            * setting. It must match one of the expected option values in the
+                                            * retro_core_option_definition::values array. If it does not, or the
+                                            * default value is NULL, the first entry in the
+                                            * retro_core_option_definition::values array is treated as the default.
+                                            *
+                                            * The number of possible options should be very limited,
+                                            * and must be less than RETRO_NUM_CORE_OPTION_VALUES_MAX.
+                                            * i.e. it should be feasible to cycle through options
+                                            * without a keyboard.
+                                            *
+                                            * Example entry:
+                                            * {
+                                            *     "foo_option",
+                                            *     "Speed hack coprocessor X",
+                                            *     "Provides increased performance at the expense of reduced accuracy",
+                                            *    {
+                                            *         { "false",    NULL },
+                                            *         { "true",     NULL },
+                                            *         { "unstable", "Turbo (Unstable)" },
+                                            *         { NULL, NULL },
+                                            *     },
+                                            *     "false"
+                                            * }
+                                            *
+                                            * Only strings are operated on. The possible values will
+                                            * generally be displayed and stored as-is by the frontend.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL 54
+                                           /* const struct retro_core_options_intl * --
+                                            * Allows an implementation to signal the environment
+                                            * which variables it might want to check for later using
+                                            * GET_VARIABLE.
+                                            * This allows the frontend to present these variables to
+                                            * a user dynamically.
+                                            * This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
+                                            * returns an API version of >= 1.
+                                            * This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
+                                            * This should be called the first time as early as
+                                            * possible (ideally in retro_set_environment).
+                                            * Afterwards it may be called again for the core to communicate
+                                            * updated options to the frontend, but the number of core
+                                            * options must not change from the number in the initial call.
+                                            *
+                                            * This is fundamentally the same as RETRO_ENVIRONMENT_SET_CORE_OPTIONS,
+                                            * with the addition of localisation support. The description of the
+                                            * RETRO_ENVIRONMENT_SET_CORE_OPTIONS callback should be consulted
+                                            * for further details.
+                                            *
+                                            * 'data' points to a retro_core_options_intl struct.
+                                            *
+                                            * retro_core_options_intl::us is a pointer to an array of
+                                            * retro_core_option_definition structs defining the US English
+                                            * core options implementation. It must point to a valid array.
+                                            *
+                                            * retro_core_options_intl::local is a pointer to an array of
+                                            * retro_core_option_definition structs defining core options for
+                                            * the current frontend language. It may be NULL (in which case
+                                            * retro_core_options_intl::us is used by the frontend). Any items
+                                            * missing from this array will be read from retro_core_options_intl::us
+                                            * instead.
+                                            *
+                                            * NOTE: Default core option values are always taken from the
+                                            * retro_core_options_intl::us array. Any default values in
+                                            * retro_core_options_intl::local array will be ignored.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY 55
+                                           /* struct retro_core_option_display * --
+                                            *
+                                            * Allows an implementation to signal the environment to show
+                                            * or hide a variable when displaying core options. This is
+                                            * considered a *suggestion*. The frontend is free to ignore
+                                            * this callback, and its implementation not considered mandatory.
+                                            *
+                                            * 'data' points to a retro_core_option_display struct
+                                            *
+                                            * retro_core_option_display::key is a variable identifier
+                                            * which has already been set by SET_VARIABLES/SET_CORE_OPTIONS.
+                                            *
+                                            * retro_core_option_display::visible is a boolean, specifying
+                                            * whether variable should be displayed
+                                            *
+                                            * Note that all core option variables will be set visible by
+                                            * default when calling SET_VARIABLES/SET_CORE_OPTIONS.
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_PREFERRED_HW_RENDER 56
+                                           /* unsigned * --
+                                            *
+                                            * Allows an implementation to ask frontend preferred hardware
+                                            * context to use. Core should use this information to deal
+                                            * with what specific context to request with SET_HW_RENDER.
+                                            *
+                                            * 'data' points to an unsigned variable
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57
+                                           /* unsigned * --
+                                            * Unsigned value is the API version number of the disk control
+                                            * interface supported by the frontend. If callback return false,
+                                            * API version is assumed to be 0.
+                                            *
+                                            * In legacy code, the disk control interface is defined by passing
+                                            * a struct of type retro_disk_control_callback to
+                                            * RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
+                                            * This may be still be done regardless of the disk control
+                                            * interface version.
+                                            *
+                                            * If version is >= 1 however, the disk control interface may
+                                            * instead be defined by passing a struct of type
+                                            * retro_disk_control_ext_callback to
+                                            * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
+                                            * This allows the core to provide additional information about
+                                            * disk images to the frontend and/or enables extra
+                                            * disk control functionality by the frontend.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58
+                                           /* const struct retro_disk_control_ext_callback * --
+                                            * Sets an interface which frontend can use to eject and insert
+                                            * disk images, and also obtain information about individual
+                                            * disk image files registered by the core.
+                                            * This is used for games which consist of multiple images and
+                                            * must be manually swapped out by the user (e.g. PSX, floppy disk
+                                            * based systems).
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION 59
+                                           /* unsigned * --
+                                            * Unsigned value is the API version number of the message
+                                            * interface supported by the frontend. If callback returns
+                                            * false, API version is assumed to be 0.
+                                            *
+                                            * In legacy code, messages may be displayed in an
+                                            * implementation-specific manner by passing a struct
+                                            * of type retro_message to RETRO_ENVIRONMENT_SET_MESSAGE.
+                                            * This may be still be done regardless of the message
+                                            * interface version.
+                                            *
+                                            * If version is >= 1 however, messages may instead be
+                                            * displayed by passing a struct of type retro_message_ext
+                                            * to RETRO_ENVIRONMENT_SET_MESSAGE_EXT. This allows the
+                                            * core to specify message logging level, priority and
+                                            * destination (OSD, logging interface or both).
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_MESSAGE_EXT 60
+                                           /* const struct retro_message_ext * --
+                                            * Sets a message to be displayed in an implementation-specific
+                                            * manner for a certain amount of 'frames'. Additionally allows
+                                            * the core to specify message logging level, priority and
+                                            * destination (OSD, logging interface or both).
+                                            * Should not be used for trivial messages, which should simply be
+                                            * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
+                                            * fallback, stderr).
+                                            */
+
+#define RETRO_ENVIRONMENT_GET_INPUT_MAX_USERS 61
+                                           /* unsigned * --
+                                            * Unsigned value is the number of active input devices
+                                            * provided by the frontend. This may change between
+                                            * frames, but will remain constant for the duration
+                                            * of each frame.
+                                            * If callback returns true, a core need not poll any
+                                            * input device with an index greater than or equal to
+                                            * the number of active devices.
+                                            * If callback returns false, the number of active input
+                                            * devices is unknown. In this case, all input devices
+                                            * should be considered active.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK 62
+                                           /* const struct retro_audio_buffer_status_callback * --
+                                            * Lets the core know the occupancy level of the frontend
+                                            * audio buffer. Can be used by a core to attempt frame
+                                            * skipping in order to avoid buffer under-runs.
+                                            * A core may pass NULL to disable buffer status reporting
+                                            * in the frontend.
+                                            */
+
+#define RETRO_ENVIRONMENT_SET_MINIMUM_AUDIO_LATENCY 63
+                                           /* const unsigned * --
+                                            * Sets minimum frontend audio latency in milliseconds.
+                                            * Resultant audio latency may be larger than set value,
+                                            * or smaller if a hardware limit is encountered. A frontend
+                                            * is expected to honour requests up to 512 ms.
+                                            *
+                                            * - If value is less than current frontend
+                                            *   audio latency, callback has no effect
+                                            * - If value is zero, default frontend audio
+                                            *   latency is set
+                                            *
+                                            * May be used by a core to increase audio latency and
+                                            * therefore decrease the probability of buffer under-runs
+                                            * (crackling) when performing 'intensive' operations.
+                                            * A core utilising RETRO_ENVIRONMENT_SET_AUDIO_BUFFER_STATUS_CALLBACK
+                                            * to implement audio-buffer-based frame skipping may achieve
+                                            * optimal results by setting the audio latency to a 'high'
+                                            * (typically 6x or 8x) integer multiple of the expected
+                                            * frame time.
+                                            *
+                                            * WARNING: This can only be called from within retro_run().
+                                            * Calling this can require a full reinitialization of audio
+                                            * drivers in the frontend, so it is important to call it very
+                                            * sparingly, and usually only with the users explicit consent.
+                                            * An eventual driver reinitialize will happen so that audio
+                                            * callbacks happening after this call within the same retro_run()
+                                            * call will target the newly initialized driver.
+                                            */
+
+/* VFS functionality */
+
+/* File paths:
+ * File paths passed as parameters when using this API shall be well formed UNIX-style,
+ * using "/" (unquoted forward slash) as directory separator regardless of the platform's native separator.
+ * Paths shall also include at least one forward slash ("game.bin" is an invalid path, use "./game.bin" instead).
+ * Other than the directory separator, cores shall not make assumptions about path format:
+ * "C:/path/game.bin", "http://example.com/game.bin", "#game/game.bin", "./game.bin" (without quotes) are all valid paths.
+ * Cores may replace the basename or remove path components from the end, and/or add new components;
+ * however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request to front end.
+ * The frontend is encouraged to make such paths work as well as it can, but is allowed to give up if the core alters paths too much.
+ * Frontends are encouraged, but not required, to support native file system paths (modulo replacing the directory separator, if applicable).
+ * Cores are allowed to try using them, but must remain functional if the front rejects such requests.
+ * Cores are encouraged to use the libretro-common filestream functions for file I/O,
+ * as they seamlessly integrate with VFS, deal with directory separator replacement as appropriate
+ * and provide platform-specific fallbacks in cases where front ends do not support VFS. */
+
+/* Opaque file handle
+ * Introduced in VFS API v1 */
+struct retro_vfs_file_handle;
+
+/* Opaque directory handle
+ * Introduced in VFS API v3 */
+struct retro_vfs_dir_handle;
+
+/* File open flags
+ * Introduced in VFS API v1 */
+#define RETRO_VFS_FILE_ACCESS_READ            (1 << 0) /* Read only mode */
+#define RETRO_VFS_FILE_ACCESS_WRITE           (1 << 1) /* Write only mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified */
+#define RETRO_VFS_FILE_ACCESS_READ_WRITE      (RETRO_VFS_FILE_ACCESS_READ | RETRO_VFS_FILE_ACCESS_WRITE) /* Read-write mode, discard contents and overwrites existing file unless RETRO_VFS_FILE_ACCESS_UPDATE is also specified*/
+#define RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING (1 << 2) /* Prevents discarding content of existing files opened for writing */
+
+/* These are only hints. The frontend may choose to ignore them. Other than RAM/CPU/etc use,
+   and how they react to unlikely external interference (for example someone else writing to that file,
+   or the file's server going down), behavior will not change. */
+#define RETRO_VFS_FILE_ACCESS_HINT_NONE              (0)
+/* Indicate that the file will be accessed many times. The frontend should aggressively cache everything. */
+#define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS   (1 << 0)
+
+/* Seek positions */
+#define RETRO_VFS_SEEK_POSITION_START    0
+#define RETRO_VFS_SEEK_POSITION_CURRENT  1
+#define RETRO_VFS_SEEK_POSITION_END      2
+
+/* stat() result flags
+ * Introduced in VFS API v3 */
+#define RETRO_VFS_STAT_IS_VALID               (1 << 0)
+#define RETRO_VFS_STAT_IS_DIRECTORY           (1 << 1)
+#define RETRO_VFS_STAT_IS_CHARACTER_SPECIAL   (1 << 2)
+
+/* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle
+ * Introduced in VFS API v1 */
+typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream);
+
+/* Open a file for reading or writing. If path points to a directory, this will
+ * fail. Returns the opaque file handle, or NULL for error.
+ * Introduced in VFS API v1 */
+typedef struct retro_vfs_file_handle *(RETRO_CALLCONV *retro_vfs_open_t)(const char *path, unsigned mode, unsigned hints);
+
+/* Close the file and release its resources. Must be called if open_file returns non-NULL. Returns 0 on success, -1 on failure.
+ * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
+ * Introduced in VFS API v1 */
+typedef int (RETRO_CALLCONV *retro_vfs_close_t)(struct retro_vfs_file_handle *stream);
+
+/* Return the size of the file in bytes, or -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_size_t)(struct retro_vfs_file_handle *stream);
+
+/* Truncate file to specified size. Returns 0 on success or -1 on error
+ * Introduced in VFS API v2 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_truncate_t)(struct retro_vfs_file_handle *stream, int64_t length);
+
+/* Get the current read / write position for the file. Returns -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle *stream);
+
+/* Set the current read/write position for the file. Returns the new position, -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position);
+
+/* Read data from a file. Returns the number of bytes read, or -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_read_t)(struct retro_vfs_file_handle *stream, void *s, uint64_t len);
+
+/* Write data to a file. Returns the number of bytes written, or -1 for error.
+ * Introduced in VFS API v1 */
+typedef int64_t (RETRO_CALLCONV *retro_vfs_write_t)(struct retro_vfs_file_handle *stream, const void *s, uint64_t len);
+
+/* Flush pending writes to file, if using buffered IO. Returns 0 on sucess, or -1 on failure.
+ * Introduced in VFS API v1 */
+typedef int (RETRO_CALLCONV *retro_vfs_flush_t)(struct retro_vfs_file_handle *stream);
+
+/* Delete the specified file. Returns 0 on success, -1 on failure
+ * Introduced in VFS API v1 */
+typedef int (RETRO_CALLCONV *retro_vfs_remove_t)(const char *path);
+
+/* Rename the specified file. Returns 0 on success, -1 on failure
+ * Introduced in VFS API v1 */
+typedef int (RETRO_CALLCONV *retro_vfs_rename_t)(const char *old_path, const char *new_path);
+
+/* Stat the specified file. Retruns a bitmask of RETRO_VFS_STAT_* flags, none are set if path was not valid.
+ * Additionally stores file size in given variable, unless NULL is given.
+ * Introduced in VFS API v3 */
+typedef int (RETRO_CALLCONV *retro_vfs_stat_t)(const char *path, int32_t *size);
+
+/* Create the specified directory. Returns 0 on success, -1 on unknown failure, -2 if already exists.
+ * Introduced in VFS API v3 */
+typedef int (RETRO_CALLCONV *retro_vfs_mkdir_t)(const char *dir);
+
+/* Open the specified directory for listing. Returns the opaque dir handle, or NULL for error.
+ * Support for the include_hidden argument may vary depending on the platform.
+ * Introduced in VFS API v3 */
+typedef struct retro_vfs_dir_handle *(RETRO_CALLCONV *retro_vfs_opendir_t)(const char *dir, bool include_hidden);
+
+/* Read the directory entry at the current position, and move the read pointer to the next position.
+ * Returns true on success, false if already on the last entry.
+ * Introduced in VFS API v3 */
+typedef bool (RETRO_CALLCONV *retro_vfs_readdir_t)(struct retro_vfs_dir_handle *dirstream);
+
+/* Get the name of the last entry read. Returns a string on success, or NULL for error.
+ * The returned string pointer is valid until the next call to readdir or closedir.
+ * Introduced in VFS API v3 */
+typedef const char *(RETRO_CALLCONV *retro_vfs_dirent_get_name_t)(struct retro_vfs_dir_handle *dirstream);
+
+/* Check if the last entry read was a directory. Returns true if it was, false otherwise (or on error).
+ * Introduced in VFS API v3 */
+typedef bool (RETRO_CALLCONV *retro_vfs_dirent_is_dir_t)(struct retro_vfs_dir_handle *dirstream);
+
+/* Close the directory and release its resources. Must be called if opendir returns non-NULL. Returns 0 on success, -1 on failure.
+ * Whether the call succeeds ot not, the handle passed as parameter becomes invalid and should no longer be used.
+ * Introduced in VFS API v3 */
+typedef int (RETRO_CALLCONV *retro_vfs_closedir_t)(struct retro_vfs_dir_handle *dirstream);
+
+struct retro_vfs_interface
+{
+   /* VFS API v1 */
+       retro_vfs_get_path_t get_path;
+       retro_vfs_open_t open;
+       retro_vfs_close_t close;
+       retro_vfs_size_t size;
+       retro_vfs_tell_t tell;
+       retro_vfs_seek_t seek;
+       retro_vfs_read_t read;
+       retro_vfs_write_t write;
+       retro_vfs_flush_t flush;
+       retro_vfs_remove_t remove;
+       retro_vfs_rename_t rename;
+   /* VFS API v2 */
+   retro_vfs_truncate_t truncate;
+   /* VFS API v3 */
+   retro_vfs_stat_t stat;
+   retro_vfs_mkdir_t mkdir;
+   retro_vfs_opendir_t opendir;
+   retro_vfs_readdir_t readdir;
+   retro_vfs_dirent_get_name_t dirent_get_name;
+   retro_vfs_dirent_is_dir_t dirent_is_dir;
+   retro_vfs_closedir_t closedir;
+};
+
+struct retro_vfs_interface_info
+{
+   /* Set by core: should this be higher than the version the front end supports,
+    * front end will return false in the RETRO_ENVIRONMENT_GET_VFS_INTERFACE call
+    * Introduced in VFS API v1 */
+   uint32_t required_interface_version;
+
+   /* Frontend writes interface pointer here. The frontend also sets the actual
+    * version, must be at least required_interface_version.
+    * Introduced in VFS API v1 */
+   struct retro_vfs_interface *iface;
+};
+
+enum retro_hw_render_interface_type
+{
+       RETRO_HW_RENDER_INTERFACE_VULKAN = 0,
+       RETRO_HW_RENDER_INTERFACE_D3D9   = 1,
+       RETRO_HW_RENDER_INTERFACE_D3D10  = 2,
+       RETRO_HW_RENDER_INTERFACE_D3D11  = 3,
+       RETRO_HW_RENDER_INTERFACE_D3D12  = 4,
+   RETRO_HW_RENDER_INTERFACE_GSKIT_PS2  = 5,
+   RETRO_HW_RENDER_INTERFACE_DUMMY  = INT_MAX
+};
+
+/* Base struct. All retro_hw_render_interface_* types
+ * contain at least these fields. */
+struct retro_hw_render_interface
+{
+   enum retro_hw_render_interface_type interface_type;
+   unsigned interface_version;
+};
+
+typedef void (RETRO_CALLCONV *retro_set_led_state_t)(int led, int state);
+struct retro_led_interface
+{
+    retro_set_led_state_t set_led_state;
+};
+
+/* Retrieves the current state of the MIDI input.
+ * Returns true if it's enabled, false otherwise. */
+typedef bool (RETRO_CALLCONV *retro_midi_input_enabled_t)(void);
+
+/* Retrieves the current state of the MIDI output.
+ * Returns true if it's enabled, false otherwise */
+typedef bool (RETRO_CALLCONV *retro_midi_output_enabled_t)(void);
+
+/* Reads next byte from the input stream.
+ * Returns true if byte is read, false otherwise. */
+typedef bool (RETRO_CALLCONV *retro_midi_read_t)(uint8_t *byte);
+
+/* Writes byte to the output stream.
+ * 'delta_time' is in microseconds and represent time elapsed since previous write.
+ * Returns true if byte is written, false otherwise. */
+typedef bool (RETRO_CALLCONV *retro_midi_write_t)(uint8_t byte, uint32_t delta_time);
+
+/* Flushes previously written data.
+ * Returns true if successful, false otherwise. */
+typedef bool (RETRO_CALLCONV *retro_midi_flush_t)(void);
+
+struct retro_midi_interface
+{
+   retro_midi_input_enabled_t input_enabled;
+   retro_midi_output_enabled_t output_enabled;
+   retro_midi_read_t read;
+   retro_midi_write_t write;
+   retro_midi_flush_t flush;
+};
+
+enum retro_hw_render_context_negotiation_interface_type
+{
+   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN = 0,
+   RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_DUMMY = INT_MAX
+};
+
+/* Base struct. All retro_hw_render_context_negotiation_interface_* types
+ * contain at least these fields. */
+struct retro_hw_render_context_negotiation_interface
+{
+   enum retro_hw_render_context_negotiation_interface_type interface_type;
+   unsigned interface_version;
+};
+
+/* Serialized state is incomplete in some way. Set if serialization is
+ * usable in typical end-user cases but should not be relied upon to
+ * implement frame-sensitive frontend features such as netplay or
+ * rerecording. */
+#define RETRO_SERIALIZATION_QUIRK_INCOMPLETE (1 << 0)
+/* The core must spend some time initializing before serialization is
+ * supported. retro_serialize() will initially fail; retro_unserialize()
+ * and retro_serialize_size() may or may not work correctly either. */
+#define RETRO_SERIALIZATION_QUIRK_MUST_INITIALIZE (1 << 1)
+/* Serialization size may change within a session. */
+#define RETRO_SERIALIZATION_QUIRK_CORE_VARIABLE_SIZE (1 << 2)
+/* Set by the frontend to acknowledge that it supports variable-sized
+ * states. */
+#define RETRO_SERIALIZATION_QUIRK_FRONT_VARIABLE_SIZE (1 << 3)
+/* Serialized state can only be loaded during the same session. */
+#define RETRO_SERIALIZATION_QUIRK_SINGLE_SESSION (1 << 4)
+/* Serialized state cannot be loaded on an architecture with a different
+ * endianness from the one it was saved on. */
+#define RETRO_SERIALIZATION_QUIRK_ENDIAN_DEPENDENT (1 << 5)
+/* Serialized state cannot be loaded on a different platform from the one it
+ * was saved on for reasons other than endianness, such as word size
+ * dependence */
+#define RETRO_SERIALIZATION_QUIRK_PLATFORM_DEPENDENT (1 << 6)
+
+#define RETRO_MEMDESC_CONST      (1 << 0)   /* The frontend will never change this memory area once retro_load_game has returned. */
+#define RETRO_MEMDESC_BIGENDIAN  (1 << 1)   /* The memory area contains big endian data. Default is little endian. */
+#define RETRO_MEMDESC_SYSTEM_RAM (1 << 2)   /* The memory area is system RAM.  This is main RAM of the gaming system. */
+#define RETRO_MEMDESC_SAVE_RAM   (1 << 3)   /* The memory area is save RAM. This RAM is usually found on a game cartridge, backed up by a battery. */
+#define RETRO_MEMDESC_VIDEO_RAM  (1 << 4)   /* The memory area is video RAM (VRAM) */
+#define RETRO_MEMDESC_ALIGN_2    (1 << 16)  /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
+#define RETRO_MEMDESC_ALIGN_4    (2 << 16)
+#define RETRO_MEMDESC_ALIGN_8    (3 << 16)
+#define RETRO_MEMDESC_MINSIZE_2  (1 << 24)  /* All memory in this region is accessed at least 2 bytes at the time. */
+#define RETRO_MEMDESC_MINSIZE_4  (2 << 24)
+#define RETRO_MEMDESC_MINSIZE_8  (3 << 24)
+struct retro_memory_descriptor
+{
+   uint64_t flags;
+
+   /* Pointer to the start of the relevant ROM or RAM chip.
+    * It's strongly recommended to use 'offset' if possible, rather than
+    * doing math on the pointer.
+    *
+    * If the same byte is mapped my multiple descriptors, their descriptors
+    * must have the same pointer.
+    * If 'start' does not point to the first byte in the pointer, put the
+    * difference in 'offset' instead.
+    *
+    * May be NULL if there's nothing usable here (e.g. hardware registers and
+    * open bus). No flags should be set if the pointer is NULL.
+    * It's recommended to minimize the number of descriptors if possible,
+    * but not mandatory. */
+   void *ptr;
+   size_t offset;
+
+   /* This is the location in the emulated address space
+    * where the mapping starts. */
+   size_t start;
+
+   /* Which bits must be same as in 'start' for this mapping to apply.
+    * The first memory descriptor to claim a certain byte is the one
+    * that applies.
+    * A bit which is set in 'start' must also be set in this.
+    * Can be zero, in which case each byte is assumed mapped exactly once.
+    * In this case, 'len' must be a power of two. */
+   size_t select;
+
+   /* If this is nonzero, the set bits are assumed not connected to the
+    * memory chip's address pins. */
+   size_t disconnect;
+
+   /* This one tells the size of the current memory area.
+    * If, after start+disconnect are applied, the address is higher than
+    * this, the highest bit of the address is cleared.
+    *
+    * If the address is still too high, the next highest bit is cleared.
+    * Can be zero, in which case it's assumed to be infinite (as limited
+    * by 'select' and 'disconnect'). */
+   size_t len;
+
+   /* To go from emulated address to physical address, the following
+    * order applies:
+    * Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'. */
+
+   /* The address space name must consist of only a-zA-Z0-9_-,
+    * should be as short as feasible (maximum length is 8 plus the NUL),
+    * and may not be any other address space plus one or more 0-9A-F
+    * at the end.
+    * However, multiple memory descriptors for the same address space is
+    * allowed, and the address space name can be empty. NULL is treated
+    * as empty.
+    *
+    * Address space names are case sensitive, but avoid lowercase if possible.
+    * The same pointer may exist in multiple address spaces.
+    *
+    * Examples:
+    * blank+blank - valid (multiple things may be mapped in the same namespace)
+    * 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace)
+    * 'A'+'B' - valid (neither is a prefix of each other)
+    * 'S'+blank - valid ('S' is not in 0-9A-F)
+    * 'a'+blank - valid ('a' is not in 0-9A-F)
+    * 'a'+'A' - valid (neither is a prefix of each other)
+    * 'AR'+blank - valid ('R' is not in 0-9A-F)
+    * 'ARB'+blank - valid (the B can't be part of the address either, because
+    *                      there is no namespace 'AR')
+    * blank+'B' - not valid, because it's ambigous which address space B1234
+    *             would refer to.
+    * The length can't be used for that purpose; the frontend may want
+    * to append arbitrary data to an address, without a separator. */
+   const char *addrspace;
+
+   /* TODO: When finalizing this one, add a description field, which should be
+    * "WRAM" or something roughly equally long. */
+
+   /* TODO: When finalizing this one, replace 'select' with 'limit', which tells
+    * which bits can vary and still refer to the same address (limit = ~select).
+    * TODO: limit? range? vary? something else? */
+
+   /* TODO: When finalizing this one, if 'len' is above what 'select' (or
+    * 'limit') allows, it's bankswitched. Bankswitched data must have both 'len'
+    * and 'select' != 0, and the mappings don't tell how the system switches the
+    * banks. */
+
+   /* TODO: When finalizing this one, fix the 'len' bit removal order.
+    * For len=0x1800, pointer 0x1C00 should go to 0x1400, not 0x0C00.
+    * Algorithm: Take bits highest to lowest, but if it goes above len, clear
+    * the most recent addition and continue on the next bit.
+    * TODO: Can the above be optimized? Is "remove the lowest bit set in both
+    * pointer and 'len'" equivalent? */
+
+   /* TODO: Some emulators (MAME?) emulate big endian systems by only accessing
+    * the emulated memory in 32-bit chunks, native endian. But that's nothing
+    * compared to Darek Mihocka <http://www.emulators.com/docs/nx07_vm101.htm>
+    * (section Emulation 103 - Nearly Free Byte Reversal) - he flips the ENTIRE
+    * RAM backwards! I'll want to represent both of those, via some flags.
+    *
+    * I suspect MAME either didn't think of that idea, or don't want the #ifdef.
+    * Not sure which, nor do I really care. */
+
+   /* TODO: Some of those flags are unused and/or don't really make sense. Clean
+    * them up. */
+};
+
+/* The frontend may use the largest value of 'start'+'select' in a
+ * certain namespace to infer the size of the address space.
+ *
+ * If the address space is larger than that, a mapping with .ptr=NULL
+ * should be at the end of the array, with .select set to all ones for
+ * as long as the address space is big.
+ *
+ * Sample descriptors (minus .ptr, and RETRO_MEMFLAG_ on the flags):
+ * SNES WRAM:
+ * .start=0x7E0000, .len=0x20000
+ * (Note that this must be mapped before the ROM in most cases; some of the
+ * ROM mappers
+ * try to claim $7E0000, or at least $7E8000.)
+ * SNES SPC700 RAM:
+ * .addrspace="S", .len=0x10000
+ * SNES WRAM mirrors:
+ * .flags=MIRROR, .start=0x000000, .select=0xC0E000, .len=0x2000
+ * .flags=MIRROR, .start=0x800000, .select=0xC0E000, .len=0x2000
+ * SNES WRAM mirrors, alternate equivalent descriptor:
+ * .flags=MIRROR, .select=0x40E000, .disconnect=~0x1FFF
+ * (Various similar constructions can be created by combining parts of
+ * the above two.)
+ * SNES LoROM (512KB, mirrored a couple of times):
+ * .flags=CONST, .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024
+ * .flags=CONST, .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024
+ * SNES HiROM (4MB):
+ * .flags=CONST,                 .start=0x400000, .select=0x400000, .len=4*1024*1024
+ * .flags=CONST, .offset=0x8000, .start=0x008000, .select=0x408000, .len=4*1024*1024
+ * SNES ExHiROM (8MB):
+ * .flags=CONST, .offset=0,                  .start=0xC00000, .select=0xC00000, .len=4*1024*1024
+ * .flags=CONST, .offset=4*1024*1024,        .start=0x400000, .select=0xC00000, .len=4*1024*1024
+ * .flags=CONST, .offset=0x8000,             .start=0x808000, .select=0xC08000, .len=4*1024*1024
+ * .flags=CONST, .offset=4*1024*1024+0x8000, .start=0x008000, .select=0xC08000, .len=4*1024*1024
+ * Clarify the size of the address space:
+ * .ptr=NULL, .select=0xFFFFFF
+ * .len can be implied by .select in many of them, but was included for clarity.
+ */
+
+struct retro_memory_map
+{
+   const struct retro_memory_descriptor *descriptors;
+   unsigned num_descriptors;
+};
+
+struct retro_controller_description
+{
+   /* Human-readable description of the controller. Even if using a generic
+    * input device type, this can be set to the particular device type the
+    * core uses. */
+   const char *desc;
+
+   /* Device type passed to retro_set_controller_port_device(). If the device
+    * type is a sub-class of a generic input device type, use the
+    * RETRO_DEVICE_SUBCLASS macro to create an ID.
+    *
+    * E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */
+   unsigned id;
+};
+
+struct retro_controller_info
+{
+   const struct retro_controller_description *types;
+   unsigned num_types;
+};
+
+struct retro_subsystem_memory_info
+{
+   /* The extension associated with a memory type, e.g. "psram". */
+   const char *extension;
+
+   /* The memory type for retro_get_memory(). This should be at
+    * least 0x100 to avoid conflict with standardized
+    * libretro memory types. */
+   unsigned type;
+};
+
+struct retro_subsystem_rom_info
+{
+   /* Describes what the content is (SGB BIOS, GB ROM, etc). */
+   const char *desc;
+
+   /* Same definition as retro_get_system_info(). */
+   const char *valid_extensions;
+
+   /* Same definition as retro_get_system_info(). */
+   bool need_fullpath;
+
+   /* Same definition as retro_get_system_info(). */
+   bool block_extract;
+
+   /* This is set if the content is required to load a game.
+    * If this is set to false, a zeroed-out retro_game_info can be passed. */
+   bool required;
+
+   /* Content can have multiple associated persistent
+    * memory types (retro_get_memory()). */
+   const struct retro_subsystem_memory_info *memory;
+   unsigned num_memory;
+};
+
+struct retro_subsystem_info
+{
+   /* Human-readable string of the subsystem type, e.g. "Super GameBoy" */
+   const char *desc;
+
+   /* A computer friendly short string identifier for the subsystem type.
+    * This name must be [a-z].
+    * E.g. if desc is "Super GameBoy", this can be "sgb".
+    * This identifier can be used for command-line interfaces, etc.
+    */
+   const char *ident;
+
+   /* Infos for each content file. The first entry is assumed to be the
+    * "most significant" content for frontend purposes.
+    * E.g. with Super GameBoy, the first content should be the GameBoy ROM,
+    * as it is the most "significant" content to a user.
+    * If a frontend creates new file paths based on the content used
+    * (e.g. savestates), it should use the path for the first ROM to do so. */
+   const struct retro_subsystem_rom_info *roms;
+
+   /* Number of content files associated with a subsystem. */
+   unsigned num_roms;
+
+   /* The type passed to retro_load_game_special(). */
+   unsigned id;
+};
+
+typedef void (RETRO_CALLCONV *retro_proc_address_t)(void);
+
+/* libretro API extension functions:
+ * (None here so far).
+ *
+ * Get a symbol from a libretro core.
+ * Cores should only return symbols which are actual
+ * extensions to the libretro API.
+ *
+ * Frontends should not use this to obtain symbols to standard
+ * libretro entry points (static linking or dlsym).
+ *
+ * The symbol name must be equal to the function name,
+ * e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo".
+ * The returned function pointer must be cast to the corresponding type.
+ */
+typedef retro_proc_address_t (RETRO_CALLCONV *retro_get_proc_address_t)(const char *sym);
+
+struct retro_get_proc_address_interface
+{
+   retro_get_proc_address_t get_proc_address;
+};
+
+enum retro_log_level
+{
+   RETRO_LOG_DEBUG = 0,
+   RETRO_LOG_INFO,
+   RETRO_LOG_WARN,
+   RETRO_LOG_ERROR,
+
+   RETRO_LOG_DUMMY = INT_MAX
+};
+
+/* Logging function. Takes log level argument as well. */
+typedef void (RETRO_CALLCONV *retro_log_printf_t)(enum retro_log_level level,
+      const char *fmt, ...);
+
+struct retro_log_callback
+{
+   retro_log_printf_t log;
+};
+
+/* Performance related functions */
+
+/* ID values for SIMD CPU features */
+#define RETRO_SIMD_SSE      (1 << 0)
+#define RETRO_SIMD_SSE2     (1 << 1)
+#define RETRO_SIMD_VMX      (1 << 2)
+#define RETRO_SIMD_VMX128   (1 << 3)
+#define RETRO_SIMD_AVX      (1 << 4)
+#define RETRO_SIMD_NEON     (1 << 5)
+#define RETRO_SIMD_SSE3     (1 << 6)
+#define RETRO_SIMD_SSSE3    (1 << 7)
+#define RETRO_SIMD_MMX      (1 << 8)
+#define RETRO_SIMD_MMXEXT   (1 << 9)
+#define RETRO_SIMD_SSE4     (1 << 10)
+#define RETRO_SIMD_SSE42    (1 << 11)
+#define RETRO_SIMD_AVX2     (1 << 12)
+#define RETRO_SIMD_VFPU     (1 << 13)
+#define RETRO_SIMD_PS       (1 << 14)
+#define RETRO_SIMD_AES      (1 << 15)
+#define RETRO_SIMD_VFPV3    (1 << 16)
+#define RETRO_SIMD_VFPV4    (1 << 17)
+#define RETRO_SIMD_POPCNT   (1 << 18)
+#define RETRO_SIMD_MOVBE    (1 << 19)
+#define RETRO_SIMD_CMOV     (1 << 20)
+#define RETRO_SIMD_ASIMD    (1 << 21)
+
+typedef uint64_t retro_perf_tick_t;
+typedef int64_t retro_time_t;
+
+struct retro_perf_counter
+{
+   const char *ident;
+   retro_perf_tick_t start;
+   retro_perf_tick_t total;
+   retro_perf_tick_t call_cnt;
+
+   bool registered;
+};
+
+/* Returns current time in microseconds.
+ * Tries to use the most accurate timer available.
+ */
+typedef retro_time_t (RETRO_CALLCONV *retro_perf_get_time_usec_t)(void);
+
+/* A simple counter. Usually nanoseconds, but can also be CPU cycles.
+ * Can be used directly if desired (when creating a more sophisticated
+ * performance counter system).
+ * */
+typedef retro_perf_tick_t (RETRO_CALLCONV *retro_perf_get_counter_t)(void);
+
+/* Returns a bit-mask of detected CPU features (RETRO_SIMD_*). */
+typedef uint64_t (RETRO_CALLCONV *retro_get_cpu_features_t)(void);
+
+/* Asks frontend to log and/or display the state of performance counters.
+ * Performance counters can always be poked into manually as well.
+ */
+typedef void (RETRO_CALLCONV *retro_perf_log_t)(void);
+
+/* Register a performance counter.
+ * ident field must be set with a discrete value and other values in
+ * retro_perf_counter must be 0.
+ * Registering can be called multiple times. To avoid calling to
+ * frontend redundantly, you can check registered field first. */
+typedef void (RETRO_CALLCONV *retro_perf_register_t)(struct retro_perf_counter *counter);
+
+/* Starts a registered counter. */
+typedef void (RETRO_CALLCONV *retro_perf_start_t)(struct retro_perf_counter *counter);
+
+/* Stops a registered counter. */
+typedef void (RETRO_CALLCONV *retro_perf_stop_t)(struct retro_perf_counter *counter);
+
+/* For convenience it can be useful to wrap register, start and stop in macros.
+ * E.g.:
+ * #ifdef LOG_PERFORMANCE
+ * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name))
+ * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name))
+ * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name))
+ * #else
+ * ... Blank macros ...
+ * #endif
+ *
+ * These can then be used mid-functions around code snippets.
+ *
+ * extern struct retro_perf_callback perf_cb;  * Somewhere in the core.
+ *
+ * void do_some_heavy_work(void)
+ * {
+ *    RETRO_PERFORMANCE_INIT(cb, work_1;
+ *    RETRO_PERFORMANCE_START(cb, work_1);
+ *    heavy_work_1();
+ *    RETRO_PERFORMANCE_STOP(cb, work_1);
+ *
+ *    RETRO_PERFORMANCE_INIT(cb, work_2);
+ *    RETRO_PERFORMANCE_START(cb, work_2);
+ *    heavy_work_2();
+ *    RETRO_PERFORMANCE_STOP(cb, work_2);
+ * }
+ *
+ * void retro_deinit(void)
+ * {
+ *    perf_cb.perf_log();  * Log all perf counters here for example.
+ * }
+ */
+
+struct retro_perf_callback
+{
+   retro_perf_get_time_usec_t    get_time_usec;
+   retro_get_cpu_features_t      get_cpu_features;
+
+   retro_perf_get_counter_t      get_perf_counter;
+   retro_perf_register_t         perf_register;
+   retro_perf_start_t            perf_start;
+   retro_perf_stop_t             perf_stop;
+   retro_perf_log_t              perf_log;
+};
+
+/* FIXME: Document the sensor API and work out behavior.
+ * It will be marked as experimental until then.
+ */
+enum retro_sensor_action
+{
+   RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,
+   RETRO_SENSOR_ACCELEROMETER_DISABLE,
+   RETRO_SENSOR_GYROSCOPE_ENABLE,
+   RETRO_SENSOR_GYROSCOPE_DISABLE,
+   RETRO_SENSOR_ILLUMINANCE_ENABLE,
+   RETRO_SENSOR_ILLUMINANCE_DISABLE,
+
+   RETRO_SENSOR_DUMMY = INT_MAX
+};
+
+/* Id values for SENSOR types. */
+#define RETRO_SENSOR_ACCELEROMETER_X 0
+#define RETRO_SENSOR_ACCELEROMETER_Y 1
+#define RETRO_SENSOR_ACCELEROMETER_Z 2
+#define RETRO_SENSOR_GYROSCOPE_X 3
+#define RETRO_SENSOR_GYROSCOPE_Y 4
+#define RETRO_SENSOR_GYROSCOPE_Z 5
+#define RETRO_SENSOR_ILLUMINANCE 6
+
+typedef bool (RETRO_CALLCONV *retro_set_sensor_state_t)(unsigned port,
+      enum retro_sensor_action action, unsigned rate);
+
+typedef float (RETRO_CALLCONV *retro_sensor_get_input_t)(unsigned port, unsigned id);
+
+struct retro_sensor_interface
+{
+   retro_set_sensor_state_t set_sensor_state;
+   retro_sensor_get_input_t get_sensor_input;
+};
+
+enum retro_camera_buffer
+{
+   RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,
+   RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,
+
+   RETRO_CAMERA_BUFFER_DUMMY = INT_MAX
+};
+
+/* Starts the camera driver. Can only be called in retro_run(). */
+typedef bool (RETRO_CALLCONV *retro_camera_start_t)(void);
+
+/* Stops the camera driver. Can only be called in retro_run(). */
+typedef void (RETRO_CALLCONV *retro_camera_stop_t)(void);
+
+/* Callback which signals when the camera driver is initialized
+ * and/or deinitialized.
+ * retro_camera_start_t can be called in initialized callback.
+ */
+typedef void (RETRO_CALLCONV *retro_camera_lifetime_status_t)(void);
+
+/* A callback for raw framebuffer data. buffer points to an XRGB8888 buffer.
+ * Width, height and pitch are similar to retro_video_refresh_t.
+ * First pixel is top-left origin.
+ */
+typedef void (RETRO_CALLCONV *retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
+      unsigned width, unsigned height, size_t pitch);
+
+/* A callback for when OpenGL textures are used.
+ *
+ * texture_id is a texture owned by camera driver.
+ * Its state or content should be considered immutable, except for things like
+ * texture filtering and clamping.
+ *
+ * texture_target is the texture target for the GL texture.
+ * These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly
+ * more depending on extensions.
+ *
+ * affine points to a packed 3x3 column-major matrix used to apply an affine
+ * transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0))
+ * After transform, normalized texture coord (0, 0) should be bottom-left
+ * and (1, 1) should be top-right (or (width, height) for RECTANGLE).
+ *
+ * GL-specific typedefs are avoided here to avoid relying on gl.h in
+ * the API definition.
+ */
+typedef void (RETRO_CALLCONV *retro_camera_frame_opengl_texture_t)(unsigned texture_id,
+      unsigned texture_target, const float *affine);
+
+struct retro_camera_callback
+{
+   /* Set by libretro core.
+    * Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER).
+    */
+   uint64_t caps;
+
+   /* Desired resolution for camera. Is only used as a hint. */
+   unsigned width;
+   unsigned height;
+
+   /* Set by frontend. */
+   retro_camera_start_t start;
+   retro_camera_stop_t stop;
+
+   /* Set by libretro core if raw framebuffer callbacks will be used. */
+   retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;
+
+   /* Set by libretro core if OpenGL texture callbacks will be used. */
+   retro_camera_frame_opengl_texture_t frame_opengl_texture;
+
+   /* Set by libretro core. Called after camera driver is initialized and
+    * ready to be started.
+    * Can be NULL, in which this callback is not called.
+    */
+   retro_camera_lifetime_status_t initialized;
+
+   /* Set by libretro core. Called right before camera driver is
+    * deinitialized.
+    * Can be NULL, in which this callback is not called.
+    */
+   retro_camera_lifetime_status_t deinitialized;
+};
+
+/* Sets the interval of time and/or distance at which to update/poll
+ * location-based data.
+ *
+ * To ensure compatibility with all location-based implementations,
+ * values for both interval_ms and interval_distance should be provided.
+ *
+ * interval_ms is the interval expressed in milliseconds.
+ * interval_distance is the distance interval expressed in meters.
+ */
+typedef void (RETRO_CALLCONV *retro_location_set_interval_t)(unsigned interval_ms,
+      unsigned interval_distance);
+
+/* Start location services. The device will start listening for changes to the
+ * current location at regular intervals (which are defined with
+ * retro_location_set_interval_t). */
+typedef bool (RETRO_CALLCONV *retro_location_start_t)(void);
+
+/* Stop location services. The device will stop listening for changes
+ * to the current location. */
+typedef void (RETRO_CALLCONV *retro_location_stop_t)(void);
+
+/* Get the position of the current location. Will set parameters to
+ * 0 if no new  location update has happened since the last time. */
+typedef bool (RETRO_CALLCONV *retro_location_get_position_t)(double *lat, double *lon,
+      double *horiz_accuracy, double *vert_accuracy);
+
+/* Callback which signals when the location driver is initialized
+ * and/or deinitialized.
+ * retro_location_start_t can be called in initialized callback.
+ */
+typedef void (RETRO_CALLCONV *retro_location_lifetime_status_t)(void);
+
+struct retro_location_callback
+{
+   retro_location_start_t         start;
+   retro_location_stop_t          stop;
+   retro_location_get_position_t  get_position;
+   retro_location_set_interval_t  set_interval;
+
+   retro_location_lifetime_status_t initialized;
+   retro_location_lifetime_status_t deinitialized;
+};
+
+enum retro_rumble_effect
+{
+   RETRO_RUMBLE_STRONG = 0,
+   RETRO_RUMBLE_WEAK = 1,
+
+   RETRO_RUMBLE_DUMMY = INT_MAX
+};
+
+/* Sets rumble state for joypad plugged in port 'port'.
+ * Rumble effects are controlled independently,
+ * and setting e.g. strong rumble does not override weak rumble.
+ * Strength has a range of [0, 0xffff].
+ *
+ * Returns true if rumble state request was honored.
+ * Calling this before first retro_run() is likely to return false. */
+typedef bool (RETRO_CALLCONV *retro_set_rumble_state_t)(unsigned port,
+      enum retro_rumble_effect effect, uint16_t strength);
+
+struct retro_rumble_interface
+{
+   retro_set_rumble_state_t set_rumble_state;
+};
+
+/* Notifies libretro that audio data should be written. */
+typedef void (RETRO_CALLCONV *retro_audio_callback_t)(void);
+
+/* True: Audio driver in frontend is active, and callback is
+ * expected to be called regularily.
+ * False: Audio driver in frontend is paused or inactive.
+ * Audio callback will not be called until set_state has been
+ * called with true.
+ * Initial state is false (inactive).
+ */
+typedef void (RETRO_CALLCONV *retro_audio_set_state_callback_t)(bool enabled);
+
+struct retro_audio_callback
+{
+   retro_audio_callback_t callback;
+   retro_audio_set_state_callback_t set_state;
+};
+
+/* Notifies a libretro core of time spent since last invocation
+ * of retro_run() in microseconds.
+ *
+ * It will be called right before retro_run() every frame.
+ * The frontend can tamper with timing to support cases like
+ * fast-forward, slow-motion and framestepping.
+ *
+ * In those scenarios the reference frame time value will be used. */
+typedef int64_t retro_usec_t;
+typedef void (RETRO_CALLCONV *retro_frame_time_callback_t)(retro_usec_t usec);
+struct retro_frame_time_callback
+{
+   retro_frame_time_callback_t callback;
+   /* Represents the time of one frame. It is computed as
+    * 1000000 / fps, but the implementation will resolve the
+    * rounding to ensure that framestepping, etc is exact. */
+   retro_usec_t reference;
+};
+
+/* Notifies a libretro core of the current occupancy
+ * level of the frontend audio buffer.
+ *
+ * - active: 'true' if audio buffer is currently
+ *           in use. Will be 'false' if audio is
+ *           disabled in the frontend
+ *
+ * - occupancy: Given as a value in the range [0,100],
+ *              corresponding to the occupancy percentage
+ *              of the audio buffer
+ *
+ * - underrun_likely: 'true' if the frontend expects an
+ *                    audio buffer underrun during the
+ *                    next frame (indicates that a core
+ *                    should attempt frame skipping)
+ *
+ * It will be called right before retro_run() every frame. */
+typedef void (RETRO_CALLCONV *retro_audio_buffer_status_callback_t)(
+      bool active, unsigned occupancy, bool underrun_likely);
+struct retro_audio_buffer_status_callback
+{
+   retro_audio_buffer_status_callback_t callback;
+};
+
+/* Pass this to retro_video_refresh_t if rendering to hardware.
+ * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
+ * */
+#define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)
+
+/* Invalidates the current HW context.
+ * Any GL state is lost, and must not be deinitialized explicitly.
+ * If explicit deinitialization is desired by the libretro core,
+ * it should implement context_destroy callback.
+ * If called, all GPU resources must be reinitialized.
+ * Usually called when frontend reinits video driver.
+ * Also called first time video driver is initialized,
+ * allowing libretro core to initialize resources.
+ */
+typedef void (RETRO_CALLCONV *retro_hw_context_reset_t)(void);
+
+/* Gets current framebuffer which is to be rendered to.
+ * Could change every frame potentially.
+ */
+typedef uintptr_t (RETRO_CALLCONV *retro_hw_get_current_framebuffer_t)(void);
+
+/* Get a symbol from HW context. */
+typedef retro_proc_address_t (RETRO_CALLCONV *retro_hw_get_proc_address_t)(const char *sym);
+
+enum retro_hw_context_type
+{
+   RETRO_HW_CONTEXT_NONE             = 0,
+   /* OpenGL 2.x. Driver can choose to use latest compatibility context. */
+   RETRO_HW_CONTEXT_OPENGL           = 1,
+   /* OpenGL ES 2.0. */
+   RETRO_HW_CONTEXT_OPENGLES2        = 2,
+   /* Modern desktop core GL context. Use version_major/
+    * version_minor fields to set GL version. */
+   RETRO_HW_CONTEXT_OPENGL_CORE      = 3,
+   /* OpenGL ES 3.0 */
+   RETRO_HW_CONTEXT_OPENGLES3        = 4,
+   /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,
+    * use the corresponding enums directly. */
+   RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,
+
+   /* Vulkan, see RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE. */
+   RETRO_HW_CONTEXT_VULKAN           = 6,
+
+   /* Direct3D, set version_major to select the type of interface
+    * returned by RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE */
+   RETRO_HW_CONTEXT_DIRECT3D         = 7,
+
+   RETRO_HW_CONTEXT_DUMMY = INT_MAX
+};
+
+struct retro_hw_render_callback
+{
+   /* Which API to use. Set by libretro core. */
+   enum retro_hw_context_type context_type;
+
+   /* Called when a context has been created or when it has been reset.
+    * An OpenGL context is only valid after context_reset() has been called.
+    *
+    * When context_reset is called, OpenGL resources in the libretro
+    * implementation are guaranteed to be invalid.
+    *
+    * It is possible that context_reset is called multiple times during an
+    * application lifecycle.
+    * If context_reset is called without any notification (context_destroy),
+    * the OpenGL context was lost and resources should just be recreated
+    * without any attempt to "free" old resources.
+    */
+   retro_hw_context_reset_t context_reset;
+
+   /* Set by frontend.
+    * TODO: This is rather obsolete. The frontend should not
+    * be providing preallocated framebuffers. */
+   retro_hw_get_current_framebuffer_t get_current_framebuffer;
+
+   /* Set by frontend.
+    * Can return all relevant functions, including glClear on Windows. */
+   retro_hw_get_proc_address_t get_proc_address;
+
+   /* Set if render buffers should have depth component attached.
+    * TODO: Obsolete. */
+   bool depth;
+
+   /* Set if stencil buffers should be attached.
+    * TODO: Obsolete. */
+   bool stencil;
+
+   /* If depth and stencil are true, a packed 24/8 buffer will be added.
+    * Only attaching stencil is invalid and will be ignored. */
+
+   /* Use conventional bottom-left origin convention. If false,
+    * standard libretro top-left origin semantics are used.
+    * TODO: Move to GL specific interface. */
+   bool bottom_left_origin;
+
+   /* Major version number for core GL context or GLES 3.1+. */
+   unsigned version_major;
+
+   /* Minor version number for core GL context or GLES 3.1+. */
+   unsigned version_minor;
+
+   /* If this is true, the frontend will go very far to avoid
+    * resetting context in scenarios like toggling fullscreen, etc.
+    * TODO: Obsolete? Maybe frontend should just always assume this ...
+    */
+   bool cache_context;
+
+   /* The reset callback might still be called in extreme situations
+    * such as if the context is lost beyond recovery.
+    *
+    * For optimal stability, set this to false, and allow context to be
+    * reset at any time.
+    */
+
+   /* A callback to be called before the context is destroyed in a
+    * controlled way by the frontend. */
+   retro_hw_context_reset_t context_destroy;
+
+   /* OpenGL resources can be deinitialized cleanly at this step.
+    * context_destroy can be set to NULL, in which resources will
+    * just be destroyed without any notification.
+    *
+    * Even when context_destroy is non-NULL, it is possible that
+    * context_reset is called without any destroy notification.
+    * This happens if context is lost by external factors (such as
+    * notified by GL_ARB_robustness).
+    *
+    * In this case, the context is assumed to be already dead,
+    * and the libretro implementation must not try to free any OpenGL
+    * resources in the subsequent context_reset.
+    */
+
+   /* Creates a debug context. */
+   bool debug_context;
+};
+
+/* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
+ * Called by the frontend in response to keyboard events.
+ * down is set if the key is being pressed, or false if it is being released.
+ * keycode is the RETROK value of the char.
+ * character is the text character of the pressed key. (UTF-32).
+ * key_modifiers is a set of RETROKMOD values or'ed together.
+ *
+ * The pressed/keycode state can be indepedent of the character.
+ * It is also possible that multiple characters are generated from a
+ * single keypress.
+ * Keycode events should be treated separately from character events.
+ * However, when possible, the frontend should try to synchronize these.
+ * If only a character is posted, keycode should be RETROK_UNKNOWN.
+ *
+ * Similarily if only a keycode event is generated with no corresponding
+ * character, character should be 0.
+ */
+typedef void (RETRO_CALLCONV *retro_keyboard_event_t)(bool down, unsigned keycode,
+      uint32_t character, uint16_t key_modifiers);
+
+struct retro_keyboard_callback
+{
+   retro_keyboard_event_t callback;
+};
+
+/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE &
+ * RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
+ * Should be set for implementations which can swap out multiple disk
+ * images in runtime.
+ *
+ * If the implementation can do this automatically, it should strive to do so.
+ * However, there are cases where the user must manually do so.
+ *
+ * Overview: To swap a disk image, eject the disk image with
+ * set_eject_state(true).
+ * Set the disk index with set_image_index(index). Insert the disk again
+ * with set_eject_state(false).
+ */
+
+/* If ejected is true, "ejects" the virtual disk tray.
+ * When ejected, the disk image index can be set.
+ */
+typedef bool (RETRO_CALLCONV *retro_set_eject_state_t)(bool ejected);
+
+/* Gets current eject state. The initial state is 'not ejected'. */
+typedef bool (RETRO_CALLCONV *retro_get_eject_state_t)(void);
+
+/* Gets current disk index. First disk is index 0.
+ * If return value is >= get_num_images(), no disk is currently inserted.
+ */
+typedef unsigned (RETRO_CALLCONV *retro_get_image_index_t)(void);
+
+/* Sets image index. Can only be called when disk is ejected.
+ * The implementation supports setting "no disk" by using an
+ * index >= get_num_images().
+ */
+typedef bool (RETRO_CALLCONV *retro_set_image_index_t)(unsigned index);
+
+/* Gets total number of images which are available to use. */
+typedef unsigned (RETRO_CALLCONV *retro_get_num_images_t)(void);
+
+struct retro_game_info;
+
+/* Replaces the disk image associated with index.
+ * Arguments to pass in info have same requirements as retro_load_game().
+ * Virtual disk tray must be ejected when calling this.
+ *
+ * Replacing a disk image with info = NULL will remove the disk image
+ * from the internal list.
+ * As a result, calls to get_image_index() can change.
+ *
+ * E.g. replace_image_index(1, NULL), and previous get_image_index()
+ * returned 4 before.
+ * Index 1 will be removed, and the new index is 3.
+ */
+typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
+      const struct retro_game_info *info);
+
+/* Adds a new valid index (get_num_images()) to the internal disk list.
+ * This will increment subsequent return values from get_num_images() by 1.
+ * This image index cannot be used until a disk image has been set
+ * with replace_image_index. */
+typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);
+
+/* Sets initial image to insert in drive when calling
+ * core_load_game().
+ * Since we cannot pass the initial index when loading
+ * content (this would require a major API change), this
+ * is set by the frontend *before* calling the core's
+ * retro_load_game()/retro_load_game_special() implementation.
+ * A core should therefore cache the index/path values and handle
+ * them inside retro_load_game()/retro_load_game_special().
+ * - If 'index' is invalid (index >= get_num_images()), the
+ *   core should ignore the set value and instead use 0
+ * - 'path' is used purely for error checking - i.e. when
+ *   content is loaded, the core should verify that the
+ *   disk specified by 'index' has the specified file path.
+ *   This is to guard against auto selecting the wrong image
+ *   if (for example) the user should modify an existing M3U
+ *   playlist. We have to let the core handle this because
+ *   set_initial_image() must be called before loading content,
+ *   i.e. the frontend cannot access image paths in advance
+ *   and thus cannot perform the error check itself.
+ *   If set path and content path do not match, the core should
+ *   ignore the set 'index' value and instead use 0
+ * Returns 'false' if index or 'path' are invalid, or core
+ * does not support this functionality
+ */
+typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);
+
+/* Fetches the path of the specified disk image file.
+ * Returns 'false' if index is invalid (index >= get_num_images())
+ * or path is otherwise unavailable.
+ */
+typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len);
+
+/* Fetches a core-provided 'label' for the specified disk
+ * image file. In the simplest case this may be a file name
+ * (without extension), but for cores with more complex
+ * content requirements information may be provided to
+ * facilitate user disk swapping - for example, a core
+ * running floppy-disk-based content may uniquely label
+ * save disks, data disks, level disks, etc. with names
+ * corresponding to in-game disk change prompts (so the
+ * frontend can provide better user guidance than a 'dumb'
+ * disk index value).
+ * Returns 'false' if index is invalid (index >= get_num_images())
+ * or label is otherwise unavailable.
+ */
+typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len);
+
+struct retro_disk_control_callback
+{
+   retro_set_eject_state_t set_eject_state;
+   retro_get_eject_state_t get_eject_state;
+
+   retro_get_image_index_t get_image_index;
+   retro_set_image_index_t set_image_index;
+   retro_get_num_images_t  get_num_images;
+
+   retro_replace_image_index_t replace_image_index;
+   retro_add_image_index_t add_image_index;
+};
+
+struct retro_disk_control_ext_callback
+{
+   retro_set_eject_state_t set_eject_state;
+   retro_get_eject_state_t get_eject_state;
+
+   retro_get_image_index_t get_image_index;
+   retro_set_image_index_t set_image_index;
+   retro_get_num_images_t  get_num_images;
+
+   retro_replace_image_index_t replace_image_index;
+   retro_add_image_index_t add_image_index;
+
+   /* NOTE: Frontend will only attempt to record/restore
+    * last used disk index if both set_initial_image()
+    * and get_image_path() are implemented */
+   retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */
+
+   retro_get_image_path_t get_image_path;       /* Optional - may be NULL */
+   retro_get_image_label_t get_image_label;     /* Optional - may be NULL */
+};
+
+enum retro_pixel_format
+{
+   /* 0RGB1555, native endian.
+    * 0 bit must be set to 0.
+    * This pixel format is default for compatibility concerns only.
+    * If a 15/16-bit pixel format is desired, consider using RGB565. */
+   RETRO_PIXEL_FORMAT_0RGB1555 = 0,
+
+   /* XRGB8888, native endian.
+    * X bits are ignored. */
+   RETRO_PIXEL_FORMAT_XRGB8888 = 1,
+
+   /* RGB565, native endian.
+    * This pixel format is the recommended format to use if a 15/16-bit
+    * format is desired as it is the pixel format that is typically
+    * available on a wide range of low-power devices.
+    *
+    * It is also natively supported in APIs like OpenGL ES. */
+   RETRO_PIXEL_FORMAT_RGB565   = 2,
+
+   /* Ensure sizeof() == sizeof(int). */
+   RETRO_PIXEL_FORMAT_UNKNOWN  = INT_MAX
+};
+
+struct retro_message
+{
+   const char *msg;        /* Message to be displayed. */
+   unsigned    frames;     /* Duration in frames of message. */
+};
+
+enum retro_message_target
+{
+   RETRO_MESSAGE_TARGET_ALL = 0,
+   RETRO_MESSAGE_TARGET_OSD,
+   RETRO_MESSAGE_TARGET_LOG
+};
+
+enum retro_message_type
+{
+   RETRO_MESSAGE_TYPE_NOTIFICATION = 0,
+   RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,
+   RETRO_MESSAGE_TYPE_STATUS,
+   RETRO_MESSAGE_TYPE_PROGRESS
+};
+
+struct retro_message_ext
+{
+   /* Message string to be displayed/logged */
+   const char *msg;
+   /* Duration (in ms) of message when targeting the OSD */
+   unsigned duration;
+   /* Message priority when targeting the OSD
+    * > When multiple concurrent messages are sent to
+    *   the frontend and the frontend does not have the
+    *   capacity to display them all, messages with the
+    *   *highest* priority value should be shown
+    * > There is no upper limit to a message priority
+    *   value (within the bounds of the unsigned data type)
+    * > In the reference frontend (RetroArch), the same
+    *   priority values are used for frontend-generated
+    *   notifications, which are typically assigned values
+    *   between 0 and 3 depending upon importance */
+   unsigned priority;
+   /* Message logging level (info, warn, error, etc.) */
+   enum retro_log_level level;
+   /* Message destination: OSD, logging interface or both */
+   enum retro_message_target target;
+   /* Message 'type' when targeting the OSD
+    * > RETRO_MESSAGE_TYPE_NOTIFICATION: Specifies that a
+    *   message should be handled in identical fashion to
+    *   a standard frontend-generated notification
+    * > RETRO_MESSAGE_TYPE_NOTIFICATION_ALT: Specifies that
+    *   message is a notification that requires user attention
+    *   or action, but that it should be displayed in a manner
+    *   that differs from standard frontend-generated notifications.
+    *   This would typically correspond to messages that should be
+    *   displayed immediately (independently from any internal
+    *   frontend message queue), and/or which should be visually
+    *   distinguishable from frontend-generated notifications.
+    *   For example, a core may wish to inform the user of
+    *   information related to a disk-change event. It is
+    *   expected that the frontend itself may provide a
+    *   notification in this case; if the core sends a
+    *   message of type RETRO_MESSAGE_TYPE_NOTIFICATION, an
+    *   uncomfortable 'double-notification' may occur. A message
+    *   of RETRO_MESSAGE_TYPE_NOTIFICATION_ALT should therefore
+    *   be presented such that visual conflict with regular
+    *   notifications does not occur
+    * > RETRO_MESSAGE_TYPE_STATUS: Indicates that message
+    *   is not a standard notification. This typically
+    *   corresponds to 'status' indicators, such as a core's
+    *   internal FPS, which are intended to be displayed
+    *   either permanently while a core is running, or in
+    *   a manner that does not suggest user attention or action
+    *   is required. 'Status' type messages should therefore be
+    *   displayed in a different on-screen location and in a manner
+    *   easily distinguishable from both standard frontend-generated
+    *   notifications and messages of type RETRO_MESSAGE_TYPE_NOTIFICATION_ALT
+    * > RETRO_MESSAGE_TYPE_PROGRESS: Indicates that message reports
+    *   the progress of an internal core task. For example, in cases
+    *   where a core itself handles the loading of content from a file,
+    *   this may correspond to the percentage of the file that has been
+    *   read. Alternatively, an audio/video playback core may use a
+    *   message of type RETRO_MESSAGE_TYPE_PROGRESS to display the current
+    *   playback position as a percentage of the runtime. 'Progress' type
+    *   messages should therefore be displayed as a literal progress bar,
+    *   where:
+    *   - 'retro_message_ext.msg' is the progress bar title/label
+    *   - 'retro_message_ext.progress' determines the length of
+    *     the progress bar
+    * NOTE: Message type is a *hint*, and may be ignored
+    * by the frontend. If a frontend lacks support for
+    * displaying messages via alternate means than standard
+    * frontend-generated notifications, it will treat *all*
+    * messages as having the type RETRO_MESSAGE_TYPE_NOTIFICATION */
+   enum retro_message_type type;
+   /* Task progress when targeting the OSD and message is
+    * of type RETRO_MESSAGE_TYPE_PROGRESS
+    * > -1:    Unmetered/indeterminate
+    * > 0-100: Current progress percentage
+    * NOTE: Since message type is a hint, a frontend may ignore
+    * progress values. Where relevant, a core should therefore
+    * include progress percentage within the message string,
+    * such that the message intent remains clear when displayed
+    * as a standard frontend-generated notification */
+   int8_t progress;
+};
+
+/* Describes how the libretro implementation maps a libretro input bind
+ * to its internal input system through a human readable string.
+ * This string can be used to better let a user configure input. */
+struct retro_input_descriptor
+{
+   /* Associates given parameters with a description. */
+   unsigned port;
+   unsigned device;
+   unsigned index;
+   unsigned id;
+
+   /* Human readable description for parameters.
+    * The pointer must remain valid until
+    * retro_unload_game() is called. */
+   const char *description;
+};
+
+struct retro_system_info
+{
+   /* All pointers are owned by libretro implementation, and pointers must
+    * remain valid until it is unloaded. */
+
+   const char *library_name;      /* Descriptive name of library. Should not
+                                   * contain any version numbers, etc. */
+   const char *library_version;   /* Descriptive version of core. */
+
+   const char *valid_extensions;  /* A string listing probably content
+                                   * extensions the core will be able to
+                                   * load, separated with pipe.
+                                   * I.e. "bin|rom|iso".
+                                   * Typically used for a GUI to filter
+                                   * out extensions. */
+
+   /* Libretro cores that need to have direct access to their content
+    * files, including cores which use the path of the content files to
+    * determine the paths of other files, should set need_fullpath to true.
+    *
+    * Cores should strive for setting need_fullpath to false,
+    * as it allows the frontend to perform patching, etc.
+    *
+    * If need_fullpath is true and retro_load_game() is called:
+    *    - retro_game_info::path is guaranteed to have a valid path
+    *    - retro_game_info::data and retro_game_info::size are invalid
+    *
+    * If need_fullpath is false and retro_load_game() is called:
+    *    - retro_game_info::path may be NULL
+    *    - retro_game_info::data and retro_game_info::size are guaranteed
+    *      to be valid
+    *
+    * See also:
+    *    - RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY
+    *    - RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY
+    */
+   bool        need_fullpath;
+
+   /* If true, the frontend is not allowed to extract any archives before
+    * loading the real content.
+    * Necessary for certain libretro implementations that load games
+    * from zipped archives. */
+   bool        block_extract;
+};
+
+struct retro_game_geometry
+{
+   unsigned base_width;    /* Nominal video width of game. */
+   unsigned base_height;   /* Nominal video height of game. */
+   unsigned max_width;     /* Maximum possible width of game. */
+   unsigned max_height;    /* Maximum possible height of game. */
+
+   float    aspect_ratio;  /* Nominal aspect ratio of game. If
+                            * aspect_ratio is <= 0.0, an aspect ratio
+                            * of base_width / base_height is assumed.
+                            * A frontend could override this setting,
+                            * if desired. */
+};
+
+struct retro_system_timing
+{
+   double fps;             /* FPS of video content. */
+   double sample_rate;     /* Sampling rate of audio. */
+};
+
+struct retro_system_av_info
+{
+   struct retro_game_geometry geometry;
+   struct retro_system_timing timing;
+};
+
+struct retro_variable
+{
+   /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE.
+    * If NULL, obtains the complete environment string if more
+    * complex parsing is necessary.
+    * The environment string is formatted as key-value pairs
+    * delimited by semicolons as so:
+    * "key1=value1;key2=value2;..."
+    */
+   const char *key;
+
+   /* Value to be obtained. If key does not exist, it is set to NULL. */
+   const char *value;
+};
+
+struct retro_core_option_display
+{
+   /* Variable to configure in RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY */
+   const char *key;
+
+   /* Specifies whether variable should be displayed
+    * when presenting core options to the user */
+   bool visible;
+};
+
+/* Maximum number of values permitted for a core option
+ * > Note: We have to set a maximum value due the limitations
+ *   of the C language - i.e. it is not possible to create an
+ *   array of structs each containing a variable sized array,
+ *   so the retro_core_option_definition values array must
+ *   have a fixed size. The size limit of 128 is a balancing
+ *   act - it needs to be large enough to support all 'sane'
+ *   core options, but setting it too large may impact low memory
+ *   platforms. In practise, if a core option has more than
+ *   128 values then the implementation is likely flawed.
+ *   To quote the above API reference:
+ *      "The number of possible options should be very limited
+ *       i.e. it should be feasible to cycle through options
+ *       without a keyboard."
+ */
+#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128
+
+struct retro_core_option_value
+{
+   /* Expected option value */
+   const char *value;
+
+   /* Human-readable value label. If NULL, value itself
+    * will be displayed by the frontend */
+   const char *label;
+};
+
+struct retro_core_option_definition
+{
+   /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE. */
+   const char *key;
+
+   /* Human-readable core option description (used as menu label) */
+   const char *desc;
+
+   /* Human-readable core option information (used as menu sublabel) */
+   const char *info;
+
+   /* Array of retro_core_option_value structs, terminated by NULL */
+   struct retro_core_option_value values[RETRO_NUM_CORE_OPTION_VALUES_MAX];
+
+   /* Default core option value. Must match one of the values
+    * in the retro_core_option_value array, otherwise will be
+    * ignored */
+   const char *default_value;
+};
+
+struct retro_core_options_intl
+{
+   /* Pointer to an array of retro_core_option_definition structs
+    * - US English implementation
+    * - Must point to a valid array */
+   struct retro_core_option_definition *us;
+
+   /* Pointer to an array of retro_core_option_definition structs
+    * - Implementation for current frontend language
+    * - May be NULL */
+   struct retro_core_option_definition *local;
+};
+
+struct retro_game_info
+{
+   const char *path;       /* Path to game, UTF-8 encoded.
+                            * Sometimes used as a reference for building other paths.
+                            * May be NULL if game was loaded from stdin or similar,
+                            * but in this case some cores will be unable to load `data`.
+                            * So, it is preferable to fabricate something here instead
+                            * of passing NULL, which will help more cores to succeed.
+                            * retro_system_info::need_fullpath requires
+                            * that this path is valid. */
+   const void *data;       /* Memory buffer of loaded game. Will be NULL
+                            * if need_fullpath was set. */
+   size_t      size;       /* Size of memory buffer. */
+   const char *meta;       /* String of implementation specific meta-data. */
+};
+
+#define RETRO_MEMORY_ACCESS_WRITE (1 << 0)
+   /* The core will write to the buffer provided by retro_framebuffer::data. */
+#define RETRO_MEMORY_ACCESS_READ (1 << 1)
+   /* The core will read from retro_framebuffer::data. */
+#define RETRO_MEMORY_TYPE_CACHED (1 << 0)
+   /* The memory in data is cached.
+    * If not cached, random writes and/or reading from the buffer is expected to be very slow. */
+struct retro_framebuffer
+{
+   void *data;                      /* The framebuffer which the core can render into.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER.
+                                       The initial contents of data are unspecified. */
+   unsigned width;                  /* The framebuffer width used by the core. Set by core. */
+   unsigned height;                 /* The framebuffer height used by the core. Set by core. */
+   size_t pitch;                    /* The number of bytes between the beginning of a scanline,
+                                       and beginning of the next scanline.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
+   enum retro_pixel_format format;  /* The pixel format the core must use to render into data.
+                                       This format could differ from the format used in
+                                       SET_PIXEL_FORMAT.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
+
+   unsigned access_flags;           /* How the core will access the memory in the framebuffer.
+                                       RETRO_MEMORY_ACCESS_* flags.
+                                       Set by core. */
+   unsigned memory_flags;           /* Flags telling core how the memory has been mapped.
+                                       RETRO_MEMORY_TYPE_* flags.
+                                       Set by frontend in GET_CURRENT_SOFTWARE_FRAMEBUFFER. */
+};
+
+/* Callbacks */
+
+/* Environment callback. Gives implementations a way of performing
+ * uncommon tasks. Extensible. */
+typedef bool (RETRO_CALLCONV *retro_environment_t)(unsigned cmd, void *data);
+
+/* Render a frame. Pixel format is 15-bit 0RGB1555 native endian
+ * unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT).
+ *
+ * Width and height specify dimensions of buffer.
+ * Pitch specifices length in bytes between two lines in buffer.
+ *
+ * For performance reasons, it is highly recommended to have a frame
+ * that is packed in memory, i.e. pitch == width * byte_per_pixel.
+ * Certain graphic APIs, such as OpenGL ES, do not like textures
+ * that are not packed in memory.
+ */
+typedef void (RETRO_CALLCONV *retro_video_refresh_t)(const void *data, unsigned width,
+      unsigned height, size_t pitch);
+
+/* Renders a single audio frame. Should only be used if implementation
+ * generates a single sample at a time.
+ * Format is signed 16-bit native endian.
+ */
+typedef void (RETRO_CALLCONV *retro_audio_sample_t)(int16_t left, int16_t right);
+
+/* Renders multiple audio frames in one go.
+ *
+ * One frame is defined as a sample of left and right channels, interleaved.
+ * I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames.
+ * Only one of the audio callbacks must ever be used.
+ */
+typedef size_t (RETRO_CALLCONV *retro_audio_sample_batch_t)(const int16_t *data,
+      size_t frames);
+
+/* Polls input. */
+typedef void (RETRO_CALLCONV *retro_input_poll_t)(void);
+
+/* Queries for input for player 'port'. device will be masked with
+ * RETRO_DEVICE_MASK.
+ *
+ * Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that
+ * have been set with retro_set_controller_port_device()
+ * will still use the higher level RETRO_DEVICE_JOYPAD to request input.
+ */
+typedef int16_t (RETRO_CALLCONV *retro_input_state_t)(unsigned port, unsigned device,
+      unsigned index, unsigned id);
+
+/* Sets callbacks. retro_set_environment() is guaranteed to be called
+ * before retro_init().
+ *
+ * The rest of the set_* functions are guaranteed to have been called
+ * before the first call to retro_run() is made. */
+RETRO_API void retro_set_environment(retro_environment_t);
+RETRO_API void retro_set_video_refresh(retro_video_refresh_t);
+RETRO_API void retro_set_audio_sample(retro_audio_sample_t);
+RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t);
+RETRO_API void retro_set_input_poll(retro_input_poll_t);
+RETRO_API void retro_set_input_state(retro_input_state_t);
+
+/* Library global initialization/deinitialization. */
+RETRO_API void retro_init(void);
+RETRO_API void retro_deinit(void);
+
+/* Must return RETRO_API_VERSION. Used to validate ABI compatibility
+ * when the API is revised. */
+RETRO_API unsigned retro_api_version(void);
+
+/* Gets statically known system info. Pointers provided in *info
+ * must be statically allocated.
+ * Can be called at any time, even before retro_init(). */
+RETRO_API void retro_get_system_info(struct retro_system_info *info);
+
+/* Gets information about system audio/video timings and geometry.
+ * Can be called only after retro_load_game() has successfully completed.
+ * NOTE: The implementation of this function might not initialize every
+ * variable if needed.
+ * E.g. geom.aspect_ratio might not be initialized if core doesn't
+ * desire a particular aspect ratio. */
+RETRO_API void retro_get_system_av_info(struct retro_system_av_info *info);
+
+/* Sets device to be used for player 'port'.
+ * By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all
+ * available ports.
+ * Setting a particular device type is not a guarantee that libretro cores
+ * will only poll input based on that particular device type. It is only a
+ * hint to the libretro core when a core cannot automatically detect the
+ * appropriate input device type on its own. It is also relevant when a
+ * core can change its behavior depending on device type.
+ *
+ * As part of the core's implementation of retro_set_controller_port_device,
+ * the core should call RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS to notify the
+ * frontend if the descriptions for any controls have changed as a
+ * result of changing the device type.
+ */
+RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device);
+
+/* Resets the current game. */
+RETRO_API void retro_reset(void);
+
+/* Runs the game for one video frame.
+ * During retro_run(), input_poll callback must be called at least once.
+ *
+ * If a frame is not rendered for reasons where a game "dropped" a frame,
+ * this still counts as a frame, and retro_run() should explicitly dupe
+ * a frame if GET_CAN_DUPE returns true.
+ * In this case, the video callback can take a NULL argument for data.
+ */
+RETRO_API void retro_run(void);
+
+/* Returns the amount of data the implementation requires to serialize
+ * internal state (save states).
+ * Between calls to retro_load_game() and retro_unload_game(), the
+ * returned size is never allowed to be larger than a previous returned
+ * value, to ensure that the frontend can allocate a save state buffer once.
+ */
+RETRO_API size_t retro_serialize_size(void);
+
+/* Serializes internal state. If failed, or size is lower than
+ * retro_serialize_size(), it should return false, true otherwise. */
+RETRO_API bool retro_serialize(void *data, size_t size);
+RETRO_API bool retro_unserialize(const void *data, size_t size);
+
+RETRO_API void retro_cheat_reset(void);
+RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code);
+
+/* Loads a game.
+ * Return true to indicate successful loading and false to indicate load failure.
+ */
+RETRO_API bool retro_load_game(const struct retro_game_info *game);
+
+/* Loads a "special" kind of game. Should not be used,
+ * except in extreme cases. */
+RETRO_API bool retro_load_game_special(
+  unsigned game_type,
+  const struct retro_game_info *info, size_t num_info
+);
+
+/* Unloads the currently loaded game. Called before retro_deinit(void). */
+RETRO_API void retro_unload_game(void);
+
+/* Gets region of game. */
+RETRO_API unsigned retro_get_region(void);
+
+/* Gets region of memory. */
+RETRO_API void *retro_get_memory_data(unsigned id);
+RETRO_API size_t retro_get_memory_size(unsigned id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libretro-common/include/memmap.h b/libretro-common/include/memmap.h
new file mode 100644 (file)
index 0000000..75a85f3
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (memmap.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _LIBRETRO_MEMMAP_H
+#define _LIBRETRO_MEMMAP_H
+
+#include <stdio.h>
+#include <stdint.h>
+
+#if defined(__CELLOS_LV2__) || defined(PSP) || defined(PS2) || defined(GEKKO) || defined(VITA) || defined(_XBOX) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(HAVE_LIBNX)
+/* No mman available */
+#elif defined(_WIN32) && !defined(_XBOX)
+#include <windows.h>
+#include <errno.h>
+#include <io.h>
+#else
+#define HAVE_MMAN
+#include <sys/mman.h>
+#endif
+
+#if !defined(HAVE_MMAN) || defined(_WIN32)
+void* mmap(void *addr, size_t len, int mmap_prot, int mmap_flags, int fildes, size_t off);
+
+int munmap(void *addr, size_t len);
+
+int mprotect(void *addr, size_t len, int prot);
+#endif
+
+int memsync(void *start, void *end);
+
+int memprotect(void *addr, size_t len);
+
+#endif
diff --git a/libretro-common/include/retro_assert.h b/libretro-common/include/retro_assert.h
new file mode 100644 (file)
index 0000000..090e9f1
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_assert.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __RETRO_ASSERT_H
+#define __RETRO_ASSERT_H
+
+#include <assert.h>
+
+#ifdef RARCH_INTERNAL
+#include <stdio.h>
+#define retro_assert(cond) do { \
+   if (!(cond)) { printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__); abort(); } \
+} while(0)
+#else
+#define retro_assert(cond) assert(cond)
+#endif
+
+#endif
diff --git a/libretro-common/include/retro_common_api.h b/libretro-common/include/retro_common_api.h
new file mode 100644 (file)
index 0000000..0f68b7d
--- /dev/null
@@ -0,0 +1,119 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_common_api.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H
+#define _LIBRETRO_COMMON_RETRO_COMMON_API_H
+
+/*
+This file is designed to normalize the libretro-common compiling environment
+for public API headers. This should be leaner than a normal compiling environment,
+since it gets #included into other project's sources.
+*/
+
+/* ------------------------------------ */
+
+/*
+Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
+headers to enable them to get used by c++ sources.
+However, we want to support building this library as C++ as well, so a
+special technique is called for.
+*/
+
+#define RETRO_BEGIN_DECLS
+#define RETRO_END_DECLS
+
+#ifdef __cplusplus
+
+#ifdef CXX_BUILD
+/* build wants everything to be built as c++, so no extern "C" */
+#else
+#undef RETRO_BEGIN_DECLS
+#undef RETRO_END_DECLS
+#define RETRO_BEGIN_DECLS extern "C" {
+#define RETRO_END_DECLS }
+#endif
+
+#else
+
+/* header is included by a C source file, so no extern "C" */
+
+#endif
+
+/*
+IMO, this non-standard ssize_t should not be used.
+However, it's a good example of how to handle something like this.
+*/
+#ifdef _MSC_VER
+#ifndef HAVE_SSIZE_T
+#define HAVE_SSIZE_T
+#if defined(_WIN64)
+typedef __int64 ssize_t;
+#elif defined(_WIN32)
+typedef int ssize_t;
+#endif
+#endif
+#elif defined(__MACH__)
+#include <sys/types.h>
+#endif
+
+#ifdef _MSC_VER
+#if _MSC_VER >= 1800
+#include <inttypes.h>
+#else
+#ifndef PRId64
+#define PRId64 "I64d"
+#define PRIu64 "I64u"
+#define PRIuPTR "Iu"
+#endif
+#endif
+#else
+/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
+/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
+/* https://github.com/libretro/RetroArch/issues/6009 */
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS 1
+#endif
+#include <inttypes.h>
+#endif
+#ifndef PRId64
+#error "inttypes.h is being screwy"
+#endif
+#define STRING_REP_INT64 "%" PRId64
+#define STRING_REP_UINT64 "%" PRIu64
+#define STRING_REP_USIZE "%" PRIuPTR
+
+/*
+I would like to see retro_inline.h moved in here; possibly boolean too.
+
+rationale: these are used in public APIs, and it is easier to find problems
+and write code that works the first time portably when theyre included uniformly
+than to do the analysis from scratch each time you think you need it, for each feature.
+
+Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
+then you should pay the price everywhere, so you can see how much grief it will cause.
+
+Of course, another school of thought is that you should do as little damage as possible
+in as few places as possible...
+*/
+
+/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
+#endif
diff --git a/libretro-common/include/retro_environment.h b/libretro-common/include/retro_environment.h
new file mode 100644 (file)
index 0000000..1389eb5
--- /dev/null
@@ -0,0 +1,114 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_environment.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_ENVIRONMENT_H
+#define __LIBRETRO_SDK_ENVIRONMENT_H
+
+/*
+This file is designed to create a normalized environment for compiling
+libretro-common's private implementations, or any other sources which might
+enjoy use of it's environment (RetroArch for instance).
+This should be an elaborately crafted environment so that sources don't
+need to be full of platform-specific workarounds.
+*/
+
+#if defined (__cplusplus)
+#if 0
+printf("This is C++, version %d.\n", __cplusplus);
+#endif
+/* The expected values would be
+ *   199711L, for ISO/IEC 14882:1998 or 14882:2003
+ */
+
+#elif defined(__STDC__)
+/* This is standard C. */
+
+#if (__STDC__ == 1)
+/* The implementation is ISO-conforming. */
+#define __STDC_ISO__
+#else
+/* The implementation is not ISO-conforming. */
+#endif
+
+#if defined(__STDC_VERSION__)
+#if (__STDC_VERSION__ >= 201112L)
+/* This is C11. */
+#define __STDC_C11__
+#elif (__STDC_VERSION__ >= 199901L)
+/* This is C99. */
+#define __STDC_C99__
+#elif (__STDC_VERSION__ >= 199409L)
+/* This is C89 with amendment 1. */
+#define __STDC_C89__
+#define __STDC_C89_AMENDMENT_1__
+#else
+/* This is C89 without amendment 1. */
+#define __STDC_C89__
+#endif
+#else /* !defined(__STDC_VERSION__) */
+/* This is C89. __STDC_VERSION__ is not defined. */
+#define __STDC_C89__
+#endif
+
+#else   /* !defined(__STDC__) */
+/* This is not standard C. __STDC__ is not defined. */
+#endif
+
+#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
+/* Try to find out if we're compiling for WinRT or non-WinRT */
+#if defined(_MSC_VER) && defined(__has_include)
+#if __has_include(<winapifamily.h>)
+#define HAVE_WINAPIFAMILY_H 1
+#else
+#define HAVE_WINAPIFAMILY_H 0
+#endif
+
+/* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
+#elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_)    /* _MSC_VER == 1700 for Visual Studio 2012 */
+#define HAVE_WINAPIFAMILY_H 1
+#else
+#define HAVE_WINAPIFAMILY_H 0
+#endif
+
+#if HAVE_WINAPIFAMILY_H
+#include <winapifamily.h>
+#define WINAPI_FAMILY_WINRT (!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP))
+#else
+#define WINAPI_FAMILY_WINRT 0
+#endif /* HAVE_WINAPIFAMILY_H */
+
+#if WINAPI_FAMILY_WINRT
+#undef __WINRT__
+#define __WINRT__ 1
+#endif
+
+/* MSVC obviously has to have some non-standard constants... */
+#if _M_IX86_FP == 1
+#define __SSE__ 1
+#elif _M_IX86_FP == 2 || (defined(_M_AMD64) || defined(_M_X64))
+#define __SSE__ 1
+#define __SSE2__ 1
+#endif
+
+#endif
+
+#endif
diff --git a/libretro-common/include/retro_inline.h b/libretro-common/include/retro_inline.h
new file mode 100644 (file)
index 0000000..b27d6dd
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_inline.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_INLINE_H
+#define __LIBRETRO_SDK_INLINE_H
+
+#ifndef INLINE
+
+#if defined(_WIN32) || defined(__INTEL_COMPILER)
+#define INLINE __inline
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
+#define INLINE inline
+#elif defined(__GNUC__)
+#define INLINE __inline__
+#else
+#define INLINE
+#endif
+
+#endif
+#endif
diff --git a/libretro-common/include/retro_miscellaneous.h b/libretro-common/include/retro_miscellaneous.h
new file mode 100644 (file)
index 0000000..1936ac7
--- /dev/null
@@ -0,0 +1,186 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (retro_miscellaneous.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __RARCH_MISCELLANEOUS_H
+#define __RARCH_MISCELLANEOUS_H
+
+#define RARCH_MAX_SUBSYSTEMS 10
+#define RARCH_MAX_SUBSYSTEM_ROMS 10
+
+#include <stdint.h>
+#include <boolean.h>
+#include <retro_inline.h>
+
+#if defined(_WIN32)
+
+#if defined(_XBOX)
+#include <Xtl.h>
+#else
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#endif
+
+#endif
+
+#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+#include <sys/fs_external.h>
+#endif
+
+#include <limits.h>
+
+#ifdef _MSC_VER
+#include <compat/msvc.h>
+#endif
+
+static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
+{
+   uint32_t i;
+   for (i = 0; i < count;i++)
+      a[i] |= b[i];
+}
+
+static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
+{
+   uint32_t i;
+   for (i = 0; i < count;i++)
+      a[i] &= ~b[i];
+}
+
+static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
+{
+   uint32_t i;
+   for (i = 0; i < count; i++)
+   {
+      if (ptr[i] != 0)
+         return true;
+   }
+   return false;
+}
+
+#ifndef PATH_MAX_LENGTH
+#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
+#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
+#define PATH_MAX_LENGTH 512
+#else
+#define PATH_MAX_LENGTH 4096
+#endif
+#endif
+
+#ifndef MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define ARRAY_SIZE(a)              (sizeof(a) / sizeof((a)[0]))
+
+#define BITS_GET_ELEM(a, i)        ((a).data[i])
+#define BITS_GET_ELEM_PTR(a, i)    ((a)->data[i])
+
+#define BIT_SET(a, bit)   ((a)[(bit) >> 3] |=  (1 << ((bit) & 7)))
+#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))
+#define BIT_GET(a, bit)   (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)
+
+#define BIT16_SET(a, bit)    ((a) |=  (1 << ((bit) & 15)))
+#define BIT16_CLEAR(a, bit)  ((a) &= ~(1 << ((bit) & 15)))
+#define BIT16_GET(a, bit)    (((a) >> ((bit) & 15)) & 1)
+#define BIT16_CLEAR_ALL(a)   ((a) = 0)
+
+#define BIT32_SET(a, bit)    ((a) |=  (UINT32_C(1) << ((bit) & 31)))
+#define BIT32_CLEAR(a, bit)  ((a) &= ~(UINT32_C(1) << ((bit) & 31)))
+#define BIT32_GET(a, bit)    (((a) >> ((bit) & 31)) & 1)
+#define BIT32_CLEAR_ALL(a)   ((a) = 0)
+
+#define BIT64_SET(a, bit)    ((a) |=  (UINT64_C(1) << ((bit) & 63)))
+#define BIT64_CLEAR(a, bit)  ((a) &= ~(UINT64_C(1) << ((bit) & 63)))
+#define BIT64_GET(a, bit)    (((a) >> ((bit) & 63)) & 1)
+#define BIT64_CLEAR_ALL(a)   ((a) = 0)
+
+#define BIT128_SET(a, bit)   ((a).data[(bit) >> 5] |=  (UINT32_C(1) << ((bit) & 31)))
+#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(UINT32_C(1) << ((bit) & 31)))
+#define BIT128_GET(a, bit)   (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
+#define BIT128_CLEAR_ALL(a)  memset(&(a), 0, sizeof(a))
+
+#define BIT128_SET_PTR(a, bit)   BIT128_SET(*a, bit)
+#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
+#define BIT128_GET_PTR(a, bit)   BIT128_GET(*a, bit)
+#define BIT128_CLEAR_ALL_PTR(a)  BIT128_CLEAR_ALL(*a)
+
+#define BIT256_SET(a, bit)       BIT128_SET(a, bit)
+#define BIT256_CLEAR(a, bit)     BIT128_CLEAR(a, bit)
+#define BIT256_GET(a, bit)       BIT128_GET(a, bit)
+#define BIT256_CLEAR_ALL(a)      BIT128_CLEAR_ALL(a)
+
+#define BIT256_SET_PTR(a, bit)   BIT256_SET(*a, bit)
+#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)
+#define BIT256_GET_PTR(a, bit)   BIT256_GET(*a, bit)
+#define BIT256_CLEAR_ALL_PTR(a)  BIT256_CLEAR_ALL(*a)
+
+#define BITS_COPY16_PTR(a,bits) \
+{ \
+   BIT128_CLEAR_ALL_PTR(a); \
+   BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \
+}
+
+#define BITS_COPY32_PTR(a,bits) \
+{ \
+   BIT128_CLEAR_ALL_PTR(a); \
+   BITS_GET_ELEM_PTR(a, 0) = (bits); \
+}
+
+/* Helper macros and struct to keep track of many booleans. */
+/* This struct has 256 bits. */
+typedef struct
+{
+   uint32_t data[8];
+} retro_bits_t;
+
+#ifdef _WIN32
+#  ifdef _WIN64
+#    define PRI_SIZET PRIu64
+#  else
+#    if _MSC_VER == 1800
+#      define PRI_SIZET PRIu32
+#    else
+#      define PRI_SIZET "u"
+#    endif
+#  endif
+#elif defined(PS2)
+#  define PRI_SIZET "u"
+#else
+#  if (SIZE_MAX == 0xFFFF)
+#    define PRI_SIZET "hu"
+#  elif (SIZE_MAX == 0xFFFFFFFF)
+#    define PRI_SIZET "u"
+#  elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
+#    define PRI_SIZET "lu"
+#  else
+#    error PRI_SIZET: unknown SIZE_MAX
+#  endif
+#endif
+
+#endif
diff --git a/libretro-common/include/streams/file_stream.h b/libretro-common/include/streams/file_stream.h
new file mode 100644 (file)
index 0000000..ab198b2
--- /dev/null
@@ -0,0 +1,115 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_stream.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_FILE_STREAM_H
+#define __LIBRETRO_SDK_FILE_STREAM_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#include <sys/types.h>
+
+#include <libretro.h>
+#include <retro_common_api.h>
+#include <retro_inline.h>
+#include <boolean.h>
+
+#include <stdarg.h>
+#include <vfs/vfs_implementation.h>
+
+#define FILESTREAM_REQUIRED_VFS_VERSION 2
+
+RETRO_BEGIN_DECLS
+
+typedef struct RFILE RFILE;
+
+#define FILESTREAM_REQUIRED_VFS_VERSION 2
+
+void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
+
+int64_t filestream_get_size(RFILE *stream);
+
+int64_t filestream_truncate(RFILE *stream, int64_t length);
+
+/**
+ * filestream_open:
+ * @path               : path to file
+ * @mode               : file mode to use when opening (read/write)
+ * @bufsize            : optional buffer size (-1 or 0 to use default)
+ *
+ * Opens a file for reading or writing, depending on the requested mode.
+ * Returns a pointer to an RFILE if opened successfully, otherwise NULL.
+ **/
+RFILE* filestream_open(const char *path, unsigned mode, unsigned hints);
+
+int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);
+
+int64_t filestream_read(RFILE *stream, void *data, int64_t len);
+
+int64_t filestream_write(RFILE *stream, const void *data, int64_t len);
+
+int64_t filestream_tell(RFILE *stream);
+
+void filestream_rewind(RFILE *stream);
+
+int filestream_close(RFILE *stream);
+
+int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
+
+char* filestream_gets(RFILE *stream, char *s, size_t len);
+
+int filestream_getc(RFILE *stream);
+
+int filestream_scanf(RFILE *stream, const char* format, ...);
+
+int filestream_eof(RFILE *stream);
+
+bool filestream_write_file(const char *path, const void *data, int64_t size);
+
+int filestream_putc(RFILE *stream, int c);
+
+int filestream_vprintf(RFILE *stream, const char* format, va_list args);
+
+int filestream_printf(RFILE *stream, const char* format, ...);
+
+int filestream_error(RFILE *stream);
+
+int filestream_flush(RFILE *stream);
+
+int filestream_delete(const char *path);
+
+int filestream_rename(const char *old_path, const char *new_path);
+
+const char* filestream_get_path(RFILE *stream);
+
+bool filestream_exists(const char *path);
+
+/* Returned pointer must be freed by the caller. */
+char* filestream_getline(RFILE *stream);
+
+libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/include/streams/file_stream_transforms.h b/libretro-common/include/streams/file_stream_transforms.h
new file mode 100644 (file)
index 0000000..327e218
--- /dev/null
@@ -0,0 +1,101 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (file_stream_transforms.h).
+* ---------------------------------------------------------------------------------------
+*
+* Permission is hereby granted, free of charge,
+* to any person obtaining a copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation the rights to
+* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H
+#define __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H
+
+#include <stdint.h>
+#include <string.h>
+#include <retro_common_api.h>
+#include <streams/file_stream.h>
+
+RETRO_BEGIN_DECLS
+
+#ifndef SKIP_STDIO_REDEFINES
+
+#define FILE RFILE
+
+#undef fopen
+#undef fclose
+#undef ftell
+#undef fseek
+#undef fread
+#undef fgets
+#undef fgetc
+#undef fwrite
+#undef fputc
+#undef fflush
+#undef fprintf
+#undef ferror
+#undef feof
+#undef fscanf
+
+#define fopen rfopen
+#define fclose rfclose
+#define ftell rftell
+#define fseek rfseek
+#define fread rfread
+#define fgets rfgets
+#define fgetc rfgetc
+#define fwrite rfwrite
+#define fputc rfputc
+#define fflush rfflush
+#define fprintf rfprintf
+#define ferror rferror
+#define feof rfeof
+#define fscanf rfscanf
+
+#endif
+
+RFILE* rfopen(const char *path, const char *mode);
+
+int rfclose(RFILE* stream);
+
+int64_t rftell(RFILE* stream);
+
+int64_t rfseek(RFILE* stream, int64_t offset, int origin);
+
+int64_t rfread(void* buffer,
+   size_t elem_size, size_t elem_count, RFILE* stream);
+
+char *rfgets(char *buffer, int maxCount, RFILE* stream);
+
+int rfgetc(RFILE* stream);
+
+int64_t rfwrite(void const* buffer,
+   size_t elem_size, size_t elem_count, RFILE* stream);
+
+int rfputc(int character, RFILE * stream);
+
+int64_t rfflush(RFILE * stream);
+
+int rfprintf(RFILE * stream, const char * format, ...);
+
+int rferror(RFILE* stream);
+
+int rfeof(RFILE* stream);
+
+int rfscanf(RFILE * stream, const char * format, ...);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/include/string/stdstring.h b/libretro-common/include/string/stdstring.h
new file mode 100644 (file)
index 0000000..5d8c31b
--- /dev/null
@@ -0,0 +1,198 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (stdstring.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_STDSTRING_H
+#define __LIBRETRO_SDK_STDSTRING_H
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <ctype.h>
+#include <string.h>
+#include <boolean.h>
+
+#include <retro_common_api.h>
+#include <retro_inline.h>
+#include <compat/strl.h>
+
+RETRO_BEGIN_DECLS
+
+#define STRLEN_CONST(x)                   ((sizeof((x))-1))
+
+#define strcpy_literal(a, b)              strcpy(a, b)
+
+#define string_is_not_equal(a, b)         !string_is_equal((a), (b))
+
+#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
+#define string_is_equal_fast(a, b, size)     (memcmp(a, b, size) == 0)
+
+#define TOLOWER(c)   (c |  (lr_char_props[c] & 0x20))
+#define TOUPPER(c)   (c & ~(lr_char_props[c] & 0x20))
+
+/* C standard says \f \v are space, but this one disagrees */
+#define ISSPACE(c)   (lr_char_props[c]  & 0x80) 
+
+#define ISDIGIT(c)   (lr_char_props[c]  & 0x40)
+#define ISALPHA(c)   (lr_char_props[c]  & 0x20)
+#define ISLOWER(c)   (lr_char_props[c]  & 0x04)
+#define ISUPPER(c)   (lr_char_props[c]  & 0x02)
+#define ISALNUM(c)   (lr_char_props[c]  & 0x60)
+#define ISUALPHA(c)  (lr_char_props[c]  & 0x28)
+#define ISUALNUM(c)  (lr_char_props[c]  & 0x68)
+#define IS_XDIGIT(c) (lr_char_props[c]  & 0x01)
+
+/* Deprecated alias, all callers should use string_is_equal_case_insensitive instead */
+#define string_is_equal_noncase string_is_equal_case_insensitive
+
+static INLINE bool string_is_empty(const char *data)
+{
+   return !data || (*data == '\0');
+}
+
+static INLINE bool string_is_equal(const char *a, const char *b)
+{
+   return (a && b) ? !strcmp(a, b) : false;
+}
+
+static INLINE bool string_starts_with_size(const char *str, const char *prefix,
+      size_t size)
+{
+   return (str && prefix) ? !strncmp(prefix, str, size) : false;
+}
+
+static INLINE bool string_starts_with(const char *str, const char *prefix)
+{
+   return (str && prefix) ? !strncmp(prefix, str, strlen(prefix)) : false;
+}
+
+static INLINE bool string_ends_with_size(const char *str, const char *suffix,
+      size_t str_len, size_t suffix_len)
+{
+   return (str_len < suffix_len) ? false :
+         !memcmp(suffix, str + (str_len - suffix_len), suffix_len);
+}
+
+static INLINE bool string_ends_with(const char *str, const char *suffix)
+{
+   if (!str || !suffix)
+      return false;
+   return string_ends_with_size(str, suffix, strlen(str), strlen(suffix));
+}
+
+/* Returns the length of 'str' (c.f. strlen()), but only
+ * checks the first 'size' characters
+ * - If 'str' is NULL, returns 0
+ * - If 'str' is not NULL and no '\0' character is found
+ *   in the first 'size' characters, returns 'size' */
+static INLINE size_t strlen_size(const char *str, size_t size)
+{
+   size_t i = 0;
+   if (str)
+      while (i < size && str[i]) i++;
+   return i;
+}
+
+
+static INLINE bool string_is_equal_case_insensitive(const char *a,
+      const char *b)
+{
+   int result              = 0;
+   const unsigned char *p1 = (const unsigned char*)a;
+   const unsigned char *p2 = (const unsigned char*)b;
+
+   if (!a || !b)
+      return false;
+   if (p1 == p2)
+      return true;
+
+   while ((result = tolower (*p1) - tolower (*p2++)) == 0)
+      if (*p1++ == '\0')
+         break;
+
+   return (result == 0);
+}
+
+char *string_to_upper(char *s);
+
+char *string_to_lower(char *s);
+
+char *string_ucwords(char *s);
+
+char *string_replace_substring(const char *in, const char *pattern,
+      const char *by);
+
+/* Remove leading whitespaces */
+char *string_trim_whitespace_left(char *const s);
+
+/* Remove trailing whitespaces */
+char *string_trim_whitespace_right(char *const s);
+
+/* Remove leading and trailing whitespaces */
+char *string_trim_whitespace(char *const s);
+
+/* max_lines == 0 means no limit */
+char *word_wrap(char *buffer, const char *string,
+      int line_width, bool unicode, unsigned max_lines);
+
+/* Splits string into tokens seperated by 'delim'
+ * > Returned token string must be free()'d
+ * > Returns NULL if token is not found
+ * > After each call, 'str' is set to the position after the
+ *   last found token
+ * > Tokens *include* empty strings
+ * Usage example:
+ *    char *str      = "1,2,3,4,5,6,7,,,10,";
+ *    char **str_ptr = &str;
+ *    char *token    = NULL;
+ *    while ((token = string_tokenize(str_ptr, ",")))
+ *    {
+ *        printf("%s\n", token);
+ *        free(token);
+ *        token = NULL;
+ *    }
+ */
+char* string_tokenize(char **str, const char *delim);
+
+/* Removes every instance of character 'c' from 'str' */
+void string_remove_all_chars(char *str, char c);
+
+/* Replaces every instance of character 'find' in 'str'
+ * with character 'replace' */
+void string_replace_all_chars(char *str, char find, char replace);
+
+/* Converts string to unsigned integer.
+ * Returns 0 if string is invalid  */
+unsigned string_to_unsigned(const char *str);
+
+/* Converts hexadecimal string to unsigned integer.
+ * Handles optional leading '0x'.
+ * Returns 0 if string is invalid  */
+unsigned string_hex_to_unsigned(const char *str);
+
+char *string_init(const char *src);
+
+void string_set(char **string, const char *src);
+
+extern const unsigned char lr_char_props[256];
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/include/time/rtime.h b/libretro-common/include/time/rtime.h
new file mode 100644 (file)
index 0000000..7629c1e
--- /dev/null
@@ -0,0 +1,48 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rtime.h).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LIBRETRO_SDK_RTIME_H__
+#define __LIBRETRO_SDK_RTIME_H__
+
+#include <retro_common_api.h>
+
+#include <stdint.h>
+#include <stddef.h>
+#include <time.h>
+
+RETRO_BEGIN_DECLS
+
+/* TODO/FIXME: Move all generic time handling functions
+ * to this file */
+
+/* Must be called before using rtime_localtime() */
+void rtime_init(void);
+
+/* Must be called upon program termination */
+void rtime_deinit(void);
+
+/* Thread-safe wrapper for localtime() */
+struct tm *rtime_localtime(const time_t *timep, struct tm *result);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/include/vfs/vfs.h b/libretro-common/include/vfs/vfs.h
new file mode 100644 (file)
index 0000000..5366f33
--- /dev/null
@@ -0,0 +1,111 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (vfs_implementation.h).
+* ---------------------------------------------------------------------------------------
+*
+* Permission is hereby granted, free of charge,
+* to any person obtaining a copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation the rights to
+* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef __LIBRETRO_SDK_VFS_H
+#define __LIBRETRO_SDK_VFS_H
+
+#include <retro_common_api.h>
+#include <boolean.h>
+
+#ifdef RARCH_INTERNAL
+#ifndef VFS_FRONTEND
+#define VFS_FRONTEND
+#endif
+#endif
+
+RETRO_BEGIN_DECLS
+
+#ifdef _WIN32
+typedef void* HANDLE;
+#endif
+
+#ifdef HAVE_CDROM
+typedef struct
+{
+   int64_t byte_pos;
+   char *cue_buf;
+   size_t cue_len;
+   unsigned cur_lba;
+   unsigned last_frame_lba;
+   unsigned char cur_min;
+   unsigned char cur_sec;
+   unsigned char cur_frame;
+   unsigned char cur_track;
+   unsigned char last_frame[2352];
+   char drive;
+   bool last_frame_valid;
+} vfs_cdrom_t;
+#endif
+
+enum vfs_scheme
+{
+   VFS_SCHEME_NONE = 0,
+   VFS_SCHEME_CDROM
+};
+
+#ifndef __WINRT__
+#ifdef VFS_FRONTEND
+struct retro_vfs_file_handle
+#else
+struct libretro_vfs_implementation_file
+#endif
+{
+#ifdef HAVE_CDROM
+   vfs_cdrom_t cdrom; /* int64_t alignment */
+#endif
+   int64_t size;
+   uint64_t mappos;
+   uint64_t mapsize;
+   FILE *fp;
+#ifdef _WIN32
+   HANDLE fh;
+#endif
+   char *buf;
+   char* orig_path;
+   uint8_t *mapped;
+   int fd;
+   unsigned hints;
+   enum vfs_scheme scheme;
+};
+#endif
+
+/* Replace the following symbol with something appropriate
+ * to signify the file is being compiled for a front end instead of a core.
+ * This allows the same code to act as reference implementation
+ * for VFS and as fallbacks for when the front end does not provide VFS functionality.
+ */
+
+#ifdef VFS_FRONTEND
+typedef struct retro_vfs_file_handle libretro_vfs_implementation_file;
+#else
+typedef struct libretro_vfs_implementation_file libretro_vfs_implementation_file;
+#endif
+
+#ifdef VFS_FRONTEND
+typedef struct retro_vfs_dir_handle libretro_vfs_implementation_dir;
+#else
+typedef struct libretro_vfs_implementation_dir libretro_vfs_implementation_dir;
+#endif
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/include/vfs/vfs_implementation.h b/libretro-common/include/vfs/vfs_implementation.h
new file mode 100644 (file)
index 0000000..c7d6bb0
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (vfs_implementation.h).
+* ---------------------------------------------------------------------------------------
+*
+* Permission is hereby granted, free of charge,
+* to any person obtaining a copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation the rights to
+* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
+#define __LIBRETRO_SDK_VFS_IMPLEMENTATION_H
+
+#include <stdio.h>
+#include <stdint.h>
+#include <libretro.h>
+#include <retro_environment.h>
+#include <vfs/vfs.h>
+
+RETRO_BEGIN_DECLS
+
+libretro_vfs_implementation_file *retro_vfs_file_open_impl(const char *path, unsigned mode, unsigned hints);
+
+int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream);
+
+int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream);
+
+int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream);
+
+int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length);
+
+int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream);
+
+int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position);
+
+int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len);
+
+int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len);
+
+int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream);
+
+int retro_vfs_file_remove_impl(const char *path);
+
+int retro_vfs_file_rename_impl(const char *old_path, const char *new_path);
+
+const char *retro_vfs_file_get_path_impl(libretro_vfs_implementation_file *stream);
+
+int retro_vfs_stat_impl(const char *path, int32_t *size);
+
+int retro_vfs_mkdir_impl(const char *dir);
+
+libretro_vfs_implementation_dir *retro_vfs_opendir_impl(const char *dir, bool include_hidden);
+
+bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *dirstream);
+
+const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *dirstream);
+
+bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *dirstream);
+
+int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *dirstream);
+
+RETRO_END_DECLS
+
+#endif
diff --git a/libretro-common/streams/file_stream.c b/libretro-common/streams/file_stream.c
new file mode 100644 (file)
index 0000000..ae64c4c
--- /dev/null
@@ -0,0 +1,662 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (file_stream.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef _MSC_VER
+#include <compat/msvc.h>
+#endif
+
+#include <string/stdstring.h>
+#include <streams/file_stream.h>
+#define VFS_FRONTEND
+#include <vfs/vfs_implementation.h>
+
+#define VFS_ERROR_RETURN_VALUE -1
+
+struct RFILE
+{
+   struct retro_vfs_file_handle *hfile;
+       bool error_flag;
+       bool eof_flag;
+};
+
+static retro_vfs_get_path_t filestream_get_path_cb = NULL;
+static retro_vfs_open_t filestream_open_cb         = NULL;
+static retro_vfs_close_t filestream_close_cb       = NULL;
+static retro_vfs_size_t filestream_size_cb         = NULL;
+static retro_vfs_truncate_t filestream_truncate_cb = NULL;
+static retro_vfs_tell_t filestream_tell_cb         = NULL;
+static retro_vfs_seek_t filestream_seek_cb         = NULL;
+static retro_vfs_read_t filestream_read_cb         = NULL;
+static retro_vfs_write_t filestream_write_cb       = NULL;
+static retro_vfs_flush_t filestream_flush_cb       = NULL;
+static retro_vfs_remove_t filestream_remove_cb     = NULL;
+static retro_vfs_rename_t filestream_rename_cb     = NULL;
+
+/* VFS Initialization */
+
+void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info)
+{
+   const struct retro_vfs_interface *
+      vfs_iface           = vfs_info->iface;
+
+   filestream_get_path_cb = NULL;
+   filestream_open_cb     = NULL;
+   filestream_close_cb    = NULL;
+   filestream_tell_cb     = NULL;
+   filestream_size_cb     = NULL;
+   filestream_truncate_cb = NULL;
+   filestream_seek_cb     = NULL;
+   filestream_read_cb     = NULL;
+   filestream_write_cb    = NULL;
+   filestream_flush_cb    = NULL;
+   filestream_remove_cb   = NULL;
+   filestream_rename_cb   = NULL;
+
+   if (
+             (vfs_info->required_interface_version < 
+             FILESTREAM_REQUIRED_VFS_VERSION)
+         || !vfs_iface)
+      return;
+
+   filestream_get_path_cb = vfs_iface->get_path;
+   filestream_open_cb     = vfs_iface->open;
+   filestream_close_cb    = vfs_iface->close;
+   filestream_size_cb     = vfs_iface->size;
+   filestream_truncate_cb = vfs_iface->truncate;
+   filestream_tell_cb     = vfs_iface->tell;
+   filestream_seek_cb     = vfs_iface->seek;
+   filestream_read_cb     = vfs_iface->read;
+   filestream_write_cb    = vfs_iface->write;
+   filestream_flush_cb    = vfs_iface->flush;
+   filestream_remove_cb   = vfs_iface->remove;
+   filestream_rename_cb   = vfs_iface->rename;
+}
+
+/* Callback wrappers */
+bool filestream_exists(const char *path)
+{
+   RFILE *dummy           = NULL;
+
+   if (!path || !*path)
+      return false;
+
+   dummy                  = filestream_open(
+         path,
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+   if (!dummy)
+      return false;
+
+   if (filestream_close(dummy) != 0)
+      if (dummy)
+         free(dummy);
+
+   dummy = NULL;
+   return true;
+}
+
+int64_t filestream_get_size(RFILE *stream)
+{
+   int64_t output;
+
+   if (filestream_size_cb)
+      output = filestream_size_cb(stream->hfile);
+   else
+      output = retro_vfs_file_size_impl(
+            (libretro_vfs_implementation_file*)stream->hfile);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+int64_t filestream_truncate(RFILE *stream, int64_t length)
+{
+   int64_t output;
+
+   if (filestream_truncate_cb)
+      output = filestream_truncate_cb(stream->hfile, length);
+   else
+      output = retro_vfs_file_truncate_impl(
+            (libretro_vfs_implementation_file*)stream->hfile, length);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+/**
+ * filestream_open:
+ * @path               : path to file
+ * @mode               : file mode to use when opening (read/write)
+ * @hints              :
+ *
+ * Opens a file for reading or writing, depending on the requested mode.
+ * Returns a pointer to an RFILE if opened successfully, otherwise NULL.
+ **/
+RFILE* filestream_open(const char *path, unsigned mode, unsigned hints)
+{
+   struct retro_vfs_file_handle  *fp = NULL;
+   RFILE* output                     = NULL;
+
+   if (filestream_open_cb)
+      fp = (struct retro_vfs_file_handle*)
+         filestream_open_cb(path, mode, hints);
+   else
+      fp = (struct retro_vfs_file_handle*)
+         retro_vfs_file_open_impl(path, mode, hints);
+
+   if (!fp)
+      return NULL;
+
+   output             = (RFILE*)malloc(sizeof(RFILE));
+   output->error_flag = false;
+   output->eof_flag   = false;
+   output->hfile      = fp;
+   return output;
+}
+
+char* filestream_gets(RFILE *stream, char *s, size_t len)
+{
+   int c   = 0;
+   char *p = s;
+   if (!stream)
+      return NULL;
+
+   /* get max bytes or up to a newline */
+
+   for (len--; len > 0; len--)
+   {
+      if ((c = filestream_getc(stream)) == EOF)
+         break;
+      *p++ = c;
+      if (c == '\n')
+         break;
+   }
+   *p = 0;
+
+   if (p == s && c == EOF)
+      return NULL;
+   return (s);
+}
+
+int filestream_getc(RFILE *stream)
+{
+   char c = 0;
+   if (stream && filestream_read(stream, &c, 1) == 1)
+      return (int)(unsigned char)c;
+   return EOF;
+}
+
+int filestream_scanf(RFILE *stream, const char* format, ...)
+{
+   char buf[4096];
+   char subfmt[64];
+   va_list args;
+   const char * bufiter = buf;
+   int        ret       = 0;
+   int64_t startpos     = filestream_tell(stream);
+   int64_t maxlen       = filestream_read(stream, buf, sizeof(buf)-1);
+
+   if (maxlen <= 0)
+      return EOF;
+
+   buf[maxlen] = '\0';
+
+   va_start(args, format);
+
+   while (*format)
+   {
+      if (*format == '%')
+      {
+         int sublen;
+         char* subfmtiter = subfmt;
+         bool asterisk    = false;
+
+         *subfmtiter++    = *format++; /* '%' */
+
+         /* %[*][width][length]specifier */
+
+         if (*format == '*')
+         {
+            asterisk      = true;
+            *subfmtiter++ = *format++;
+         }
+
+         while (ISDIGIT((unsigned char)*format))
+            *subfmtiter++ = *format++; /* width */
+
+         /* length */
+         if (*format == 'h' || *format == 'l')
+         {
+            if (format[1] == format[0])
+               *subfmtiter++ = *format++;
+            *subfmtiter++    = *format++;
+         }
+         else if (
+               *format == 'j' || 
+               *format == 'z' || 
+               *format == 't' || 
+               *format == 'L')
+         {
+            *subfmtiter++ = *format++;
+         }
+
+         /* specifier - always a single character (except ]) */
+         if (*format == '[')
+         {
+            while (*format != ']')
+               *subfmtiter++ = *format++;
+            *subfmtiter++    = *format++;
+         }
+         else
+            *subfmtiter++    = *format++;
+
+         *subfmtiter++       = '%';
+         *subfmtiter++       = 'n';
+         *subfmtiter++       = '\0';
+
+         if (sizeof(void*) != sizeof(long*))
+            abort(); /* all pointers must have the same size */
+
+         if (asterisk)
+         {
+            int v = sscanf(bufiter, subfmt, &sublen);
+            if (v == EOF)
+               return EOF;
+            if (v != 0)
+               break;
+         }
+         else
+         {
+            int v = sscanf(bufiter, subfmt, va_arg(args, void*), &sublen);
+            if (v == EOF)
+               return EOF;
+            if (v != 1)
+               break;
+         }
+
+         ret++;
+         bufiter += sublen;
+      }
+      else if (isspace((unsigned char)*format))
+      {
+         while (isspace((unsigned char)*bufiter))
+            bufiter++;
+         format++;
+      }
+      else
+      {
+         if (*bufiter != *format)
+            break;
+         bufiter++;
+         format++;
+      }
+   }
+
+   va_end(args);
+   filestream_seek(stream, startpos+(bufiter-buf),
+         RETRO_VFS_SEEK_POSITION_START);
+
+   return ret;
+}
+
+int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position)
+{
+   int64_t output;
+
+   if (filestream_seek_cb)
+      output = filestream_seek_cb(stream->hfile, offset, seek_position);
+   else
+      output = retro_vfs_file_seek_impl(
+            (libretro_vfs_implementation_file*)stream->hfile,
+            offset, seek_position);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   stream->eof_flag      = false;
+
+   return output;
+}
+
+int filestream_eof(RFILE *stream)
+{
+   return stream->eof_flag;
+}
+
+int64_t filestream_tell(RFILE *stream)
+{
+   int64_t output;
+
+   if (filestream_size_cb)
+      output = filestream_tell_cb(stream->hfile);
+   else
+      output = retro_vfs_file_tell_impl(
+            (libretro_vfs_implementation_file*)stream->hfile);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+void filestream_rewind(RFILE *stream)
+{
+   if (!stream)
+      return;
+   filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START);
+   stream->error_flag = false;
+   stream->eof_flag   = false;
+}
+
+int64_t filestream_read(RFILE *stream, void *s, int64_t len)
+{
+   int64_t output;
+
+   if (filestream_read_cb)
+      output = filestream_read_cb(stream->hfile, s, len);
+   else
+      output = retro_vfs_file_read_impl(
+            (libretro_vfs_implementation_file*)stream->hfile, s, len);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+   if (output < len)
+      stream->eof_flag   = true;
+
+   return output;
+}
+
+int filestream_flush(RFILE *stream)
+{
+   int output;
+
+   if (filestream_flush_cb)
+      output = filestream_flush_cb(stream->hfile);
+   else
+      output = retro_vfs_file_flush_impl(
+            (libretro_vfs_implementation_file*)stream->hfile);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+int filestream_delete(const char *path)
+{
+   if (filestream_remove_cb)
+      return filestream_remove_cb(path);
+
+   return retro_vfs_file_remove_impl(path);
+}
+
+int filestream_rename(const char *old_path, const char *new_path)
+{
+   if (filestream_rename_cb)
+      return filestream_rename_cb(old_path, new_path);
+
+   return retro_vfs_file_rename_impl(old_path, new_path);
+}
+
+const char* filestream_get_path(RFILE *stream)
+{
+   if (filestream_get_path_cb)
+      return filestream_get_path_cb(stream->hfile);
+
+   return retro_vfs_file_get_path_impl(
+         (libretro_vfs_implementation_file*)stream->hfile);
+}
+
+int64_t filestream_write(RFILE *stream, const void *s, int64_t len)
+{
+   int64_t output;
+
+   if (filestream_write_cb)
+      output = filestream_write_cb(stream->hfile, s, len);
+   else
+      output = retro_vfs_file_write_impl(
+            (libretro_vfs_implementation_file*)stream->hfile, s, len);
+
+   if (output == VFS_ERROR_RETURN_VALUE)
+      stream->error_flag = true;
+
+   return output;
+}
+
+int filestream_putc(RFILE *stream, int c)
+{
+   char c_char = (char)c;
+   if (!stream)
+      return EOF;
+   return filestream_write(stream, &c_char, 1) == 1 
+      ? (int)(unsigned char)c 
+      : EOF;
+}
+
+int filestream_vprintf(RFILE *stream, const char* format, va_list args)
+{
+   static char buffer[8 * 1024];
+   int64_t num_chars = vsnprintf(buffer, sizeof(buffer),
+         format, args);
+
+   if (num_chars < 0)
+      return -1;
+   else if (num_chars == 0)
+      return 0;
+
+   return (int)filestream_write(stream, buffer, num_chars);
+}
+
+int filestream_printf(RFILE *stream, const char* format, ...)
+{
+   va_list vl;
+   int result;
+   va_start(vl, format);
+   result = filestream_vprintf(stream, format, vl);
+   va_end(vl);
+   return result;
+}
+
+int filestream_error(RFILE *stream)
+{
+   if (stream && stream->error_flag)
+      return 1;
+   return 0;
+}
+
+int filestream_close(RFILE *stream)
+{
+   int output;
+   struct retro_vfs_file_handle* fp = stream->hfile;
+
+   if (filestream_close_cb)
+      output = filestream_close_cb(fp);
+   else
+      output = retro_vfs_file_close_impl(
+            (libretro_vfs_implementation_file*)fp);
+
+   if (output == 0)
+      free(stream);
+
+   return output;
+}
+
+/**
+ * filestream_read_file:
+ * @path             : path to file.
+ * @buf              : buffer to allocate and read the contents of the
+ *                     file into. Needs to be freed manually.
+ *
+ * Read the contents of a file into @buf.
+ *
+ * Returns: number of items read, -1 on error.
+ */
+int64_t filestream_read_file(const char *path, void **buf, int64_t *len)
+{
+   int64_t ret              = 0;
+   int64_t content_buf_size = 0;
+   void *content_buf        = NULL;
+   RFILE *file              = filestream_open(path,
+         RETRO_VFS_FILE_ACCESS_READ,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+   if (!file)
+   {
+      *buf = NULL;
+      return 0;
+   }
+
+   content_buf_size = filestream_get_size(file);
+
+   if (content_buf_size < 0)
+      goto error;
+
+   content_buf      = malloc((size_t)(content_buf_size + 1));
+
+   if (!content_buf)
+      goto error;
+   if ((int64_t)(uint64_t)(content_buf_size + 1) != (content_buf_size + 1))
+      goto error;
+
+   ret = filestream_read(file, content_buf, (int64_t)content_buf_size);
+   if (ret < 0)
+      goto error;
+
+   if (filestream_close(file) != 0)
+      if (file)
+         free(file);
+
+   *buf    = content_buf;
+
+   /* Allow for easy reading of strings to be safe.
+    * Will only work with sane character formatting (Unix). */
+   ((char*)content_buf)[ret] = '\0';
+
+   if (len)
+      *len = ret;
+
+   return 1;
+
+error:
+   if (file)
+      if (filestream_close(file) != 0)
+         free(file);
+   if (content_buf)
+      free(content_buf);
+   if (len)
+      *len = -1;
+   *buf = NULL;
+   return 0;
+}
+
+/**
+ * filestream_write_file:
+ * @path             : path to file.
+ * @data             : contents to write to the file.
+ * @size             : size of the contents.
+ *
+ * Writes data to a file.
+ *
+ * Returns: true (1) on success, false (0) otherwise.
+ */
+bool filestream_write_file(const char *path, const void *data, int64_t size)
+{
+   int64_t ret   = 0;
+   RFILE *file   = filestream_open(path,
+         RETRO_VFS_FILE_ACCESS_WRITE,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+   if (!file)
+      return false;
+
+   ret = filestream_write(file, data, size);
+   if (filestream_close(file) != 0)
+      if (file)
+         free(file);
+
+   if (ret != size)
+      return false;
+
+   return true;
+}
+
+/* Returned pointer must be freed by the caller. */
+char* filestream_getline(RFILE *stream)
+{
+   char *newline_tmp  = NULL;
+   size_t cur_size    = 8;
+   size_t idx         = 0;
+   int in             = 0;
+   char *newline      = (char*)malloc(9);
+
+   if (!stream || !newline)
+   {
+      if (newline)
+         free(newline);
+      return NULL;
+   }
+
+   in                 = filestream_getc(stream);
+
+   while (in != EOF && in != '\n')
+   {
+      if (idx == cur_size)
+      {
+         cur_size    *= 2;
+         newline_tmp  = (char*)realloc(newline, cur_size + 1);
+
+         if (!newline_tmp)
+         {
+            free(newline);
+            return NULL;
+         }
+
+         newline     = newline_tmp;
+      }
+
+      newline[idx++] = in;
+      in             = filestream_getc(stream);
+   }
+
+   newline[idx]      = '\0';
+   return newline;
+}
+
+libretro_vfs_implementation_file* filestream_get_vfs_handle(RFILE *stream)
+{
+   return (libretro_vfs_implementation_file*)stream->hfile;
+}
diff --git a/libretro-common/streams/file_stream_transforms.c b/libretro-common/streams/file_stream_transforms.c
new file mode 100644 (file)
index 0000000..099b27b
--- /dev/null
@@ -0,0 +1,159 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (file_stream_transforms.c).
+* ---------------------------------------------------------------------------------------
+*
+* Permission is hereby granted, free of charge,
+* to any person obtaining a copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation the rights to
+* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <string.h>
+#include <stdarg.h>
+
+#include <libretro.h>
+#include <streams/file_stream.h>
+
+RFILE* rfopen(const char *path, const char *mode)
+{
+   RFILE          *output  = NULL;
+   unsigned int retro_mode = RETRO_VFS_FILE_ACCESS_READ;
+   bool position_to_end    = false;
+
+   if (strstr(mode, "r"))
+   {
+      retro_mode = RETRO_VFS_FILE_ACCESS_READ;
+      if (strstr(mode, "+"))
+      {
+         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
+            RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
+      }
+   }
+   else if (strstr(mode, "w"))
+   {
+      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE;
+      if (strstr(mode, "+"))
+         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE;
+   }
+   else if (strstr(mode, "a"))
+   {
+      retro_mode = RETRO_VFS_FILE_ACCESS_WRITE |
+         RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
+      position_to_end = true;
+      if (strstr(mode, "+"))
+      {
+         retro_mode = RETRO_VFS_FILE_ACCESS_READ_WRITE |
+            RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING;
+      }
+   }
+
+   output = filestream_open(path, retro_mode,
+         RETRO_VFS_FILE_ACCESS_HINT_NONE);
+   if (output && position_to_end)
+      filestream_seek(output, 0, RETRO_VFS_SEEK_POSITION_END);
+
+   return output;
+}
+
+int rfclose(RFILE* stream)
+{
+   return filestream_close(stream);
+}
+
+int64_t rftell(RFILE* stream)
+{
+   return filestream_tell(stream);
+}
+
+int64_t rfseek(RFILE* stream, int64_t offset, int origin)
+{
+   int seek_position = -1;
+   switch (origin)
+   {
+      case SEEK_SET:
+         seek_position = RETRO_VFS_SEEK_POSITION_START;
+         break;
+      case SEEK_CUR:
+         seek_position = RETRO_VFS_SEEK_POSITION_CURRENT;
+         break;
+      case SEEK_END:
+         seek_position = RETRO_VFS_SEEK_POSITION_END;
+         break;
+   }
+
+   return filestream_seek(stream, offset, seek_position);
+}
+
+int64_t rfread(void* buffer,
+   size_t elem_size, size_t elem_count, RFILE* stream)
+{
+   return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
+}
+
+char *rfgets(char *buffer, int maxCount, RFILE* stream)
+{
+   return filestream_gets(stream, buffer, maxCount);
+}
+
+int rfgetc(RFILE* stream)
+{
+   return filestream_getc(stream);
+}
+
+int64_t rfwrite(void const* buffer,
+   size_t elem_size, size_t elem_count, RFILE* stream)
+{
+   return filestream_write(stream, buffer, elem_size * elem_count);
+}
+
+int rfputc(int character, RFILE * stream)
+{
+    return filestream_putc(stream, character);
+}
+
+int64_t rfflush(RFILE * stream)
+{
+    return filestream_flush(stream);
+}
+
+int rfprintf(RFILE * stream, const char * format, ...)
+{
+   int result;
+   va_list vl;
+   va_start(vl, format);
+   result = filestream_vprintf(stream, format, vl);
+   va_end(vl);
+   return result;
+}
+
+int rferror(RFILE* stream)
+{
+   return filestream_error(stream);
+}
+
+int rfeof(RFILE* stream)
+{
+   return filestream_eof(stream);
+}
+
+int rfscanf(RFILE * stream, const char * format, ...)
+{
+   int result;
+   va_list vl;
+   va_start(vl, format);
+   result = filestream_scanf(stream, format, vl);
+   va_end(vl);
+   return result;
+}
diff --git a/libretro-common/string/stdstring.c b/libretro-common/string/stdstring.c
new file mode 100644 (file)
index 0000000..50c35dd
--- /dev/null
@@ -0,0 +1,416 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (stdstring.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <ctype.h>
+
+#include <string/stdstring.h>
+#include <encodings/utf.h>
+
+const uint8_t lr_char_props[256] = {
+       /*x0   x1   x2   x3   x4   x5   x6   x7   x8   x9   xA   xB   xC   xD   xE   xF */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, /* 0x                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 1x                  */
+       0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 2x  !"#$%&'()*+,-./ */
+       0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, /* 3x 0123456789:;<=>? */
+       0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, /* 4x @ABCDEFGHIJKLMNO */
+       0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, /* 5x PQRSTUVWXYZ[\]^_ */
+       0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, /* 6x `abcdefghijklmno */
+       0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, /* 7x pqrstuvwxyz{|}~  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 8x                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 9x                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ax                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Bx                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Cx                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Dx                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Ex                  */
+       0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* Fx                  */
+};
+
+char *string_init(const char *src)
+{
+   return src ? strdup(src) : NULL;
+}
+
+void string_set(char **string, const char *src)
+{
+   free(*string);
+   *string = string_init(src);
+}
+
+
+char *string_to_upper(char *s)
+{
+   char *cs = (char *)s;
+   for ( ; *cs != '\0'; cs++)
+      *cs = toupper((unsigned char)*cs);
+   return s;
+}
+
+char *string_to_lower(char *s)
+{
+   char *cs = (char *)s;
+   for ( ; *cs != '\0'; cs++)
+      *cs = tolower((unsigned char)*cs);
+   return s;
+}
+
+char *string_ucwords(char *s)
+{
+   char *cs = (char *)s;
+   for ( ; *cs != '\0'; cs++)
+   {
+      if (*cs == ' ')
+         *(cs+1) = toupper((unsigned char)*(cs+1));
+   }
+
+   s[0] = toupper((unsigned char)s[0]);
+   return s;
+}
+
+char *string_replace_substring(const char *in,
+      const char *pattern, const char *replacement)
+{
+   size_t numhits, pattern_len, replacement_len, outlen;
+   const char *inat   = NULL;
+   const char *inprev = NULL;
+   char          *out = NULL;
+   char        *outat = NULL;
+
+   /* if either pattern or replacement is NULL,
+    * duplicate in and let caller handle it. */
+   if (!pattern || !replacement)
+      return strdup(in);
+
+   pattern_len     = strlen(pattern);
+   replacement_len = strlen(replacement);
+   numhits         = 0;
+   inat            = in;
+
+   while ((inat = strstr(inat, pattern)))
+   {
+      inat += pattern_len;
+      numhits++;
+   }
+
+   outlen          = strlen(in) - pattern_len*numhits + replacement_len*numhits;
+   out             = (char *)malloc(outlen+1);
+
+   if (!out)
+      return NULL;
+
+   outat           = out;
+   inat            = in;
+   inprev          = in;
+
+   while ((inat = strstr(inat, pattern)))
+   {
+      memcpy(outat, inprev, inat-inprev);
+      outat += inat-inprev;
+      memcpy(outat, replacement, replacement_len);
+      outat += replacement_len;
+      inat += pattern_len;
+      inprev = inat;
+   }
+   strcpy(outat, inprev);
+
+   return out;
+}
+
+/* Remove leading whitespaces */
+char *string_trim_whitespace_left(char *const s)
+{
+   if (s && *s)
+   {
+      size_t len     = strlen(s);
+      char *current  = s;
+
+      while (*current && ISSPACE((unsigned char)*current))
+      {
+         ++current;
+         --len;
+      }
+
+      if (s != current)
+         memmove(s, current, len + 1);
+   }
+
+   return s;
+}
+
+/* Remove trailing whitespaces */
+char *string_trim_whitespace_right(char *const s)
+{
+   if (s && *s)
+   {
+      size_t len     = strlen(s);
+      char  *current = s + len - 1;
+
+      while (current != s && ISSPACE((unsigned char)*current))
+      {
+         --current;
+         --len;
+      }
+
+      current[ISSPACE((unsigned char)*current) ? 0 : 1] = '\0';
+   }
+
+   return s;
+}
+
+/* Remove leading and trailing whitespaces */
+char *string_trim_whitespace(char *const s)
+{
+   string_trim_whitespace_right(s);  /* order matters */
+   string_trim_whitespace_left(s);
+
+   return s;
+}
+
+char *word_wrap(char* buffer, const char *string, int line_width, bool unicode, unsigned max_lines)
+{
+   unsigned i     = 0;
+   unsigned len   = (unsigned)strlen(string);
+   unsigned lines = 1;
+
+   while (i < len)
+   {
+      unsigned counter;
+      int pos = (int)(&buffer[i] - buffer);
+
+      /* copy string until the end of the line is reached */
+      for (counter = 1; counter <= (unsigned)line_width; counter++)
+      {
+         const char *character;
+         unsigned char_len;
+         unsigned j = i;
+
+         /* check if end of string reached */
+         if (i == len)
+         {
+            buffer[i] = 0;
+            return buffer;
+         }
+
+         character = utf8skip(&string[i], 1);
+         char_len  = (unsigned)(character - &string[i]);
+
+         if (!unicode)
+            counter += char_len - 1;
+
+         do
+         {
+            buffer[i] = string[i];
+            char_len--;
+            i++;
+         } while (char_len);
+
+         /* check for newlines embedded in the original input
+          * and reset the index */
+         if (buffer[j] == '\n')
+         {
+            lines++;
+            counter = 1;
+         }
+      }
+
+      /* check for whitespace */
+      if (string[i] == ' ')
+      {
+         if ((max_lines == 0 || lines < max_lines))
+         {
+            buffer[i] = '\n';
+            i++;
+            lines++;
+         }
+      }
+      else
+      {
+         int k;
+
+         /* check for nearest whitespace back in string */
+         for (k = i; k > 0; k--)
+         {
+            if (string[k] != ' ' || (max_lines != 0 && lines >= max_lines))
+               continue;
+
+            buffer[k] = '\n';
+            /* set string index back to character after this one */
+            i         = k + 1;
+            lines++;
+            break;
+         }
+
+         if (&buffer[i] - buffer == pos)
+            return buffer;
+      }
+   }
+
+   buffer[i] = 0;
+
+   return buffer;
+}
+
+/* Splits string into tokens seperated by 'delim'
+ * > Returned token string must be free()'d
+ * > Returns NULL if token is not found
+ * > After each call, 'str' is set to the position after the
+ *   last found token
+ * > Tokens *include* empty strings
+ * Usage example:
+ *    char *str      = "1,2,3,4,5,6,7,,,10,";
+ *    char **str_ptr = &str;
+ *    char *token    = NULL;
+ *    while ((token = string_tokenize(str_ptr, ",")))
+ *    {
+ *        printf("%s\n", token);
+ *        free(token);
+ *        token = NULL;
+ *    }
+ */
+char* string_tokenize(char **str, const char *delim)
+{
+   /* Taken from https://codereview.stackexchange.com/questions/216956/strtok-function-thread-safe-supports-empty-tokens-doesnt-change-string# */
+   char *str_ptr    = NULL;
+   char *delim_ptr  = NULL;
+   char *token      = NULL;
+   size_t token_len = 0;
+
+   /* Sanity checks */
+   if (!str || string_is_empty(delim))
+      return NULL;
+
+   str_ptr = *str;
+
+   /* Note: we don't check string_is_empty() here,
+    * empty strings are valid */
+   if (!str_ptr)
+      return NULL;
+
+   /* Search for delimiter */
+   delim_ptr = strstr(str_ptr, delim);
+
+   if (delim_ptr)
+      token_len = delim_ptr - str_ptr;
+   else
+      token_len = strlen(str_ptr);
+
+   /* Allocate token string */
+   token = (char *)malloc((token_len + 1) * sizeof(char));
+
+   if (!token)
+      return NULL;
+
+   /* Copy token */
+   strlcpy(token, str_ptr, (token_len + 1) * sizeof(char));
+   token[token_len] = '\0';
+
+   /* Update input string pointer */
+   *str = delim_ptr ? delim_ptr + strlen(delim) : NULL;
+
+   return token;
+}
+
+/* Removes every instance of character 'c' from 'str' */
+void string_remove_all_chars(char *str, char c)
+{
+   char *read_ptr  = NULL;
+   char *write_ptr = NULL;
+
+   if (string_is_empty(str))
+      return;
+
+   read_ptr  = str;
+   write_ptr = str;
+
+   while (*read_ptr != '\0')
+   {
+      *write_ptr = *read_ptr++;
+      write_ptr += (*write_ptr != c) ? 1 : 0;
+   }
+
+   *write_ptr = '\0';
+}
+
+/* Replaces every instance of character 'find' in 'str'
+ * with character 'replace' */
+void string_replace_all_chars(char *str, char find, char replace)
+{
+   char *str_ptr = str;
+
+   if (string_is_empty(str))
+      return;
+
+   while ((str_ptr = strchr(str_ptr, find)))
+      *str_ptr++ = replace;
+}
+
+/* Converts string to unsigned integer.
+ * Returns 0 if string is invalid  */
+unsigned string_to_unsigned(const char *str)
+{
+   const char *ptr = NULL;
+
+   if (string_is_empty(str))
+      return 0;
+
+   for (ptr = str; *ptr != '\0'; ptr++)
+   {
+      if (!ISDIGIT((unsigned char)*ptr))
+         return 0;
+   }
+
+   return (unsigned)strtoul(str, NULL, 10);
+}
+
+/* Converts hexadecimal string to unsigned integer.
+ * Handles optional leading '0x'.
+ * Returns 0 if string is invalid  */
+unsigned string_hex_to_unsigned(const char *str)
+{
+   const char *hex_str = str;
+   const char *ptr     = NULL;
+   size_t len;
+
+   if (string_is_empty(str))
+      return 0;
+
+   /* Remove leading '0x', if required */
+   len = strlen(str);
+
+   if (len >= 2)
+      if ((str[0] == '0') &&
+          ((str[1] == 'x') || (str[1] == 'X')))
+         hex_str = str + 2;
+
+   if (string_is_empty(hex_str))
+      return 0;
+
+   /* Check for valid characters */
+   for (ptr = hex_str; *ptr != '\0'; ptr++)
+   {
+      if (!isxdigit((unsigned char)*ptr))
+         return 0;
+   }
+
+   return (unsigned)strtoul(hex_str, NULL, 16);
+}
diff --git a/libretro-common/time/rtime.c b/libretro-common/time/rtime.c
new file mode 100644 (file)
index 0000000..d66c228
--- /dev/null
@@ -0,0 +1,81 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+ *
+ * ---------------------------------------------------------------------------------------
+ * The following license statement only applies to this file (rtime.c).
+ * ---------------------------------------------------------------------------------------
+ *
+ * Permission is hereby granted, free of charge,
+ * to any person obtaining a copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_THREADS
+#include <rthreads/rthreads.h>
+#include <retro_assert.h>
+#include <stdlib.h>
+#endif
+
+#include <string.h>
+#include <time/rtime.h>
+
+#ifdef HAVE_THREADS
+/* TODO/FIXME - global */
+slock_t *rtime_localtime_lock = NULL;
+#endif
+
+/* Must be called before using rtime_localtime() */
+void rtime_init(void)
+{
+   rtime_deinit();
+#ifdef HAVE_THREADS
+   if (!rtime_localtime_lock)
+      rtime_localtime_lock = slock_new();
+
+   retro_assert(rtime_localtime_lock);
+#endif
+}
+
+/* Must be called upon program termination */
+void rtime_deinit(void)
+{
+#ifdef HAVE_THREADS
+   if (rtime_localtime_lock)
+   {
+      slock_free(rtime_localtime_lock);
+      rtime_localtime_lock = NULL;
+   }
+#endif
+}
+
+/* Thread-safe wrapper for localtime() */
+struct tm *rtime_localtime(const time_t *timep, struct tm *result)
+{
+   struct tm *time_info = NULL;
+
+   /* Lock mutex */
+#ifdef HAVE_THREADS
+   slock_lock(rtime_localtime_lock);
+#endif
+
+   time_info = localtime(timep);
+   if (time_info)
+      memcpy(result, time_info, sizeof(struct tm));
+
+   /* Unlock mutex */
+#ifdef HAVE_THREADS
+   slock_unlock(rtime_localtime_lock);
+#endif
+
+   return result;
+}
diff --git a/libretro-common/vfs/vfs_implementation.c b/libretro-common/vfs/vfs_implementation.c
new file mode 100644 (file)
index 0000000..b710e2f
--- /dev/null
@@ -0,0 +1,1329 @@
+/* Copyright  (C) 2010-2020 The RetroArch team
+*
+* ---------------------------------------------------------------------------------------
+* The following license statement only applies to this file (vfs_implementation.c).
+* ---------------------------------------------------------------------------------------
+*
+* Permission is hereby granted, free of charge,
+* to any person obtaining a copy of this software and associated documentation files (the "Software"),
+* to deal in the Software without restriction, including without limitation the rights to
+* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
+* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include <string/stdstring.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(_WIN32)
+#  ifdef _MSC_VER
+#    define setmode _setmode
+#  endif
+#include <sys/stat.h>
+#  ifdef _XBOX
+#    include <xtl.h>
+#    define INVALID_FILE_ATTRIBUTES -1
+#  else
+
+#    include <fcntl.h>
+#    include <direct.h>
+#    include <windows.h>
+#  endif
+#    include <io.h>
+#else
+#  if defined(PSP)
+#    include <pspiofilemgr.h>
+#  endif
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  if !defined(VITA)
+#  include <dirent.h>
+#  endif
+#  include <unistd.h>
+#  if defined(ORBIS)
+#  include <sys/fcntl.h>
+#  include <sys/dirent.h>
+#  include <orbisFile.h>
+#  endif
+#endif
+
+#if defined (__CELLOS_LV2__)  && !defined(__PSL1GHT__)
+#include <cell/cell_fs.h>
+#define O_RDONLY CELL_FS_O_RDONLY
+#define O_WRONLY CELL_FS_O_WRONLY
+#define O_CREAT CELL_FS_O_CREAT
+#define O_TRUNC CELL_FS_O_TRUNC
+#define O_RDWR CELL_FS_O_RDWR
+#else
+#include <fcntl.h>
+#endif
+
+/* TODO: Some things are duplicated but I'm really afraid of breaking other platforms by touching this */
+#if defined(VITA)
+#  include <psp2/io/fcntl.h>
+#  include <psp2/io/dirent.h>
+#  include <psp2/io/stat.h>
+#elif defined(ORBIS)
+#  include <orbisFile.h>
+#  include <ps4link.h>
+#  include <sys/dirent.h>
+#  include <sys/fcntl.h>
+#elif !defined(_WIN32)
+#  if defined(PSP)
+#    include <pspiofilemgr.h>
+#  endif
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  include <dirent.h>
+#  include <unistd.h>
+#endif
+
+#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
+#include <unistd.h> /* stat() is defined here */
+#endif
+
+#ifdef __APPLE__
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+#ifdef __HAIKU__
+#include <kernel/image.h>
+#endif
+#ifndef __MACH__
+#include <compat/strl.h>
+#include <compat/posix_string.h>
+#endif
+#include <compat/strcasestr.h>
+#include <retro_miscellaneous.h>
+#include <encodings/utf.h>
+
+#if defined(_WIN32)
+#ifndef _XBOX
+#if defined(_MSC_VER) && _MSC_VER <= 1200
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
+#endif
+#elif defined(VITA)
+#define SCE_ERROR_ERRNO_EEXIST 0x80010011
+#include <psp2/io/fcntl.h>
+#include <psp2/io/dirent.h>
+#include <psp2/io/stat.h>
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#if defined(ORBIS)
+#include <orbisFile.h>
+#include <sys/fcntl.h>
+#include <sys/dirent.h>
+#endif
+#if defined(PSP)
+#include <pspkernel.h>
+#endif
+
+#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+#include <cell/cell_fs.h>
+#endif
+
+#if defined(VITA)
+#define FIO_S_ISDIR SCE_S_ISDIR
+#endif
+
+#if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
+#include <unistd.h> /* stat() is defined here */
+#endif
+
+/* Assume W-functions do not work below Win2K and Xbox platforms */
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500 || defined(_XBOX)
+
+#ifndef LEGACY_WIN32
+#define LEGACY_WIN32
+#endif
+
+#endif
+
+#if defined(_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#define ATLEAST_VC2005
+#endif
+#endif
+
+#include <vfs/vfs_implementation.h>
+#include <libretro.h>
+#include <memmap.h>
+#include <encodings/utf.h>
+#include <compat/fopen_utf8.h>
+#include <file/file_path.h>
+
+#ifdef HAVE_CDROM
+#include <vfs/vfs_implementation_cdrom.h>
+#endif
+
+#if (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE - 0) >= 200112) || (defined(__POSIX_VISIBLE) && __POSIX_VISIBLE >= 200112) || (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || __USE_LARGEFILE || (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
+#ifndef HAVE_64BIT_OFFSETS
+#define HAVE_64BIT_OFFSETS
+#endif
+#endif
+
+#define RFILE_HINT_UNBUFFERED (1 << 8)
+
+int64_t retro_vfs_file_seek_internal(
+      libretro_vfs_implementation_file *stream,
+      int64_t offset, int whence)
+{
+   if (!stream)
+      return -1;
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+#ifdef HAVE_CDROM
+      if (stream->scheme == VFS_SCHEME_CDROM)
+         return retro_vfs_file_seek_cdrom(stream, offset, whence);
+#endif
+#ifdef ATLEAST_VC2005
+      /* VC2005 and up have a special 64-bit fseek */
+      return _fseeki64(stream->fp, offset, whence);
+#elif defined(ORBIS)
+      {
+         int ret = orbisLseek(stream->fd, offset, whence);
+         if (ret < 0)
+            return -1;
+         return 0;
+      }
+#elif defined(HAVE_64BIT_OFFSETS)
+      return fseeko(stream->fp, (off_t)offset, whence);
+#else
+      return fseek(stream->fp, (long)offset, whence);
+#endif
+   }
+#ifdef HAVE_MMAP
+   /* Need to check stream->mapped because this function is
+    * called in filestream_open() */
+   if (stream->mapped && stream->hints &
+         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+   {
+      /* fseek() returns error on under/overflow but
+       * allows cursor > EOF for
+       read-only file descriptors. */
+      switch (whence)
+      {
+         case SEEK_SET:
+            if (offset < 0)
+               return -1;
+
+            stream->mappos = offset;
+            break;
+
+         case SEEK_CUR:
+            if (  (offset < 0 && stream->mappos + offset > stream->mappos) ||
+                  (offset > 0 && stream->mappos + offset < stream->mappos))
+               return -1;
+
+            stream->mappos += offset;
+            break;
+
+         case SEEK_END:
+            if (stream->mapsize + offset < stream->mapsize)
+               return -1;
+
+            stream->mappos = stream->mapsize + offset;
+            break;
+      }
+      return stream->mappos;
+   }
+#endif
+
+   if (lseek(stream->fd, (off_t)offset, whence) < 0)
+      return -1;
+
+   return 0;
+}
+
+/**
+ * retro_vfs_file_open_impl:
+ * @path               : path to file
+ * @mode               : file mode to use when opening (read/write)
+ * @hints              :
+ *
+ * Opens a file for reading or writing, depending on the requested mode.
+ * Returns a pointer to an RFILE if opened successfully, otherwise NULL.
+ **/
+
+libretro_vfs_implementation_file *retro_vfs_file_open_impl(
+      const char *path, unsigned mode, unsigned hints)
+{
+#if defined(VFS_FRONTEND) || defined(HAVE_CDROM)
+   int                             path_len = (int)strlen(path);
+#endif
+#ifdef VFS_FRONTEND
+   const char                 *dumb_prefix  = "vfsonly://";
+   size_t                   dumb_prefix_siz = STRLEN_CONST("vfsonly://");
+   int                      dumb_prefix_len = (int)dumb_prefix_siz;
+#endif
+#ifdef HAVE_CDROM
+   const char *cdrom_prefix                 = "cdrom://";
+   size_t cdrom_prefix_siz                  = STRLEN_CONST("cdrom://");
+   int cdrom_prefix_len                     = (int)cdrom_prefix_siz;
+#endif
+   int                                flags = 0;
+   const char                     *mode_str = NULL;
+   libretro_vfs_implementation_file *stream = 
+      (libretro_vfs_implementation_file*)
+      malloc(sizeof(*stream));
+
+   if (!stream)
+      return NULL;
+
+   stream->fd                     = 0;
+   stream->hints                  = hints;
+   stream->size                   = 0;
+   stream->buf                    = NULL;
+   stream->fp                     = NULL;
+#ifdef _WIN32
+   stream->fh                     = 0;
+#endif
+   stream->orig_path              = NULL;
+   stream->mappos                 = 0;
+   stream->mapsize                = 0;
+   stream->mapped                 = NULL;
+   stream->scheme                 = VFS_SCHEME_NONE;
+
+#ifdef VFS_FRONTEND
+   if (path_len >= dumb_prefix_len)
+      if (!memcmp(path, dumb_prefix, dumb_prefix_len))
+         path             += dumb_prefix_siz;
+#endif
+
+#ifdef HAVE_CDROM
+   stream->cdrom.cue_buf          = NULL;
+   stream->cdrom.cue_len          = 0;
+   stream->cdrom.byte_pos         = 0;
+   stream->cdrom.drive            = 0;
+   stream->cdrom.cur_min          = 0;
+   stream->cdrom.cur_sec          = 0;
+   stream->cdrom.cur_frame        = 0;
+   stream->cdrom.cur_track        = 0;
+   stream->cdrom.cur_lba          = 0;
+   stream->cdrom.last_frame_lba   = 0;
+   stream->cdrom.last_frame[0]    = '\0';
+   stream->cdrom.last_frame_valid = false;
+
+   if (path_len > cdrom_prefix_len)
+   {
+      if (!memcmp(path, cdrom_prefix, cdrom_prefix_len))
+      {
+         path             += cdrom_prefix_siz;
+         stream->scheme    = VFS_SCHEME_CDROM;
+      }
+   }
+#endif
+
+   stream->orig_path       = strdup(path);
+
+#ifdef HAVE_MMAP
+   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS && mode == RETRO_VFS_FILE_ACCESS_READ)
+      stream->hints |= RFILE_HINT_UNBUFFERED;
+   else
+#endif
+      stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
+
+   switch (mode)
+   {
+      case RETRO_VFS_FILE_ACCESS_READ:
+         mode_str = "rb";
+
+         flags    = O_RDONLY;
+#ifdef _WIN32
+         flags   |= O_BINARY;
+#endif
+         break;
+
+      case RETRO_VFS_FILE_ACCESS_WRITE:
+         mode_str = "wb";
+
+         flags    = O_WRONLY | O_CREAT | O_TRUNC;
+#if !defined(ORBIS)
+#if !defined(_WIN32)
+         flags   |= S_IRUSR | S_IWUSR;
+#else
+         flags   |= O_BINARY;
+#endif
+#endif
+         break;
+
+      case RETRO_VFS_FILE_ACCESS_READ_WRITE:
+         mode_str = "w+b";
+         flags    = O_RDWR | O_CREAT | O_TRUNC;
+#if !defined(ORBIS)
+#if !defined(_WIN32)
+         flags   |= S_IRUSR | S_IWUSR;
+#else
+         flags   |= O_BINARY;
+#endif
+#endif
+         break;
+
+      case RETRO_VFS_FILE_ACCESS_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
+      case RETRO_VFS_FILE_ACCESS_READ_WRITE | RETRO_VFS_FILE_ACCESS_UPDATE_EXISTING:
+         mode_str = "r+b";
+
+         flags    = O_RDWR;
+#if !defined(ORBIS)
+#if !defined(_WIN32)
+         flags   |= S_IRUSR | S_IWUSR;
+#else
+         flags   |= O_BINARY;
+#endif
+#endif
+         break;
+
+      default:
+         goto error;
+   }
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+#ifdef ORBIS
+      int fd = orbisOpen(path, flags, 0644);
+      if (fd < 0)
+      {
+         stream->fd = -1;
+         goto error;
+      }
+      stream->fd    = fd;
+#else
+      FILE *fp;
+#ifdef HAVE_CDROM
+      if (stream->scheme == VFS_SCHEME_CDROM)
+      {
+         retro_vfs_file_open_cdrom(stream, path, mode, hints);
+#if defined(_WIN32) && !defined(_XBOX)
+         if (!stream->fh)
+            goto error;
+#else
+         if (!stream->fp)
+            goto error;
+#endif
+      }
+      else
+#endif
+      {
+         fp = (FILE*)fopen_utf8(path, mode_str);
+
+         if (!fp)
+            goto error;
+
+         stream->fp  = fp;
+      }
+      /* Regarding setvbuf:
+       *
+       * https://www.freebsd.org/cgi/man.cgi?query=setvbuf&apropos=0&sektion=0&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
+       *
+       * If the size argument is not zero but buf is NULL, 
+       * a buffer of the given size will be allocated immediately, and
+       * released on close. This is an extension to ANSI C.
+       *
+       * Since C89 does not support specifying a NULL buffer 
+       * with a non-zero size, we create and track our own buffer for it.
+       */
+      /* TODO: this is only useful for a few platforms, 
+       * find which and add ifdef */
+#if defined(_3DS)
+      if (stream->scheme != VFS_SCHEME_CDROM)
+      {
+         stream->buf = (char*)calloc(1, 0x10000);
+         if (stream->fp)
+            setvbuf(stream->fp, stream->buf, _IOFBF, 0x10000);
+      }
+#elif !defined(PSP)
+      if (stream->scheme != VFS_SCHEME_CDROM)
+      {
+         stream->buf = (char*)calloc(1, 0x4000);
+         if (stream->fp)
+            setvbuf(stream->fp, stream->buf, _IOFBF, 0x4000);
+      }
+#endif
+#endif
+   }
+   else
+   {
+#if defined(_WIN32) && !defined(_XBOX)
+#if defined(LEGACY_WIN32)
+      char *path_local    = utf8_to_local_string_alloc(path);
+      stream->fd          = open(path_local, flags, 0);
+      if (path_local)
+         free(path_local);
+#else
+      wchar_t * path_wide = utf8_to_utf16_string_alloc(path);
+      stream->fd          = _wopen(path_wide, flags, 0);
+      if (path_wide)
+         free(path_wide);
+#endif
+#else
+      stream->fd          = open(path, flags, 0);
+#endif
+
+      if (stream->fd == -1)
+         goto error;
+
+#ifdef HAVE_MMAP
+      if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+      {
+         stream->mappos  = 0;
+         stream->mapped  = NULL;
+         stream->mapsize = retro_vfs_file_seek_internal(stream, 0, SEEK_END);
+
+         if (stream->mapsize == (uint64_t)-1)
+            goto error;
+
+         retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
+
+         stream->mapped = (uint8_t*)mmap((void*)0,
+               stream->mapsize, PROT_READ,  MAP_SHARED, stream->fd, 0);
+
+         if (stream->mapped == MAP_FAILED)
+            stream->hints &= ~RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS;
+      }
+#endif
+   }
+#ifdef ORBIS
+   stream->size = orbisLseek(stream->fd, 0, SEEK_END);
+   orbisLseek(stream->fd, 0, SEEK_SET);
+#else
+#ifdef HAVE_CDROM
+   if (stream->scheme == VFS_SCHEME_CDROM)
+   {
+      retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
+      retro_vfs_file_seek_cdrom(stream, 0, SEEK_END);
+
+      stream->size = retro_vfs_file_tell_impl(stream);
+
+      retro_vfs_file_seek_cdrom(stream, 0, SEEK_SET);
+   }
+   else
+#endif
+   {
+      retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
+      retro_vfs_file_seek_internal(stream, 0, SEEK_END);
+
+      stream->size = retro_vfs_file_tell_impl(stream);
+
+      retro_vfs_file_seek_internal(stream, 0, SEEK_SET);
+   }
+#endif
+   return stream;
+
+error:
+   retro_vfs_file_close_impl(stream);
+   return NULL;
+}
+
+int retro_vfs_file_close_impl(libretro_vfs_implementation_file *stream)
+{
+   if (!stream)
+      return -1;
+
+#ifdef HAVE_CDROM
+   if (stream->scheme == VFS_SCHEME_CDROM)
+   {
+      retro_vfs_file_close_cdrom(stream);
+      goto end;
+   }
+#endif
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+      if (stream->fp)
+         fclose(stream->fp);
+   }
+   else
+   {
+#ifdef HAVE_MMAP
+      if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+         munmap(stream->mapped, stream->mapsize);
+#endif
+   }
+
+   if (stream->fd > 0)
+   {
+#ifdef ORBIS
+      orbisClose(stream->fd);
+      stream->fd = -1;
+#else
+      close(stream->fd);
+#endif
+   }
+#ifdef HAVE_CDROM
+end:
+   if (stream->cdrom.cue_buf)
+      free(stream->cdrom.cue_buf);
+#endif
+   if (stream->buf)
+      free(stream->buf);
+
+   if (stream->orig_path)
+      free(stream->orig_path);
+
+   free(stream);
+
+   return 0;
+}
+
+int retro_vfs_file_error_impl(libretro_vfs_implementation_file *stream)
+{
+#ifdef HAVE_CDROM
+   if (stream->scheme == VFS_SCHEME_CDROM)
+      return retro_vfs_file_error_cdrom(stream);
+#endif
+#ifdef ORBIS
+   /* TODO/FIXME - implement this? */
+   return 0;
+#else
+   return ferror(stream->fp);
+#endif
+}
+
+int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream)
+{
+   if (stream)
+      return stream->size;
+   return 0;
+}
+
+int64_t retro_vfs_file_truncate_impl(libretro_vfs_implementation_file *stream, int64_t length)
+{
+   if (!stream)
+      return -1;
+
+#ifdef _WIN32
+   if (_chsize(_fileno(stream->fp), length) != 0)
+      return -1;
+#elif !defined(VITA) && !defined(PSP) && !defined(PS2) && !defined(ORBIS) && (!defined(SWITCH) || defined(HAVE_LIBNX))
+   if (ftruncate(fileno(stream->fp), (off_t)length) != 0)
+      return -1;
+#endif
+
+   return 0;
+}
+
+int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream)
+{
+   if (!stream)
+      return -1;
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+#ifdef HAVE_CDROM
+      if (stream->scheme == VFS_SCHEME_CDROM)
+         return retro_vfs_file_tell_cdrom(stream);
+#endif
+#ifdef ORBIS
+      {
+         int64_t ret = orbisLseek(stream->fd, 0, SEEK_CUR);
+         if (ret < 0)
+            return -1;
+         return ret;
+      }
+#else
+#ifdef ATLEAST_VC2005
+      /* VC2005 and up have a special 64-bit ftell */
+      return _ftelli64(stream->fp);
+#elif defined(HAVE_64BIT_OFFSETS)
+      return ftello(stream->fp);
+#else
+      return ftell(stream->fp);
+#endif
+#endif
+   }
+#ifdef HAVE_MMAP
+   /* Need to check stream->mapped because this function
+    * is called in filestream_open() */
+   if (stream->mapped && stream->hints & 
+         RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+      return stream->mappos;
+#endif
+   if (lseek(stream->fd, 0, SEEK_CUR) < 0)
+      return -1;
+
+   return 0;
+}
+
+int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream,
+      int64_t offset, int seek_position)
+{
+   int whence = -1;
+   switch (seek_position)
+   {
+      case RETRO_VFS_SEEK_POSITION_START:
+         whence = SEEK_SET;
+         break;
+      case RETRO_VFS_SEEK_POSITION_CURRENT:
+         whence = SEEK_CUR;
+         break;
+      case RETRO_VFS_SEEK_POSITION_END:
+         whence = SEEK_END;
+         break;
+   }
+
+   return retro_vfs_file_seek_internal(stream, offset, whence);
+}
+
+int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream,
+      void *s, uint64_t len)
+{
+   if (!stream || !s)
+      return -1;
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+#ifdef HAVE_CDROM
+      if (stream->scheme == VFS_SCHEME_CDROM)
+         return retro_vfs_file_read_cdrom(stream, s, len);
+#endif
+#ifdef ORBIS
+      if (orbisRead(stream->fd, s, (size_t)len) < 0)
+         return -1;
+      return 0;
+#else
+      return fread(s, 1, (size_t)len, stream->fp);
+#endif
+   }
+#ifdef HAVE_MMAP
+   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+   {
+      if (stream->mappos > stream->mapsize)
+         return -1;
+
+      if (stream->mappos + len > stream->mapsize)
+         len = stream->mapsize - stream->mappos;
+
+      memcpy(s, &stream->mapped[stream->mappos], len);
+      stream->mappos += len;
+
+      return len;
+   }
+#endif
+
+   return read(stream->fd, s, (size_t)len);
+}
+
+int64_t retro_vfs_file_write_impl(libretro_vfs_implementation_file *stream, const void *s, uint64_t len)
+{
+   if (!stream)
+      return -1;
+
+   if ((stream->hints & RFILE_HINT_UNBUFFERED) == 0)
+   {
+#ifdef ORBIS
+      if (orbisWrite(stream->fd, s, (size_t)len) < 0)
+         return -1;
+      return 0;
+#else
+      return fwrite(s, 1, (size_t)len, stream->fp);
+#endif
+   }
+
+#ifdef HAVE_MMAP
+   if (stream->hints & RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS)
+      return -1;
+#endif
+   return write(stream->fd, s, (size_t)len);
+}
+
+int retro_vfs_file_flush_impl(libretro_vfs_implementation_file *stream)
+{
+   if (!stream)
+      return -1;
+#ifdef ORBIS
+   return 0;
+#else
+   return fflush(stream->fp) == 0 ? 0 : -1;
+#endif
+}
+
+int retro_vfs_file_remove_impl(const char *path)
+{
+#if defined(_WIN32) && !defined(_XBOX)
+   /* Win32 (no Xbox) */
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
+   char *path_local    = NULL;
+#else
+   wchar_t *path_wide  = NULL;
+#endif
+   if (!path || !*path)
+      return -1;
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
+   path_local = utf8_to_local_string_alloc(path);
+
+   if (path_local)
+   {
+      int ret = remove(path_local);
+      free(path_local);
+
+      if (ret == 0)
+         return 0;
+   }
+#else
+   path_wide = utf8_to_utf16_string_alloc(path);
+
+   if (path_wide)
+   {
+      int ret = _wremove(path_wide);
+      free(path_wide);
+
+      if (ret == 0)
+         return 0;
+   }
+#endif
+   return -1;
+#elif defined(ORBIS)
+   /* Orbis
+    * TODO/FIXME - stub for now */
+   return 0;
+#else
+   if (remove(path) == 0)
+      return 0;
+   return -1;
+#endif
+}
+
+int retro_vfs_file_rename_impl(const char *old_path, const char *new_path)
+{
+#if defined(_WIN32) && !defined(_XBOX)
+   /* Win32 (no Xbox) */
+   int ret                 = -1;
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
+   char *old_path_local    = NULL;
+#else
+   wchar_t *old_path_wide  = NULL;
+#endif
+
+   if (!old_path || !*old_path || !new_path || !*new_path)
+      return -1;
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0500
+   old_path_local = utf8_to_local_string_alloc(old_path);
+
+   if (old_path_local)
+   {
+      char *new_path_local = utf8_to_local_string_alloc(new_path);
+
+      if (new_path_local)
+      {
+         if (rename(old_path_local, new_path_local) == 0)
+            ret = 0;
+         free(new_path_local);
+      }
+
+      free(old_path_local);
+   }
+#else
+   old_path_wide = utf8_to_utf16_string_alloc(old_path);
+
+   if (old_path_wide)
+   {
+      wchar_t *new_path_wide = utf8_to_utf16_string_alloc(new_path);
+
+      if (new_path_wide)
+      {
+         if (_wrename(old_path_wide, new_path_wide) == 0)
+            ret = 0;
+         free(new_path_wide);
+      }
+
+      free(old_path_wide);
+   }
+#endif
+   return ret;
+
+#elif defined(ORBIS)
+   /* Orbis */
+   /* TODO/FIXME - Stub for now */
+   if (!old_path || !*old_path || !new_path || !*new_path)
+      return -1;
+   return 0;
+
+#else
+   /* Every other platform */
+   if (!old_path || !*old_path || !new_path || !*new_path)
+      return -1;
+   return rename(old_path, new_path) == 0 ? 0 : -1;
+#endif
+}
+
+const char *retro_vfs_file_get_path_impl(
+      libretro_vfs_implementation_file *stream)
+{
+   /* should never happen, do something noisy so caller can be fixed */
+   if (!stream)
+      abort();
+   return stream->orig_path;
+}
+
+int retro_vfs_stat_impl(const char *path, int32_t *size)
+{
+   bool is_dir               = false;
+   bool is_character_special = false;
+#if defined(VITA) || defined(PSP)
+   /* Vita / PSP */
+   SceIoStat buf;
+   int dir_ret;
+   char *tmp                 = NULL;
+   size_t len                = 0;
+
+   if (!path || !*path)
+      return 0;
+
+   tmp                       = strdup(path);
+   len                       = strlen(tmp);
+   if (tmp[len-1] == '/')
+      tmp[len-1] = '\0';
+
+   dir_ret                   = sceIoGetstat(tmp, &buf);
+   free(tmp);
+   if (dir_ret < 0)
+      return 0;
+
+   if (size)
+      *size                  = (int32_t)buf.st_size;
+
+   is_dir                    = FIO_S_ISDIR(buf.st_mode);
+#elif defined(ORBIS)
+   /* Orbis */
+   int dir_ret               = 0;
+
+   if (!path || !*path)
+      return 0;
+
+   if (size)
+      *size                  = (int32_t)buf.st_size;
+
+   dir_ret                   = orbisDopen(path);
+   is_dir                    = dir_ret > 0;
+   orbisDclose(dir_ret);
+
+   is_character_special      = S_ISCHR(buf.st_mode);
+#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+   /* CellOS Lv2 */
+   CellFsStat buf;
+
+   if (!path || !*path)
+      return 0;
+   if (cellFsStat(path, &buf) < 0)
+      return 0;
+
+   if (size)
+      *size                  = (int32_t)buf.st_size;
+
+   is_dir                    = ((buf.st_mode & S_IFMT) == S_IFDIR);
+
+#elif defined(_WIN32)
+   /* Windows */
+   DWORD file_info;
+   struct _stat buf;
+#if defined(LEGACY_WIN32)
+   char *path_local          = NULL;
+#else
+   wchar_t *path_wide        = NULL;
+#endif
+
+   if (!path || !*path)
+      return 0;
+
+#if defined(LEGACY_WIN32)
+   path_local                = utf8_to_local_string_alloc(path);
+   file_info                 = GetFileAttributes(path_local);
+
+   if (!string_is_empty(path_local))
+      _stat(path_local, &buf);
+
+   if (path_local)
+      free(path_local);
+#else
+   path_wide                 = utf8_to_utf16_string_alloc(path);
+   file_info                 = GetFileAttributesW(path_wide);
+
+   _wstat(path_wide, &buf);
+
+   if (path_wide)
+      free(path_wide);
+#endif
+
+   if (file_info == INVALID_FILE_ATTRIBUTES)
+      return 0;
+
+   if (size)
+      *size = (int32_t)buf.st_size;
+
+   is_dir = (file_info & FILE_ATTRIBUTE_DIRECTORY);
+
+#elif defined(GEKKO)
+   /* On GEKKO platforms, paths cannot have
+    * trailing slashes - we must therefore
+    * remove them */
+   char *path_buf = NULL;
+   int stat_ret   = -1;
+   struct stat stat_buf;
+   size_t len;
+
+   if (string_is_empty(path))
+      return 0;
+
+   path_buf = strdup(path);
+   if (!path_buf)
+      return 0;
+
+   len = strlen(path_buf);
+   if (len > 0)
+      if (path_buf[len - 1] == '/')
+         path_buf[len - 1] = '\0';
+
+   stat_ret = stat(path_buf, &stat_buf);
+   free(path_buf);
+
+   if (stat_ret < 0)
+      return 0;
+
+   if (size)
+      *size             = (int32_t)stat_buf.st_size;
+
+   is_dir               = S_ISDIR(stat_buf.st_mode);
+   is_character_special = S_ISCHR(stat_buf.st_mode);
+
+#else
+   /* Every other platform */
+   struct stat buf;
+
+   if (!path || !*path)
+      return 0;
+   if (stat(path, &buf) < 0)
+      return 0;
+
+   if (size)
+      *size             = (int32_t)buf.st_size;
+
+   is_dir               = S_ISDIR(buf.st_mode);
+   is_character_special = S_ISCHR(buf.st_mode);
+#endif
+   return RETRO_VFS_STAT_IS_VALID | (is_dir ? RETRO_VFS_STAT_IS_DIRECTORY : 0) | (is_character_special ? RETRO_VFS_STAT_IS_CHARACTER_SPECIAL : 0);
+}
+
+#if defined(VITA)
+#define path_mkdir_error(ret) (((ret) == SCE_ERROR_ERRNO_EEXIST))
+#elif defined(PSP) || defined(PS2) || defined(_3DS) || defined(WIIU) || defined(SWITCH) || defined(ORBIS)
+#define path_mkdir_error(ret) ((ret) == -1)
+#else
+#define path_mkdir_error(ret) ((ret) < 0 && errno == EEXIST)
+#endif
+
+int retro_vfs_mkdir_impl(const char *dir)
+{
+#if defined(_WIN32)
+#ifdef LEGACY_WIN32
+   int ret        = _mkdir(dir);
+#else
+   wchar_t *dir_w = utf8_to_utf16_string_alloc(dir);
+   int       ret  = -1;
+
+   if (dir_w)
+   {
+      ret = _wmkdir(dir_w);
+      free(dir_w);
+   }
+#endif
+#elif defined(IOS)
+   int ret = mkdir(dir, 0755);
+#elif defined(VITA) || defined(PSP)
+   int ret = sceIoMkdir(dir, 0777);
+#elif defined(ORBIS)
+   int ret = orbisMkdir(dir, 0755);
+#elif defined(__QNX__)
+   int ret = mkdir(dir, 0777);
+#elif defined(GEKKO)
+   /* On GEKKO platforms, mkdir() fails if
+    * the path has a trailing slash. We must
+    * therefore remove it. */
+   int ret = -1;
+   if (!string_is_empty(dir))
+   {
+      char *dir_buf = strdup(dir);
+
+      if (dir_buf)
+      {
+         size_t len = strlen(dir_buf);
+
+         if (len > 0)
+            if (dir_buf[len - 1] == '/')
+               dir_buf[len - 1] = '\0';
+
+         ret = mkdir(dir_buf, 0750);
+
+         free(dir_buf);
+      }
+   }
+#else
+   int ret = mkdir(dir, 0750);
+#endif
+
+   if (path_mkdir_error(ret))
+      return -2;
+   return ret < 0 ? -1 : 0;
+}
+
+#ifdef VFS_FRONTEND
+struct retro_vfs_dir_handle
+#else
+struct libretro_vfs_implementation_dir
+#endif
+{
+   char* orig_path;
+#if defined(_WIN32)
+#if defined(LEGACY_WIN32)
+   WIN32_FIND_DATA entry;
+#else
+   WIN32_FIND_DATAW entry;
+#endif
+   HANDLE directory;
+   bool next;
+   char path[PATH_MAX_LENGTH];
+#elif defined(VITA) || defined(PSP)
+   SceUID directory;
+   SceIoDirent entry;
+#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+   CellFsErrno error;
+   int directory;
+   CellFsDirent entry;
+#elif defined(ORBIS)
+   int directory;
+   struct dirent entry;
+#else
+   DIR *directory;
+   const struct dirent *entry;
+#endif
+};
+
+static bool dirent_check_error(libretro_vfs_implementation_dir *rdir)
+{
+#if defined(_WIN32)
+   return (rdir->directory == INVALID_HANDLE_VALUE);
+#elif defined(VITA) || defined(PSP) || defined(ORBIS)
+   return (rdir->directory < 0);
+#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+   return (rdir->error != CELL_FS_SUCCEEDED);
+#else
+   return !(rdir->directory);
+#endif
+}
+
+libretro_vfs_implementation_dir *retro_vfs_opendir_impl(
+      const char *name, bool include_hidden)
+{
+#if defined(_WIN32)
+   unsigned path_len;
+   char path_buf[1024];
+   size_t copied      = 0;
+#if defined(LEGACY_WIN32)
+   char *path_local   = NULL;
+#else
+   wchar_t *path_wide = NULL;
+#endif
+#endif
+   libretro_vfs_implementation_dir *rdir;
+
+   /*Reject null or empty string paths*/
+   if (!name || (*name == 0))
+      return NULL;
+
+   /*Allocate RDIR struct. Tidied later with retro_closedir*/
+   rdir = (libretro_vfs_implementation_dir*)calloc(1, sizeof(*rdir));
+   if (!rdir)
+      return NULL;
+
+   rdir->orig_path       = strdup(name);
+
+#if defined(_WIN32)
+   path_buf[0]           = '\0';
+   path_len              = strlen(name);
+
+   copied                = strlcpy(path_buf, name, sizeof(path_buf));
+
+   /* Non-NT platforms don't like extra slashes in the path */
+   if (name[path_len - 1] != '\\')
+      path_buf[copied++]   = '\\';
+
+   path_buf[copied]        = '*';
+   path_buf[copied+1]      = '\0';
+
+#if defined(LEGACY_WIN32)
+   path_local              = utf8_to_local_string_alloc(path_buf);
+   rdir->directory         = FindFirstFile(path_local, &rdir->entry);
+
+   if (path_local)
+      free(path_local);
+#else
+   path_wide               = utf8_to_utf16_string_alloc(path_buf);
+   rdir->directory         = FindFirstFileW(path_wide, &rdir->entry);
+
+   if (path_wide)
+      free(path_wide);
+#endif
+
+#elif defined(VITA) || defined(PSP)
+   rdir->directory       = sceIoDopen(name);
+#elif defined(_3DS)
+   rdir->directory       = !string_is_empty(name) ? opendir(name) : NULL;
+   rdir->entry           = NULL;
+#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+   rdir->error           = cellFsOpendir(name, &rdir->directory);
+#elif defined(ORBIS)
+   rdir->directory       = orbisDopen(name);
+#else
+   rdir->directory       = opendir(name);
+   rdir->entry           = NULL;
+#endif
+
+#ifdef _WIN32
+   if (include_hidden)
+      rdir->entry.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+   else
+      rdir->entry.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
+#endif
+
+   if (rdir->directory && !dirent_check_error(rdir))
+      return rdir;
+
+   retro_vfs_closedir_impl(rdir);
+   return NULL;
+}
+
+bool retro_vfs_readdir_impl(libretro_vfs_implementation_dir *rdir)
+{
+#if defined(_WIN32)
+   if (rdir->next)
+#if defined(LEGACY_WIN32)
+      return (FindNextFile(rdir->directory, &rdir->entry) != 0);
+#else
+      return (FindNextFileW(rdir->directory, &rdir->entry) != 0);
+#endif
+
+   rdir->next = true;
+   return (rdir->directory != INVALID_HANDLE_VALUE);
+#elif defined(VITA) || defined(PSP)
+   return (sceIoDread(rdir->directory, &rdir->entry) > 0);
+#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+   uint64_t nread;
+   rdir->error = cellFsReaddir(rdir->directory, &rdir->entry, &nread);
+   return (nread != 0);
+#elif defined(ORBIS)
+   return (orbisDread(rdir->directory, &rdir->entry) > 0);
+#else
+   return ((rdir->entry = readdir(rdir->directory)) != NULL);
+#endif
+}
+
+const char *retro_vfs_dirent_get_name_impl(libretro_vfs_implementation_dir *rdir)
+{
+#if defined(_WIN32)
+#if defined(LEGACY_WIN32)
+   char *name       = local_to_utf8_string_alloc(rdir->entry.cFileName);
+#else
+   char *name       = utf16_to_utf8_string_alloc(rdir->entry.cFileName);
+#endif
+   memset(rdir->entry.cFileName, 0, sizeof(rdir->entry.cFileName));
+   strlcpy((char*)rdir->entry.cFileName, name, sizeof(rdir->entry.cFileName));
+   if (name)
+      free(name);
+   return (char*)rdir->entry.cFileName;
+#elif defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) && !defined(__PSL1GHT__) || defined(ORBIS)
+   return rdir->entry.d_name;
+#else
+   if (!rdir || !rdir->entry)
+      return NULL;
+   return rdir->entry->d_name;
+#endif
+}
+
+bool retro_vfs_dirent_is_dir_impl(libretro_vfs_implementation_dir *rdir)
+{
+#if defined(_WIN32)
+   const WIN32_FIND_DATA *entry = (const WIN32_FIND_DATA*)&rdir->entry;
+   return entry->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+#elif defined(PSP) || defined(VITA)
+   const SceIoDirent *entry     = (const SceIoDirent*)&rdir->entry;
+#if defined(PSP)
+   return (entry->d_stat.st_attr & FIO_SO_IFDIR) == FIO_SO_IFDIR;
+#elif defined(VITA)
+   return SCE_S_ISDIR(entry->d_stat.st_mode);
+#endif
+#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+   CellFsDirent *entry          = (CellFsDirent*)&rdir->entry;
+   return (entry->d_type == CELL_FS_TYPE_DIRECTORY);
+#elif defined(ORBIS)
+   const struct dirent *entry   = &rdir->entry;
+   if (entry->d_type == DT_DIR)
+      return true;
+   if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
+      return false;
+#else
+   struct stat buf;
+   char path[PATH_MAX_LENGTH];
+#if defined(DT_DIR)
+   const struct dirent *entry = (const struct dirent*)rdir->entry;
+   if (entry->d_type == DT_DIR)
+      return true;
+   /* This can happen on certain file systems. */
+   if (!(entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK))
+      return false;
+#endif
+   /* dirent struct doesn't have d_type, do it the slow way ... */
+   path[0] = '\0';
+   fill_pathname_join(path, rdir->orig_path, retro_vfs_dirent_get_name_impl(rdir), sizeof(path));
+   if (stat(path, &buf) < 0)
+      return false;
+   return S_ISDIR(buf.st_mode);
+#endif
+}
+
+int retro_vfs_closedir_impl(libretro_vfs_implementation_dir *rdir)
+{
+   if (!rdir)
+      return -1;
+
+#if defined(_WIN32)
+   if (rdir->directory != INVALID_HANDLE_VALUE)
+      FindClose(rdir->directory);
+#elif defined(VITA) || defined(PSP)
+   sceIoDclose(rdir->directory);
+#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
+   rdir->error = cellFsClosedir(rdir->directory);
+#elif defined(ORBIS)
+   orbisDclose(rdir->directory);
+#else
+   if (rdir->directory)
+      closedir(rdir->directory);
+#endif
+
+   if (rdir->orig_path)
+      free(rdir->orig_path);
+   free(rdir);
+   return 0;
+}
diff --git a/maemo/hildon.c b/maemo/hildon.c
deleted file mode 100644 (file)
index 7e9cd9f..0000000
+++ /dev/null
@@ -1,843 +0,0 @@
-#include <gtk/gtk.h>
-#include <glib.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <hildon/hildon.h>
-#include <string.h>
-#include <pthread.h>
-
-#include "../frontend/plugin_lib.h"
-#include "../frontend/main.h"
-#include "../libpcsxcore/misc.h"
-#include "../include/psemu_plugin_defs.h"
-#include "../libpcsxcore/cdrom.h"
-#include "../libpcsxcore/cdriso.h"
-#include "../plugins/dfinput/main.h"
-#include "../frontend/libpicofe/readpng.h"
-#include "maemo_common.h"
-#include <libosso.h>
-#include <dbus/dbus.h>
-
-#define X_RES           800
-#define Y_RES           480
-#define D_WIDTH                        640
-#define D_HEIGHT               480
-
-#define CALL_SIGNAL_IF "com.nokia.csd.Call"
-#define CALL_SIGNAL_PATH "/com/nokia/csd/call"
-#define CALL_INCOMING_SIG "Coming"
-
-#define DBUS_RULE_CALL_INCOMING "type='signal',interface='" CALL_SIGNAL_IF \
-                                "',path='" CALL_SIGNAL_PATH \
-                                "',member='" CALL_INCOMING_SIG "'"
-
-osso_context_t* osso = NULL;
-int bRunning = TRUE;
-extern int bKeepDisplayOn;
-extern int bAutosaveOnExit;
-extern int cornerActions[4];
-extern char keys_config_file[MAXPATHLEN];
-static pthread_t display_thread = (pthread_t)0;
-int g_layer_x = (X_RES - D_WIDTH) / 2;
-int g_layer_y = (Y_RES - D_HEIGHT) / 2;
-int g_layer_w = D_WIDTH, g_layer_h = D_HEIGHT;
-
-static GdkImage *image;
-static HildonAnimationActor *actor;
-static GtkWidget *window, *drawing = NULL;
-
-static int pl_buf_w, pl_buf_h;
-int keymap[65536];
-int direction_keys[4];
-
-// map psx4m compatible keymap to PSX keys
-static const unsigned char keymap2[14] = {
-       DKEY_LEFT,   // 0
-       DKEY_RIGHT,
-       DKEY_UP,
-       DKEY_DOWN,
-       DKEY_CIRCLE,
-       DKEY_CROSS,  // 5
-       DKEY_TRIANGLE,
-       DKEY_SQUARE,
-       DKEY_SELECT,
-       DKEY_START,
-       DKEY_L1,     // 10
-       DKEY_R1,
-       DKEY_L2,
-       DKEY_R2,
-};
-
-void hildon_quit()
-{
-       maemo_finish();
-       gtk_main_quit();
-       exit(0);
-}
-
-gdouble press_x = -1;
-gdouble press_y = -1;
-
-int maemo_x11_update_keys();
-void show_notification(char* text);
-
-void change_slot(int delta)
-{
-       state_slot += delta;
-       if (state_slot > 9)
-               state_slot = 0;
-       else if (state_slot < 0)
-               state_slot = 9;
-       char message[50];
-       sprintf(message,"Savestate slot: %i",state_slot + 1);
-       show_notification(message);
-}
-
-void save(int state_slot)
-{
-       emu_save_state(state_slot);
-       char buf[MAXPATHLEN];
-       if (image && image->mem){
-               sprintf (buf,"/opt/maemo/usr/games/screenshots%s.%3.3d",file_name,state_slot);
-               writepng(buf, image->mem, pl_buf_w,pl_buf_h);
-       }
-       char message[50];
-       sprintf(message,"Saved savestate slot: %i",state_slot + 1);
-       show_notification(message);
-}
-
-void quit()
-{
-       if (bAutosaveOnExit){
-               show_notification("Autosaving");
-               emu_save_state(99);
-               char buf[MAXPATHLEN];
-               if (image && image->mem){
-                       sprintf (buf,"/opt/maemo/usr/games/screenshots%s.%3.3d",file_name,99);
-                       writepng(buf, image->mem, pl_buf_w,pl_buf_h);
-               }
-       }
-       hildon_quit();
-}
-
-int show_confirmbox(char* text)
-{
-       if (!window)
-               return TRUE;
-
-       GtkWidget *dialog;
-       dialog = gtk_message_dialog_new (GTK_WINDOW(window),
-                                                                        GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                                        GTK_MESSAGE_QUESTION,
-                                                                        GTK_BUTTONS_YES_NO,
-                                                                        text);
-       gint result = gtk_dialog_run (GTK_DIALOG (dialog));
-       gtk_widget_destroy (dialog);
-       if (result == GTK_RESPONSE_YES)
-               return TRUE;
-       return FALSE;
-}
-
-static void
-window_button_proxy(GtkWidget *widget,
-                                   GdkEventButton *event,
-                                   gpointer user_data)
-{
-       int corner = -1;
-       int sens = 100;
-
-       switch (event->type){
-       case GDK_BUTTON_PRESS:
-               //printf("GDK_BUTTON_PRESS: x=%f y=%f\n", event->x, event->y);
-               press_x = event->x;
-               press_y = event->y;
-               break;
-       case GDK_BUTTON_RELEASE:
-               //printf("GDK_BUTTON_RELEASE: x=%f y=%f\n", event->x, event->y);
-               if (press_x < sens && press_y < sens && event->x < sens && event->y < sens)
-                       corner = 0;
-               else if (press_x > 800 - sens && press_y < sens && event->x > 800 - sens && event->y < sens)
-                       corner = 1;
-               else if (press_x > 800 - sens && press_y > 480 - sens && event->x > 800 - sens && event->y > 480 - sens)
-                       corner = 2;
-               else if (press_x < sens && press_y > 480 - sens && event->x < sens && event->y > 480 - sens)
-                       corner = 3;
-
-               press_x = -1;
-               press_y = -1;
-               break;
-       default:
-               break;
-       }
-
-       if (corner >= 0){
-               switch (cornerActions[corner]){
-                       case 1:
-                               if (show_confirmbox("Save savestate?"))
-                                       save(state_slot);
-                               break;
-                       case 2:
-                               if (show_confirmbox("Load savestate?"))
-                                       emu_load_state(state_slot);
-                               break;
-                       case 3:
-                               change_slot(1);
-                               break;
-                       case 4:
-                               change_slot(-1);
-                               break;
-                       case 5:
-                               if (show_confirmbox("Quit?"))
-                                       quit();
-                               break;
-               }
-       }
-}
-
-static void *displayThread(void *arg)
-{
-       DBusConnection* system_bus = (DBusConnection*)osso_get_sys_dbus_connection(osso);
-       DBusMessage* msg = dbus_message_new_method_call("com.nokia.mce",
-                                                                                                   "/com/nokia/mce/request",
-                                                                                                   "com.nokia.mce.request",
-                                                                                                   "req_display_blanking_pause");
-       if (msg && system_bus) {
-               bRunning = TRUE;
-               while (bRunning) {
-                       dbus_connection_send(system_bus, msg, NULL);
-                       dbus_connection_flush(system_bus);
-                       int i = 0;
-                       for (i=0; i<8; i++){
-                               usleep(500000);
-                               if (!bRunning)
-                                       break;
-                       }
-               }
-               dbus_message_unref(msg);
-       }
-
-       pthread_exit(0);
-       return NULL;
-}
-
-void show_notification(char* text)
-{
-       if (window){
-               GtkWidget* banner = hildon_banner_show_information(GTK_WIDGET(window), NULL, text);
-               hildon_banner_set_timeout(HILDON_BANNER(banner), 3000);
-       }else{
-               DBusConnection* session_bus = (DBusConnection*)osso_get_dbus_connection(osso);
-               DBusMessageIter args;
-               DBusMessage*msg = dbus_message_new_method_call("org.freedesktop.Notifications",
-                                                                                                          "/org/freedesktop/Notifications",
-                                                                                                          "org.freedesktop.Notifications",
-                                                                                                          "SystemNoteInfoprint");
-               if (msg) {
-                       dbus_message_iter_init_append(msg, &args);
-                       char* param = text;
-                       if (dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &param)) {
-                               dbus_connection_send(session_bus, msg, NULL);
-                               dbus_connection_flush(session_bus);
-                       }
-                       dbus_message_unref(msg);
-               }
-       }
-}
-
-void show_messagebox(char* text)
-{
-       if (!window)
-               return;
-
-       GtkWidget *dialog;
-       dialog = gtk_message_dialog_new (GTK_WINDOW(window),
-                                                                        GTK_DIALOG_DESTROY_WITH_PARENT,
-                                                                        GTK_MESSAGE_INFO,
-                                                                        GTK_BUTTONS_OK,
-                                                                        text);
-       gtk_dialog_run (GTK_DIALOG (dialog));
-       gtk_widget_destroy (dialog);
-}
-
-#include <hildon/hildon-file-chooser-dialog.h>
-void change_disc()
-{
-       GtkWidget *dialog;
-       dialog = hildon_file_chooser_dialog_new (GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_OPEN);
-    gtk_window_set_title (GTK_WINDOW (dialog), "Change disc");
-
-       char currentFile[MAXPATHLEN];
-       strcpy(currentFile, GetIsoFile());
-       if (strlen(currentFile))
-               gtk_file_chooser_set_filename (GTK_FILE_CHOOSER(dialog), currentFile);
-       else
-               gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), "/home/user/MyDocs/");
-
-       GtkFileFilter *filter=gtk_file_filter_new();
-       gtk_file_filter_add_pattern (filter,"*.bin");
-       gtk_file_filter_add_pattern (filter,"*.BIN");
-       gtk_file_filter_add_pattern (filter,"*.iso");
-       gtk_file_filter_add_pattern (filter,"*.ISO");
-       gtk_file_filter_add_pattern (filter,"*.img");
-       gtk_file_filter_add_pattern (filter,"*.IMG");
-       gtk_file_filter_add_pattern (filter,"*.z");
-       gtk_file_filter_add_pattern (filter,"*.Z");
-       gtk_file_filter_add_pattern (filter,"*.znx");
-       gtk_file_filter_add_pattern (filter,"*.ZNX");
-       gtk_file_filter_add_pattern (filter,"*.pbp");
-       gtk_file_filter_add_pattern (filter,"*.PBP");
-       gtk_file_filter_add_pattern (filter,"*.mdf");
-       gtk_file_filter_add_pattern (filter,"*.MDF");
-       gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog),filter);
-
-       if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
-               char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
-
-               //if (strcmp(filename, currentFile)) {
-                       CdromId[0] = '\0';
-                       CdromLabel[0] = '\0';
-
-                       set_cd_image(filename);
-                       if (ReloadCdromPlugin() < 0)
-                               printf("Failed to load cdr plugin\n");
-
-                       if (CDR_open() < 0)
-                               printf("Failed to open cdr plugin\n");
-
-                       strcpy(file_name, strrchr(filename,'/'));
-
-                       SetCdOpenCaseTime(time(NULL) + 3);
-                       LidInterrupt();
-               //}
-               g_free (filename);
-       }
-
-       gtk_widget_destroy (dialog);
-}
-
-void change_multi_disc()
-{
-    HildonDialog* window = HILDON_DIALOG(hildon_dialog_new());
-    gtk_window_set_title (GTK_WINDOW (window), "Change disc");
-    gtk_window_set_default_size(GTK_WINDOW (window), 480, 300);
-
-    GtkWidget* sw = hildon_pannable_area_new ();
-    gtk_box_pack_start (GTK_BOX(GTK_DIALOG(window)->vbox), sw, TRUE, TRUE, 0);
-
-    GtkWidget* tree_view = hildon_gtk_tree_view_new (HILDON_UI_MODE_EDIT);
-    gtk_widget_set_name (tree_view, "fremantle-widget");
-
-    gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tree_view), TRUE);
-
-    int i;
-    GtkListStore *store = gtk_list_store_new (1, G_TYPE_STRING);
-    for (i = 0; i < cdrIsoMultidiskCount; i++) {
-        gchar *str;
-
-        str = g_strdup_printf ("Disc %d", i+1);
-        gtk_list_store_insert_with_values (store, NULL, i, 0, str, -1);
-        g_free (str);
-    }
-    GtkTreeModel* model =  GTK_TREE_MODEL (store);
-
-    gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), model);
-    g_object_unref (model);
-
-    GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
-    gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
-
-    GtkCellRenderer* renderer = gtk_cell_renderer_text_new ();
-    g_object_set (renderer,
-                  "xalign", 0.5,
-                  "weight", PANGO_WEIGHT_NORMAL,
-                  NULL);
-
-    gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view),
-                                                 0, "Column 0",
-                                                 renderer,
-                                                 "text", 0,
-                                                 NULL);
-
-    char current[5];
-    sprintf(current, "%i", cdrIsoMultidiskSelect);
-    GtkTreePath* path = gtk_tree_path_new_from_string(current);
-    gtk_tree_selection_select_path (selection, path);
-    gtk_tree_path_free(path);
-
-    gtk_widget_set_size_request (tree_view, 480, 800);
-    gtk_container_add (GTK_CONTAINER (sw), tree_view);
-
-    hildon_dialog_add_button (HILDON_DIALOG(window), GTK_STOCK_OK, GTK_RESPONSE_ACCEPT);
-
-    gtk_widget_show_all (GTK_WIDGET(window));
-    gint result = gtk_dialog_run (GTK_DIALOG (window));
-    if (result == GTK_RESPONSE_ACCEPT) {
-      GtkTreeModel* model;
-      GtkTreeIter iter;
-      GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
-      if (gtk_tree_selection_get_selected(selection, &model, &iter)){
-           GtkTreePath* path = gtk_tree_model_get_path(model , &iter);
-               int* i = gtk_tree_path_get_indices(path) ;
-
-               cdrIsoMultidiskSelect = *i;
-               CdromId[0] = '\0';
-               CdromLabel[0] = '\0';
-
-               CDR_close();
-               if (CDR_open() < 0) {
-                       printf("Failed to load cdr plugin\n");
-                       return;
-               }
-
-               SetCdOpenCaseTime(time(NULL) + 3);
-               LidInterrupt();
-      }
-    }
-       gtk_widget_destroy(GTK_WIDGET(window));
-}
-
-static DBusHandlerResult on_msg_recieved(DBusConnection* connection G_GNUC_UNUSED, DBusMessage* message, void* data)
-{
-       const char* path = dbus_message_get_path(message);
-       if (path && g_str_equal(path, CALL_SIGNAL_PATH)){
-               const char* mbr = dbus_message_get_member(message);
-               if (mbr && g_str_equal(mbr, CALL_INCOMING_SIG))
-                       show_messagebox("Paused");
-       }
-
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static void
-window_key_proxy(GtkWidget *widget,
-                    GdkEventKey *event,
-                    gpointer user_data)
-{
-       key_press_event(event->hardware_keycode, event->type == GDK_KEY_PRESS ? 1 : (event->type == GDK_KEY_RELEASE ? 2 : 0) );
-}
-
-int last_key_pressed = 0;
-inline void key_press_event(int key2,int type)
-{
-       int psxkey1 = -1, psxkey2 = -1;
-       int key=keymap[key2];
-
-       if (key < 0)
-               return;
-
-       if (type == 1 && key2 == last_key_pressed)
-               return;
-       last_key_pressed = type == 1 ? key2 : 0;
-
-       //printf("Key: %i %s\n", key2, type == 1 ? "Pressed" : (type == 2 ? "Released" : "Unknown"));
-       if (key < ARRAY_SIZE(keymap2)){
-               psxkey1 = keymap2[key];
-       }else switch (key) {
-               case 14:
-                       quit();
-                       break;
-               case 15:
-                       psxkey1 = DKEY_UP;
-                       psxkey2 = DKEY_LEFT;
-                       break;
-               case 16:
-                       psxkey1 = DKEY_UP;
-                       psxkey2 = DKEY_RIGHT;
-                       break;
-               case 17:
-                       psxkey1 = DKEY_DOWN;
-                       psxkey2 = DKEY_LEFT;
-                       break;
-               case 18:
-                       psxkey1 = DKEY_DOWN;
-                       psxkey2 = DKEY_RIGHT;
-                       break;
-               case 19:
-                       if (type == 1)
-                               save(state_slot);
-                       return;
-               case 20:
-                       if (type == 1)
-                               emu_load_state(state_slot);
-                       return;
-               case 21:
-                       if (type == 1)
-                               change_slot(1);
-                       return;
-               case 22:
-                       if (type == 1)
-                               change_slot(-1);
-                       return;
-               case 23:
-                       if (type == 1){
-                               if (cdrIsoMultidiskCount > 1)
-                                       change_multi_disc();
-                               else
-                                       change_disc();
-                       }
-                       return;
-       }
-
-       if (in_type1 == PSE_PAD_TYPE_GUNCON){
-               if (type == 1) {
-                       switch (psxkey1){
-                               case DKEY_CROSS:
-                                       in_state_gun |= SACTION_GUN_A;
-                                       break;          
-                               case DKEY_CIRCLE:
-                                       in_state_gun |= SACTION_GUN_B;
-                                       break;          
-                               case DKEY_TRIANGLE:
-                                       in_state_gun |= SACTION_GUN_TRIGGER2;
-                                       break;          
-                               case DKEY_SQUARE:
-                                       in_state_gun |= SACTION_GUN_TRIGGER;
-                                       break;          
-                       }
-               }else if (type == 2) {
-                       switch (psxkey1){
-                               case DKEY_CROSS:
-                                       in_state_gun &= ~SACTION_GUN_A;
-                                       break;          
-                               case DKEY_CIRCLE:
-                                       in_state_gun &= ~SACTION_GUN_B;
-                                       break;          
-                               case DKEY_TRIANGLE:
-                                       in_state_gun &= ~SACTION_GUN_TRIGGER2;
-                                       break;          
-                               case DKEY_SQUARE:
-                                       in_state_gun &= ~SACTION_GUN_TRIGGER;
-                                       break;          
-                       }
-               }
-       }else{
-               if (type == 1) {
-               if (psxkey1 >= 0)
-                       in_keystate |= 1 << psxkey1;
-               if (psxkey2 >= 0)
-                       in_keystate |= 1 << psxkey2;
-
-                       if (in_type1 == PSE_PAD_TYPE_ANALOGPAD){
-                               switch(psxkey1){
-                                       case DKEY_LEFT:
-                                               in_a1[0] = 0;
-                                               break;
-                                       case DKEY_RIGHT:
-                                               in_a1[0] = 255;
-                                               break;
-                                       case DKEY_UP:
-                                               in_a1[1] = 0;
-                                               break;
-                                       case DKEY_DOWN:
-                                               in_a1[1] = 255;
-                                               break;
-                               }
-       }
-               }
-               else if (type == 2) {
-               if (psxkey1 >= 0)
-                       in_keystate &= ~(1 << psxkey1);
-               if (psxkey2 >= 0)
-                       in_keystate &= ~(1 << psxkey2);
-
-                       if (in_type1 == PSE_PAD_TYPE_ANALOGPAD){
-                               switch(psxkey1){
-                                       case DKEY_LEFT:
-                                       case DKEY_RIGHT:
-                                               in_a1[0] = 127;
-                                               break;
-                                       case DKEY_UP:
-                                       case DKEY_DOWN:
-                                               in_a1[1] = 127;
-                                               break;
-                               }
-                       }
-               emu_set_action(SACTION_NONE);
-       }
-       }
-}
-
-void plat_finish()
-{
-       hildon_quit();
-}
-
-void set_accel_multipliers()
-{
-       accelOptions.xMultiplier = 255.0 / ( (accelOptions.maxValue - accelOptions.sens) * 2.0);
-       accelOptions.yMultiplier = 255.0 / ( (accelOptions.maxValue - accelOptions.sens) * 2.0);
-}
-
-#include <gdk/gdkx.h>
-int maemo_init(int *argc, char ***argv)
-{
-       osso = osso_initialize("pcsxrearmed", PACKAGE_VERSION, FALSE, NULL);
-
-       DBusConnection* system_bus = (DBusConnection*)osso_get_sys_dbus_connection(osso);
-    dbus_bus_add_match(system_bus, DBUS_RULE_CALL_INCOMING, NULL);
-       dbus_connection_add_filter(system_bus, on_msg_recieved, NULL, NULL);
-
-       FILE* pFile;
-       pFile = fopen(keys_config_file, "r");
-       if (pFile == NULL){
-               fprintf(stderr, "Error opening keys config file %s\n", keys_config_file);
-               return 1;
-       }
-       printf("Keys config read from %s\n", keys_config_file);
-
-       int ch;
-       int i=0;
-       for (i=0;i<65536;i++)
-               keymap[i]=-1;
-       if (NULL != pFile) {
-               for(i=0;i<24;i++){
-                       fscanf(pFile, "%i",&ch);
-                       keymap[ch]=i;
-                       if (i < 4)
-                               direction_keys[i] = ch;
-               }
-               fclose(pFile);
-       }
-       
-       switch (in_type1){
-               case PSE_PAD_TYPE_GUNCON:
-                       memset(cornerActions, 0, sizeof(cornerActions));
-                       printf("Controller set to GUNCON (SLPH-00034)\n");
-                       break;
-               case PSE_PAD_TYPE_STANDARD:
-                       printf("Controller set to standard (SCPH-1080)\n");
-                       break;
-               case PSE_PAD_TYPE_ANALOGPAD:
-                       printf("Controller set to analog (SCPH-1150)\n");
-                       break;  
-       }
-
-       if (in_enable_vibration)
-               printf("Vibration enabled\n");
-
-       if (!(g_maemo_opts&8)){
-       gtk_init (argc, argv);
-
-       window = hildon_stackable_window_new ();
-       gtk_widget_realize (window);
-       gtk_window_fullscreen (GTK_WINDOW(window));
-
-               if (cornerActions[0] + cornerActions[1] + cornerActions[2] + cornerActions[3] > 0){
-                       g_signal_connect (G_OBJECT (window), "button_release_event",
-                                               G_CALLBACK (window_button_proxy), NULL);
-                       g_signal_connect (G_OBJECT (window), "button_press_event",
-                                               G_CALLBACK (window_button_proxy), NULL);
-               }
-
-       g_signal_connect (G_OBJECT (window), "key-press-event",
-                               G_CALLBACK (window_key_proxy), NULL);
-       g_signal_connect (G_OBJECT (window), "key-release-event",
-                               G_CALLBACK (window_key_proxy), NULL);
-       g_signal_connect (G_OBJECT (window), "delete_event",
-                               G_CALLBACK (hildon_quit), NULL);
-       gtk_widget_add_events (window,
-                               GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
-
-       actor = HILDON_ANIMATION_ACTOR (hildon_animation_actor_new());
-       if (g_maemo_opts & 2)
-               hildon_animation_actor_set_position (actor, 0, 0 );
-       else
-               hildon_animation_actor_set_position (actor, (X_RES - D_WIDTH)/2, (Y_RES - D_HEIGHT)/2 );
-       hildon_animation_actor_set_parent (actor, GTK_WINDOW (window));
-
-       drawing = gtk_image_new ();
-
-       gtk_container_add (GTK_CONTAINER (actor), drawing);
-
-       gtk_widget_show_all (GTK_WIDGET (actor));
-       gtk_widget_show_all (GTK_WIDGET (window));
-       }else{
-               gtk_init (argc, argv);
-               /*GdkScreen* scr = gdk_screen_get_default();
-               window = GTK_WIDGET(gdk_screen_get_root_window(scr));
-               if (!window)
-                       window = GTK_WIDGET(gdk_get_default_root_window());*/
-       }
-
-       set_accel_multipliers();
-
-       if (bKeepDisplayOn){
-               if (pthread_create(&display_thread, NULL, displayThread, NULL))
-                       printf("Failed to create display thread.\n");           
-       }
-
-       pl_rearmed_cbs.only_16bpp = 1;
-       return 0;
-}
-
-void maemo_finish()
-{
-       if (display_thread > 0){
-               bRunning = FALSE;
-               pthread_join(display_thread, NULL);
-       }
-
-       if (osso){
-               osso_deinitialize(osso);
-               osso = NULL;
-       }
-       printf("Exiting\n");
-}
-
-void menu_loop(void)
-{
-}
-
-void *plat_gvideo_set_mode(int *w_, int *h_, int *bpp_)
-{
-       int w = *w_, h = *h_;
-
-       if (g_maemo_opts&8) return pl_vout_buf;
-       //printf("Setting video mode %ix%i\n", w, h);
-
-       if (w <= 0 || h <= 0)
-               return pl_vout_buf;
-
-       if (image) gdk_image_destroy(image);
-       image = gdk_image_new( GDK_IMAGE_FASTEST, gdk_visual_get_system(), w, h );
-
-       pl_vout_buf = (void *) image->mem;
-
-       gtk_image_set_from_image (GTK_IMAGE(drawing), image, NULL);
-
-       gtk_window_resize (GTK_WINDOW (actor), w, h);
-       if (g_maemo_opts & 2)
-               hildon_animation_actor_set_scale (actor,
-                               (gdouble)800 / (gdouble)w,
-                               (gdouble)480 / (gdouble)h
-                               );
-       else
-               hildon_animation_actor_set_scale (actor,
-                               (gdouble)D_WIDTH / (gdouble)w,
-                               (gdouble)D_HEIGHT / (gdouble)h
-                               );
-       pl_buf_w=w;pl_buf_h=h;
-       return pl_vout_buf;
-}
-
-void *plat_gvideo_flip(void)
-{
-       if (!(g_maemo_opts&8))
-               gtk_widget_queue_draw(drawing);
-
-       // process accelometer
-       if (g_maemo_opts & 4) {
-               float x, y, z;
-               FILE* f = fopen( "/sys/class/i2c-adapter/i2c-3/3-001d/coord", "r" );
-               if( !f ) {printf ("err in accel"); exit(1);}
-               fscanf( f, "%f %f %f", &x, &y, &z );
-               fclose( f );
-
-               if (in_type1 == PSE_PAD_TYPE_ANALOGPAD){
-                       if (x > accelOptions.maxValue) x = accelOptions.maxValue;
-                       else if (x < -accelOptions.maxValue) x = -accelOptions.maxValue;
-
-                       const int maxValue = accelOptions.maxValue - accelOptions.sens;
-                       if(x > accelOptions.sens){
-                               x -= accelOptions.sens;
-                               in_a1[0] = (-x + maxValue ) *  accelOptions.xMultiplier;
-                       }else if (x < -accelOptions.sens){
-                               x += accelOptions.sens;
-                               in_a1[0] = (-x + maxValue ) *  accelOptions.xMultiplier;
-                       }else in_a1[0] = 127;
-
-                       y += accelOptions.y_def;
-                       if (y > accelOptions.maxValue) y = accelOptions.maxValue;
-                       else if (y < -accelOptions.maxValue) y = -accelOptions.maxValue;
-
-                       if(y > accelOptions.sens){
-                               y -= accelOptions.sens;
-                               in_a1[1] = (-y + maxValue ) *  accelOptions.yMultiplier;
-                       }else if (y < -accelOptions.sens){
-                               y += accelOptions.sens;
-                               in_a1[1] = (-y + maxValue ) *  accelOptions.yMultiplier;
-                       }else in_a1[1] = 127;
-
-                       //printf("x: %i y: %i\n", in_a1[0], in_a1[1]);
-               }else{
-                       if( x > accelOptions.sens ) in_keystate |= 1 << DKEY_LEFT;
-                       else if( x < -accelOptions.sens ) in_keystate |= 1 << DKEY_RIGHT;
-               else {in_keystate &= ~(1 << DKEY_LEFT);in_keystate &= ~(1 << DKEY_RIGHT);}
-
-                       y += accelOptions.y_def;
-                       if( y > accelOptions.sens )in_keystate |= 1 << DKEY_UP;
-                       else if( y < -accelOptions.sens ) in_keystate |= 1 << DKEY_DOWN;
-               else {in_keystate &= ~(1 << DKEY_DOWN);in_keystate &= ~(1 << DKEY_UP);}
-               }
-       }
-
-       return pl_vout_buf;
-}
-
-// for frontend/plugin_lib.c
-void update_input(void)
-{
-       if (g_maemo_opts & 8)
-               maemo_x11_update_keys();
-       else {
-               /* process GTK+ events */
-               while (gtk_events_pending())
-                       gtk_main_iteration();
-       }
-}
-
-int omap_enable_layer(int enabled)
-{
-       return 0;
-}
-
-void menu_notify_mode_change(int w, int h, int bpp)
-{
-}
-
-void *plat_prepare_screenshot(int *w, int *h, int *bpp)
-{
-       return NULL;
-}
-
-void plat_step_volume(int is_up)
-{
-}
-
-void plat_trigger_vibrate(int pad, int low, int high)
-{
-       const int vDuration = 10;
-
-       DBusConnection* system_bus = (DBusConnection*)osso_get_sys_dbus_connection(osso);
-       DBusMessageIter args;
-       DBusMessage*msg = dbus_message_new_method_call("com.nokia.mce",
-                                                                                                  "/com/nokia/mce/request",
-                                                                                                  "com.nokia.mce.request",
-                                                                                                  "req_start_manual_vibration");
-       if (msg) {
-               dbus_message_iter_init_append(msg, &args);
-               // FIXME: somebody with hardware should tune this
-               int speed = high; // is_strong ? 200 : 150;
-               int duration = vDuration;
-               if (dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &speed)) {
-                       if (dbus_message_iter_append_basic(&args, DBUS_TYPE_INT32, &duration)) {
-                               dbus_connection_send(system_bus, msg, NULL);
-                               //dbus_connection_flush(system_bus);
-                       }
-               }
-               dbus_message_unref(msg);
-       }
-}
-
-void plat_minimize(void)
-{
-}
-
-void plat_gvideo_close(void)
-{
-}
-
-void plat_gvideo_open(int is_pal)
-{
-}
diff --git a/maemo/maemo_common.h b/maemo/maemo_common.h
deleted file mode 100644 (file)
index ace0bfd..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-int maemo_init(int *argc, char ***argv);
-void maemo_finish();
-
-extern char file_name[MAXPATHLEN];
-extern int g_maemo_opts;
-
-extern inline void key_press_event(int key,int type);
-
-typedef struct
-{ 
-       int sens;
-       int y_def;
-       float maxValue;
-       float xMultiplier;
-       float yMultiplier;
-} accel_option;
-
-extern accel_option accelOptions;
diff --git a/maemo/maemo_xkb.c b/maemo/maemo_xkb.c
deleted file mode 100644 (file)
index 52af2ca..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2009, Wei Mingzhi <whistler@openoffice.org>.
- * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/keysym.h>
-#include <X11/XKBlib.h>
-
-#include "../frontend/main.h"
-#include "../frontend/plugin_lib.h"
-
-static Atom wmprotocols, wmdelwindow;
-static int initialized;
-
-
-
-static void InitKeyboard(void) {
-       Display *disp = (Display *)gpuDisp;
-       if (disp){
-               wmprotocols = XInternAtom(disp, "WM_PROTOCOLS", 0);
-               wmdelwindow = XInternAtom(disp, "WM_DELETE_WINDOW", 0);
-               XkbSetDetectableAutoRepeat(disp, 1, NULL);
-       }
-}
-
-static void DestroyKeyboard(void) {
-       Display *disp = (Display *)gpuDisp;
-       if (disp)
-               XkbSetDetectableAutoRepeat(disp, 0, NULL);
-}
-#include "maemo_common.h"
-
-int maemo_x11_update_keys() {
-
-       XEvent                                  evt;
-       XClientMessageEvent             *xce;
-       int leave = 0;
-       Display *disp = (Display *)gpuDisp;
-       
-       if (!disp)
-               return 0;
-               
-       if (!initialized) {
-               initialized++;
-               InitKeyboard();
-       }
-
-       while (XPending(disp)>0) {
-               XNextEvent(disp, &evt);
-               switch (evt.type) {
-                       case KeyPress:
-                       case KeyRelease:
-                               key_press_event(evt.xkey.keycode, evt.type==KeyPress ? 1 : (evt.type==KeyRelease ? 2 : 0) );
-                               break;
-
-                       case ClientMessage:
-                               xce = (XClientMessageEvent *)&evt;
-                               if (xce->message_type == wmprotocols && (Atom)xce->data.l[0] == wmdelwindow)
-                                       leave = 1;
-                               break;
-               }
-       }
-
-       if (leave) {
-               DestroyKeyboard();
-               exit(1);
-       }
-
-       return 0;
-}
diff --git a/maemo/main.c b/maemo/main.c
deleted file mode 100644 (file)
index c382c51..0000000
+++ /dev/null
@@ -1,418 +0,0 @@
-/*
- * (C) notaz, 2010-2011
- *
- * This work is licensed under the terms of the GNU GPLv2 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <unistd.h>
-
-#include "../frontend/main.h"
-#include "../frontend/menu.h"
-#include "../frontend/plugin.h"
-#include "../frontend/plugin_lib.h"
-#include "../libpcsxcore/misc.h"
-#include "../libpcsxcore/cdriso.h"
-#include "../libpcsxcore/new_dynarec/new_dynarec.h"
-#include "../plugins/dfinput/main.h"
-#include "../plugins/dfsound/spu_config.h"
-#include "maemo_common.h"
-
-extern int in_enable_vibration;
-extern int cycle_multiplier;
-extern int in_type1, in_type2;
-
-accel_option accelOptions;
-int ready_to_go, g_emu_want_quit, g_emu_resetting;
-int g_menuscreen_w, g_menuscreen_h;
-int g_scaler, soft_filter;
-int g_opts = 0;
-int g_maemo_opts;
-int cornerActions[4] = {0,0,0,0};
-int bKeepDisplayOn = FALSE;
-int bAutosaveOnExit = FALSE;
-char file_name[MAXPATHLEN];
-char keys_config_file[MAXPATHLEN] = "/opt/psx4m/keys";
-
-enum sched_action emu_action;
-void do_emu_action(void);
-
-static void ChangeWorkingDirectory(char *exe)
-{
-       char exepath[1024];
-       char *s;
-       snprintf(exepath, sizeof(exepath), "%s", exe);
-       s = strrchr(exepath, '/');
-       if (s != NULL) {
-               *s = '\0';
-               chdir(exepath);
-       }
-}
-
-void PrintHelp()
-{
-       printf("PCSX-ReARMed version %s for Maemo\n\n", PACKAGE_VERSION);
-
-       printf("Usage:\n");
-       printf("  pcsx [options] -cdfile FILE\n\n");
-
-       printf("Options:\n");
-       printf("  -help          : This help\n");
-       printf("  -disc VALUE    : Disc number for multi discs images\n");
-       printf("  -fullscreen    : Run fullscreen\n");
-       printf("  -frameskip     : Frameskip\n");
-       printf("                   -1=Auto (Default)\n");
-       printf("                    0=Disabled\n");
-       printf("                    1=Set to 1\n");
-       printf("                    ...\n");
-       printf("  -autosave      : Enable auto save on exit\n");
-       printf("  -accel         : Enable accelerometer\n");
-       printf("  -analog        : Use analog pad for accel\n");
-       printf("  -vibration     : Activate vibration\n");
-       printf("  -sens VALUE    : Set accelerometer sens [0-1000]\n");
-    printf("                   (Default 150)\n");
-       printf("  -ydef VALUE    : Set accelerometer y zero [0-1000]\n");
-    printf("                   (Default 500)\n");
-       printf("  -max VALUE     : Set accelerometer max value[0-1000]\n");
-    printf("                   (Default 500)\n");
-       printf("  -nosound       : No sound output\n");
-       printf("  -bdir PATH     : Set the bios path\n");
-       printf("  -pdir PATH     : Set the plugins path\n");
-       printf("  -bios          : Set the bios\n");
-       printf("  -cdda          : Disable CD Audio for a performance boost\n");
-       printf("  -xa            : Disables XA sound, which can sometimes\n");
-       printf("                   improve performance\n");
-       printf("  -sio           : SIO IRQ Always Enabled\n");
-       printf("  -spuirq        : SPU IRQ Always Enabled\n");
-       printf("  -fps           : Show fps\n");
-       printf("  -cpu           : Show CPU load\n");
-       printf("  -spu           : Show SPU channels\n");
-       printf("  -nofl          : Disable Frame Limiter\n");
-       printf("  -mcd1 FILE     : Set memory card 1 file\n");
-       printf("  -mcd2 FILE     : Set memory card 2 file\n");
-       printf("  -region VALUE  : Set PSX region\n");
-       printf("                   -1=Auto (Default)\n");
-       printf("                    0=NTSC\n");
-       printf("                    1=PAL\n");
-       printf("  -cpuclock VALUE: PSX CPU clock %% [1-500]\n");
-    printf("                   (Default 50)\n");
-       printf("  -displayon     : Prevent display from blanking\n");
-    printf("                   (Default disabled)\n");
-       printf("  -keys FILE     : File with keys configuration\n");
-    printf("                   (Default /opt/psx4m/keys)\n");
-       printf("  -corners VALUE : Define actions for click on the\n");
-    printf("                   display corners\n");
-    printf("                   VALUE is a four digit number, each number\n");
-    printf("                   represent a corner (topleft, topright,\n");
-    printf("                   bottomright and bottomleft\n");
-    printf("                   Actions:\n");
-    printf("                   0=No action\n");
-    printf("                   1=Save\n");
-    printf("                   2=Load\n");
-    printf("                   3=Change slot (+1)\n");
-    printf("                   4=Change slot (-1)\n");
-    printf("                   5=Quit\n");
-       printf("  -guncon        : Set the controller to guncon\n");
-       printf("  -gunnotrigger  : Don't trigger (shoot) when touching screen\n");
-    printf("                   0=Auto (Default)\n");
-    printf("                   1=On\n");
-    printf("                   2=Off\n");
-
-
-       printf("\nGPU Options:\n");
-       printf("  -gles          : Use the GLES plugin (gpu_gles.so)\n");
-       printf("  -oldgpu        : Use the peops plugin (gpu_peops.so)\n");
-       printf("  -unai          : Use the unai plugin (gpu_unai.so)\n");
-
-       printf("\nSound Options:\n");
-       printf("  -spu_reverb VALUE        : Enable/disable reverb [0/1]\n");
-    printf("                             (Default disabled)\n");
-       printf("  -spu_interpolation VALUE : Set interpolation mode\n");
-       printf("                             0=None (Default)\n");
-    printf("                             1=Simple\n");
-       printf("                             2=Gaussian\n");
-       printf("                             3=Cubic\n");
-
-       printf("\nNeon Options (default GPU):\n");
-       printf("  -enhance       : Enable graphic enhancement\n");
-
-       printf("\nGles Options:\n");
-       printf("  -gles_dithering VALUE : Enable/disable dithering [0/1]\n");
-    printf("                          (Default disabled)\n");
-       printf("  -gles_mask VALUE      : Enable/disable mask detect [0/1]\n");
-    printf("                          (Default disabled)\n");
-       printf("  -gles_filtering VALUE : Texture Filtering\n");
-       printf("                          0=None (Default)\n");
-       printf("                          1=Standard\n");
-       printf("                          2=Extended\n");
-       printf("                          3=Standard-sprites\n");
-       printf("                          4=Extended-sprites\n");
-       printf("                          5=Standard+sprites\n");
-       printf("                          6=Extended+sprites\n");
-       printf("  -gles_fbtex VALUE     : Framebuffer Textures\n");
-       printf("                          0=Emulated VRam (Default)\n");
-       printf("                          1=Black\n");
-       printf("                          2=Card\n");
-       printf("                          3=Card+soft\n");
-       printf("  -gles_vram VALUE      : Texture RAM size in MB [4-128]\n");
-    printf("                          (Default 64)\n");
-    printf("  -gles_fastmdec VALUE  : Enable/disable Fast Mdec [0/1]\n");
-    printf("                          (Default disabled)\n");
-    printf("  -gles_advblend VALUE  : Enable/disable Adv. Blend [0/1]\n");
-    printf("                          (Default disabled)\n");
-    printf("  -gles_opaque VALUE    : Enable/disable Opaque Pass [0/1]\n");
-    printf("                          (Default disabled)\n");
-}
-
-int main(int argc, char **argv)
-{
-       if (argc == 1 || (argc == 2 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-help") || !strcmp(argv[1], "-h")))) {
-               PrintHelp();
-               return 0;
-       }
-
-       emu_core_preinit();
-       ChangeWorkingDirectory("c");
-       char file[MAXPATHLEN] = "";
-       char path[MAXPATHLEN];
-       const char *cdfile = NULL;
-       int loadst = 0;
-       int i;
-       int getst = -1;
-       int discNumber = 0;
-
-       g_menuscreen_w = 800;
-       g_menuscreen_h = 480;
-
-       strcpy(Config.Gpu, "builtin_gpu");
-       strcpy(Config.Spu, "builtin_spu");
-       strcpy(Config.BiosDir, "/home/user/MyDocs");
-       strcpy(Config.PluginsDir, "/opt/maemo/usr/games/plugins");
-       snprintf(Config.PatchesDir, sizeof(Config.PatchesDir), "/opt/maemo/usr/games" PATCHES_DIR);
-       Config.PsxAuto = 1;
-       pl_rearmed_cbs.frameskip = -1;
-       strcpy(Config.Bios, "HLE");
-       spu_config.iUseReverb = 1;
-       spu_config.iUseInterpolation = 1;
-       spu_config.idiablofix = 0;
-       in_type1 = PSE_PAD_TYPE_STANDARD;
-       in_type2 = PSE_PAD_TYPE_STANDARD;
-
-       accelOptions.sens     = 150;
-       accelOptions.y_def        = 500;
-       accelOptions.maxValue = 500.0;
-
-       // read command line options
-       for (i = 1; i < argc; i++) {
-                    if (!strcmp(argv[i], "-psxout")) Config.PsxOut = 1;
-               else if (!strcmp(argv[i], "-load")) loadst = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-cdfile")) {
-                       char isofilename[MAXPATHLEN];
-                       if (i+1 >= argc) break;
-                       strncpy(isofilename, argv[++i], MAXPATHLEN);
-                       if (isofilename[0] != '/') {
-                               getcwd(path, MAXPATHLEN);
-                               if (strlen(path) + strlen(isofilename) + 1 < MAXPATHLEN) {
-                                       strcat(path, "/");
-                                       strcat(path, isofilename);
-                                       strcpy(isofilename, path);
-                               } else
-                                       isofilename[0] = 0;
-                       }
-                       cdfile = isofilename;
-               }
-               else if (!strcmp(argv[i],"-frameskip")) {
-                       int tv_reg = atol(argv[++i]);
-                       if (tv_reg < -1)
-                               pl_rearmed_cbs.frameskip = -1;
-                       else
-                               pl_rearmed_cbs.frameskip = tv_reg;
-               }
-               else if (!strcmp(argv[i],"-region")) {
-                       int psx_reg = atol(argv[++i]);
-                       if (psx_reg == 0 || psx_reg == 1){
-                               Config.PsxAuto = 0;
-                               Config.PsxType = psx_reg;
-                       }
-               }
-
-               else if (!strcmp(argv[i],"-get_sstatename")) getst = atol(argv[++i]);
-
-               else if (!strcmp(argv[i], "-fullscreen"))               g_maemo_opts |= 2;
-               else if (!strcmp(argv[i], "-accel"))                            g_maemo_opts |= 4;
-               else if (!strcmp(argv[i], "-nosound"))                  strcpy(Config.Spu, "spunull.so");
-               else if (!strcmp(argv[i], "-bdir"))                     sprintf(Config.BiosDir, "%s", argv[++i]);
-               else if (!strcmp(argv[i], "-pdir"))                             sprintf(Config.PluginsDir, "%s", argv[++i]);
-               else if (!strcmp(argv[i], "-bios"))                     sprintf(Config.Bios, "%s", argv[++i]);
-               else if (!strcmp(argv[i], "-gles"))                             { strcpy(Config.Gpu, "gpu_gles.so"); g_maemo_opts |= 8 ;}
-               else if (!strcmp(argv[i], "-oldgpu"))                   strcpy(Config.Gpu, "gpu_peops.so");
-               else if (!strcmp(argv[i], "-unai"))                         strcpy(Config.Gpu, "gpu_unai.so");
-               else if (!strcmp(argv[i], "-cdda"))             Config.Cdda = 1;
-               else if (!strcmp(argv[i], "-xa"))               Config.Xa = 1;
-               else if (!strcmp(argv[i], "-rcnt"))             Config.RCntFix = 1 ;
-               else if (!strcmp(argv[i], "-sio"))              Config.Sio = 1;
-               else if (!strcmp(argv[i], "-spuirq"))   Config.SpuIrq = 1;
-               else if (!strcmp(argv[i], "-vsync"))    Config.VSyncWA = 1;
-               else if (!strcmp(argv[i], "-fps"))                          g_opts |=OPT_SHOWFPS;
-               else if (!strcmp(argv[i], "-cpu"))                          g_opts |=OPT_SHOWCPU;
-               else if (!strcmp(argv[i], "-spu"))                          g_opts |=OPT_SHOWSPU;
-               else if (!strcmp(argv[i], "-nofl"))                     g_opts |=OPT_NO_FRAMELIM;
-               else if (!strcmp(argv[i], "-mcd1"))                 sprintf(Config.Mcd1, "%s", argv[++i]);
-               else if (!strcmp(argv[i], "-mcd2"))                 sprintf(Config.Mcd2, "%s", argv[++i]);
-
-               else if (!strcmp(argv[i], "-cpuclock"))                 cycle_multiplier = 10000 / atol(argv[++i]);
-               else if (!strcmp(argv[i], "-guncon"))               in_type1 = PSE_PAD_TYPE_GUNCON;
-               else if (!strcmp(argv[i], "-gunnotrigger"))             g_opts |= OPT_TSGUN_NOTRIGGER;
-               else if (!strcmp(argv[i], "-analog"))               in_type1 = PSE_PAD_TYPE_ANALOGPAD;
-               else if (!strcmp(argv[i], "-vibration"))                { in_type1 = PSE_PAD_TYPE_ANALOGPAD; in_enable_vibration = 1; }
-               else if (!strcmp(argv[i], "-sens"))                             accelOptions.sens = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-ydef"))                             accelOptions.y_def = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-max"))                                  accelOptions.maxValue = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-displayon"))                    bKeepDisplayOn = TRUE;
-               else if (!strcmp(argv[i], "-keys"))                             sprintf(keys_config_file, "%s", argv[++i]);
-               else if (!strcmp(argv[i], "-autosave"))                     bAutosaveOnExit = TRUE;
-               else if (!strcmp(argv[i], "-disc"))                     discNumber = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-corners")){
-                       int j = 0;
-                       i++;
-                       char num[2];
-                       for (j=0; j<strlen(argv[i]); j++){
-                               strncpy(num, argv[i] + j, 1);
-                               cornerActions[j] = atoi(num);
-                       }
-       }
-
-               else if (!strcmp(argv[i], "-spu_reverb"))               spu_config.iUseReverb = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-spu_interpolation"))        spu_config.iUseInterpolation = atol(argv[++i]);
-
-               else if (!strcmp(argv[i], "-enhance"))                  pl_rearmed_cbs.gpu_neon.enhancement_enable = 1;
-               else if (!strcmp(argv[i], "-enhancehack"))              pl_rearmed_cbs.gpu_neon.enhancement_no_main = 1;
-
-               else if (!strcmp(argv[i], "-gles_dithering"))   pl_rearmed_cbs.gpu_peopsgl.bDrawDither = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-gles_mask"))            pl_rearmed_cbs.gpu_peopsgl.iUseMask = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-gles_filtering"))   pl_rearmed_cbs.gpu_peopsgl.iFilterType = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-gles_fbtex"))           pl_rearmed_cbs.gpu_peopsgl.iFrameTexType = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-gles_vram"))            pl_rearmed_cbs.gpu_peopsgl.iVRamSize = atol(argv[++i]);
-               else if (!strcmp(argv[i], "-gles_fastmdec"))    pl_rearmed_cbs.gpu_peopsgl.bUseFastMdec = atol(argv[++i]);
-        else if (!strcmp(argv[i], "-gles_advblend"))   pl_rearmed_cbs.gpu_peopsgl.bAdvancedBlend = atol(argv[++i]);
-        else if (!strcmp(argv[i], "-gles_opaque"))         pl_rearmed_cbs.gpu_peopsgl.bOpaquePass = atol(argv[++i]);
-
-               else {
-                       fprintf(stderr, "Unknown option: %s\n", argv[i]);
-                       return 1;
-               }
-       }
-       
-       pl_init();
-       if (emu_core_init() == -1)
-               return 1;
-       
-       if (cdfile) {
-               set_cd_image(cdfile);
-               strcpy(file_name, strrchr(cdfile,'/'));
-       }
-
-       if (LoadPlugins() == -1) {
-               SysMessage("Failed loading plugins!");
-               return 1;
-       }
-
-       if (discNumber > 0)
-               cdrIsoMultidiskSelect = discNumber - 1;
-
-       if (OpenPlugins() == -1) {
-               return 1;
-       }
-       plugin_call_rearmed_cbs();
-
-       CheckCdrom();
-
-       if (getst >= 0){
-               char fname[MAXPATHLEN];
-
-               get_state_filename(fname, sizeof(fname), getst);
-               printf("SAVESTATE: %s\n", fname);
-               if (cdrIsoMultidiskCount > 1){
-                       int i = 0;
-                       for (i=1; i<cdrIsoMultidiskCount; i++){
-                               cdrIsoMultidiskSelect = i;
-                               CdromId[0] = '\0';
-                               CdromLabel[0] = '\0';
-
-                               CDR_close();
-                               if (CDR_open() == 0){
-                                       CheckCdrom();
-                                       get_state_filename(fname, sizeof(fname), getst);
-                                       printf("SAVESTATE: %s\n", fname);
-                               }
-                       }
-               }
-               return 0;
-       }
-
-       SysReset();
-
-       if (file[0] != '\0') {
-               if (Load(file) != -1)
-                       ready_to_go = 1;
-       } else {
-               if (cdfile) {
-                       if (LoadCdrom() == -1) {
-                               ClosePlugins();
-                               printf(_("Could not load CD-ROM!\n"));
-                               return -1;
-                       }
-                       emu_on_new_cd(0);
-                       ready_to_go = 1;
-               }
-       }
-
-       if (!ready_to_go) {
-               printf ("something goes wrong, maybe you forgot -cdfile ? \n");
-               return 1;
-       }
-
-       if (cdrIsoMultidiskCount > 1)
-               printf ("Loaded a multidisc image: %i discs.\n", cdrIsoMultidiskCount);
-
-       // If a state has been specified, then load that
-       if (loadst) {
-               int ret = emu_load_state(loadst - 1);
-               printf("%s state %d\n", ret ? "Failed to load" : "Loaded", loadst);
-               state_slot = loadst - 1;
-       }
-
-       if (maemo_init(&argc, &argv))
-               return 1;
-
-       if (GPU_open != NULL) {
-               int ret = GPU_open(&gpuDisp, "PCSX", NULL);
-               if (ret){
-                       fprintf(stderr, "Warning: GPU_open returned %d\n", ret);
-                       gpuDisp=ret;
-               }
-       }
-
-       if (Config.HLE)
-               printf("Note: running without BIOS, expect compatibility problems\n");
-
-       dfinput_activate();
-       pl_timing_prepare(Config.PsxType);
-
-       while (1)
-       {
-               stop = 0;
-               emu_action = SACTION_NONE;
-
-               psxCpu->Execute();
-               if (emu_action != SACTION_NONE)
-                       do_emu_action();
-       }
-
-       maemo_finish();
-       return 0;
-}
-
index 91cf1ca..9a74908 100644 (file)
@@ -14,7 +14,9 @@
 #include <zlib.h>
 #ifndef _WIN32
 #define CALLBACK
+#ifndef NO_DYLIB
 #include <dlfcn.h>
+#endif
 #else
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
@@ -285,7 +287,7 @@ static long CDRinit(void)
                        return -1;
                }
        }
-#ifndef _WIN32
+#if !defined(_WIN32) && !defined(NO_DYLIB)
        if (pBZ2_bzBuffToBuffDecompress == NULL) {
                void *h = dlopen("/usr/lib/libbz2.so.1", RTLD_LAZY);
                if (h == NULL)
@@ -415,6 +417,8 @@ static long CDRopen(void)
        char *ext;
        FILE *f = NULL;
 
+       printf("%s cd_file=%d\n", __func__, cd_file == NULL ? 0 : 1);
+
        if (cd_file != NULL)
                return 0; // it's already open
 
index efeaaf9..0c6d001 100644 (file)
@@ -1,3 +1,7 @@
+#ifndef __P_CDRCIMG_H__
+#define __P_CDRCIMG_H__
 
 void  cdrcimg_set_fname(const char *fname);
 void *cdrcimg_get_sym(const char *sym);
+
+#endif /* __P_CDRCIMG_H__ */
index a446956..2e216fd 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef __P_EXTERNALS_H__
+#define __P_EXTERNALS_H__
 
 void dfinput_activate(void);
 
@@ -12,3 +14,5 @@ extern void pl_update_gun(int *xn, int *yn, int *xres, int *yres, int *in);
 /* vibration trigger to frontend */
 extern int in_enable_vibration;
 extern void plat_trigger_vibrate(int pad, int low, int high);
+
+#endif /* __P_EXTERNALS_H__ */
index 475ea07..9c19bb6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) Gražvydas "notaz" Ignotas, 2011
+ * (C) GraÃ\85¾vydas "notaz" Ignotas, 2011
  *
  * This work is licensed under the terms of any of these licenses
  * (at your option):
@@ -27,6 +27,8 @@ extern unsigned char CALLBACK PAD2__startPoll(int pad);
 extern unsigned char CALLBACK PAD1__poll(unsigned char value);
 extern unsigned char CALLBACK PAD2__poll(unsigned char value);
 
+#ifndef HAVE_LIBRETRO
+
 static int old_controller_type1 = -1, old_controller_type2 = -1;
 
 #define select_pad(n) \
@@ -40,10 +42,12 @@ static int old_controller_type1 = -1, old_controller_type2 = -1;
                        pad_init(); \
                        break; \
                case PSE_PAD_TYPE_GUNCON: \
-                       PAD##n##_startPoll = PADstartPoll_guncon; \
-                       PAD##n##_poll = PADpoll_guncon; \
-                       guncon_init(); \
-                       break; \
+                       /* Removed for new Guncon functionality, may have been required for very old touchscreen support */ \
+                       /* PAD##n##_startPoll = PADstartPoll_guncon; */ \
+                       /* PAD##n##_poll = PADpoll_guncon; */ \
+                       /* guncon_init(); */ \
+                       /* break; */ \
+               case PSE_PAD_TYPE_NEGCON: \
                case PSE_PAD_TYPE_GUN: \
                default: \
                        PAD##n##_startPoll = PAD##n##__startPoll; \
@@ -51,14 +55,21 @@ static int old_controller_type1 = -1, old_controller_type2 = -1;
                        break; \
                } \
        }
+#endif /* HAVE_LIBRETRO */
+
 
 void dfinput_activate(void)
 {
+       #ifndef HAVE_LIBRETRO
        PadDataS pad;
 
+       pad.portMultitap = -1;
+       pad.requestPadIndex = 0;
        PAD1_readPort1(&pad);
        select_pad(1);
 
+       pad.requestPadIndex = 1;
        PAD2_readPort2(&pad);
        select_pad(2);
+       #endif
 }
index e83306a..96cebfa 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __P_MAIN_H__
+#define __P_MAIN_H__
+
 #include "psemu_plugin_defs.h"
 #include "externals.h"
 
@@ -16,3 +19,5 @@ void guncon_init(void);
 /* get button state and pad type from main emu */
 extern long (*PAD1_readPort1)(PadDataS *pad);
 extern long (*PAD2_readPort2)(PadDataS *pad);
+
+#endif /* __P_MAIN_H__ */
index 7e00a11..3e33366 100644 (file)
@@ -42,6 +42,7 @@ enum {
        CMD_VIBRATION_TOGGLE = 0x4D,
 };
 
+#ifndef HAVE_LIBRETRO
 static struct {
        uint8_t PadMode;
        uint8_t PadID;
@@ -242,6 +243,7 @@ static void do_vibration(unsigned char value)
             break;
     }
 }
+#endif
 
 #if 0
 #include <stdio.h>
@@ -254,6 +256,7 @@ unsigned char PADpoll(unsigned char value) {
 #define PADpoll PADpoll_
 #endif
 
+#ifndef HAVE_LIBRETRO
 unsigned char PADpoll_pad(unsigned char value) {
        if (CurByte == 0) {
                CurCmd = value;
@@ -302,3 +305,4 @@ void pad_init(void)
                padstate[i].PadMode = padstate[i].pad.controllerType == PSE_PAD_TYPE_ANALOGPAD;
        }
 }
+#endif
index ff2af1f..2374f41 100644 (file)
  *                                                                         *\r
  ***************************************************************************/\r
 \r
+#ifndef __P_ADER_H__\r
+#define __P_ADER_H__\r
+\r
 INLINE void StartADSR(int ch);\r
 INLINE int  MixADSR(int ch);\r
+\r
+#endif /* __P_ADER_H__ */\r
index 440536f..4982432 100644 (file)
 //\r
 //*************************************************************************//\r
 \r
+#ifndef __P_DMA_H__\r
+#define __P_DMA_H__\r
 \r
 unsigned short CALLBACK SPUreadDMA(void);\r
 void CALLBACK SPUreadDMAMem(unsigned short * pusPSXMem,int iSize);\r
 void CALLBACK SPUwriteDMA(unsigned short val);\r
 void CALLBACK SPUwriteDMAMem(unsigned short * pusPSXMem,int iSize);\r
+\r
+#endif /* __P_DMA_H__ */\r
index 2db75ac..c038ea3 100644 (file)
@@ -15,6 +15,9 @@
  *                                                                         *\r
  ***************************************************************************/\r
 \r
+#ifndef __P_SOUND_EXTERNALS_H__\r
+#define __P_SOUND_EXTERNALS_H__\r
+\r
 #include <stdint.h>\r
 \r
 /////////////////////////////////////////////////////////\r
@@ -110,7 +113,7 @@ typedef struct
  unsigned int      bNoise:1;                           // noise active flag\r
  unsigned int      bFMod:2;                            // freq mod (0=off, 1=sound channel, 2=freq channel)\r
  unsigned int      prevflags:3;                        // flags from previous block\r
-\r
+ unsigned int      bIgnoreLoop:1;                      // Ignore loop\r
  int               iLeftVolume;                        // left volume\r
  int               iRightVolume;                       // right volume\r
  ADSRInfoEx        ADSRX;\r
@@ -232,6 +235,9 @@ typedef struct
  unsigned short  regArea[0x400];\r
 } SPUInfo;\r
 \r
+#define regAreaGet(ch,offset) \\r
+  spu.regArea[((ch<<4)|(offset))>>1]\r
+\r
 ///////////////////////////////////////////////////////////\r
 // SPU.C globals\r
 ///////////////////////////////////////////////////////////\r
@@ -243,9 +249,6 @@ extern SPUInfo spu;
 void do_samples(unsigned int cycles_to, int do_sync);\r
 void schedule_next_irq(void);\r
 \r
-#define regAreaGet(ch,offset) \\r
-  spu.regArea[((ch<<4)|(offset))>>1]\r
-\r
 #define do_samples_if_needed(c, sync) \\r
  do { \\r
   if (sync || (int)((c) - spu.cycles_played) >= 16 * 768) \\r
@@ -254,3 +257,4 @@ void schedule_next_irq(void);
 \r
 #endif\r
 \r
+#endif /* __P_SOUND_EXTERNALS_H__ */\r
index 4405e57..012cf70 100644 (file)
@@ -5,6 +5,7 @@
     copyright            : (C) 2003 by Chris Moeller, eh, whatever\r
     email                : chris@kode54.tk\r
  ***************************************************************************/\r
+                       \r
 /***************************************************************************\r
  *                                                                         *\r
  *   This program is free software; you can redistribute it and/or modify  *\r
  *                                                                         *\r
  ***************************************************************************/\r
                            \r
+//*************************************************************************//\r
+// History of changes:\r
+//\r
+// 2003/02/08 - kode54\r
+// - generated by interleaving table from gauss.h from the libopenspc\r
+//   project; a gaussian bell curve table logged from the SPC-700,\r
+//   though Neill says he logged the same curve from a PSX SPU. Also\r
+//   says that interleaving the coefficients together runs faster. Meh.\r
+//\r
+//*************************************************************************//\r
+\r
 #ifndef GAUSS_H\r
 #define GAUSS_H\r
 \r
-static const short gauss[]={\r
-       0x172, 0x519, 0x176, 0x000, 0x16E, 0x519, 0x17A, 0x000, \r
-       0x16A, 0x518, 0x17D, 0x000, 0x166, 0x518, 0x181, 0x000, \r
-       0x162, 0x518, 0x185, 0x000, 0x15F, 0x518, 0x189, 0x000, \r
-       0x15B, 0x518, 0x18D, 0x000, 0x157, 0x517, 0x191, 0x000, \r
-       0x153, 0x517, 0x195, 0x000, 0x150, 0x517, 0x19A, 0x000, \r
-       0x14C, 0x516, 0x19E, 0x000, 0x148, 0x516, 0x1A2, 0x000, \r
-       0x145, 0x515, 0x1A6, 0x000, 0x141, 0x514, 0x1AA, 0x000, \r
-       0x13E, 0x514, 0x1AE, 0x000, 0x13A, 0x513, 0x1B2, 0x000, \r
-       0x137, 0x512, 0x1B7, 0x001, 0x133, 0x511, 0x1BB, 0x001, \r
-       0x130, 0x511, 0x1BF, 0x001, 0x12C, 0x510, 0x1C3, 0x001, \r
-       0x129, 0x50F, 0x1C8, 0x001, 0x125, 0x50E, 0x1CC, 0x001, \r
-       0x122, 0x50D, 0x1D0, 0x001, 0x11E, 0x50C, 0x1D5, 0x001, \r
-       0x11B, 0x50B, 0x1D9, 0x001, 0x118, 0x50A, 0x1DD, 0x001, \r
-       0x114, 0x508, 0x1E2, 0x001, 0x111, 0x507, 0x1E6, 0x002, \r
-       0x10E, 0x506, 0x1EB, 0x002, 0x10B, 0x504, 0x1EF, 0x002, \r
-       0x107, 0x503, 0x1F3, 0x002, 0x104, 0x502, 0x1F8, 0x002, \r
-       0x101, 0x500, 0x1FC, 0x002, 0x0FE, 0x4FF, 0x201, 0x002, \r
-       0x0FB, 0x4FD, 0x205, 0x003, 0x0F8, 0x4FB, 0x20A, 0x003, \r
-       0x0F5, 0x4FA, 0x20F, 0x003, 0x0F2, 0x4F8, 0x213, 0x003, \r
-       0x0EF, 0x4F6, 0x218, 0x003, 0x0EC, 0x4F5, 0x21C, 0x004, \r
-       0x0E9, 0x4F3, 0x221, 0x004, 0x0E6, 0x4F1, 0x226, 0x004, \r
-       0x0E3, 0x4EF, 0x22A, 0x004, 0x0E0, 0x4ED, 0x22F, 0x004, \r
-       0x0DD, 0x4EB, 0x233, 0x005, 0x0DA, 0x4E9, 0x238, 0x005, \r
-       0x0D7, 0x4E7, 0x23D, 0x005, 0x0D4, 0x4E5, 0x241, 0x005, \r
-       0x0D2, 0x4E3, 0x246, 0x006, 0x0CF, 0x4E0, 0x24B, 0x006, \r
-       0x0CC, 0x4DE, 0x250, 0x006, 0x0C9, 0x4DC, 0x254, 0x006, \r
-       0x0C7, 0x4D9, 0x259, 0x007, 0x0C4, 0x4D7, 0x25E, 0x007, \r
-       0x0C1, 0x4D5, 0x263, 0x007, 0x0BF, 0x4D2, 0x267, 0x008, \r
-       0x0BC, 0x4D0, 0x26C, 0x008, 0x0BA, 0x4CD, 0x271, 0x008, \r
-       0x0B7, 0x4CB, 0x276, 0x009, 0x0B4, 0x4C8, 0x27B, 0x009, \r
-       0x0B2, 0x4C5, 0x280, 0x009, 0x0AF, 0x4C3, 0x284, 0x00A, \r
-       0x0AD, 0x4C0, 0x289, 0x00A, 0x0AB, 0x4BD, 0x28E, 0x00A, \r
-       0x0A8, 0x4BA, 0x293, 0x00B, 0x0A6, 0x4B7, 0x298, 0x00B, \r
-       0x0A3, 0x4B5, 0x29D, 0x00B, 0x0A1, 0x4B2, 0x2A2, 0x00C, \r
-       0x09F, 0x4AF, 0x2A6, 0x00C, 0x09C, 0x4AC, 0x2AB, 0x00D, \r
-       0x09A, 0x4A9, 0x2B0, 0x00D, 0x098, 0x4A6, 0x2B5, 0x00E, \r
-       0x096, 0x4A2, 0x2BA, 0x00E, 0x093, 0x49F, 0x2BF, 0x00F, \r
-       0x091, 0x49C, 0x2C4, 0x00F, 0x08F, 0x499, 0x2C9, 0x00F, \r
-       0x08D, 0x496, 0x2CE, 0x010, 0x08B, 0x492, 0x2D3, 0x010, \r
-       0x089, 0x48F, 0x2D8, 0x011, 0x086, 0x48C, 0x2DC, 0x011, \r
-       0x084, 0x488, 0x2E1, 0x012, 0x082, 0x485, 0x2E6, 0x013, \r
-       0x080, 0x481, 0x2EB, 0x013, 0x07E, 0x47E, 0x2F0, 0x014, \r
-       0x07C, 0x47A, 0x2F5, 0x014, 0x07A, 0x477, 0x2FA, 0x015, \r
-       0x078, 0x473, 0x2FF, 0x015, 0x076, 0x470, 0x304, 0x016, \r
-       0x075, 0x46C, 0x309, 0x017, 0x073, 0x468, 0x30E, 0x017, \r
-       0x071, 0x465, 0x313, 0x018, 0x06F, 0x461, 0x318, 0x018, \r
-       0x06D, 0x45D, 0x31D, 0x019, 0x06B, 0x459, 0x322, 0x01A, \r
-       0x06A, 0x455, 0x326, 0x01B, 0x068, 0x452, 0x32B, 0x01B, \r
-       0x066, 0x44E, 0x330, 0x01C, 0x064, 0x44A, 0x335, 0x01D, \r
-       0x063, 0x446, 0x33A, 0x01D, 0x061, 0x442, 0x33F, 0x01E, \r
-       0x05F, 0x43E, 0x344, 0x01F, 0x05E, 0x43A, 0x349, 0x020, \r
-       0x05C, 0x436, 0x34E, 0x020, 0x05A, 0x432, 0x353, 0x021, \r
-       0x059, 0x42E, 0x357, 0x022, 0x057, 0x42A, 0x35C, 0x023, \r
-       0x056, 0x425, 0x361, 0x024, 0x054, 0x421, 0x366, 0x024, \r
-       0x053, 0x41D, 0x36B, 0x025, 0x051, 0x419, 0x370, 0x026, \r
-       0x050, 0x415, 0x374, 0x027, 0x04E, 0x410, 0x379, 0x028, \r
-       0x04D, 0x40C, 0x37E, 0x029, 0x04C, 0x408, 0x383, 0x02A, \r
-       0x04A, 0x403, 0x388, 0x02B, 0x049, 0x3FF, 0x38C, 0x02C, \r
-       0x047, 0x3FB, 0x391, 0x02D, 0x046, 0x3F6, 0x396, 0x02E, \r
-       0x045, 0x3F2, 0x39B, 0x02F, 0x043, 0x3ED, 0x39F, 0x030, \r
-       0x042, 0x3E9, 0x3A4, 0x031, 0x041, 0x3E5, 0x3A9, 0x032, \r
-       0x040, 0x3E0, 0x3AD, 0x033, 0x03E, 0x3DC, 0x3B2, 0x034, \r
-       0x03D, 0x3D7, 0x3B7, 0x035, 0x03C, 0x3D2, 0x3BB, 0x036, \r
-       0x03B, 0x3CE, 0x3C0, 0x037, 0x03A, 0x3C9, 0x3C5, 0x038, \r
-       0x038, 0x3C5, 0x3C9, 0x03A, 0x037, 0x3C0, 0x3CE, 0x03B, \r
-       0x036, 0x3BB, 0x3D2, 0x03C, 0x035, 0x3B7, 0x3D7, 0x03D, \r
-       0x034, 0x3B2, 0x3DC, 0x03E, 0x033, 0x3AD, 0x3E0, 0x040, \r
-       0x032, 0x3A9, 0x3E5, 0x041, 0x031, 0x3A4, 0x3E9, 0x042, \r
-       0x030, 0x39F, 0x3ED, 0x043, 0x02F, 0x39B, 0x3F2, 0x045, \r
-       0x02E, 0x396, 0x3F6, 0x046, 0x02D, 0x391, 0x3FB, 0x047, \r
-       0x02C, 0x38C, 0x3FF, 0x049, 0x02B, 0x388, 0x403, 0x04A, \r
-       0x02A, 0x383, 0x408, 0x04C, 0x029, 0x37E, 0x40C, 0x04D, \r
-       0x028, 0x379, 0x410, 0x04E, 0x027, 0x374, 0x415, 0x050, \r
-       0x026, 0x370, 0x419, 0x051, 0x025, 0x36B, 0x41D, 0x053, \r
-       0x024, 0x366, 0x421, 0x054, 0x024, 0x361, 0x425, 0x056, \r
-       0x023, 0x35C, 0x42A, 0x057, 0x022, 0x357, 0x42E, 0x059, \r
-       0x021, 0x353, 0x432, 0x05A, 0x020, 0x34E, 0x436, 0x05C, \r
-       0x020, 0x349, 0x43A, 0x05E, 0x01F, 0x344, 0x43E, 0x05F, \r
-       0x01E, 0x33F, 0x442, 0x061, 0x01D, 0x33A, 0x446, 0x063, \r
-       0x01D, 0x335, 0x44A, 0x064, 0x01C, 0x330, 0x44E, 0x066, \r
-       0x01B, 0x32B, 0x452, 0x068, 0x01B, 0x326, 0x455, 0x06A, \r
-       0x01A, 0x322, 0x459, 0x06B, 0x019, 0x31D, 0x45D, 0x06D, \r
-       0x018, 0x318, 0x461, 0x06F, 0x018, 0x313, 0x465, 0x071, \r
-       0x017, 0x30E, 0x468, 0x073, 0x017, 0x309, 0x46C, 0x075, \r
-       0x016, 0x304, 0x470, 0x076, 0x015, 0x2FF, 0x473, 0x078, \r
-       0x015, 0x2FA, 0x477, 0x07A, 0x014, 0x2F5, 0x47A, 0x07C, \r
-       0x014, 0x2F0, 0x47E, 0x07E, 0x013, 0x2EB, 0x481, 0x080, \r
-       0x013, 0x2E6, 0x485, 0x082, 0x012, 0x2E1, 0x488, 0x084, \r
-       0x011, 0x2DC, 0x48C, 0x086, 0x011, 0x2D8, 0x48F, 0x089, \r
-       0x010, 0x2D3, 0x492, 0x08B, 0x010, 0x2CE, 0x496, 0x08D, \r
-       0x00F, 0x2C9, 0x499, 0x08F, 0x00F, 0x2C4, 0x49C, 0x091, \r
-       0x00F, 0x2BF, 0x49F, 0x093, 0x00E, 0x2BA, 0x4A2, 0x096, \r
-       0x00E, 0x2B5, 0x4A6, 0x098, 0x00D, 0x2B0, 0x4A9, 0x09A, \r
-       0x00D, 0x2AB, 0x4AC, 0x09C, 0x00C, 0x2A6, 0x4AF, 0x09F, \r
-       0x00C, 0x2A2, 0x4B2, 0x0A1, 0x00B, 0x29D, 0x4B5, 0x0A3, \r
-       0x00B, 0x298, 0x4B7, 0x0A6, 0x00B, 0x293, 0x4BA, 0x0A8, \r
-       0x00A, 0x28E, 0x4BD, 0x0AB, 0x00A, 0x289, 0x4C0, 0x0AD, \r
-       0x00A, 0x284, 0x4C3, 0x0AF, 0x009, 0x280, 0x4C5, 0x0B2, \r
-       0x009, 0x27B, 0x4C8, 0x0B4, 0x009, 0x276, 0x4CB, 0x0B7, \r
-       0x008, 0x271, 0x4CD, 0x0BA, 0x008, 0x26C, 0x4D0, 0x0BC, \r
-       0x008, 0x267, 0x4D2, 0x0BF, 0x007, 0x263, 0x4D5, 0x0C1, \r
-       0x007, 0x25E, 0x4D7, 0x0C4, 0x007, 0x259, 0x4D9, 0x0C7, \r
-       0x006, 0x254, 0x4DC, 0x0C9, 0x006, 0x250, 0x4DE, 0x0CC, \r
-       0x006, 0x24B, 0x4E0, 0x0CF, 0x006, 0x246, 0x4E3, 0x0D2, \r
-       0x005, 0x241, 0x4E5, 0x0D4, 0x005, 0x23D, 0x4E7, 0x0D7, \r
-       0x005, 0x238, 0x4E9, 0x0DA, 0x005, 0x233, 0x4EB, 0x0DD, \r
-       0x004, 0x22F, 0x4ED, 0x0E0, 0x004, 0x22A, 0x4EF, 0x0E3, \r
-       0x004, 0x226, 0x4F1, 0x0E6, 0x004, 0x221, 0x4F3, 0x0E9, \r
-       0x004, 0x21C, 0x4F5, 0x0EC, 0x003, 0x218, 0x4F6, 0x0EF, \r
-       0x003, 0x213, 0x4F8, 0x0F2, 0x003, 0x20F, 0x4FA, 0x0F5, \r
-       0x003, 0x20A, 0x4FB, 0x0F8, 0x003, 0x205, 0x4FD, 0x0FB, \r
-       0x002, 0x201, 0x4FF, 0x0FE, 0x002, 0x1FC, 0x500, 0x101, \r
-       0x002, 0x1F8, 0x502, 0x104, 0x002, 0x1F3, 0x503, 0x107, \r
-       0x002, 0x1EF, 0x504, 0x10B, 0x002, 0x1EB, 0x506, 0x10E, \r
-       0x002, 0x1E6, 0x507, 0x111, 0x001, 0x1E2, 0x508, 0x114, \r
-       0x001, 0x1DD, 0x50A, 0x118, 0x001, 0x1D9, 0x50B, 0x11B, \r
-       0x001, 0x1D5, 0x50C, 0x11E, 0x001, 0x1D0, 0x50D, 0x122, \r
-       0x001, 0x1CC, 0x50E, 0x125, 0x001, 0x1C8, 0x50F, 0x129, \r
-       0x001, 0x1C3, 0x510, 0x12C, 0x001, 0x1BF, 0x511, 0x130, \r
-       0x001, 0x1BB, 0x511, 0x133, 0x001, 0x1B7, 0x512, 0x137, \r
-       0x000, 0x1B2, 0x513, 0x13A, 0x000, 0x1AE, 0x514, 0x13E, \r
-       0x000, 0x1AA, 0x514, 0x141, 0x000, 0x1A6, 0x515, 0x145, \r
-       0x000, 0x1A2, 0x516, 0x148, 0x000, 0x19E, 0x516, 0x14C, \r
-       0x000, 0x19A, 0x517, 0x150, 0x000, 0x195, 0x517, 0x153, \r
-       0x000, 0x191, 0x517, 0x157, 0x000, 0x18D, 0x518, 0x15B, \r
-       0x000, 0x189, 0x518, 0x15F, 0x000, 0x185, 0x518, 0x162, \r
-       0x000, 0x181, 0x518, 0x166, 0x000, 0x17D, 0x518, 0x16A, \r
-       0x000, 0x17A, 0x519, 0x16E, 0x000, 0x176, 0x519, 0x172};\r
-#endif\r
+\r
+/*\r
+128 * 4 table\r
+- 0 = past #3\r
+- 1 = past #2\r
+- 2 = past #1\r
+- 3 = past #0\r
+\r
+\r
+offset 0\r
+for(0) + for(256) + rev(256) + rev(0)\r
+*/\r
+\r
+\r
+// NOTE: Dr. Hell\r
+// - Excel NORMDIST($A6,2,0.567,FALSE) [0-4] = 98%\r
+\r
+\r
+// Mednafen's table (PSX) 99-100%\r
+const int gauss[]={\r
+       0x12c7, 0x59b3, 0x1307, 0xffffffff, \r
+       0x1288, 0x59b2, 0x1347, 0xffffffff, \r
+       0x1249, 0x59b0, 0x1388, 0xffffffff, \r
+       0x120b, 0x59ad, 0x13c9, 0xffffffff, \r
+       0x11cd, 0x59a9, 0x140b, 0xffffffff, \r
+       0x118f, 0x59a4, 0x144d, 0xffffffff, \r
+       0x1153, 0x599e, 0x1490, 0xffffffff, \r
+       0x1116, 0x5997, 0x14d4, 0xffffffff, \r
+       0x10db, 0x598f, 0x1517, 0xffffffff, \r
+       0x109f, 0x5986, 0x155c, 0xffffffff, \r
+       0x1065, 0x597c, 0x15a0, 0xffffffff, \r
+       0x102a, 0x5971, 0x15e6, 0xffffffff, \r
+       0x0ff1, 0x5965, 0x162c, 0xffffffff, \r
+       0x0fb7, 0x5958, 0x1672, 0xffffffff, \r
+       0x0f7f, 0x5949, 0x16b9, 0xffffffff, \r
+       0x0f46, 0x593a, 0x1700, 0xffffffff, \r
+       0x0f0f, 0x592a, 0x1747, 0x0000, \r
+       0x0ed7, 0x5919, 0x1790, 0x0000, \r
+       0x0ea1, 0x5907, 0x17d8, 0x0000, \r
+       0x0e6b, 0x58f4, 0x1821, 0x0000, \r
+       0x0e35, 0x58e0, 0x186b, 0x0000, \r
+       0x0e00, 0x58cb, 0x18b5, 0x0000, \r
+       0x0dcb, 0x58b5, 0x1900, 0x0000, \r
+       0x0d97, 0x589e, 0x194b, 0x0001, \r
+       0x0d63, 0x5886, 0x1996, 0x0001, \r
+       0x0d30, 0x586d, 0x19e2, 0x0001, \r
+       0x0cfd, 0x5853, 0x1a2e, 0x0001, \r
+       0x0ccb, 0x5838, 0x1a7b, 0x0002, \r
+       0x0c99, 0x581c, 0x1ac8, 0x0002, \r
+       0x0c68, 0x57ff, 0x1b16, 0x0002, \r
+       0x0c38, 0x57e2, 0x1b64, 0x0003, \r
+       0x0c07, 0x57c3, 0x1bb3, 0x0003, \r
+       0x0bd8, 0x57a3, 0x1c02, 0x0003, \r
+       0x0ba9, 0x5782, 0x1c51, 0x0004, \r
+       0x0b7a, 0x5761, 0x1ca1, 0x0004, \r
+       0x0b4c, 0x573e, 0x1cf1, 0x0005, \r
+       0x0b1e, 0x571b, 0x1d42, 0x0005, \r
+       0x0af1, 0x56f6, 0x1d93, 0x0006, \r
+       0x0ac4, 0x56d1, 0x1de5, 0x0007, \r
+       0x0a98, 0x56ab, 0x1e37, 0x0007, \r
+       0x0a6c, 0x5684, 0x1e89, 0x0008, \r
+       0x0a40, 0x565b, 0x1edc, 0x0009, \r
+       0x0a16, 0x5632, 0x1f2f, 0x0009, \r
+       0x09eb, 0x5609, 0x1f82, 0x000a, \r
+       0x09c1, 0x55de, 0x1fd6, 0x000b, \r
+       0x0998, 0x55b2, 0x202a, 0x000c, \r
+       0x096f, 0x5585, 0x207f, 0x000d, \r
+       0x0946, 0x5558, 0x20d4, 0x000e, \r
+       0x091e, 0x5529, 0x2129, 0x000f, \r
+       0x08f7, 0x54fa, 0x217f, 0x0010, \r
+       0x08d0, 0x54ca, 0x21d5, 0x0011, \r
+       0x08a9, 0x5499, 0x222c, 0x0012, \r
+       0x0883, 0x5467, 0x2282, 0x0013, \r
+       0x085d, 0x5434, 0x22da, 0x0015, \r
+       0x0838, 0x5401, 0x2331, 0x0016, \r
+       0x0813, 0x53cc, 0x2389, 0x0018, \r
+       0x07ef, 0x5397, 0x23e1, 0x0019, \r
+       0x07cb, 0x5361, 0x2439, 0x001b, \r
+       0x07a7, 0x532a, 0x2492, 0x001c, \r
+       0x0784, 0x52f3, 0x24eb, 0x001e, \r
+       0x0762, 0x52ba, 0x2545, 0x0020, \r
+       0x0740, 0x5281, 0x259e, 0x0021, \r
+       0x071e, 0x5247, 0x25f8, 0x0023, \r
+       0x06fd, 0x520c, 0x2653, 0x0025, \r
+       0x06dc, 0x51d0, 0x26ad, 0x0027, \r
+       0x06bb, 0x5194, 0x2708, 0x0029, \r
+       0x069b, 0x5156, 0x2763, 0x002c, \r
+       0x067c, 0x5118, 0x27be, 0x002e, \r
+       0x065c, 0x50da, 0x281a, 0x0030, \r
+       0x063e, 0x509a, 0x2876, 0x0033, \r
+       0x061f, 0x505a, 0x28d2, 0x0035, \r
+       0x0601, 0x5019, 0x292e, 0x0038, \r
+       0x05e4, 0x4fd7, 0x298b, 0x003a, \r
+       0x05c7, 0x4f95, 0x29e7, 0x003d, \r
+       0x05aa, 0x4f52, 0x2a44, 0x0040, \r
+       0x058e, 0x4f0e, 0x2aa1, 0x0043, \r
+       0x0572, 0x4ec9, 0x2aff, 0x0046, \r
+       0x0556, 0x4e84, 0x2b5c, 0x0049, \r
+       0x053b, 0x4e3e, 0x2bba, 0x004d, \r
+       0x0520, 0x4df7, 0x2c18, 0x0050, \r
+       0x0506, 0x4db0, 0x2c76, 0x0054, \r
+       0x04ec, 0x4d68, 0x2cd4, 0x0057, \r
+       0x04d2, 0x4d20, 0x2d33, 0x005b, \r
+       0x04b9, 0x4cd7, 0x2d91, 0x005f, \r
+       0x04a0, 0x4c8d, 0x2df0, 0x0063, \r
+       0x0488, 0x4c42, 0x2e4f, 0x0067, \r
+       0x0470, 0x4bf7, 0x2eae, 0x006b, \r
+       0x0458, 0x4bac, 0x2f0d, 0x006f, \r
+       0x0441, 0x4b5f, 0x2f6c, 0x0074, \r
+       0x042a, 0x4b13, 0x2fcc, 0x0078, \r
+       0x0413, 0x4ac5, 0x302b, 0x007d, \r
+       0x03fc, 0x4a77, 0x308b, 0x0082, \r
+       0x03e7, 0x4a29, 0x30ea, 0x0087, \r
+       0x03d1, 0x49d9, 0x314a, 0x008c, \r
+       0x03bc, 0x498a, 0x31aa, 0x0091, \r
+       0x03a7, 0x493a, 0x3209, 0x0096, \r
+       0x0392, 0x48e9, 0x3269, 0x009c, \r
+       0x037e, 0x4898, 0x32c9, 0x00a1, \r
+       0x036a, 0x4846, 0x3329, 0x00a7, \r
+       0x0356, 0x47f4, 0x3389, 0x00ad, \r
+       0x0343, 0x47a1, 0x33e9, 0x00b3, \r
+       0x0330, 0x474e, 0x3449, 0x00ba, \r
+       0x031d, 0x46fa, 0x34a9, 0x00c0, \r
+       0x030b, 0x46a6, 0x3509, 0x00c7, \r
+       0x02f9, 0x4651, 0x3569, 0x00cd, \r
+       0x02e7, 0x45fc, 0x35c9, 0x00d4, \r
+       0x02d6, 0x45a6, 0x3629, 0x00db, \r
+       0x02c4, 0x4550, 0x3689, 0x00e3, \r
+       0x02b4, 0x44fa, 0x36e8, 0x00ea, \r
+       0x02a3, 0x44a3, 0x3748, 0x00f2, \r
+       0x0293, 0x444c, 0x37a8, 0x00fa, \r
+       0x0283, 0x43f4, 0x3807, 0x0101, \r
+       0x0273, 0x439c, 0x3867, 0x010a, \r
+       0x0264, 0x4344, 0x38c6, 0x0112, \r
+       0x0255, 0x42eb, 0x3926, 0x011b, \r
+       0x0246, 0x4292, 0x3985, 0x0123, \r
+       0x0237, 0x4239, 0x39e4, 0x012c, \r
+       0x0229, 0x41df, 0x3a43, 0x0135, \r
+       0x021b, 0x4185, 0x3aa2, 0x013f, \r
+       0x020d, 0x412a, 0x3b00, 0x0148, \r
+       0x0200, 0x40d0, 0x3b5f, 0x0152, \r
+       0x01f2, 0x4074, 0x3bbd, 0x015c, \r
+       0x01e5, 0x4019, 0x3c1b, 0x0166, \r
+       0x01d9, 0x3fbd, 0x3c79, 0x0171, \r
+       0x01cc, 0x3f62, 0x3cd7, 0x017b, \r
+       0x01c0, 0x3f05, 0x3d35, 0x0186, \r
+       0x01b4, 0x3ea9, 0x3d92, 0x0191, \r
+       0x01a8, 0x3e4c, 0x3def, 0x019c, \r
+       0x019c, 0x3def, 0x3e4c, 0x01a8, \r
+       0x0191, 0x3d92, 0x3ea9, 0x01b4, \r
+       0x0186, 0x3d35, 0x3f05, 0x01c0, \r
+       0x017b, 0x3cd7, 0x3f62, 0x01cc, \r
+       0x0171, 0x3c79, 0x3fbd, 0x01d9, \r
+       0x0166, 0x3c1b, 0x4019, 0x01e5, \r
+       0x015c, 0x3bbd, 0x4074, 0x01f2, \r
+       0x0152, 0x3b5f, 0x40d0, 0x0200, \r
+       0x0148, 0x3b00, 0x412a, 0x020d, \r
+       0x013f, 0x3aa2, 0x4185, 0x021b, \r
+       0x0135, 0x3a43, 0x41df, 0x0229, \r
+       0x012c, 0x39e4, 0x4239, 0x0237, \r
+       0x0123, 0x3985, 0x4292, 0x0246, \r
+       0x011b, 0x3926, 0x42eb, 0x0255, \r
+       0x0112, 0x38c6, 0x4344, 0x0264, \r
+       0x010a, 0x3867, 0x439c, 0x0273, \r
+       0x0101, 0x3807, 0x43f4, 0x0283, \r
+       0x00fa, 0x37a8, 0x444c, 0x0293, \r
+       0x00f2, 0x3748, 0x44a3, 0x02a3, \r
+       0x00ea, 0x36e8, 0x44fa, 0x02b4, \r
+       0x00e3, 0x3689, 0x4550, 0x02c4, \r
+       0x00db, 0x3629, 0x45a6, 0x02d6, \r
+       0x00d4, 0x35c9, 0x45fc, 0x02e7, \r
+       0x00cd, 0x3569, 0x4651, 0x02f9, \r
+       0x00c7, 0x3509, 0x46a6, 0x030b, \r
+       0x00c0, 0x34a9, 0x46fa, 0x031d, \r
+       0x00ba, 0x3449, 0x474e, 0x0330, \r
+       0x00b3, 0x33e9, 0x47a1, 0x0343, \r
+       0x00ad, 0x3389, 0x47f4, 0x0356, \r
+       0x00a7, 0x3329, 0x4846, 0x036a, \r
+       0x00a1, 0x32c9, 0x4898, 0x037e, \r
+       0x009c, 0x3269, 0x48e9, 0x0392, \r
+       0x0096, 0x3209, 0x493a, 0x03a7, \r
+       0x0091, 0x31aa, 0x498a, 0x03bc, \r
+       0x008c, 0x314a, 0x49d9, 0x03d1, \r
+       0x0087, 0x30ea, 0x4a29, 0x03e7, \r
+       0x0082, 0x308b, 0x4a77, 0x03fc, \r
+       0x007d, 0x302b, 0x4ac5, 0x0413, \r
+       0x0078, 0x2fcc, 0x4b13, 0x042a, \r
+       0x0074, 0x2f6c, 0x4b5f, 0x0441, \r
+       0x006f, 0x2f0d, 0x4bac, 0x0458, \r
+       0x006b, 0x2eae, 0x4bf7, 0x0470, \r
+       0x0067, 0x2e4f, 0x4c42, 0x0488, \r
+       0x0063, 0x2df0, 0x4c8d, 0x04a0, \r
+       0x005f, 0x2d91, 0x4cd7, 0x04b9, \r
+       0x005b, 0x2d33, 0x4d20, 0x04d2, \r
+       0x0057, 0x2cd4, 0x4d68, 0x04ec, \r
+       0x0054, 0x2c76, 0x4db0, 0x0506, \r
+       0x0050, 0x2c18, 0x4df7, 0x0520, \r
+       0x004d, 0x2bba, 0x4e3e, 0x053b, \r
+       0x0049, 0x2b5c, 0x4e84, 0x0556, \r
+       0x0046, 0x2aff, 0x4ec9, 0x0572, \r
+       0x0043, 0x2aa1, 0x4f0e, 0x058e, \r
+       0x0040, 0x2a44, 0x4f52, 0x05aa, \r
+       0x003d, 0x29e7, 0x4f95, 0x05c7, \r
+       0x003a, 0x298b, 0x4fd7, 0x05e4, \r
+       0x0038, 0x292e, 0x5019, 0x0601, \r
+       0x0035, 0x28d2, 0x505a, 0x061f, \r
+       0x0033, 0x2876, 0x509a, 0x063e, \r
+       0x0030, 0x281a, 0x50da, 0x065c, \r
+       0x002e, 0x27be, 0x5118, 0x067c, \r
+       0x002c, 0x2763, 0x5156, 0x069b, \r
+       0x0029, 0x2708, 0x5194, 0x06bb, \r
+       0x0027, 0x26ad, 0x51d0, 0x06dc, \r
+       0x0025, 0x2653, 0x520c, 0x06fd, \r
+       0x0023, 0x25f8, 0x5247, 0x071e, \r
+       0x0021, 0x259e, 0x5281, 0x0740, \r
+       0x0020, 0x2545, 0x52ba, 0x0762, \r
+       0x001e, 0x24eb, 0x52f3, 0x0784, \r
+       0x001c, 0x2492, 0x532a, 0x07a7, \r
+       0x001b, 0x2439, 0x5361, 0x07cb, \r
+       0x0019, 0x23e1, 0x5397, 0x07ef, \r
+       0x0018, 0x2389, 0x53cc, 0x0813, \r
+       0x0016, 0x2331, 0x5401, 0x0838, \r
+       0x0015, 0x22da, 0x5434, 0x085d, \r
+       0x0013, 0x2282, 0x5467, 0x0883, \r
+       0x0012, 0x222c, 0x5499, 0x08a9, \r
+       0x0011, 0x21d5, 0x54ca, 0x08d0, \r
+       0x0010, 0x217f, 0x54fa, 0x08f7, \r
+       0x000f, 0x2129, 0x5529, 0x091e, \r
+       0x000e, 0x20d4, 0x5558, 0x0946, \r
+       0x000d, 0x207f, 0x5585, 0x096f, \r
+       0x000c, 0x202a, 0x55b2, 0x0998, \r
+       0x000b, 0x1fd6, 0x55de, 0x09c1, \r
+       0x000a, 0x1f82, 0x5609, 0x09eb, \r
+       0x0009, 0x1f2f, 0x5632, 0x0a16, \r
+       0x0009, 0x1edc, 0x565b, 0x0a40, \r
+       0x0008, 0x1e89, 0x5684, 0x0a6c, \r
+       0x0007, 0x1e37, 0x56ab, 0x0a98, \r
+       0x0007, 0x1de5, 0x56d1, 0x0ac4, \r
+       0x0006, 0x1d93, 0x56f6, 0x0af1, \r
+       0x0005, 0x1d42, 0x571b, 0x0b1e, \r
+       0x0005, 0x1cf1, 0x573e, 0x0b4c, \r
+       0x0004, 0x1ca1, 0x5761, 0x0b7a, \r
+       0x0004, 0x1c51, 0x5782, 0x0ba9, \r
+       0x0003, 0x1c02, 0x57a3, 0x0bd8, \r
+       0x0003, 0x1bb3, 0x57c3, 0x0c07, \r
+       0x0003, 0x1b64, 0x57e2, 0x0c38, \r
+       0x0002, 0x1b16, 0x57ff, 0x0c68, \r
+       0x0002, 0x1ac8, 0x581c, 0x0c99, \r
+       0x0002, 0x1a7b, 0x5838, 0x0ccb, \r
+       0x0001, 0x1a2e, 0x5853, 0x0cfd, \r
+       0x0001, 0x19e2, 0x586d, 0x0d30, \r
+       0x0001, 0x1996, 0x5886, 0x0d63, \r
+       0x0001, 0x194b, 0x589e, 0x0d97, \r
+       0x0000, 0x1900, 0x58b5, 0x0dcb, \r
+       0x0000, 0x18b5, 0x58cb, 0x0e00, \r
+       0x0000, 0x186b, 0x58e0, 0x0e35, \r
+       0x0000, 0x1821, 0x58f4, 0x0e6b, \r
+       0x0000, 0x17d8, 0x5907, 0x0ea1, \r
+       0x0000, 0x1790, 0x5919, 0x0ed7, \r
+       0x0000, 0x1747, 0x592a, 0x0f0f, \r
+       0xffffffff, 0x1700, 0x593a, 0x0f46, \r
+       0xffffffff, 0x16b9, 0x5949, 0x0f7f, \r
+       0xffffffff, 0x1672, 0x5958, 0x0fb7, \r
+       0xffffffff, 0x162c, 0x5965, 0x0ff1, \r
+       0xffffffff, 0x15e6, 0x5971, 0x102a, \r
+       0xffffffff, 0x15a0, 0x597c, 0x1065, \r
+       0xffffffff, 0x155c, 0x5986, 0x109f, \r
+       0xffffffff, 0x1517, 0x598f, 0x10db, \r
+       0xffffffff, 0x14d4, 0x5997, 0x1116, \r
+       0xffffffff, 0x1490, 0x599e, 0x1153, \r
+       0xffffffff, 0x144d, 0x59a4, 0x118f, \r
+       0xffffffff, 0x140b, 0x59a9, 0x11cd, \r
+       0xffffffff, 0x13c9, 0x59ad, 0x120b, \r
+       0xffffffff, 0x1388, 0x59b0, 0x1249, \r
+       0xffffffff, 0x1347, 0x59b2, 0x1288, \r
+       0xffffffff, 0x1307, 0x59b3, 0x12c7, \r
+};\r
+\r
+#endif
\ No newline at end of file
index 5ddd3f4..4443dae 100644 (file)
@@ -47,6 +47,6 @@ void SetupSound(void)
        }
 
        out_current = &out_drivers[i];
-       printf("selected sound output driver: %s\n", out_current->name);
+       // printf("selected sound output driver: %s\n", out_current->name);
 }
 
index 4607099..e4878a8 100644 (file)
@@ -1,3 +1,5 @@
+#ifndef __P_OUT_H__
+#define __P_OUT_H__
 
 struct out_driver {
        const char *name;
@@ -10,3 +12,5 @@ struct out_driver {
 extern struct out_driver *out_current;
 
 void SetupSound(void);
+
+#endif /* __P_OUT_H__ */
index bb64658..cc72020 100644 (file)
@@ -112,6 +112,7 @@ void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val,
      //------------------------------------------------//\r
      case 14:                                          // loop?\r
        spu.s_chan[ch].pLoop=spu.spuMemC+((val&~1)<<3);\r
+       spu.s_chan[ch].bIgnoreLoop = 1;\r
        goto upd_irq;\r
      //------------------------------------------------//\r
     }\r
@@ -315,7 +316,7 @@ unsigned short CALLBACK SPUreadRegister(unsigned long reg)
      return spu.spuCtrl;\r
 \r
     case H_SPUstat:\r
-     return spu.spuStat;\r
+     return (spu.spuStat & ~0x3F) | (spu.spuCtrl & 0x3F);\r
         \r
     case H_SPUaddr:\r
      return (unsigned short)(spu.spuAddr>>3);\r
@@ -351,8 +352,7 @@ static void SoundOn(int start,int end,unsigned short val)
   {\r
    if((val&1) && regAreaGet(ch,6))                     // mmm... start has to be set before key on !?!\r
     {\r
-     spu.s_chan[ch].pCurr=spu.spuMemC+((regAreaGet(ch,6)&~1)<<3); // must be block aligned\r
-     if (spu_config.idiablofix == 0) spu.s_chan[ch].pLoop=spu.spuMemC+((regAreaGet(ch,14)&~1)<<3);\r
+     spu.s_chan[ch].bIgnoreLoop = 0;\r
      spu.dwNewChannel|=(1<<ch);\r
     }\r
   }\r
index 3bca518..28641b8 100644 (file)
@@ -15,6 +15,9 @@
  *                                                                         *\r
  ***************************************************************************/\r
 \r
+#ifndef __P_REGISTERS_H__\r
+#define __P_REGISTERS_H__\r
+\r
 #define H_SPUReverbAddr  0x0da2\r
 #define H_SPUirqAddr     0x0da4\r
 #define H_SPUaddr        0x0da6\r
 \r
 void CALLBACK SPUwriteRegister(unsigned long reg, unsigned short val, unsigned int cycles);\r
 \r
+#endif /* __P_REGISTERS_H__ */\r
index 0058ad2..e1b8a40 100644 (file)
@@ -247,6 +247,8 @@ static void StartSoundMain(int ch)
  s_chan->iSBPos=27;
  s_chan->spos=0;
 
+ s_chan->pCurr = spu.spuMemC+((regAreaGet(ch,6)&~1)<<3);
+
  spu.dwNewChannel&=~(1<<ch);                           // clear new channel bit
  spu.dwChannelOn|=1<<ch;
  spu.dwChannelDead&=~(1<<ch);
@@ -345,11 +347,11 @@ INLINE int iGetInterpolationVal(int *SB, int sinc, int spos, int fmod_freq)
      int vl, vr;int gpos;
      vl = (spos >> 6) & ~3;
      gpos = SB[28];
-     vr=(gauss[vl]*(int)gval0)&~2047;
-     vr+=(gauss[vl+1]*gval(1))&~2047;
-     vr+=(gauss[vl+2]*gval(2))&~2047;
-     vr+=(gauss[vl+3]*gval(3))&~2047;
-     fa = vr>>11;
+     vr=(gauss[vl]*(int)gval0) >> 15;
+     vr+=(gauss[vl+1]*gval(1)) >> 15;
+     vr+=(gauss[vl+2]*gval(2)) >> 15;
+     vr+=(gauss[vl+3]*gval(3)) >> 15;
+     fa = vr;
     } break;
    //--------------------------------------------------//
    case 1:                                             // simple interpolation
@@ -433,7 +435,7 @@ static int decode_block(void *unused, int ch, int *SB)
  decode_block_data(SB, start + 2, predict_nr, shift_factor);
 
  flags = start[1];
- if (flags & 4)
+ if (flags & 4 && (!s_chan->bIgnoreLoop))
   s_chan->pLoop = start;                   // loop adress
 
  start += 16;
@@ -1489,6 +1491,7 @@ long CALLBACK SPUinit(void)
    spu.s_chan[i].ADSRX.SustainIncrease = 1;
    spu.s_chan[i].pLoop = spu.spuMemC;
    spu.s_chan[i].pCurr = spu.spuMemC;
+   spu.s_chan[i].bIgnoreLoop = 0;
   }
 
  spu.bSpuInit=1;                                       // flag: we are inited
index d42425d..23425d9 100644 (file)
  *                                                                         *\r
  ***************************************************************************/\r
 \r
+#ifndef __P_SPU_H__\r
+#define __P_SPU_H__\r
+\r
 void ClearWorkingState(void);\r
 void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap);\r
 int  CALLBACK SPUplayCDDAchannel(short *pcm, int bytes);\r
+\r
+#endif /* __P_SPU_H__ */\r
index 7c4d565..56ede38 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __P_SPU_C64X_H__
+#define __P_SPU_C64X_H__
+
 #define COMPONENT_NAME "pcsxr_spu"
 
 enum {
@@ -26,3 +29,5 @@ struct region_mem {
 };
 
 #define ACTIVE_CNT 3
+
+#endif /* __P_SPU_C64X_H__ */
index 6b46bf3..95c8948 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __P_SPU_CONFIG_H__
+#define __P_SPU_CONFIG_H__
+
 // user settings
 
 typedef struct
@@ -7,7 +10,6 @@ typedef struct
  int        iUseReverb;
  int        iUseInterpolation;
  int        iTempo;
- int        idiablofix;
  int        iUseThread;
  int        iUseFixedUpdates;  // output fixed number of samples/frame
 
@@ -16,3 +18,5 @@ typedef struct
 } SPUConfig;
 
 extern SPUConfig spu_config;
+
+#endif /* __P_SPU_CONFIG_H__ */
index 7e22029..04aa233 100644 (file)
@@ -15,6 +15,9 @@
  *                                                                         *
  ***************************************************************************/
 
+#ifndef __P_STDAFX_H__
+#define __P_STDAFX_H__
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h> 
@@ -35,3 +38,5 @@
 #endif
 
 #include "psemuxa.h"
+
+#endif /* __P_STDAFX_H__ */
index ad7e824..bfebe3e 100644 (file)
@@ -189,16 +189,16 @@ INLINE void FeedXA(xa_decode_t *xap)
            spos -= 0x10000L;
           }
          vl = (spos >> 6) & ~3;
-         vr=(gauss[vl]*gvall0)&~2047;
-         vr+=(gauss[vl+1]*gvall(1))&~2047;
-         vr+=(gauss[vl+2]*gvall(2))&~2047;
-         vr+=(gauss[vl+3]*gvall(3))&~2047;
-         l= (vr >> 11) & 0xffff;
-         vr=(gauss[vl]*gvalr0)&~2047;
-         vr+=(gauss[vl+1]*gvalr(1))&~2047;
-         vr+=(gauss[vl+2]*gvalr(2))&~2047;
-         vr+=(gauss[vl+3]*gvalr(3))&~2047;
-         l |= vr << 5;
+         vr=(gauss[vl]*gvall0) >> 15;
+         vr+=(gauss[vl+1]*gvall(1)) >> 15;
+         vr+=(gauss[vl+2]*gvall(2)) >> 15;
+         vr+=(gauss[vl+3]*gvall(3)) >> 15;
+         l= vr & 0xffff;
+         vr=(gauss[vl]*gvalr0) >> 15;
+         vr+=(gauss[vl+1]*gvalr(1)) >> 15;
+         vr+=(gauss[vl+2]*gvalr(2)) >> 15;
+         vr+=(gauss[vl+3]*gvalr(3)) >> 15;
+         l |= vr << 16;
         }
        else
         {
@@ -246,16 +246,16 @@ INLINE void FeedXA(xa_decode_t *xap)
            spos -= 0x10000L;
           }
          vl = (spos >> 6) & ~3;
-         vr=(gauss[vl]*gvall0)&~2047;
-         vr+=(gauss[vl+1]*gvall(1))&~2047;
-         vr+=(gauss[vl+2]*gvall(2))&~2047;
-         vr+=(gauss[vl+3]*gvall(3))&~2047;
-         l= (vr >> 11) & 0xffff;
-         vr=(gauss[vl]*gvalr0)&~2047;
-         vr+=(gauss[vl+1]*gvalr(1))&~2047;
-         vr+=(gauss[vl+2]*gvalr(2))&~2047;
-         vr+=(gauss[vl+3]*gvalr(3))&~2047;
-         l |= vr << 5;
+         vr=(gauss[vl]*gvall0) >> 15;
+         vr+=(gauss[vl+1]*gvall(1)) >> 15;
+         vr+=(gauss[vl+2]*gvall(2)) >> 15;
+         vr+=(gauss[vl+3]*gvall(3)) >> 15;
+         l= vr & 0xffff;
+         vr=(gauss[vl]*gvalr0) >> 15;
+         vr+=(gauss[vl+1]*gvalr(1)) >> 15;
+         vr+=(gauss[vl+2]*gvalr(2)) >> 15;
+         vr+=(gauss[vl+3]*gvalr(3)) >> 15;
+         l |= vr << 16;
         }
        else
         {
@@ -298,11 +298,11 @@ INLINE void FeedXA(xa_decode_t *xap)
            spos -= 0x10000L;
           }
          vl = (spos >> 6) & ~3;
-         vr=(gauss[vl]*gvall0)&~2047;
-         vr+=(gauss[vl+1]*gvall(1))&~2047;
-         vr+=(gauss[vl+2]*gvall(2))&~2047;
-         vr+=(gauss[vl+3]*gvall(3))&~2047;
-         l1=s= vr >> 11;
+         vr=(gauss[vl]*gvall0) >> 15;
+         vr+=(gauss[vl+1]*gvall(1)) >> 15;
+         vr+=(gauss[vl+2]*gvall(2)) >> 15;
+         vr+=(gauss[vl+3]*gvall(3)) >> 15;
+         l1=s= vr;
          l1 &= 0xffff;
         }
        else
@@ -343,11 +343,11 @@ INLINE void FeedXA(xa_decode_t *xap)
            spos -= 0x10000L;
           }
          vl = (spos >> 6) & ~3;
-         vr=(gauss[vl]*gvall0)&~2047;
-         vr+=(gauss[vl+1]*gvall(1))&~2047;
-         vr+=(gauss[vl+2]*gvall(2))&~2047;
-         vr+=(gauss[vl+3]*gvall(3))&~2047;
-         l=s= vr >> 11;
+         vr=(gauss[vl]*gvall0) >> 15;
+         vr+=(gauss[vl+1]*gvall(1)) >> 15;
+         vr+=(gauss[vl+2]*gvall(2)) >> 15;
+         vr+=(gauss[vl+3]*gvall(3)) >> 15;
+         l=s= vr;
         }
        else
         {
index cbf2843..137fe43 100644 (file)
  *                                                                         *\r
  ***************************************************************************/\r
 \r
+#ifndef __P_XA_H__\r
+#define __P_XA_H__\r
+\r
 INLINE void MixXA(void);\r
 INLINE void FeedXA(xa_decode_t *xap);\r
-INLINE int  FeedCDDA(unsigned char *pcm, int nBytes);
+INLINE int  FeedCDDA(unsigned char *pcm, int nBytes);\r
+\r
+#endif /* __P_XA_H__ */\r
index 01b8dde..b2cca19 100644 (file)
 #include <string.h>
 #include "../gpulib/gpu.h"
 
+#ifdef THREAD_RENDERING
+#include "../gpulib/gpulib_thread_if.h"
+#define do_cmd_list real_do_cmd_list
+#define renderer_init real_renderer_init
+#define renderer_finish real_renderer_finish
+#define renderer_sync_ecmds real_renderer_sync_ecmds
+#define renderer_update_caches real_renderer_update_caches
+#define renderer_flush_queues real_renderer_flush_queues
+#define renderer_set_interlace real_renderer_set_interlace
+#define renderer_set_config real_renderer_set_config
+#define renderer_notify_res_change real_renderer_notify_res_change
+#define renderer_notify_update_lace real_renderer_notify_update_lace
+#define renderer_sync real_renderer_sync
+#define ex_regs scratch_ex_regs
+#endif
+
 #define u32 uint32_t
 
 #define INFO_TW        0
@@ -309,11 +325,11 @@ void renderer_notify_res_change(void)
 
 extern const unsigned char cmd_lengths[256];
 
-int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
+int do_cmd_list(uint32_t *list, int list_len, int *last_cmd)
 {
   unsigned int cmd = 0, len;
-  unsigned int *list_start = list;
-  unsigned int *list_end = list + list_len;
+  uint32_t *list_start = list;
+  uint32_t *list_end = list + list_len;
 
   for (; list < list_end; list += 1 + len)
   {
@@ -426,6 +442,14 @@ void renderer_set_interlace(int enable, int is_odd)
 {
 }
 
+void renderer_sync(void)
+{
+}
+
+void renderer_notify_update_lace(int updated)
+{
+}
+
 #include "../../frontend/plugin_lib.h"
 
 void renderer_set_config(const struct rearmed_cbs *cbs)
index c1c3bef..1b22ed5 100644 (file)
@@ -6316,6 +6316,7 @@ static void DrawSoftwareSpriteMirror(unsigned char * baseAddr,int32_t w,int32_t
     sprtYa=(sprtY<<10);
     clutP=(clutY0<<10)+clutX0;
     for (sprCY=0;sprCY<sprtH;sprCY++)
+    {
      for (sprCX=0;sprCX<sprtW;sprCX++)
       {
        tC= psxVub[((textY0+(sprCY*lYDir))<<11) + textX0 +(sprCX*lXDir)];
@@ -6323,28 +6324,33 @@ static void DrawSoftwareSpriteMirror(unsigned char * baseAddr,int32_t w,int32_t
        GetTextureTransColG_SPR(&psxVuw[sprA],GETLE16(&psxVuw[clutP+((tC>>4)&0xf)]));
        GetTextureTransColG_SPR(&psxVuw[sprA+1],GETLE16(&psxVuw[clutP+(tC&0xf)]));
       }
+    }
     return;
 
    case 1: 
 
     clutP>>=1;
     for(sprCY=0;sprCY<sprtH;sprCY++)
+    {
      for(sprCX=0;sprCX<sprtW;sprCX++)
       { 
        tC = psxVub[((textY0+(sprCY*lYDir))<<11)+(GlobalTextAddrX<<1) + textX0 + (sprCX*lXDir)] & 0xff;
        GetTextureTransColG_SPR(&psxVuw[((sprtY+sprCY)<<10)+sprtX + sprCX],psxVuw[clutP+tC]);
       }
-     return;
+    }
+    return;
 
    case 2:
 
     for (sprCY=0;sprCY<sprtH;sprCY++)
+    {
      for (sprCX=0;sprCX<sprtW;sprCX++)
       { 
        GetTextureTransColG_SPR(&psxVuw[((sprtY+sprCY)<<10)+sprtX+sprCX],
            GETLE16(&psxVuw[((textY0+(sprCY*lYDir))<<10)+GlobalTextAddrX + textX0 +(sprCX*lXDir)]));
       }
-     return;
+    }
+    return;
   }
 }
 
index 1f4a23d..8cc1469 100644 (file)
@@ -769,3 +769,11 @@ static void fps_update(void)
   DisplayText(buf, 1);
  }
 }
+
+void renderer_sync(void)
+{
+}
+
+void renderer_notify_update_lace(int updated)
+{
+}
index 1eaa99a..1fa6b98 100644 (file)
@@ -207,6 +207,7 @@ typedef struct
   u8 texture_4bpp_cache[32][256 * 256];
   u8 texture_8bpp_even_cache[16][256 * 256];
   u8 texture_8bpp_odd_cache[16][256 * 256];
+  int use_dithering;
 } psx_gpu_struct;
 
 typedef struct __attribute__((aligned(16)))
index 5460e40..161384e 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __P_PSX_GPU_OFFSETS_H__
+#define __P_PSX_GPU_OFFSETS_H__
+
 #define psx_gpu_test_mask_offset                          0x0
 #define psx_gpu_uvrg_offset                               0x10
 #define psx_gpu_uvrg_dx_offset                            0x20
@@ -56,3 +59,5 @@
 #define psx_gpu_texture_4bpp_cache_offset                 0x5a00
 #define psx_gpu_texture_8bpp_even_cache_offset            0x205a00
 #define psx_gpu_texture_8bpp_odd_cache_offset             0x305a00
+
+#endif /* __P_PSX_GPU_OFFSETS_H__ */
index ffa9b9a..87d8c38 100644 (file)
@@ -868,7 +868,72 @@ extern void scale2x_tiles8(void *dst, const void *src, int w8, int h);
 
 #ifndef NEON_BUILD
 // TODO?
-void scale2x_tiles8(void *dst, const void *src, int w8, int h) {}
+void scale2x_tiles8(void *dst, const void *src, int w8, int h)
+{
+  uint16_t* d = (uint16_t*)dst;
+  const uint16_t* s = (const uint16_t*)src;
+
+  while ( h-- )
+  {
+    uint16_t* d_save = d;
+    const uint16_t* s_save = s;
+    int w = w8;
+
+    while ( w-- )
+    {
+      d[    0 ] = *s;
+      d[    1 ] = *s;
+      d[ 1024 ] = *s;
+      d[ 1025 ] = *s;
+      d += 2; s++;
+
+      d[    0 ] = *s;
+      d[    1 ] = *s;
+      d[ 1024 ] = *s;
+      d[ 1025 ] = *s;
+      d += 2; s++;
+
+      d[    0 ] = *s;
+      d[    1 ] = *s;
+      d[ 1024 ] = *s;
+      d[ 1025 ] = *s;
+      d += 2; s++;
+
+      d[    0 ] = *s;
+      d[    1 ] = *s;
+      d[ 1024 ] = *s;
+      d[ 1025 ] = *s;
+      d += 2; s++;
+
+      d[    0 ] = *s;
+      d[    1 ] = *s;
+      d[ 1024 ] = *s;
+      d[ 1025 ] = *s;
+      d += 2; s++;
+
+      d[    0 ] = *s;
+      d[    1 ] = *s;
+      d[ 1024 ] = *s;
+      d[ 1025 ] = *s;
+      d += 2; s++;
+
+      d[    0 ] = *s;
+      d[    1 ] = *s;
+      d[ 1024 ] = *s;
+      d[ 1025 ] = *s;
+      d += 2; s++;
+
+      d[    0 ] = *s;
+      d[    1 ] = *s;
+      d[ 1024 ] = *s;
+      d[ 1025 ] = *s;
+      d += 2; s++;
+    }
+
+    d = d_save + 2048;
+    s = s_save + 1024; /* or 512? */
+  }
+}
 #endif
 
 static int disable_main_render;
index ad01761..81b9bae 100644 (file)
@@ -9,7 +9,12 @@
  */
 
 #include <stdio.h>
+
+#ifdef _WIN32
+#include <mman.h>
+#else
 #include <sys/mman.h>
+#endif
 
 extern const unsigned char cmd_lengths[256];
 #define command_lengths cmd_lengths
@@ -184,4 +189,24 @@ void renderer_set_config(const struct rearmed_cbs *cbs)
     map_enhancement_buffer();
   if (cbs->pl_set_gpu_caps)
     cbs->pl_set_gpu_caps(GPU_CAP_SUPPORTS_2X);
+  
+  egpu.use_dithering = cbs->gpu_neon.allow_dithering;
+  if(!egpu.use_dithering) {
+    egpu.dither_table[0] = dither_table_row(0, 0, 0, 0);
+    egpu.dither_table[1] = dither_table_row(0, 0, 0, 0);
+    egpu.dither_table[2] = dither_table_row(0, 0, 0, 0);
+    egpu.dither_table[3] = dither_table_row(0, 0, 0, 0);
+  } else {
+    egpu.dither_table[0] = dither_table_row(-4, 0, -3, 1);
+    egpu.dither_table[1] = dither_table_row(2, -2, 3, -1);
+    egpu.dither_table[2] = dither_table_row(-3, 1, -4, 0);
+    egpu.dither_table[3] = dither_table_row(3, -1, 2, -2); 
+  }
+
+}
+void renderer_sync(void)
+{
+}
+void renderer_notify_update_lace(int updated)
+{
 }
index 1075ee5..756d19a 100644 (file)
@@ -1,6 +1,9 @@
 CFLAGS += -ggdb -Wall -O3 -ffast-math
 CFLAGS += -DREARMED
 CFLAGS += -I../../include
+#CFLAGS += -DINLINE="static __inline__"
+#CFLAGS += -Dasm="__asm__ __volatile__"
+CFLAGS += -DUSE_GPULIB=1
 
 include ../../config.mak
 
@@ -8,7 +11,7 @@ SRC_STANDALONE += gpu.cpp
 SRC_GPULIB += gpulib_if.cpp
 
 ifeq "$(ARCH)" "arm"
-SRC += gpu_arm.s
+SRC += gpu_arm.S
 endif
 
 #BIN_STANDALONE = gpuPCSX4ALL.so
diff --git a/plugins/gpu_unai/README_senquack.txt b/plugins/gpu_unai/README_senquack.txt
new file mode 100644 (file)
index 0000000..cda17fc
--- /dev/null
@@ -0,0 +1,956 @@
+//NOTE: You can find the set of original Unai poly routines (disabled now)
+// at the bottom end of this file.
+
+//senquack - Original Unai GPU poly routines have been replaced with new
+// ones based on DrHell routines. The original routines suffered from
+// shifted rows, causing many quads to have their first triangle drawn
+// correctly, but the second triangle would randomly have pixels shifted
+// either left or right or entire rows not drawn at all. Furthermore,
+// some times entire triangles seemed to be either missing or only
+// partially drawn (most clearly seen in sky/road textures in NFS3,
+// clock tower in beginning of Castlevania SOTN). Pixel gaps were
+// prevalent.
+//
+// Since DrHell GPU didn't seem to exhibit these artifacts at all, I adapted
+// its routines to GPU Unai (Unai was probably already originally based on it).
+// DrHell uses 22.10 fixed point instead of Unai's 16.16, so gpu_fixedpoint.h
+// required modification as well as gpu_inner.h (where gpuPolySpanFn driver
+// functions are).
+//
+// Originally, I tried to patch up original Unai routines and got as far
+// as fixing the shifted rows, but still had other problem of triangles rendered
+// wrong (black triangular gaps in NFS3 sky, clock tower in Castlevania SOTN).
+// I eventually gave up. Even after rewriting/adapting the routines,
+// however, I still had some random pixel droupouts, specifically in
+// NFS3 sky texture. I discovered that gpu_inner.h gpuPolySpanFn function
+// was taking optimizations to an extreme and packing u/v texture coords
+// into one 32-bit word, reducing their accuracy. Only once they were
+// handled in full-accuracy individual words was that problem fixed.
+//
+// NOTE: I also added support for doing divisions using the FPU, either
+//  with normal division or multiplication-by-reciprocal.
+//  To use float division, GPU_UNAI_USE_FLOATMATH should be defined.
+//  To use float mult-by-reciprocal, GPU_UNAI_USE_FLOAT_DIV_MULTINV
+//   can be specified (GPU_UNAI_USE_FLOATMATH must also be specified)
+//  To use inaccurate fixed-point mult-by-reciprocal, define
+//   GPU_UNAI_USE_INT_DIV_MULTINV. This is the default on older
+//   ARM devices like Wiz/Caanoo that have neither integer division
+//   in hardware or an FPU. It results in some pixel dropouts,
+//   texture glitches, but less than the original GPU UNAI code.
+//
+//  If nothing is specified, integer division will be used.
+//
+// NOTE 2: Even with MIPS32R2 having FPU recip.s instruction, and it is
+//  used when this platform is detected, I found it not to give any
+//  noticeable speedup over normal float division (in fact seemed a tiny
+//  tiny bit slower). I also found float division to not provide any
+//  noticeable speedups versus integer division on MISP32R2 platform.
+//  Granted, the differences were all around .5 FPS or less.
+//
+// TODO:
+// * See if anything can be done about remaining pixel gaps in Gran
+//   Turismo car models, track.
+// * Find better way of passing parameters to gpuPolySpanFn functions than
+//   through original Unai method of using global variables u4,v4,du4 etc.
+// * Come up with some newer way of drawing rows of pixels than by calling
+//   gpuPolySpanFn through function pointer. For every row, at least on
+//   MIPS platforms, many registers are having to be pushed/popped from stack
+//   on each call, which is strange since MIPS has so many registers.
+// * MIPS MXU/ASM optimized gpuPolySpanFn ?
+
+//////////////////////////////////////////////////////////////////////////
+//senquack - Disabled original Unai poly routines left here for reference:
+// ( from gpu_raster_polygon.h )
+//////////////////////////////////////////////////////////////////////////
+#define GPU_TESTRANGE3() \
+{ \
+       if(x0<0) { if((x1-x0)>CHKMAX_X) return; if((x2-x0)>CHKMAX_X) return; } \
+       if(x1<0) { if((x0-x1)>CHKMAX_X) return; if((x2-x1)>CHKMAX_X) return; } \
+       if(x2<0) { if((x0-x2)>CHKMAX_X) return; if((x1-x2)>CHKMAX_X) return; } \
+       if(y0<0) { if((y1-y0)>CHKMAX_Y) return; if((y2-y0)>CHKMAX_Y) return; } \
+       if(y1<0) { if((y0-y1)>CHKMAX_Y) return; if((y2-y1)>CHKMAX_Y) return; } \
+       if(y2<0) { if((y0-y2)>CHKMAX_Y) return; if((y1-y2)>CHKMAX_Y) return; } \
+}
+
+/*----------------------------------------------------------------------
+F3
+----------------------------------------------------------------------*/
+
+void gpuDrawF3(const PP gpuPolySpanDriver)
+{
+       const int li=linesInterlace;
+       const int pi=(progressInterlace?(linesInterlace+1):0);
+       const int pif=(progressInterlace?(progressInterlace_flag?(linesInterlace+1):0):1);
+       s32 temp;
+       s32 xa, xb, xmin, xmax;
+       s32 ya, yb, ymin, ymax;
+       s32 x0, x1, x2, x3, dx3=0, x4, dx4=0, dx;
+       s32 y0, y1, y2;
+
+       x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2]);
+       y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3]);
+       x1 = GPU_EXPANDSIGN(PacketBuffer.S2[4]);
+       y1 = GPU_EXPANDSIGN(PacketBuffer.S2[5]);
+       x2 = GPU_EXPANDSIGN(PacketBuffer.S2[6]);
+       y2 = GPU_EXPANDSIGN(PacketBuffer.S2[7]);
+
+       GPU_TESTRANGE3();
+       
+       x0 += DrawingOffset[0];   x1 += DrawingOffset[0];   x2 += DrawingOffset[0];
+       y0 += DrawingOffset[1];   y1 += DrawingOffset[1];   y2 += DrawingOffset[1];
+
+       xmin = DrawingArea[0];  xmax = DrawingArea[2];
+       ymin = DrawingArea[1];  ymax = DrawingArea[3];
+
+       {
+               int rx0 = Max2(xmin,Min3(x0,x1,x2));
+               int ry0 = Max2(ymin,Min3(y0,y1,y2));
+               int rx1 = Min2(xmax,Max3(x0,x1,x2));
+               int ry1 = Min2(ymax,Max3(y0,y1,y2));
+               if( rx0>=rx1 || ry0>=ry1) return;
+       }
+       
+       PixelData = GPU_RGB16(PacketBuffer.U4[0]);
+
+       if (y0 >= y1)
+       {
+               if( y0!=y1 || x0>x1 )
+               {
+                       GPU_SWAP(x0, x1, temp);
+                       GPU_SWAP(y0, y1, temp);
+               }
+       }
+       if (y1 >= y2)
+       {
+               if( y1!=y2 || x1>x2 )
+               {
+                       GPU_SWAP(x1, x2, temp);
+                       GPU_SWAP(y1, y2, temp);
+               }
+       }
+       if (y0 >= y1)
+       {
+               if( y0!=y1 || x0>x1 )
+               {
+                       GPU_SWAP(x0, x1, temp);
+                       GPU_SWAP(y0, y1, temp);
+               }
+       }
+
+       ya = y2 - y0;
+       yb = y2 - y1;
+       dx =(x2 - x1) * ya - (x2 - x0) * yb;
+
+       for (s32 loop0 = 2; loop0; --loop0)
+       {
+               if (loop0 == 2)
+               {
+                       ya = y0;
+                       yb = y1;
+                       x3 = i2x(x0);
+                       x4 = y0!=y1 ? x3 : i2x(x1);
+                       if (dx < 0)
+                       {
+                               dx3 = xLoDivx((x2 - x0), (y2 - y0));
+                               dx4 = xLoDivx((x1 - x0), (y1 - y0));
+                       }
+                       else
+                       {
+                               dx3 = xLoDivx((x1 - x0), (y1 - y0));
+                               dx4 = xLoDivx((x2 - x0), (y2 - y0));
+                       }
+               }
+               else
+               {
+                       ya = y1;
+                       yb = y2;
+                       if (dx < 0)
+                       {
+                               x4  = i2x(x1);
+                               x3  = i2x(x0) + (dx3 * (y1 - y0));
+                               dx4 = xLoDivx((x2 - x1), (y2 - y1));
+                       }
+                       else
+                       {
+                               x3  = i2x(x1);
+                               x4  = i2x(x0) + (dx4 * (y1 - y0));
+                               dx3 = xLoDivx((x2 - x1), (y2 - y1));
+                       }
+               }
+
+               temp = ymin - ya;
+               if (temp > 0)
+               {
+                       ya  = ymin;
+                       x3 += dx3*temp;
+                       x4 += dx4*temp;
+               }
+               if (yb > ymax) yb = ymax;
+               if (ya>=yb) continue;
+
+               x3+= fixed_HALF;
+               x4+= fixed_HALF;
+
+               u16* PixelBase  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(0, ya)];
+               
+               for(;ya<yb;++ya, PixelBase += FRAME_WIDTH, x3+=dx3, x4+=dx4)
+               {
+                       if (ya&li) continue;
+                       if ((ya&pi)==pif) continue;
+                       xa = x2i(x3);
+                       xb = x2i(x4);
+                       if( (xa>xmax) || (xb<xmin) ) continue;
+                       if(xa < xmin) xa = xmin;
+                       if(xb > xmax) xb = xmax;
+                       xb-=xa;
+                       if(xb>0) gpuPolySpanDriver(PixelBase + xa,xb);
+               }
+       }
+}
+
+/*----------------------------------------------------------------------
+FT3
+----------------------------------------------------------------------*/
+
+void gpuDrawFT3(const PP gpuPolySpanDriver)
+{
+       const int li=linesInterlace;
+       const int pi=(progressInterlace?(linesInterlace+1):0);
+       const int pif=(progressInterlace?(progressInterlace_flag?(linesInterlace+1):0):1);
+       s32 temp;
+       s32 xa, xb, xmin, xmax;
+       s32 ya, yb, ymin, ymax;
+       s32 x0, x1, x2, x3, dx3=0, x4, dx4=0, dx;
+       s32 y0, y1, y2;
+       s32 u0, u1, u2, u3, du3=0;
+       s32 v0, v1, v2, v3, dv3=0;
+
+       x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2] );
+       y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3] );
+       x1 = GPU_EXPANDSIGN(PacketBuffer.S2[6] );
+       y1 = GPU_EXPANDSIGN(PacketBuffer.S2[7] );
+       x2 = GPU_EXPANDSIGN(PacketBuffer.S2[10]);
+       y2 = GPU_EXPANDSIGN(PacketBuffer.S2[11]);
+
+       GPU_TESTRANGE3();
+       
+       x0 += DrawingOffset[0];   x1 += DrawingOffset[0];   x2 += DrawingOffset[0];
+       y0 += DrawingOffset[1];   y1 += DrawingOffset[1];   y2 += DrawingOffset[1];
+
+       xmin = DrawingArea[0];  xmax = DrawingArea[2];
+       ymin = DrawingArea[1];  ymax = DrawingArea[3];
+
+       {
+               int rx0 = Max2(xmin,Min3(x0,x1,x2));
+               int ry0 = Max2(ymin,Min3(y0,y1,y2));
+               int rx1 = Min2(xmax,Max3(x0,x1,x2));
+               int ry1 = Min2(ymax,Max3(y0,y1,y2));
+               if( rx0>=rx1 || ry0>=ry1) return;
+       }
+       
+       u0 = PacketBuffer.U1[8];  v0 = PacketBuffer.U1[9];
+       u1 = PacketBuffer.U1[16]; v1 = PacketBuffer.U1[17];
+       u2 = PacketBuffer.U1[24]; v2 = PacketBuffer.U1[25];
+
+       r4 = s32(PacketBuffer.U1[0]);
+       g4 = s32(PacketBuffer.U1[1]);
+       b4 = s32(PacketBuffer.U1[2]);
+       dr4 = dg4 = db4 = 0;
+
+       if (y0 >= y1)
+       {
+               if( y0!=y1 || x0>x1 )
+               {
+                       GPU_SWAP(x0, x1, temp);
+                       GPU_SWAP(y0, y1, temp);
+                       GPU_SWAP(u0, u1, temp);
+                       GPU_SWAP(v0, v1, temp);
+               }
+       }
+       if (y1 >= y2)
+       {
+               if( y1!=y2 || x1>x2 )
+               {
+                       GPU_SWAP(x1, x2, temp);
+                       GPU_SWAP(y1, y2, temp);
+                       GPU_SWAP(u1, u2, temp);
+                       GPU_SWAP(v1, v2, temp);
+               }
+       }
+       if (y0 >= y1)
+       {
+               if( y0!=y1 || x0>x1 )
+               {
+                       GPU_SWAP(x0, x1, temp);
+                       GPU_SWAP(y0, y1, temp);
+                       GPU_SWAP(u0, u1, temp);
+                       GPU_SWAP(v0, v1, temp);
+               }
+       }
+
+       ya  = y2 - y0;
+       yb  = y2 - y1;
+       dx  = (x2 - x1) * ya - (x2 - x0) * yb;
+       du4 = (u2 - u1) * ya - (u2 - u0) * yb;
+       dv4 = (v2 - v1) * ya - (v2 - v0) * yb;
+
+       s32 iF,iS;
+       xInv( dx, iF, iS);
+       du4 = xInvMulx( du4, iF, iS);
+       dv4 = xInvMulx( dv4, iF, iS);
+       tInc = ((u32)(du4<<7)&0x7fff0000) | ((u32)(dv4>>9)&0x00007fff);
+       tMsk = (TextureWindow[2]<<23) | (TextureWindow[3]<<7) | 0x00ff00ff;
+
+       for (s32 loop0 = 2; loop0; --loop0)
+       {
+               if (loop0 == 2)
+               {
+                       ya = y0;
+                       yb = y1;
+                       u3 = i2x(u0);
+                       v3 = i2x(v0);
+                       x3 = i2x(x0);
+                       x4 = y0!=y1 ? x3 : i2x(x1);
+                       if (dx < 0)
+                       {
+                               xInv( (y2 - y0), iF, iS);
+                               dx3 = xInvMulx( (x2 - x0), iF, iS);
+                               du3 = xInvMulx( (u2 - u0), iF, iS);
+                               dv3 = xInvMulx( (v2 - v0), iF, iS);
+                               dx4 = xLoDivx ( (x1 - x0), (y1 - y0));
+                       }
+                       else
+                       {
+                               xInv( (y1 - y0), iF, iS);
+                               dx3 = xInvMulx( (x1 - x0), iF, iS);
+                               du3 = xInvMulx( (u1 - u0), iF, iS);
+                               dv3 = xInvMulx( (v1 - v0), iF, iS);
+                               dx4 = xLoDivx ( (x2 - x0), (y2 - y0));
+                       }
+               }
+               else
+               {
+                       ya = y1;
+                       yb = y2;
+                       if (dx < 0)
+                       {
+                               temp = y1 - y0;
+                               u3 = i2x(u0) + (du3 * temp);
+                               v3 = i2x(v0) + (dv3 * temp);
+                               x3 = i2x(x0) + (dx3 * temp);
+                               x4 = i2x(x1);
+                               dx4 = xLoDivx((x2 - x1), (y2 - y1));
+                       }
+                       else
+                       {
+                               u3 = i2x(u1);
+                               v3 = i2x(v1);
+                               x3 = i2x(x1);
+                               x4 = i2x(x0) + (dx4 * (y1 - y0));
+                               xInv( (y2 - y1), iF, iS);
+                               dx3 = xInvMulx( (x2 - x1), iF, iS);
+                               du3 = xInvMulx( (u2 - u1), iF, iS);
+                               dv3 = xInvMulx( (v2 - v1), iF, iS);
+                       }
+               }
+
+               temp = ymin - ya;
+               if (temp > 0)
+               {
+                       ya  = ymin;
+                       x3 += dx3*temp;
+                       x4 += dx4*temp;
+                       u3 += du3*temp;
+                       v3 += dv3*temp;
+               }
+               if (yb > ymax) yb = ymax;
+               if (ya>=yb) continue;
+
+               x3+= fixed_HALF;
+               x4+= fixed_HALF;
+               u3+= fixed_HALF;
+               v4+= fixed_HALF;
+
+               u16* PixelBase  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(0, ya)];
+
+               for(;ya<yb;++ya, PixelBase += FRAME_WIDTH, x3+=dx3, x4+=dx4, u3+=du3, v3+=dv3)
+               {
+                       if (ya&li) continue;
+                       if ((ya&pi)==pif) continue;
+                       xa = x2i(x3);
+                       xb = x2i(x4);
+                       if( (xa>xmax) || (xb<xmin) ) continue;
+
+                       temp = xmin - xa;
+                       if(temp > 0)
+                       {
+                               xa  = xmin;
+                               u4 = u3 + du4*temp;
+                               v4 = v3 + dv4*temp;
+                       }
+                       else
+                       {
+                               u4 = u3;
+                               v4 = v3;
+                       }
+                       if(xb > xmax) xb = xmax;
+                       xb-=xa;
+                       if(xb>0) gpuPolySpanDriver(PixelBase + xa,xb);
+               }
+       }
+}
+
+/*----------------------------------------------------------------------
+G3
+----------------------------------------------------------------------*/
+
+void gpuDrawG3(const PP gpuPolySpanDriver)
+{
+       const int li=linesInterlace;
+       const int pi=(progressInterlace?(linesInterlace+1):0);
+       const int pif=(progressInterlace?(progressInterlace_flag?(linesInterlace+1):0):1);
+       s32 temp;
+       s32 xa, xb, xmin, xmax;
+       s32 ya, yb, ymin, ymax;
+       s32 x0, x1, x2, x3, dx3=0, x4, dx4=0, dx;
+       s32 y0, y1, y2;
+       s32 r0, r1, r2, r3, dr3=0;
+       s32 g0, g1, g2, g3, dg3=0;
+       s32 b0, b1, b2, b3, db3=0;
+
+       x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2] );
+       y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3] );
+       x1 = GPU_EXPANDSIGN(PacketBuffer.S2[6] );
+       y1 = GPU_EXPANDSIGN(PacketBuffer.S2[7] );
+       x2 = GPU_EXPANDSIGN(PacketBuffer.S2[10]);
+       y2 = GPU_EXPANDSIGN(PacketBuffer.S2[11]);
+
+       GPU_TESTRANGE3();
+       
+       x0 += DrawingOffset[0];   x1 += DrawingOffset[0];   x2 += DrawingOffset[0];
+       y0 += DrawingOffset[1];   y1 += DrawingOffset[1];   y2 += DrawingOffset[1];
+
+       xmin = DrawingArea[0];  xmax = DrawingArea[2];
+       ymin = DrawingArea[1];  ymax = DrawingArea[3];
+
+       {
+               int rx0 = Max2(xmin,Min3(x0,x1,x2));
+               int ry0 = Max2(ymin,Min3(y0,y1,y2));
+               int rx1 = Min2(xmax,Max3(x0,x1,x2));
+               int ry1 = Min2(ymax,Max3(y0,y1,y2));
+               if( rx0>=rx1 || ry0>=ry1) return;
+       }
+       
+       r0 = PacketBuffer.U1[0];        g0 = PacketBuffer.U1[1];        b0 = PacketBuffer.U1[2];
+       r1 = PacketBuffer.U1[8];        g1 = PacketBuffer.U1[9];        b1 = PacketBuffer.U1[10];
+       r2 = PacketBuffer.U1[16];       g2 = PacketBuffer.U1[17];       b2 = PacketBuffer.U1[18];
+
+       if (y0 >= y1)
+       {
+               if( y0!=y1 || x0>x1 )
+               {
+                       GPU_SWAP(x0, x1, temp);         GPU_SWAP(y0, y1, temp);
+                       GPU_SWAP(r0, r1, temp);         GPU_SWAP(g0, g1, temp);         GPU_SWAP(b0, b1, temp);
+               }
+       }
+       if (y1 >= y2)
+       {
+               if( y1!=y2 || x1>x2 )
+               {
+                       GPU_SWAP(x1, x2, temp);         GPU_SWAP(y1, y2, temp);
+                       GPU_SWAP(r1, r2, temp);         GPU_SWAP(g1, g2, temp);   GPU_SWAP(b1, b2, temp);
+               }
+       }
+       if (y0 >= y1)
+       {
+               if( y0!=y1 || x0>x1 )
+               {
+                       GPU_SWAP(x0, x1, temp);         GPU_SWAP(y0, y1, temp);
+                       GPU_SWAP(r0, r1, temp);   GPU_SWAP(g0, g1, temp);               GPU_SWAP(b0, b1, temp);
+               }
+       }
+
+       ya  = y2 - y0;
+       yb  = y2 - y1;
+       dx  = (x2 - x1) * ya - (x2 - x0) * yb;
+       dr4 = (r2 - r1) * ya - (r2 - r0) * yb;
+       dg4 = (g2 - g1) * ya - (g2 - g0) * yb;
+       db4 = (b2 - b1) * ya - (b2 - b0) * yb;
+
+       s32 iF,iS;
+       xInv(            dx, iF, iS);
+       dr4 = xInvMulx( dr4, iF, iS);
+       dg4 = xInvMulx( dg4, iF, iS);
+       db4 = xInvMulx( db4, iF, iS);
+       u32 dr = (u32)(dr4<< 8)&(0xffffffff<<21);   if(dr4<0) dr+= 1<<21;
+       u32 dg = (u32)(dg4>> 3)&(0xffffffff<<10);   if(dg4<0) dg+= 1<<10;
+       u32 db = (u32)(db4>>14)&(0xffffffff    );   if(db4<0) db+= 1<< 0;
+       lInc = db + dg + dr;
+
+       for (s32 loop0 = 2; loop0; --loop0)
+       {
+               if (loop0 == 2)
+               {
+                       ya = y0;
+                       yb = y1;
+                       r3 = i2x(r0);
+                       g3 = i2x(g0);
+                       b3 = i2x(b0);
+                       x3 = i2x(x0);
+                       x4 = y0!=y1 ? x3 : i2x(x1);
+                       if (dx < 0)
+                       {
+                               xInv(           (y2 - y0), iF, iS);
+                               dx3 = xInvMulx( (x2 - x0), iF, iS);
+                               dr3 = xInvMulx( (r2 - r0), iF, iS);
+                               dg3 = xInvMulx( (g2 - g0), iF, iS);
+                               db3 = xInvMulx( (b2 - b0), iF, iS);
+                               dx4 = xLoDivx ( (x1 - x0), (y1 - y0));
+                       }
+                       else
+                       {
+                               xInv(           (y1 - y0), iF, iS);
+                               dx3 = xInvMulx( (x1 - x0), iF, iS);
+                               dr3 = xInvMulx( (r1 - r0), iF, iS);
+                               dg3 = xInvMulx( (g1 - g0), iF, iS);
+                               db3 = xInvMulx( (b1 - b0), iF, iS);
+                               dx4 = xLoDivx ( (x2 - x0), (y2 - y0));
+                       }
+               }
+               else
+               {
+                       ya = y1;
+                       yb = y2;
+                       if (dx < 0)
+                       {
+                               temp = y1 - y0;
+                               r3  = i2x(r0) + (dr3 * temp);
+                               g3  = i2x(g0) + (dg3 * temp);
+                               b3  = i2x(b0) + (db3 * temp);
+                               x3  = i2x(x0) + (dx3 * temp);
+                               x4  = i2x(x1);
+                               dx4 = xLoDivx((x2 - x1), (y2 - y1));
+                       }
+                       else
+                       {
+                               r3 = i2x(r1);
+                               g3 = i2x(g1);
+                               b3 = i2x(b1);
+                               x3 = i2x(x1);
+                               x4 = i2x(x0) + (dx4 * (y1 - y0));
+
+                               xInv(           (y2 - y1), iF, iS);
+                               dx3 = xInvMulx( (x2 - x1), iF, iS);
+                               dr3 = xInvMulx( (r2 - r1), iF, iS);
+                               dg3 = xInvMulx( (g2 - g1), iF, iS);
+                               db3 = xInvMulx( (b2 - b1), iF, iS);
+                       }
+               }
+
+               temp = ymin - ya;
+               if (temp > 0)
+               {
+                       ya  = ymin;
+                       x3 += dx3*temp;   x4 += dx4*temp;
+                       r3 += dr3*temp;   g3 += dg3*temp;   b3 += db3*temp;
+               }
+               if (yb > ymax) yb = ymax;
+               if (ya>=yb) continue;
+
+               x3+= fixed_HALF;  x4+= fixed_HALF;
+               r3+= fixed_HALF;  g3+= fixed_HALF;  b3+= fixed_HALF;
+
+               u16* PixelBase  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(0, ya)];
+               
+               for(;ya<yb;++ya, PixelBase += FRAME_WIDTH, x3+=dx3, x4+=dx4, r3+=dr3, g3+=dg3, b3+=db3)
+               {
+                       if (ya&li) continue;
+                       if ((ya&pi)==pif) continue;
+                       xa = x2i(x3);
+                       xb = x2i(x4);
+                       if( (xa>xmax) || (xb<xmin) ) continue;
+
+                       temp = xmin - xa;
+                       if(temp > 0)
+                       {
+                               xa  = xmin;
+                               r4 = r3 + dr4*temp;   g4 = g3 + dg4*temp;   b4 = b3 + db4*temp;
+                       }
+                       else
+                       {
+                               r4 = r3;  g4 = g3;  b4 = b3;
+                       }
+                       if(xb > xmax) xb = xmax;
+                       xb-=xa;
+                       if(xb>0) gpuPolySpanDriver(PixelBase + xa,xb);
+               }
+       }
+}
+
+/*----------------------------------------------------------------------
+GT3
+----------------------------------------------------------------------*/
+
+void gpuDrawGT3(const PP gpuPolySpanDriver)
+{
+       const int li=linesInterlace;
+       const int pi=(progressInterlace?(linesInterlace+1):0);
+       const int pif=(progressInterlace?(progressInterlace_flag?(linesInterlace+1):0):1);
+       s32 temp;
+       s32 xa, xb, xmin, xmax;
+       s32 ya, yb, ymin, ymax;
+       s32 x0, x1, x2, x3, dx3=0, x4, dx4=0, dx;
+       s32 y0, y1, y2;
+       s32 u0, u1, u2, u3, du3=0;
+       s32 v0, v1, v2, v3, dv3=0;
+       s32 r0, r1, r2, r3, dr3=0;
+       s32 g0, g1, g2, g3, dg3=0;
+       s32 b0, b1, b2, b3, db3=0;
+
+       x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2] );
+       y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3] );
+       x1 = GPU_EXPANDSIGN(PacketBuffer.S2[8] );
+       y1 = GPU_EXPANDSIGN(PacketBuffer.S2[9] );
+       x2 = GPU_EXPANDSIGN(PacketBuffer.S2[14]);
+       y2 = GPU_EXPANDSIGN(PacketBuffer.S2[15]);
+
+       GPU_TESTRANGE3();
+       
+       x0 += DrawingOffset[0];   x1 += DrawingOffset[0];   x2 += DrawingOffset[0];
+       y0 += DrawingOffset[1];   y1 += DrawingOffset[1];   y2 += DrawingOffset[1];
+
+       xmin = DrawingArea[0];  xmax = DrawingArea[2];
+       ymin = DrawingArea[1];  ymax = DrawingArea[3];
+
+       {
+               int rx0 = Max2(xmin,Min3(x0,x1,x2));
+               int ry0 = Max2(ymin,Min3(y0,y1,y2));
+               int rx1 = Min2(xmax,Max3(x0,x1,x2));
+               int ry1 = Min2(ymax,Max3(y0,y1,y2));
+               if( rx0>=rx1 || ry0>=ry1) return;
+       }
+
+       r0 = PacketBuffer.U1[0];        g0 = PacketBuffer.U1[1];        b0 = PacketBuffer.U1[2];
+       u0 = PacketBuffer.U1[8];        v0 = PacketBuffer.U1[9];
+       r1 = PacketBuffer.U1[12];       g1 = PacketBuffer.U1[13];       b1 = PacketBuffer.U1[14];
+       u1 = PacketBuffer.U1[20];       v1 = PacketBuffer.U1[21];
+       r2 = PacketBuffer.U1[24];       g2 = PacketBuffer.U1[25];       b2 = PacketBuffer.U1[26];
+       u2 = PacketBuffer.U1[32];       v2 = PacketBuffer.U1[33];
+
+       if (y0 >= y1)
+       {
+               if( y0!=y1 || x0>x1 )
+               {
+                       GPU_SWAP(x0, x1, temp);         GPU_SWAP(y0, y1, temp);
+                       GPU_SWAP(u0, u1, temp);         GPU_SWAP(v0, v1, temp);
+                       GPU_SWAP(r0, r1, temp);         GPU_SWAP(g0, g1, temp);   GPU_SWAP(b0, b1, temp);
+               }
+       }
+       if (y1 >= y2)
+       {
+               if( y1!=y2 || x1>x2 )
+               {
+                       GPU_SWAP(x1, x2, temp);         GPU_SWAP(y1, y2, temp);
+                       GPU_SWAP(u1, u2, temp);         GPU_SWAP(v1, v2, temp);
+                       GPU_SWAP(r1, r2, temp);   GPU_SWAP(g1, g2, temp);               GPU_SWAP(b1, b2, temp);
+               }
+       }
+       if (y0 >= y1)
+       {
+               if( y0!=y1 || x0>x1 )
+               {
+                       GPU_SWAP(x0, x1, temp);         GPU_SWAP(y0, y1, temp);
+                       GPU_SWAP(u0, u1, temp);         GPU_SWAP(v0, v1, temp);
+                       GPU_SWAP(r0, r1, temp);         GPU_SWAP(g0, g1, temp);         GPU_SWAP(b0, b1, temp);
+               }
+       }
+
+       ya  = y2 - y0;
+       yb  = y2 - y1;
+       dx  = (x2 - x1) * ya - (x2 - x0) * yb;
+       du4 = (u2 - u1) * ya - (u2 - u0) * yb;
+       dv4 = (v2 - v1) * ya - (v2 - v0) * yb;
+       dr4 = (r2 - r1) * ya - (r2 - r0) * yb;
+       dg4 = (g2 - g1) * ya - (g2 - g0) * yb;
+       db4 = (b2 - b1) * ya - (b2 - b0) * yb;
+
+       s32 iF,iS;
+
+       xInv(            dx, iF, iS);
+       du4 = xInvMulx( du4, iF, iS);
+       dv4 = xInvMulx( dv4, iF, iS);
+       dr4 = xInvMulx( dr4, iF, iS);
+       dg4 = xInvMulx( dg4, iF, iS);
+       db4 = xInvMulx( db4, iF, iS);
+       u32 dr = (u32)(dr4<< 8)&(0xffffffff<<21);   if(dr4<0) dr+= 1<<21;
+       u32 dg = (u32)(dg4>> 3)&(0xffffffff<<10);   if(dg4<0) dg+= 1<<10;
+       u32 db = (u32)(db4>>14)&(0xffffffff    );   if(db4<0) db+= 1<< 0;
+       lInc = db + dg + dr;
+       tInc = ((u32)(du4<<7)&0x7fff0000) | ((u32)(dv4>>9)&0x00007fff);
+       tMsk = (TextureWindow[2]<<23) | (TextureWindow[3]<<7) | 0x00ff00ff;
+
+       for (s32 loop0 = 2; loop0; --loop0)
+       {
+               if (loop0 == 2)
+               {
+                       ya = y0;
+                       yb = y1;
+                       u3 = i2x(u0);
+                       v3 = i2x(v0);
+                       r3 = i2x(r0);
+                       g3 = i2x(g0);
+                       b3 = i2x(b0);
+                       x3 = i2x(x0);
+                       x4 = y0!=y1 ? x3 : i2x(x1);
+                       if (dx < 0)
+                       {
+                               xInv(           (y2 - y0), iF, iS);
+                               dx3 = xInvMulx( (x2 - x0), iF, iS);
+                               du3 = xInvMulx( (u2 - u0), iF, iS);
+                               dv3 = xInvMulx( (v2 - v0), iF, iS);
+                               dr3 = xInvMulx( (r2 - r0), iF, iS);
+                               dg3 = xInvMulx( (g2 - g0), iF, iS);
+                               db3 = xInvMulx( (b2 - b0), iF, iS);
+                               dx4 = xLoDivx ( (x1 - x0), (y1 - y0));
+                       }
+                       else
+                       {
+                               xInv(           (y1 - y0), iF, iS);
+                               dx3 = xInvMulx( (x1 - x0), iF, iS);
+                               du3 = xInvMulx( (u1 - u0), iF, iS);
+                               dv3 = xInvMulx( (v1 - v0), iF, iS);
+                               dr3 = xInvMulx( (r1 - r0), iF, iS);
+                               dg3 = xInvMulx( (g1 - g0), iF, iS);
+                               db3 = xInvMulx( (b1 - b0), iF, iS);
+                               dx4 = xLoDivx ( (x2 - x0), (y2 - y0));
+                       }
+               }
+               else
+               {
+                       ya = y1;
+                       yb = y2;
+                       if (dx < 0)
+                       {
+                               temp = y1 - y0;
+                               u3  = i2x(u0) + (du3 * temp);
+                               v3  = i2x(v0) + (dv3 * temp);
+                               r3  = i2x(r0) + (dr3 * temp);
+                               g3  = i2x(g0) + (dg3 * temp);
+                               b3  = i2x(b0) + (db3 * temp);
+                               x3  = i2x(x0) + (dx3 * temp);
+                               x4  = i2x(x1);
+                               dx4 = xLoDivx((x2 - x1), (y2 - y1));
+                       }
+                       else
+                       {
+                               u3 = i2x(u1);
+                               v3 = i2x(v1);
+                               r3 = i2x(r1);
+                               g3 = i2x(g1);
+                               b3 = i2x(b1);
+                               x3 = i2x(x1);
+                               x4 = i2x(x0) + (dx4 * (y1 - y0));
+
+                               xInv(           (y2 - y1), iF, iS);
+                               dx3 = xInvMulx( (x2 - x1), iF, iS);
+                               du3 = xInvMulx( (u2 - u1), iF, iS);
+                               dv3 = xInvMulx( (v2 - v1), iF, iS);
+                               dr3 = xInvMulx( (r2 - r1), iF, iS);
+                               dg3 = xInvMulx( (g2 - g1), iF, iS);
+                               db3 = xInvMulx( (b2 - b1), iF, iS);
+                       }
+               }
+
+               temp = ymin - ya;
+               if (temp > 0)
+               {
+                       ya  = ymin;
+                       x3 += dx3*temp;   x4 += dx4*temp;
+                       u3 += du3*temp;   v3 += dv3*temp;
+                       r3 += dr3*temp;   g3 += dg3*temp;   b3 += db3*temp;
+               }
+               if (yb > ymax) yb = ymax;
+               if (ya>=yb) continue;
+
+               x3+= fixed_HALF;  x4+= fixed_HALF;
+               u3+= fixed_HALF;  v4+= fixed_HALF;
+               r3+= fixed_HALF;  g3+= fixed_HALF;  b3+= fixed_HALF;
+               u16* PixelBase  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(0, ya)];
+               
+               for(;ya<yb;++ya, PixelBase += FRAME_WIDTH, x3+=dx3, x4+=dx4, u3+=du3, v3+=dv3, r3+=dr3, g3+=dg3,        b3+=db3)
+               {
+                       if (ya&li) continue;
+                       if ((ya&pi)==pif) continue;
+                       xa = x2i(x3);
+                       xb = x2i(x4);
+                       if( (xa>xmax) || (xb<xmin))     continue;
+
+                       temp = xmin - xa;
+                       if(temp > 0)
+                       {
+                               xa  = xmin;
+                               u4 = u3 + du4*temp;   v4 = v3 + dv4*temp;
+                               r4 = r3 + dr4*temp;   g4 = g3 + dg4*temp;   b4 = b3 + db4*temp;
+                       }
+                       else
+                       {
+                               u4 = u3;  v4 = v3;
+                               r4 = r3;  g4 = g3;  b4 = b3;
+                       }
+                       if(xb > xmax) xb = xmax;
+                       xb-=xa;
+                       if(xb>0) gpuPolySpanDriver(PixelBase + xa,xb);
+               }
+       }
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//senquack - Original Unai poly routines left here for reference:
+// ( from gpu_inner.h ) NOTE: this uses 16.16, not 22.10 fixed point
+//////////////////////////////////////////////////////////////////////////
+template<const int CF>
+INLINE void  gpuPolySpanFn(u16 *pDst, u32 count)
+{
+       if (!TM)
+       {       
+               // NO TEXTURE
+               if (!G)
+               {
+                       // NO GOURAUD
+                       u16 data;
+                       if (L) { u32 lCol=((u32)(b4<< 2)&(0x03ff)) | ((u32)(g4<<13)&(0x07ff<<10)) | ((u32)(r4<<24)&(0x07ff<<21)); gpuLightingRGB(data,lCol); }
+                       else data=PixelData;
+                       if ((!M)&&(!B))
+                       {
+                               if (MB) { data = data | 0x8000; }
+                               do { *pDst++ = data; } while (--count);
+                       }
+                       else if ((M)&&(!B))
+                       {
+                               if (MB) { data = data | 0x8000; }
+                               do { if (!(*pDst&0x8000)) { *pDst = data; } pDst++; } while (--count);
+                       }
+                       else
+                       {
+                               u16 uSrc;
+                               u16 uDst;
+                               u32 uMsk; if (BM==0) uMsk=0x7BDE;
+                               u32 bMsk; if (BI) bMsk=blit_mask;
+                               do
+                               {
+                                       // blit-mask
+                                       if (BI) { if((bMsk>>((((u32)pDst)>>1)&7))&1) goto endtile; }
+                                       //  masking
+                                       uDst = *pDst;
+                                       if(M) { if (uDst&0x8000) goto endtile;  }
+                                       uSrc = data;
+                                       //  blend
+                                       if (BM==0) gpuBlending00(uSrc, uDst);
+                                       if (BM==1) gpuBlending01(uSrc, uDst);
+                                       if (BM==2) gpuBlending02(uSrc, uDst);
+                                       if (BM==3) gpuBlending03(uSrc, uDst);
+                                       if (MB) { *pDst = uSrc | 0x8000; }
+                                       else    { *pDst = uSrc; }
+                                       endtile: pDst++;
+                               }
+                               while (--count);
+                       }
+               }
+               else
+               {
+                       // GOURAUD
+                       u16 uDst;
+                       u16 uSrc;
+                       u32 linc=lInc;
+                       u32 lCol=((u32)(b4>>14)&(0x03ff)) | ((u32)(g4>>3)&(0x07ff<<10)) | ((u32)(r4<<8)&(0x07ff<<21));
+                       u32 uMsk; if ((B)&&(BM==0)) uMsk=0x7BDE;
+                       u32 bMsk; if (BI) bMsk=blit_mask;
+                       do
+                       {
+                               // blit-mask
+                               if (BI) { if((bMsk>>((((u32)pDst)>>1)&7))&1) goto endgou; }
+                               //  masking
+                               if(M) { uDst = *pDst;  if (uDst&0x8000) goto endgou;  }
+                               //  blend
+                               if(B)
+                               {
+                                       //  light
+                                       gpuLightingRGB(uSrc,lCol);
+                                       if(!M)    { uDst = *pDst; }
+                                       if (BM==0) gpuBlending00(uSrc, uDst);
+                                       if (BM==1) gpuBlending01(uSrc, uDst);
+                                       if (BM==2) gpuBlending02(uSrc, uDst);
+                                       if (BM==3) gpuBlending03(uSrc, uDst);
+                               }
+                               else
+                               {
+                                       //  light
+                                       gpuLightingRGB(uSrc,lCol);
+                               }
+                               if (MB) { *pDst = uSrc | 0x8000; }
+                               else    { *pDst = uSrc; }
+                               endgou: pDst++; lCol=(lCol+linc);
+                       }
+                       while (--count);
+               }
+       }
+       else
+       {
+               // TEXTURE
+               u16 uDst;
+               u16 uSrc;
+               u32 linc; if (L&&G) linc=lInc;
+               u32 tinc=tInc;
+               u32 tmsk=tMsk;
+               u32 tCor = ((u32)( u4<<7)&0x7fff0000) | ((u32)( v4>>9)&0x00007fff); tCor&= tmsk;
+               const u16* _TBA=TBA;
+               const u16* _CBA; if (TM!=3) _CBA=CBA;
+               u32 lCol;
+               if(L && !G) { lCol = ((u32)(b4<< 2)&(0x03ff)) | ((u32)(g4<<13)&(0x07ff<<10)) | ((u32)(r4<<24)&(0x07ff<<21)); }
+               else if(L && G) { lCol = ((u32)(b4>>14)&(0x03ff)) | ((u32)(g4>>3)&(0x07ff<<10)) | ((u32)(r4<<8)&(0x07ff<<21));  }
+               u32 uMsk; if ((B)&&(BM==0)) uMsk=0x7BDE;
+               u32 bMsk; if (BI) bMsk=blit_mask;
+               do
+               {
+                       // blit-mask
+                       if (BI) { if((bMsk>>((((u32)pDst)>>1)&7))&1) goto endpoly; }
+                       //  masking
+                       if(M) { uDst = *pDst;  if (uDst&0x8000) goto endpoly;  }
+                       //  texture
+                       if (TM==1) { u32 tu=(tCor>>23); u32 tv=(tCor<<4)&(0xff<<11); u8 rgb=((u8*)_TBA)[tv+(tu>>1)]; uSrc=_CBA[(rgb>>((tu&1)<<2))&0xf]; if(!uSrc) goto endpoly; }
+                       if (TM==2) { uSrc = _CBA[(((u8*)_TBA)[(tCor>>23)+((tCor<<4)&(0xff<<11))])]; if(!uSrc)  goto endpoly; }
+                       if (TM==3) { uSrc = _TBA[(tCor>>23)+((tCor<<3)&(0xff<<10))]; if(!uSrc)  goto endpoly; }
+                       //  blend
+                       if(B)
+                       {
+                               if (uSrc&0x8000)
+                               {
+                                       //  light
+                                       if(L) gpuLightingTXT(uSrc, lCol);
+                                       if(!M)    { uDst = *pDst; }
+                                       if (BM==0) gpuBlending00(uSrc, uDst);
+                                       if (BM==1) gpuBlending01(uSrc, uDst);
+                                       if (BM==2) gpuBlending02(uSrc, uDst);
+                                       if (BM==3) gpuBlending03(uSrc, uDst);
+                               }
+                               else
+                               {
+                                       // light
+                                       if(L) gpuLightingTXT(uSrc, lCol);
+                               }
+                       }
+                       else
+                       {
+                               //  light
+                               if(L)  { gpuLightingTXT(uSrc, lCol); } else if(!MB) { uSrc&= 0x7fff; }
+                       }
+                       if (MB) { *pDst = uSrc | 0x8000; }
+                       else    { *pDst = uSrc; }
+                       endpoly: pDst++;
+                       tCor=(tCor+tinc)&tmsk;
+                       if (L&&G) lCol=(lCol+linc);
+               }
+               while (--count);
+       }
+}
index 1552bed..c3f7095 100644 (file)
@@ -1,6 +1,7 @@
 /***************************************************************************
 *   Copyright (C) 2010 PCSX4ALL Team                                      *
 *   Copyright (C) 2010 Unai                                               *
+*   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
 ***************************************************************************/
 
-#include "port.h"
-#include "gpu.h"
-#include "profiler.h"
-#include "debug.h"
+#include <stddef.h>
+#include "plugins.h"
+#include "psxcommon.h"
+//#include "port.h"
+#include "gpu_unai.h"
 
-int skipCount = 2; /* frame skip (0,1,2,3...) */
-int skCount = 0; /* internal frame skip */
-int linesInterlace = 0;  /* internal lines interlace */
-int linesInterlace_user = 0; /* Lines interlace */
+#define VIDEO_WIDTH 320
 
-bool isSkip = false; /* skip frame (info coming from GPU) */
-bool wasSkip = false;
-bool skipFrame = false; /* skip frame (according to frame skip) */
-bool alt_fps = false; /* Alternative FPS algorithm */
-bool show_fps = false; /* Show FPS statistics */
-
-bool isPAL = false; /* PAL video timing */
-bool progressInterlace_flag = false; /* Progressive interlace flag */
-bool progressInterlace = false; /* Progressive interlace option*/
-bool frameLimit = false; /* frames to wait */
-
-bool light = true; /* lighting */
-bool blend = true; /* blending */
-bool FrameToRead = false; /* load image in progress */
-bool FrameToWrite = false; /* store image in progress */
-bool fb_dirty = false;
-
-bool enableAbbeyHack = false; /* Abe's Odyssey hack */
-
-u8 BLEND_MODE;
-u8 TEXT_MODE;
-u8 Masking;
-
-u16 PixelMSB;
-u16 PixelData;
-
-///////////////////////////////////////////////////////////////////////////////
-//  GPU Global data
-///////////////////////////////////////////////////////////////////////////////
-
-///////////////////////////////////////////////////////////////////////////////
-//  Dma Transfers info
-s32            px,py;
-s32            x_end,y_end;
-u16*  pvram;
-
-u32 GP0;
-s32 PacketCount;
-s32 PacketIndex;
-
-///////////////////////////////////////////////////////////////////////////////
-//  Display status
-u32 DisplayArea   [6];
-
-///////////////////////////////////////////////////////////////////////////////
-//  Rasterizer status
-u32 TextureWindow [4];
-u32 DrawingArea   [4];
-u32 DrawingOffset [2];
+#ifdef TIME_IN_MSEC
+#define TPS 1000
+#else
+#define TPS 1000000
+#endif
 
-///////////////////////////////////////////////////////////////////////////////
-//  Rasterizer status
+#define IS_PAL (gpu_unai.GPU_GP1&(0x08<<17))
 
-u16* TBA;
-u16* CBA;
+//senquack - Original 512KB of guard space seems not to be enough, as Xenogears
+// accesses outside this range and crashes in town intro fight sequence.
+// Increased to 2MB total (double PSX VRAM) and Xenogears no longer
+// crashes, but some textures are still messed up. Also note that alignment min
+// is 16 bytes, needed for pixel-skipping rendering/blitting in high horiz res.
+// Extra 4KB is for guard room at beginning.
+// TODO: Determine cause of out-of-bounds write/reads. <-- Note: this is largely
+//  solved by adoption of PCSX Rearmed's 'gpulib' in gpulib_if.cpp, which
+//  replaces this file (gpu.cpp)
+//u16   GPU_FrameBuffer[(FRAME_BUFFER_SIZE+512*1024)/2] __attribute__((aligned(32)));
+static u16 GPU_FrameBuffer[(FRAME_BUFFER_SIZE*2 + 4096)/2] __attribute__((aligned(32)));
 
 ///////////////////////////////////////////////////////////////////////////////
-//  Inner Loops
-s32   u4, du4;
-s32   v4, dv4;
-s32   r4, dr4;
-s32   g4, dg4;
-s32   b4, db4;
-u32   lInc;
-u32   tInc, tMsk;
-
-GPUPacket PacketBuffer;
-// FRAME_BUFFER_SIZE is defined in bytes; 512K is guard memory for out of range reads
-u16   GPU_FrameBuffer[(FRAME_BUFFER_SIZE+512*1024)/2] __attribute__((aligned(2048)));
-u32   GPU_GP1;
+// GPU fixed point math
+#include "gpu_fixedpoint.h"
 
 ///////////////////////////////////////////////////////////////////////////////
-//  Inner loop driver instanciation file
+// Inner loop driver instantiation file
 #include "gpu_inner.h"
 
-///////////////////////////////////////////////////////////////////////////////
-//  GPU Raster Macros
-#define        GPU_RGB16(rgb)        ((((rgb)&0xF80000)>>9)|(((rgb)&0xF800)>>6)|(((rgb)&0xF8)>>3))
-
-#define GPU_EXPANDSIGN(x)  (((s32)(x)<<21)>>21)
-
-#define CHKMAX_X 1024
-#define CHKMAX_Y 512
-
-#define        GPU_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
-
 ///////////////////////////////////////////////////////////////////////////////
 // GPU internal image drawing functions
 #include "gpu_raster_image.h"
@@ -135,72 +76,88 @@ u32   GPU_GP1;
 #include "gpu_command.h"
 
 ///////////////////////////////////////////////////////////////////////////////
-INLINE void gpuReset(void)
+static void gpuReset(void)
 {
-       GPU_GP1 = 0x14802000;
-       TextureWindow[0] = 0;
-       TextureWindow[1] = 0;
-       TextureWindow[2] = 255;
-       TextureWindow[3] = 255;
-       DrawingArea[2] = 256;
-       DrawingArea[3] = 240;
-       DisplayArea[2] = 256;
-       DisplayArea[3] = 240;
-       DisplayArea[5] = 240;
+       memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
+       gpu_unai.vram = (u16*)GPU_FrameBuffer + (4096/2); //4kb guard room in front
+       gpu_unai.GPU_GP1 = 0x14802000;
+       gpu_unai.DrawingArea[2] = 256;
+       gpu_unai.DrawingArea[3] = 240;
+       gpu_unai.DisplayArea[2] = 256;
+       gpu_unai.DisplayArea[3] = 240;
+       gpu_unai.DisplayArea[5] = 240;
+       gpu_unai.TextureWindow[0] = 0;
+       gpu_unai.TextureWindow[1] = 0;
+       gpu_unai.TextureWindow[2] = 255;
+       gpu_unai.TextureWindow[3] = 255;
+       //senquack - new vars must be updated whenever texture window is changed:
+       //           (used for polygon-drawing in gpu_inner.h, gpu_raster_polygon.h)
+       const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
+       gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
+       gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
+
+       // Configuration options
+       gpu_unai.config = gpu_unai_config_ext;
+       gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
+       gpu_unai.frameskip.skipCount = gpu_unai.config.frameskip_count;
+
+       SetupLightLUT();
+       SetupDitheringConstants();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-bool  GPU_init(void)
+long GPU_init(void)
 {
        gpuReset();
-       
+
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
        // s_invTable
-       for(int i=1;i<=(1<<TABLE_BITS);++i)
+       for(unsigned int i=1;i<=(1<<TABLE_BITS);++i)
        {
-               double v = 1.0 / double(i);
-               #ifdef GPU_TABLE_10_BITS
-               v *= double(0xffffffff>>1);
-               #else
-               v *= double(0x80000000);
-               #endif
-               s_invTable[i-1]=s32(v);
+               s_invTable[i-1]=0x7fffffff/i;
        }
+#endif
+
+       gpu_unai.fb_dirty = true;
+       gpu_unai.dma.last_dma = NULL;
        return (0);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-void  GPU_shutdown(void)
+long GPU_shutdown(void)
 {
+       return 0;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-long  GPU_freeze(unsigned int bWrite, GPUFreeze_t* p2)
+long GPU_freeze(u32 bWrite, GPUFreeze_t* p2)
 {
        if (!p2) return (0);
-       if (p2->Version != 1) return (0);
+       if (p2->ulFreezeVersion != 1) return (0);
 
        if (bWrite)
        {
-               p2->GPU_gp1 = GPU_GP1;
-               memset(p2->Control, 0, sizeof(p2->Control));
+               p2->ulStatus = gpu_unai.GPU_GP1;
+               memset(p2->ulControl, 0, sizeof(p2->ulControl));
                // save resolution and registers for P.E.Op.S. compatibility
-               p2->Control[3] = (3 << 24) | ((GPU_GP1 >> 23) & 1);
-               p2->Control[4] = (4 << 24) | ((GPU_GP1 >> 29) & 3);
-               p2->Control[5] = (5 << 24) | (DisplayArea[0] | (DisplayArea[1] << 10));
-               p2->Control[6] = (6 << 24) | (2560 << 12);
-               p2->Control[7] = (7 << 24) | (DisplayArea[4] | (DisplayArea[5] << 10));
-               p2->Control[8] = (8 << 24) | ((GPU_GP1 >> 17) & 0x3f) | ((GPU_GP1 >> 10) & 0x40);
-               memcpy(p2->FrameBuffer, (u16*)GPU_FrameBuffer, FRAME_BUFFER_SIZE);
+               p2->ulControl[3] = (3 << 24) | ((gpu_unai.GPU_GP1 >> 23) & 1);
+               p2->ulControl[4] = (4 << 24) | ((gpu_unai.GPU_GP1 >> 29) & 3);
+               p2->ulControl[5] = (5 << 24) | (gpu_unai.DisplayArea[0] | (gpu_unai.DisplayArea[1] << 10));
+               p2->ulControl[6] = (6 << 24) | (2560 << 12);
+               p2->ulControl[7] = (7 << 24) | (gpu_unai.DisplayArea[4] | (gpu_unai.DisplayArea[5] << 10));
+               p2->ulControl[8] = (8 << 24) | ((gpu_unai.GPU_GP1 >> 17) & 0x3f) | ((gpu_unai.GPU_GP1 >> 10) & 0x40);
+               memcpy((void*)p2->psxVRam, (void*)gpu_unai.vram, FRAME_BUFFER_SIZE);
                return (1);
        }
        else
        {
-               GPU_GP1 = p2->GPU_gp1;
-               memcpy((u16*)GPU_FrameBuffer, p2->FrameBuffer, FRAME_BUFFER_SIZE);
-               GPU_writeStatus((5 << 24) | p2->Control[5]);
-               GPU_writeStatus((7 << 24) | p2->Control[7]);
-               GPU_writeStatus((8 << 24) | p2->Control[8]);
-               gpuSetTexture(GPU_GP1);
+               extern void GPU_writeStatus(u32 data);
+               gpu_unai.GPU_GP1 = p2->ulStatus;
+               memcpy((void*)gpu_unai.vram, (void*)p2->psxVRam, FRAME_BUFFER_SIZE);
+               GPU_writeStatus((5 << 24) | p2->ulControl[5]);
+               GPU_writeStatus((7 << 24) | p2->ulControl[7]);
+               GPU_writeStatus((8 << 24) | p2->ulControl[8]);
+               gpuSetTexture(gpu_unai.GPU_GP1);
                return (1);
        }
        return (0);
@@ -233,72 +190,69 @@ u8 PacketSize[256] =
 ///////////////////////////////////////////////////////////////////////////////
 INLINE void gpuSendPacket()
 {
-#ifdef DEBUG_ANALYSIS
-       dbg_anacnt_GPU_sendPacket++;
-#endif
-       gpuSendPacketFunction(PacketBuffer.U4[0]>>24);
+       gpuSendPacketFunction(gpu_unai.PacketBuffer.U4[0]>>24);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 INLINE void gpuCheckPacket(u32 uData)
 {
-       if (PacketCount)
+       if (gpu_unai.PacketCount)
        {
-               PacketBuffer.U4[PacketIndex++] = uData;
-               --PacketCount;
+               gpu_unai.PacketBuffer.U4[gpu_unai.PacketIndex++] = uData;
+               --gpu_unai.PacketCount;
        }
        else
        {
-               PacketBuffer.U4[0] = uData;
-               PacketCount = PacketSize[uData >> 24];
-               PacketIndex = 1;
+               gpu_unai.PacketBuffer.U4[0] = uData;
+               gpu_unai.PacketCount = PacketSize[uData >> 24];
+               gpu_unai.PacketIndex = 1;
        }
-       if (!PacketCount) gpuSendPacket();
+       if (!gpu_unai.PacketCount) gpuSendPacket();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-void  GPU_writeDataMem(u32* dmaAddress, s32 dmaCount)
+void GPU_writeDataMem(u32* dmaAddress, int dmaCount)
 {
-#ifdef DEBUG_ANALYSIS
-       dbg_anacnt_GPU_writeDataMem++;
-#endif
-       pcsx4all_prof_pause(PCSX4ALL_PROF_CPU);
-       pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"GPU_writeDataMem(%d)\n",dmaCount);
+       #endif
        u32 data;
-       const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
-       GPU_GP1 &= ~0x14000000;
+       const u16 *VIDEO_END = (u16*)gpu_unai.vram+(FRAME_BUFFER_SIZE/2)-1;
+       gpu_unai.GPU_GP1 &= ~0x14000000;
 
        while (dmaCount) 
        {
-               if (FrameToWrite) 
+               if (gpu_unai.dma.FrameToWrite)
                {
                        while (dmaCount)
                        {
                                dmaCount--;
                                data = *dmaAddress++;
-                               if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
-                               pvram[px] = data;
-                               if (++px>=x_end) 
+                               if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024;
+                               gpu_unai.dma.pvram[gpu_unai.dma.px] = data;
+                               if (++gpu_unai.dma.px >= gpu_unai.dma.x_end)
                                {
-                                       px = 0;
-                                       pvram += 1024;
-                                       if (++py>=y_end) 
+                                       gpu_unai.dma.px = 0;
+                                       gpu_unai.dma.pvram += 1024;
+                                       if (++gpu_unai.dma.py >= gpu_unai.dma.y_end)
                                        {
-                                               FrameToWrite = false;
-                                               GPU_GP1 &= ~0x08000000;
+                                               gpu_unai.dma.FrameToWrite = false;
+                                               gpu_unai.GPU_GP1 &= ~0x08000000;
+                                               gpu_unai.fb_dirty = true;
                                                break;
                                        }
                                }
-                               if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
-                               pvram[px] = data>>16;
-                               if (++px>=x_end) 
+                               if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024;
+                               gpu_unai.dma.pvram[gpu_unai.dma.px] = data>>16;
+                               if (++gpu_unai.dma.px >= gpu_unai.dma.x_end)
                                {
-                                       px = 0;
-                                       pvram += 1024;
-                                       if (++py>=y_end) 
+                                       gpu_unai.dma.px = 0;
+                                       gpu_unai.dma.pvram += 1024;
+                                       if (++gpu_unai.dma.py >= gpu_unai.dma.y_end)
                                        {
-                                               FrameToWrite = false;
-                                               GPU_GP1 &= ~0x08000000;
+                                               gpu_unai.dma.FrameToWrite = false;
+                                               gpu_unai.GPU_GP1 &= ~0x08000000;
+                                               gpu_unai.fb_dirty = true;
                                                break;
                                        }
                                }
@@ -312,95 +266,100 @@ void  GPU_writeDataMem(u32* dmaAddress, s32 dmaCount)
                }
        }
 
-       GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000;
-       fb_dirty = true;
-       pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
-       pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
+       gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 | 0x14000000) & ~0x60000000;
 }
 
-u32 *lUsedAddr[3];
-INLINE int CheckForEndlessLoop(u32 *laddr)
+long GPU_dmaChain(u32 *rambase, u32 start_addr)
 {
-       if(laddr==lUsedAddr[1]) return 1;
-       if(laddr==lUsedAddr[2]) return 1;
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"GPU_dmaChain(0x%x)\n",start_addr);
+       #endif
 
-       if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
-       else                   lUsedAddr[2]=laddr;
-       lUsedAddr[0]=laddr;
-       return 0;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-long GPU_dmaChain(u32* baseAddr, u32 dmaVAddr)
-{
-#ifdef DEBUG_ANALYSIS
-       dbg_anacnt_GPU_dmaChain++;
-#endif
-       pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
-       u32 data, *address, count, offset;
-       unsigned int DMACommandCounter = 0;
+       u32 addr, *list;
+       u32 len, count;
        long dma_words = 0;
 
-       GPU_GP1 &= ~0x14000000;
-       lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=(u32*)0x1fffff;
-       dmaVAddr &= 0x001FFFFF;
-       while (dmaVAddr != 0x1FFFFF)
+       if (gpu_unai.dma.last_dma) *gpu_unai.dma.last_dma |= 0x800000;
+       
+       gpu_unai.GPU_GP1 &= ~0x14000000;
+       
+       addr = start_addr & 0xffffff;
+       for (count = 0; addr != 0xffffff; count++)
        {
-               address = (baseAddr + (dmaVAddr >> 2));
-               if(DMACommandCounter++ > 2000000) break;
-               if(CheckForEndlessLoop(address)) break;
-               data = *address++;
-               count = (data >> 24);
-               offset = data & 0x001FFFFF;
-               if (dmaVAddr != offset) dmaVAddr = offset;
-               else dmaVAddr = 0x1FFFFF;
-
-               if(count>0) GPU_writeDataMem(address,count);
-               dma_words += 1 + count;
+               list = rambase + (addr & 0x1fffff) / 4;
+               len = list[0] >> 24;
+               addr = list[0] & 0xffffff;
+
+               dma_words += 1 + len;
+
+               // add loop detection marker
+               list[0] |= 0x800000;
+
+               if (len) GPU_writeDataMem(list + 1, len);
+
+               if (addr & 0x800000)
+               {
+                       #ifdef ENABLE_GPU_LOG_SUPPORT
+                               fprintf(stdout,"GPU_dmaChain(LOOP)\n");
+                       #endif
+                       break;
+               }
        }
-       GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000;
-       pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+
+       // remove loop detection markers
+       addr = start_addr & 0x1fffff;
+       while (count-- > 0)
+       {
+               list = rambase + addr / 4;
+               addr = list[0] & 0x1fffff;
+               list[0] &= ~0x800000;
+       }
+       
+       if (gpu_unai.dma.last_dma) *gpu_unai.dma.last_dma &= ~0x800000;
+       gpu_unai.dma.last_dma = rambase + (start_addr & 0x1fffff) / 4;
+
+       gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 | 0x14000000) & ~0x60000000;
 
        return dma_words;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-void  GPU_writeData(u32 data)
+void GPU_writeData(u32 data)
 {
-       const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
-#ifdef DEBUG_ANALYSIS
-       dbg_anacnt_GPU_writeData++;
-#endif
-       pcsx4all_prof_pause(PCSX4ALL_PROF_CPU);
-       pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
-       GPU_GP1 &= ~0x14000000;
+       const u16 *VIDEO_END = (u16*)gpu_unai.vram+(FRAME_BUFFER_SIZE/2)-1;
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"GPU_writeData()\n");
+       #endif
+       gpu_unai.GPU_GP1 &= ~0x14000000;
 
-       if (FrameToWrite)
+       if (gpu_unai.dma.FrameToWrite)
        {
-               if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
-               pvram[px]=(u16)data;
-               if (++px>=x_end)
+               if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024;
+               gpu_unai.dma.pvram[gpu_unai.dma.px]=(u16)data;
+               if (++gpu_unai.dma.px >= gpu_unai.dma.x_end)
                {
-                       px = 0;
-                       pvram += 1024;
-                       if (++py>=y_end) 
+                       gpu_unai.dma.px = 0;
+                       gpu_unai.dma.pvram += 1024;
+                       if (++gpu_unai.dma.py >= gpu_unai.dma.y_end)
                        {
-                               FrameToWrite = false;
-                               GPU_GP1 &= ~0x08000000;
+                               gpu_unai.dma.FrameToWrite = false;
+                               gpu_unai.GPU_GP1 &= ~0x08000000;
+                               gpu_unai.fb_dirty = true;
                        }
                }
-               if (FrameToWrite)
+               if (gpu_unai.dma.FrameToWrite)
                {
-                       if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
-                       pvram[px]=data>>16;
-                       if (++px>=x_end)
+                       if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024;
+                       gpu_unai.dma.pvram[gpu_unai.dma.px]=data>>16;
+                       if (++gpu_unai.dma.px >= gpu_unai.dma.x_end)
                        {
-                               px = 0;
-                               pvram += 1024;
-                               if (++py>=y_end) 
+                               gpu_unai.dma.px = 0;
+                               gpu_unai.dma.pvram += 1024;
+                               if (++gpu_unai.dma.py >= gpu_unai.dma.y_end)
                                {
-                                       FrameToWrite = false;
-                                       GPU_GP1 &= ~0x08000000;
+                                       gpu_unai.dma.FrameToWrite = false;
+                                       gpu_unai.GPU_GP1 &= ~0x08000000;
+                                       gpu_unai.fb_dirty = true;
                                }
                        }
                }
@@ -409,507 +368,463 @@ void  GPU_writeData(u32 data)
        {
                gpuCheckPacket(data);
        }
-       GPU_GP1 |= 0x14000000;
-       fb_dirty = true;
-       pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
-       pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
-
+       gpu_unai.GPU_GP1 |= 0x14000000;
 }
 
 
 ///////////////////////////////////////////////////////////////////////////////
-void  GPU_readDataMem(u32* dmaAddress, s32 dmaCount)
+void GPU_readDataMem(u32* dmaAddress, int dmaCount)
 {
-       const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
-#ifdef DEBUG_ANALYSIS
-       dbg_anacnt_GPU_readDataMem++;
-#endif
-       if(!FrameToRead) return;
+       const u16 *VIDEO_END = (u16*)gpu_unai.vram+(FRAME_BUFFER_SIZE/2)-1;
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"GPU_readDataMem(%d)\n",dmaCount);
+       #endif
+       if(!gpu_unai.dma.FrameToRead) return;
 
-       pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
-       GPU_GP1 &= ~0x14000000;
+       gpu_unai.GPU_GP1 &= ~0x14000000;
        do 
        {
-               if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+               if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024;
                // lower 16 bit
-               u32 data = pvram[px];
+               //senquack - 64-bit fix (from notaz)
+               //u32 data = (unsigned long)gpu_unai.dma.pvram[gpu_unai.dma.px];
+               u32 data = (u32)gpu_unai.dma.pvram[gpu_unai.dma.px];
 
-               if (++px>=x_end) 
+               if (++gpu_unai.dma.px >= gpu_unai.dma.x_end)
                {
-                       px = 0;
-                       pvram += 1024;
+                       gpu_unai.dma.px = 0;
+                       gpu_unai.dma.pvram += 1024;
                }
 
-               if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+               if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024;
                // higher 16 bit (always, even if it's an odd width)
-               data |= (u32)(pvram[px])<<16;
+               //senquack - 64-bit fix (from notaz)
+               //data |= (unsigned long)(gpu_unai.dma.pvram[gpu_unai.dma.px])<<16;
+               data |= (u32)(gpu_unai.dma.pvram[gpu_unai.dma.px])<<16;
                
                *dmaAddress++ = data;
 
-               if (++px>=x_end) 
+               if (++gpu_unai.dma.px >= gpu_unai.dma.x_end)
                {
-                       px = 0;
-                       pvram += 1024;
-                       if (++py>=y_end) 
+                       gpu_unai.dma.px = 0;
+                       gpu_unai.dma.pvram += 1024;
+                       if (++gpu_unai.dma.py >= gpu_unai.dma.y_end)
                        {
-                               FrameToRead = false;
-                               GPU_GP1 &= ~0x08000000;
+                               gpu_unai.dma.FrameToRead = false;
+                               gpu_unai.GPU_GP1 &= ~0x08000000;
                                break;
                        }
                }
        } while (--dmaCount);
 
-       GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000;
-       pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+       gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 | 0x14000000) & ~0x60000000;
 }
 
 
 
 ///////////////////////////////////////////////////////////////////////////////
-u32  GPU_readData(void)
+u32 GPU_readData(void)
 {
-       const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
-#ifdef DEBUG_ANALYSIS
-       dbg_anacnt_GPU_readData++;
-#endif
-       pcsx4all_prof_pause(PCSX4ALL_PROF_CPU);
-       pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_READ);
-       GPU_GP1 &= ~0x14000000;
-       if (FrameToRead)
+       const u16 *VIDEO_END = (u16*)gpu_unai.vram+(FRAME_BUFFER_SIZE/2)-1;
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"GPU_readData()\n");
+       #endif
+       gpu_unai.GPU_GP1 &= ~0x14000000;
+       if (gpu_unai.dma.FrameToRead)
        {
-               if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
-               GP0 = pvram[px];
-               if (++px>=x_end)
+               if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024;
+               gpu_unai.GPU_GP0 = gpu_unai.dma.pvram[gpu_unai.dma.px];
+               if (++gpu_unai.dma.px >= gpu_unai.dma.x_end)
                {
-                       px = 0;
-                       pvram += 1024;
-                       if (++py>=y_end) 
+                       gpu_unai.dma.px = 0;
+                       gpu_unai.dma.pvram += 1024;
+                       if (++gpu_unai.dma.py >= gpu_unai.dma.y_end)
                        {
-                               FrameToRead = false;
-                               GPU_GP1 &= ~0x08000000;
+                               gpu_unai.dma.FrameToRead = false;
+                               gpu_unai.GPU_GP1 &= ~0x08000000;
                        }
                }
-               if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
-               GP0 |= pvram[px]<<16;
-               if (++px>=x_end)
+               if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024;
+               gpu_unai.GPU_GP0 |= gpu_unai.dma.pvram[gpu_unai.dma.px]<<16;
+               if (++gpu_unai.dma.px >= gpu_unai.dma.x_end)
                {
-                       px = 0;
-                       pvram +=1024;
-                       if (++py>=y_end) 
+                       gpu_unai.dma.px = 0;
+                       gpu_unai.dma.pvram += 1024;
+                       if (++gpu_unai.dma.py >= gpu_unai.dma.y_end)
                        {
-                               FrameToRead = false;
-                               GPU_GP1 &= ~0x08000000;
+                               gpu_unai.dma.FrameToRead = false;
+                               gpu_unai.GPU_GP1 &= ~0x08000000;
                        }
                }
 
        }
-       GPU_GP1 |= 0x14000000;
+       gpu_unai.GPU_GP1 |= 0x14000000;
 
-       pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_READ);
-       pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
-       return (GP0);
+       return (gpu_unai.GPU_GP0);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-u32     GPU_readStatus(void)
+u32 GPU_readStatus(void)
 {
-#ifdef DEBUG_ANALYSIS
-       dbg_anacnt_GPU_readStatus++;
-#endif
-       return GPU_GP1;
+       return gpu_unai.GPU_GP1;
+}
+
+INLINE void GPU_NoSkip(void)
+{
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"GPU_NoSkip()\n");
+       #endif
+       gpu_unai.frameskip.wasSkip = gpu_unai.frameskip.isSkip;
+       if (gpu_unai.frameskip.isSkip)
+       {
+               gpu_unai.frameskip.isSkip = false;
+               gpu_unai.frameskip.skipGPU = false;
+       }
+       else
+       {
+               gpu_unai.frameskip.isSkip = gpu_unai.frameskip.skipFrame;
+               gpu_unai.frameskip.skipGPU = gpu_unai.frameskip.skipFrame;
+       }
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 void  GPU_writeStatus(u32 data)
 {
-#ifdef DEBUG_ANALYSIS
-       dbg_anacnt_GPU_writeStatus++;
-#endif
-       pcsx4all_prof_pause(PCSX4ALL_PROF_CPU);
-       pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"GPU_writeStatus(%d,%d)\n",data>>24,data & 0xff);
+       #endif
        switch (data >> 24) {
        case 0x00:
                gpuReset();
                break;
        case 0x01:
-               GPU_GP1 &= ~0x08000000;
-               PacketCount = 0; FrameToRead = FrameToWrite = false;
+               gpu_unai.GPU_GP1 &= ~0x08000000;
+               gpu_unai.PacketCount = 0;
+               gpu_unai.dma.FrameToRead = gpu_unai.dma.FrameToWrite = false;
                break;
        case 0x02:
-               GPU_GP1 &= ~0x08000000;
-               PacketCount = 0; FrameToRead = FrameToWrite = false;
+               gpu_unai.GPU_GP1 &= ~0x08000000;
+               gpu_unai.PacketCount = 0;
+               gpu_unai.dma.FrameToRead = gpu_unai.dma.FrameToWrite = false;
                break;
        case 0x03:
-               GPU_GP1 = (GPU_GP1 & ~0x00800000) | ((data & 1) << 23);
+               gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x00800000) | ((data & 1) << 23);
                break;
        case 0x04:
-               if (data == 0x04000000)
-               PacketCount = 0;
-               GPU_GP1 = (GPU_GP1 & ~0x60000000) | ((data & 3) << 29);
+               if (data == 0x04000000) gpu_unai.PacketCount = 0;
+               gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x60000000) | ((data & 3) << 29);
                break;
        case 0x05:
-               DisplayArea[0] = (data & 0x000003FF); //(short)(data & 0x3ff);
-               DisplayArea[1] = ((data & 0x0007FC00)>>10); //(data & 0x000FFC00) >> 10; //(short)((data>>10)&0x1ff);
-               fb_dirty = true;
-               wasSkip = isSkip;
-               if (isSkip)
-                       isSkip = false;
-               else
-                       isSkip = skipFrame;
+               // Start of Display Area in VRAM
+               gpu_unai.DisplayArea[0] = data & 0x3ff;         // X (0..1023)
+               gpu_unai.DisplayArea[1] = (data >> 10) & 0x1ff; // Y (0..511)
+               GPU_NoSkip();
+               break;
+       case 0x06:
+               // GP1(06h) - Horizontal Display range (on Screen)
+               // 0-11   X1 (260h+0)       ;12bit       ;\counted in 53.222400MHz units,
+               // 12-23  X2 (260h+320*8)   ;12bit       ;/relative to HSYNC
+
+               // senquack - gpu_unai completely ignores GP1(0x06) command and
+               // lacks even a place in DisplayArea[] array to store the values.
+               // It seems to have been concerned only with vertical display range
+               // and centering top/bottom. I will not add support here, and
+               // focus instead on the gpulib version (gpulib_if.cpp) which uses
+               // gpulib for its PS1->host framebuffer blitting.
                break;
        case 0x07:
-               DisplayArea[4] = data & 0x000003FF; //(short)(data & 0x3ff);
-               DisplayArea[5] = (data & 0x000FFC00) >> 10; //(short)((data>>10) & 0x3ff);
-               fb_dirty = true;
+               // GP1(07h) - Vertical Display range (on Screen)
+               // 0-9   Y1 (NTSC=88h-(224/2), (PAL=A3h-(264/2))  ;\scanline numbers on screen,
+               // 10-19 Y2 (NTSC=88h+(224/2), (PAL=A3h+(264/2))  ;/relative to VSYNC
+               // 20-23 Not used (zero)
+               {
+                       u32 v1=data & 0x000003FF; //(short)(data & 0x3ff);
+                       u32 v2=(data & 0x000FFC00) >> 10; //(short)((data>>10) & 0x3ff);
+                       if ((gpu_unai.DisplayArea[4]!=v1)||(gpu_unai.DisplayArea[5]!=v2))
+                       {
+                               gpu_unai.DisplayArea[4] = v1;
+                               gpu_unai.DisplayArea[5] = v2;
+                               #ifdef ENABLE_GPU_LOG_SUPPORT
+                                       fprintf(stdout,"video_clear(CHANGE_Y)\n");
+                               #endif
+                               video_clear();
+                       }
+               }
                break;
        case 0x08:
                {
-                       GPU_GP1 = (GPU_GP1 & ~0x007F0000) | ((data & 0x3F) << 17) | ((data & 0x40) << 10);
-                       static u32 HorizontalResolution[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
-                       DisplayArea[2] = HorizontalResolution[(GPU_GP1 >> 16) & 7];
-                       static u32 VerticalResolution[4] = { 240, 480, 256, 480 };
-                       DisplayArea[3] = VerticalResolution[(GPU_GP1 >> 19) & 3];
-                       isPAL = (data & 0x08) ? true : false; // if 1 - PAL mode, else NTSC
+                       static const u32 HorizontalResolution[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
+                       static const u32 VerticalResolution[4] = { 240, 480, 256, 480 };
+                       gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x007F0000) | ((data & 0x3F) << 17) | ((data & 0x40) << 10);
+                       #ifdef ENABLE_GPU_LOG_SUPPORT
+                               fprintf(stdout,"GPU_writeStatus(RES=%dx%d,BITS=%d,PAL=%d)\n",HorizontalResolution[(gpu_unai.GPU_GP1 >> 16) & 7],
+                                               VerticalResolution[(gpu_unai.GPU_GP1 >> 19) & 3],(gpu_unai.GPU_GP1&0x00200000?24:15),(IS_PAL?1:0));
+                       #endif
+                       // Video mode change
+                       u32 new_width = HorizontalResolution[(gpu_unai.GPU_GP1 >> 16) & 7];
+                       u32 new_height = VerticalResolution[(gpu_unai.GPU_GP1 >> 19) & 3];
+
+                       if (gpu_unai.DisplayArea[2] != new_width || gpu_unai.DisplayArea[3] != new_height)
+                       {
+                               // Update width
+                               gpu_unai.DisplayArea[2] = new_width;
+
+                               if (PixelSkipEnabled()) {
+                                       // Set blit_mask for high horizontal resolutions. This allows skipping
+                                       //  rendering pixels that would never get displayed on low-resolution
+                                       //  platforms that use simple pixel-dropping scaler.
+                                       switch (gpu_unai.DisplayArea[2])
+                                       {
+                                               case 512: gpu_unai.blit_mask = 0xa4; break; // GPU_BlitWWSWWSWS
+                                               case 640: gpu_unai.blit_mask = 0xaa; break; // GPU_BlitWS
+                                               default:  gpu_unai.blit_mask = 0;    break;
+                                       }
+                               } else {
+                                       gpu_unai.blit_mask = 0;
+                               }
+
+                               // Update height
+                               gpu_unai.DisplayArea[3] = new_height;
+
+                               if (LineSkipEnabled()) {
+                                       // Set rendering line-skip (only render every other line in high-res
+                                       //  480 vertical mode, or, optionally, force it for all video modes)
+
+                                       if (gpu_unai.DisplayArea[3] == 480) {
+                                               if (gpu_unai.config.ilace_force) {
+                                                       gpu_unai.ilace_mask = 3; // Only need 1/4 of lines
+                                               } else {
+                                                       gpu_unai.ilace_mask = 1; // Only need 1/2 of lines
+                                               }
+                                       } else {
+                                               // Vert resolution changed from 480 to lower one
+                                               gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
+                                       }
+                               } else {
+                                       gpu_unai.ilace_mask = 0;
+                               }
+
+                               #ifdef ENABLE_GPU_LOG_SUPPORT
+                                       fprintf(stdout,"video_clear(CHANGE_RES)\n");
+                               #endif
+                               video_clear();
+                       }
+
                }
-               fb_dirty = true;
                break;
        case 0x10:
-               switch (data & 0xffff) {
-               case 0:
-               case 1:
-               case 3:
-                       GP0 = (DrawingArea[1] << 10) | DrawingArea[0];
-                       break;
-               case 4:
-                       GP0 = ((DrawingArea[3]-1) << 10) | (DrawingArea[2]-1);
-                       break;
-               case 6:
-               case 5:
-                       GP0 = (DrawingOffset[1] << 11) | DrawingOffset[0];
-                       break;
-               case 7:
-                       GP0 = 2;
-                       break;
-               default:
-                       GP0 = 0;
+               switch (data & 0xff) {
+                       case 2: gpu_unai.GPU_GP0 = gpu_unai.tex_window; break;
+                       case 3: gpu_unai.GPU_GP0 = (gpu_unai.DrawingArea[1] << 10) | gpu_unai.DrawingArea[0]; break;
+                       case 4: gpu_unai.GPU_GP0 = ((gpu_unai.DrawingArea[3]-1) << 10) | (gpu_unai.DrawingArea[2]-1); break;
+                       case 5: case 6: gpu_unai.GPU_GP0 = (((u32)gpu_unai.DrawingOffset[1] & 0x7ff) << 11) | ((u32)gpu_unai.DrawingOffset[0] & 0x7ff); break;
+                       case 7: gpu_unai.GPU_GP0 = 2; break;
+                       case 8: case 15: gpu_unai.GPU_GP0 = 0xBFC03720; break;
                }
                break;
        }
-       pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
-       pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
 }
 
-#ifndef REARMED
-
 // Blitting functions
 #include "gpu_blit.h"
 
-INLINE void gpuVideoOutput(void)
+static void gpuVideoOutput(void)
 {
-       static s16 old_res_horz, old_res_vert, old_rgb24;
-       s16 h0, x0, y0, w0, h1;
+       int h0, x0, y0, w0, h1;
 
-       x0 = DisplayArea[0];
-       y0 = DisplayArea[1];
+       x0 = gpu_unai.DisplayArea[0];
+       y0 = gpu_unai.DisplayArea[1];
 
-       w0 = DisplayArea[2];
-       h0 = DisplayArea[3];  // video mode
+       w0 = gpu_unai.DisplayArea[2];
+       h0 = gpu_unai.DisplayArea[3];  // video mode
 
-       h1 = DisplayArea[5] - DisplayArea[4]; // display needed
+       h1 = gpu_unai.DisplayArea[5] - gpu_unai.DisplayArea[4]; // display needed
        if (h0 == 480) h1 = Min2(h1*2,480);
 
-       u16* dest_screen16 = SCREEN;
-       u16* src_screen16  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0,y0)];
-       u32 isRGB24 = (GPU_GP1 & 0x00200000 ? 32 : 0);
+       bool isRGB24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false);
+       u16* dst16 = SCREEN;
+       u16* src16 = (u16*)gpu_unai.vram;
 
-       /* Clear the screen if resolution changed to prevent interlacing and clipping to clash */
-       if( (w0 != old_res_horz || h1 != old_res_vert || (s16)isRGB24 != old_rgb24) )
-       {
-               // Update old resolution
-               old_res_horz = w0;
-               old_res_vert = h1;
-               old_rgb24 = (s16)isRGB24;
-               // Finally, clear the screen for this special case
-               video_clear();
-       }
+       // PS1 fb read wraps around (fixes black screen in 'Tobal no. 1')
+       unsigned int src16_offs_msk = 1024*512-1;
+       unsigned int src16_offs = (x0 + y0*1024) & src16_offs_msk;
 
        //  Height centering
        int sizeShift = 1;
-       if(h0==256) h0 = 240; else if(h0==480) sizeShift = 2;
-       if(h1>h0) { src_screen16 += ((h1-h0)>>sizeShift)*1024; h1 = h0; }
-       else if(h1<h0) dest_screen16 += ((h0-h1)>>sizeShift)*VIDEO_WIDTH;
+       if (h0 == 256) {
+               h0 = 240;
+       } else if (h0 == 480) {
+               sizeShift = 2;
+       }
+       if (h1 > h0) {
+               src16_offs = (src16_offs + (((h1-h0) / 2) * 1024)) & src16_offs_msk;
+               h1 = h0;
+       } else if (h1<h0) {
+               dst16 += ((h0-h1) >> sizeShift) * VIDEO_WIDTH;
+       }
+
 
        /* Main blitter */
        int incY = (h0==480) ? 2 : 1;
        h0=(h0==480 ? 2048 : 1024);
 
        {
-               const int li=linesInterlace;
-               bool pi=progressInterlace;
-               bool pif=progressInterlace_flag;
+               const int li=gpu_unai.ilace_mask;
+               bool pi = ProgressiveInterlaceEnabled();
+               bool pif = gpu_unai.prog_ilace_flag;
                switch ( w0 )
                {
                        case 256:
                                for(int y1=y0+h1; y0<y1; y0+=incY)
                                {
-                                       if(( 0 == (y0&li) ) && ((!pi) || (pif=!pif))) GPU_BlitWWDWW(    src_screen16,   dest_screen16, isRGB24);
-                                       dest_screen16 += VIDEO_WIDTH;
-                                       src_screen16  += h0;
+                                       if (( 0 == (y0&li) ) && ((!pi) || (pif=!pif)))
+                                               GPU_BlitWWDWW(src16 + src16_offs, dst16, isRGB24);
+                                       dst16 += VIDEO_WIDTH;
+                                       src16_offs = (src16_offs + h0) & src16_offs_msk;
                                }
                                break;
                        case 368:
                                for(int y1=y0+h1; y0<y1; y0+=incY)
                                {
-                                       if(( 0 == (y0&li) ) && ((!pi) || (pif=!pif))) GPU_BlitWWWWWWWWS(        src_screen16,   dest_screen16, isRGB24, 4);
-                                       dest_screen16 += VIDEO_WIDTH;
-                                       src_screen16  += h0;
+                                       if (( 0 == (y0&li) ) && ((!pi) || (pif=!pif)))
+                                               GPU_BlitWWWWWWWWS(src16 + src16_offs, dst16, isRGB24, 4);
+                                       dst16 += VIDEO_WIDTH;
+                                       src16_offs = (src16_offs + h0) & src16_offs_msk;
                                }
                                break;
                        case 320:
+                               // Ensure 32-bit alignment for GPU_BlitWW() blitter:
+                               src16_offs &= ~1;
                                for(int y1=y0+h1; y0<y1; y0+=incY)
                                {
-                                       if(( 0 == (y0&li) ) && ((!pi) || (pif=!pif))) GPU_BlitWW(       src_screen16,   dest_screen16, isRGB24);
-                                       dest_screen16 += VIDEO_WIDTH;
-                                       src_screen16  += h0;
+                                       if (( 0 == (y0&li) ) && ((!pi) || (pif=!pif)))
+                                               GPU_BlitWW(src16 + src16_offs, dst16, isRGB24);
+                                       dst16 += VIDEO_WIDTH;
+                                       src16_offs = (src16_offs + h0) & src16_offs_msk;
                                }
                                break;
                        case 384:
                                for(int y1=y0+h1; y0<y1; y0+=incY)
                                {
-                                       if(( 0 == (y0&li) ) && ((!pi) || (pif=!pif))) GPU_BlitWWWWWS(   src_screen16,   dest_screen16, isRGB24);
-                                       dest_screen16 += VIDEO_WIDTH;
-                                       src_screen16  += h0;
+                                       if (( 0 == (y0&li) ) && ((!pi) || (pif=!pif)))
+                                               GPU_BlitWWWWWS(src16 + src16_offs, dst16, isRGB24);
+                                       dst16 += VIDEO_WIDTH;
+                                       src16_offs = (src16_offs + h0) & src16_offs_msk;
                                }
                                break;
                        case 512:
                                for(int y1=y0+h1; y0<y1; y0+=incY)
                                {
-                                       if(( 0 == (y0&li) ) && ((!pi) || (pif=!pif))) GPU_BlitWWSWWSWS( src_screen16, dest_screen16, isRGB24);
-                                       dest_screen16 += VIDEO_WIDTH;
-                                       src_screen16  += h0;
+                                       if (( 0 == (y0&li) ) && ((!pi) || (pif=!pif)))
+                                               GPU_BlitWWSWWSWS(src16 + src16_offs, dst16, isRGB24);
+                                       dst16 += VIDEO_WIDTH;
+                                       src16_offs = (src16_offs + h0) & src16_offs_msk;
                                }
                                break;
                        case 640:
                                for(int y1=y0+h1; y0<y1; y0+=incY)
                                {
-                                       if(( 0 == (y0&li) ) && ((!pi) || (pif=!pif))) GPU_BlitWS(       src_screen16, dest_screen16, isRGB24);
-                                       dest_screen16 += VIDEO_WIDTH;
-                                       src_screen16  += h0;
+                                       if (( 0 == (y0&li) ) && ((!pi) || (pif=!pif)))
+                                               GPU_BlitWS(src16 + src16_offs, dst16, isRGB24);
+                                       dst16 += VIDEO_WIDTH;
+                                       src16_offs = (src16_offs + h0) & src16_offs_msk;
                                }
                                break;
                }
-               progressInterlace_flag=!progressInterlace_flag;
+               gpu_unai.prog_ilace_flag = !gpu_unai.prog_ilace_flag;
        }
        video_flip();
 }
 
-///////////////////////////////////////////////////////////////////////////////
-void  GPU_updateLace(void)
-{
-#ifdef  ENABLE_GPU_LOG_SUPPORT
-       fprintf(stdout,"GPU_updateLace()\n");
-#endif
-#ifdef DEBUG_ANALYSIS
-       dbg_anacnt_GPU_updateLace++;
-#endif
-       pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_COUNTERS);
-#ifdef PROFILER_PCSX4ALL
-       pcsx4all_prof_frames++;
-#endif
-#ifdef DEBUG_FRAME
-       if(isdbg_frame())
-       {
-               static int passed=0;
-               if (!passed) dbg_enable();
-               else pcsx4all_exit();
-               passed++;
-       }
-#endif
-
-       // Frame skip table
-       static const unsigned char skipTable[12][12] =
-       {
-               { 0,0,0,0,0,0,0,0,0,0,0,0 },
-               { 0,0,0,0,0,0,0,0,0,0,0,1 },
-               { 0,0,0,0,0,1,0,0,0,0,0,1 },
-               { 0,0,0,1,0,0,0,1,0,0,0,1 },
-               { 0,0,1,0,0,1,0,0,1,0,0,1 },
-               { 0,1,0,0,1,0,1,0,0,1,0,1 },
-               { 0,1,0,1,0,1,0,1,0,1,0,1 },
-               { 0,1,0,1,1,0,1,0,1,1,0,1 },
-               { 0,1,1,0,1,1,0,1,1,0,1,1 },
-               { 0,1,1,1,0,1,1,1,0,1,1,1 },
-               { 0,1,1,1,1,1,0,1,1,1,1,1 },
-               { 0,1,1,1,1,1,1,1,1,1,1,1 }
-       };
-       
-       // Interlace bit toggle
-       GPU_GP1 ^= 0x80000000;
-
-       // Update display
-       if ((!skipFrame) && (!isSkip) && (fb_dirty) && (!(((GPU_GP1&0x08000000))||((GPU_GP1&0x00800000)))))
-       {
-               gpuVideoOutput(); // Display updated
-
-               if (DisplayArea[3] == 480)
-               {
-                       if (linesInterlace_user) linesInterlace = 3; // 1/4 of lines
-                       else linesInterlace = 1; // if 480 we only need half of lines
-               }
-               else if (linesInterlace != linesInterlace_user)
-               {
-                       linesInterlace = linesInterlace_user; // resolution changed from 480 to lower one
-                       video_clear();
-               }
-       }
+// Update frames-skip each second>>3 (8 times per second)
+#define GPU_FRAMESKIP_UPDATE 3
 
-       // Limit FPS
-       if (frameLimit)
-       {
-               static unsigned next=get_ticks();
-               if (!skipFrame)
-               {
-                       unsigned now=get_ticks();
-                       if (now<next) wait_ticks(next-now);
-               }
-               next+=(isPAL?(1000000/50):((unsigned)(1000000.0/59.94)));
-       }
+static void GPU_frameskip (bool show)
+{
+       u32 now=get_ticks(); // current frame
 
-       // Show FPS statistics
-       if (show_fps)
+       // Update frameskip
+       if (gpu_unai.frameskip.skipCount==0) gpu_unai.frameskip.skipFrame=false; // frameskip off
+       else if (gpu_unai.frameskip.skipCount==7) { if (show) gpu_unai.frameskip.skipFrame=!gpu_unai.frameskip.skipFrame; } // frameskip medium
+       else if (gpu_unai.frameskip.skipCount==8) gpu_unai.frameskip.skipFrame=true; // frameskip maximum
+       else
        {
-               static u32 real_fps=0;
-               static u32 prev=get_ticks();
-               static char msg[32]="FPS=000/00 SPD=000%";
-               u32 now=get_ticks();
-               real_fps++;
-               if ((now-prev)>=1000000)
+               static u32 spd=100; // speed %
+               static u32 frames=0; // frames counter
+               static u32 prev=now; // previous fps calculation
+               frames++;
+               if ((now-prev)>=(TPS>>GPU_FRAMESKIP_UPDATE))
                {
-                       u32 expected_fps=(isPAL?50:60);
-                       sprintf(msg,"FPS=%3d/%2d SPD=%3d%%",((real_fps*(12-skipCount))/12),((expected_fps*(12-skipCount))/12),((real_fps*100)/expected_fps));
+                       if (IS_PAL) spd=(frames<<1);
+                       else spd=((frames*1001)/600);
+                       spd<<=GPU_FRAMESKIP_UPDATE;
+                       frames=0;
                        prev=now;
-                       real_fps=0;
                }
-               port_printf(5,5,msg);
-       }
-
-       // Update frame-skip
-       if (!alt_fps)
-       {
-               // Video frame-skip
-               skipFrame=skipTable[skipCount][skCount];
-               skCount--; if (skCount<0) skCount=11;
-               isSkip=skipFrame;
-       }
-       else
-       {
-               // Game frame-skip
-               if (!isSkip)
+               switch(gpu_unai.frameskip.skipCount)
                {
-                       skipFrame=skipTable[skipCount][skCount];
-                       skCount--; if (skCount<0) skCount=11;
-                       isSkip=true;
+                       case 1: if (spd<50) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<50%)
+                       case 2: if (spd<60) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<60%)
+                       case 3: if (spd<70) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<70%)
+                       case 4: if (spd<80) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<80%)
+                       case 5: if (spd<90) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<90%)
                }
        }
-       fb_dirty=false;
-
-       pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_COUNTERS);
-}
-
-#else
-
-#include "../../frontend/plugin_lib.h"
-
-extern "C" {
-
-static const struct rearmed_cbs *cbs;
-static s16 old_res_horz, old_res_vert, old_rgb24;
-
-static void blit(void)
-{
-       u16 *base = (u16 *)GPU_FrameBuffer;
-       s16 isRGB24 = (GPU_GP1 & 0x00200000) ? 1 : 0;
-       s16 h0, x0, y0, w0, h1;
-
-       x0 = DisplayArea[0] & ~1; // alignment needed by blitter
-       y0 = DisplayArea[1];
-       base += FRAME_OFFSET(x0, y0);
-
-       w0 = DisplayArea[2];
-       h0 = DisplayArea[3];  // video mode
-
-       h1 = DisplayArea[5] - DisplayArea[4]; // display needed
-       if (h0 == 480) h1 = Min2(h1*2,480);
-
-       if (h1 <= 0)
-               return;
-
-       if (w0 != old_res_horz || h1 != old_res_vert || isRGB24 != old_rgb24)
-       {
-               old_res_horz = w0;
-               old_res_vert = h1;
-               old_rgb24 = (s16)isRGB24;
-               cbs->pl_vout_set_mode(w0, h1, w0, h1, isRGB24 ? 24 : 16);
-       }
-
-       cbs->pl_vout_flip(base, 1024, isRGB24, w0, h1);
 }
 
+///////////////////////////////////////////////////////////////////////////////
 void GPU_updateLace(void)
 {
        // Interlace bit toggle
-       GPU_GP1 ^= 0x80000000;
+       gpu_unai.GPU_GP1 ^= 0x80000000;
 
-       if (!fb_dirty || (GPU_GP1&0x08800000))
-               return;
-
-       if (!wasSkip) {
-               blit();
-               fb_dirty = false;
-               skCount = 0;
-       }
-       else {
-               skCount++;
-               if (skCount >= 8)
-                       wasSkip = isSkip = 0;
+       // Update display?
+       if ((gpu_unai.fb_dirty) && (!gpu_unai.frameskip.wasSkip) && (!(gpu_unai.GPU_GP1&0x00800000)))
+       {
+               // Display updated
+               gpuVideoOutput();
+               GPU_frameskip(true);
+               #ifdef ENABLE_GPU_LOG_SUPPORT
+                       fprintf(stdout,"GPU_updateLace(UPDATE)\n");
+               #endif
+       } else {
+               GPU_frameskip(false);
+               #ifdef ENABLE_GPU_LOG_SUPPORT
+                       fprintf(stdout,"GPU_updateLace(SKIP)\n");
+               #endif
        }
 
-       skipFrame = cbs->fskip_advice || cbs->frameskip == 1;
-}
+       if ((!gpu_unai.frameskip.skipCount) && (gpu_unai.DisplayArea[3] == 480)) gpu_unai.frameskip.skipGPU=true; // Tekken 3 hack
 
-long GPUopen(unsigned long *, char *, char *)
-{
-       cbs->pl_vout_open();
-       return 0;
+       gpu_unai.fb_dirty=false;
+       gpu_unai.dma.last_dma = NULL;
 }
 
-long GPUclose(void)
+// Allows frontend to signal plugin to redraw screen after returning to emu
+void GPU_requestScreenRedraw()
 {
-       cbs->pl_vout_close();
-       return 0;
+       gpu_unai.fb_dirty = true;
 }
 
-long GPUfreeze(unsigned int ulGetFreezeData, GPUFreeze_t* p2)
+void GPU_getScreenInfo(GPUScreenInfo_t *sinfo)
 {
-       if (ulGetFreezeData > 1)
-               return 0;
-
-       return GPU_freeze(ulGetFreezeData, p2);
+       bool depth24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false);
+       int16_t hres = (uint16_t)gpu_unai.DisplayArea[2];
+       int16_t vres = (uint16_t)gpu_unai.DisplayArea[3];
+       int16_t w = hres; // Original gpu_unai doesn't support width < 100%
+       int16_t h = gpu_unai.DisplayArea[5] - gpu_unai.DisplayArea[4];
+       if (vres == 480)
+               h *= 2;
+       if (h <= 0 || h > vres)
+               h = vres;
+
+       sinfo->vram    = (uint8_t*)gpu_unai.vram;
+       sinfo->x       = (uint16_t)gpu_unai.DisplayArea[0];
+       sinfo->y       = (uint16_t)gpu_unai.DisplayArea[1];
+       sinfo->w       = w;
+       sinfo->h       = h;
+       sinfo->hres    = hres;
+       sinfo->vres    = vres;
+       sinfo->depth24 = depth24;
+       sinfo->pal     = IS_PAL;
 }
-
-void GPUrearmedCallbacks(const struct rearmed_cbs *cbs_)
-{
-       enableAbbeyHack = cbs_->gpu_unai.abe_hack;
-       light = !cbs_->gpu_unai.no_light;
-       blend = !cbs_->gpu_unai.no_blend;
-       if (cbs_->pl_vout_set_raw_vram)
-               cbs_->pl_vout_set_raw_vram((void *)GPU_FrameBuffer);
-
-       cbs = cbs_;
-       if (cbs->pl_set_gpu_caps)
-               cbs->pl_set_gpu_caps(0);
-}
-
-} /* extern "C" */
-
-#endif
index 1811630..f5eb69b 100644 (file)
@@ -1,6 +1,7 @@
 /***************************************************************************
 *   Copyright (C) 2010 PCSX4ALL Team                                      *
 *   Copyright (C) 2010 Unai                                               *
+*   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
 ***************************************************************************/
 
-#ifndef NEW_GPU_H
-#define NEW_GPU_H
+#ifndef GPU_UNAI_GPU_H
+#define GPU_UNAI_GPU_H
 
-///////////////////////////////////////////////////////////////////////////////
-//  GPU global definitions
-#define        FRAME_BUFFER_SIZE       (1024*512*2)
-#define        FRAME_WIDTH                       1024
-#define        FRAME_HEIGHT              512
-#define        FRAME_OFFSET(x,y)       (((y)<<10)+(x))
+struct gpu_unai_config_t {
+       uint8_t pixel_skip:1;     // If 1, allows skipping rendering pixels that
+                                 //  would not be visible when a high horizontal
+                                 //  resolution PS1 video mode is set.
+                                 //  Only applies to devices with low resolutions
+                                 //  like 320x240. Should not be used if a
+                                 //  down-scaling framebuffer blitter is in use.
+                                 //  Can cause gfx artifacts if game reads VRAM
+                                 //  to do framebuffer effects.
 
-#define VIDEO_WIDTH 320
+       uint8_t ilace_force:3;    // Option to force skipping rendering of lines,
+                                 //  for very slow platforms. Value will be
+                                 //  assigned to 'ilace_mask' in gpu_unai struct.
+                                 //  Normally 0. Value '1' will skip rendering
+                                 //  odd lines.
 
-typedef char                           s8;
-typedef signed short           s16;
-typedef signed int                     s32;
-typedef signed long long       s64;
+       uint8_t scale_hires:1;    // If 1, will scale hi-res output to
+                                 //  320x240 when gpulib reads the frame.
+                                 //  Implies pixel_skip and ilace_force
+                                 //  (when height > 240).
+       uint8_t lighting:1;
+       uint8_t fast_lighting:1;
+       uint8_t blending:1;
+       uint8_t dithering:1;
 
-typedef unsigned char          u8;
-typedef unsigned short         u16;
-typedef unsigned int           u32;
-typedef unsigned long long     u64;
+       //senquack Only PCSX Rearmed's version of gpu_unai had this, and I
+       // don't think it's necessary. It would require adding 'AH' flag to
+       // gpuSpriteSpanFn() increasing size of sprite span function array.
+       //uint8_t enableAbbeyHack:1;  // Abe's Odyssey hack
 
-#include "gpu_fixedpoint.h"
-
-///////////////////////////////////////////////////////////////////////////////
-//  Tweaks and Hacks
-extern  int  skipCount;
-extern  bool enableAbbeyHack;
-extern  bool show_fps;
-extern  bool alt_fps;
-
-///////////////////////////////////////////////////////////////////////////////
-//  interlaced rendering
-extern  int linesInterlace_user;
-extern  bool progressInterlace;
-
-extern  bool light;
-extern  bool blend;
-
-typedef struct {
-       u32 Version;
-       u32 GPU_gp1;
-       u32 Control[256];
-       unsigned char FrameBuffer[1024*512*2];
-} GPUFreeze_t;
-
-struct  GPUPacket
-{
-       union
-       {
-               u32 U4[16];
-               s32 S4[16];
-               u16 U2[32];
-               s16 S2[32];
-               u8  U1[64];
-               s8  S1[64];
-       };
+       ////////////////////////////////////////////////////////////////////////////
+       // Variables used only by older standalone version of gpu_unai (gpu.cpp)
+#ifndef USE_GPULIB
+       uint8_t prog_ilace:1;         // Progressive interlace option (old option)
+                                     //  This option was somewhat oddly named:
+                                     //  When in interlaced video mode, on a low-res
+                                     //  320x240 device, only the even lines are
+                                     //  rendered. This option will take that one
+                                     //  step further and only render half the even
+                                     //  even lines one frame, and then the other half.
+       uint8_t frameskip_count:3;    // Frame skip (0..7)
+#endif
 };
 
-///////////////////////////////////////////////////////////////////////////////
-//  Compile Options
+extern gpu_unai_config_t gpu_unai_config_ext;
 
-//#define ENABLE_GPU_NULL_SUPPORT   // Enables NullGPU support
-//#define ENABLE_GPU_LOG_SUPPORT    // Enables gpu logger, very slow only for windows debugging
+// TODO: clean up show_fps frontend option
+extern  bool show_fps;
 
-///////////////////////////////////////////////////////////////////////////////
-#endif  // NEW_GPU_H
+#endif // GPU_UNAI_GPU_H
similarity index 97%
rename from plugins/gpu_unai/gpu_arm.s
rename to plugins/gpu_unai/gpu_arm.S
index 8fa44a7..ec87f21 100644 (file)
@@ -5,6 +5,7 @@
  * See the COPYING file in the top-level directory.
  */
 
+#include "arm_features.h"
 
 .text
 .align 2
index a0b2248..b9f8f97 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __GPU_UNAI_GPU_ARM_H__
+#define __GPU_UNAI_GPU_ARM_H__
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -7,3 +10,5 @@ void draw_spr16_full(u16 *d, void *s, u16 *pal, int lines);
 #ifdef __cplusplus
 }
 #endif
+
+#endif /* __GPU_UNAI_GPU_ARM_H__ */
index 35cd056..e93f12f 100644 (file)
 ///////////////////////////////////////////////////////////////////////////////
 //  GPU Blitting code with rescale and interlace support.
 
-INLINE void GPU_BlitWW(const void* src, u16* dst16, u32 isRGB24)
+INLINE void GPU_BlitWW(const void* src, u16* dst16, bool isRGB24)
 {
        u32 uCount;
-       if(isRGB24 == 0)
+       if(!isRGB24)
        {
                #ifndef USE_BGR15
                        uCount = 20;
@@ -85,10 +85,10 @@ INLINE void GPU_BlitWW(const void* src, u16* dst16, u32 isRGB24)
        }
 }
 
-INLINE void GPU_BlitWWSWWSWS(const void* src, u16* dst16, u32 isRGB24)
+INLINE void GPU_BlitWWSWWSWS(const void* src, u16* dst16, bool isRGB24)
 {
        u32 uCount;
-       if(isRGB24 == 0)
+       if(!isRGB24)
        {
                #ifndef USE_BGR15
                        uCount = 32;
@@ -145,10 +145,10 @@ INLINE void GPU_BlitWWSWWSWS(const void* src, u16* dst16, u32 isRGB24)
        }
 }
 
-INLINE void GPU_BlitWWWWWS(const void* src, u16* dst16, u32 isRGB24)
+INLINE void GPU_BlitWWWWWS(const void* src, u16* dst16, bool isRGB24)
 {
        u32 uCount;
-       if(isRGB24 == 0)
+       if(!isRGB24)
        {
                #ifndef USE_BGR15
                        uCount = 32;
@@ -201,10 +201,10 @@ INLINE void GPU_BlitWWWWWS(const void* src, u16* dst16, u32 isRGB24)
        }
 }
 
-INLINE void GPU_BlitWWWWWWWWS(const void* src, u16* dst16, u32 isRGB24, u32 uClip_src)
+INLINE void GPU_BlitWWWWWWWWS(const void* src, u16* dst16, bool isRGB24, u32 uClip_src)
 {
        u32 uCount;
-       if(isRGB24 == 0)
+       if(!isRGB24)
        {
                #ifndef USE_BGR15
                        uCount = 20;
@@ -274,10 +274,10 @@ INLINE void GPU_BlitWWWWWWWWS(const void* src, u16* dst16, u32 isRGB24, u32 uCli
        }
 }
 
-INLINE void GPU_BlitWWDWW(const void* src, u16* dst16, u32 isRGB24)
+INLINE void GPU_BlitWWDWW(const void* src, u16* dst16, bool isRGB24)
 {
        u32 uCount;
-       if(isRGB24 == 0)
+       if(!isRGB24)
        {
                #ifndef USE_BGR15
                        uCount = 32;
@@ -331,10 +331,10 @@ INLINE void GPU_BlitWWDWW(const void* src, u16* dst16, u32 isRGB24)
 }
 
 
-INLINE void GPU_BlitWS(const void* src, u16* dst16, u32 isRGB24)
+INLINE void GPU_BlitWS(const void* src, u16* dst16, bool isRGB24)
 {
        u32 uCount;
-       if(isRGB24 == 0)
+       if(!isRGB24)
        {
                #ifndef USE_BGR15
                        uCount = 20;
index d6e7a74..c39c81b 100644 (file)
@@ -1,6 +1,7 @@
 /***************************************************************************
 *   Copyright (C) 2010 PCSX4ALL Team                                      *
 *   Copyright (C) 2010 Unai                                               *
+*   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
 ***************************************************************************/
 
+#ifndef __GPU_UNAI_GPU_COMMAND_H__
+#define __GPU_UNAI_GPU_COMMAND_H__
+
 ///////////////////////////////////////////////////////////////////////////////
-INLINE void gpuSetTexture(u16 tpage)
+void gpuSetTexture(u16 tpage)
 {
-       u32 tp;
-       u32 tx, ty;
-       GPU_GP1 = (GPU_GP1 & ~0x1FF) | (tpage & 0x1FF);
+       u32 tmode, tx, ty;
+       gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x1FF) | (tpage & 0x1FF);
+       gpu_unai.TextureWindow[0]&= ~gpu_unai.TextureWindow[2];
+       gpu_unai.TextureWindow[1]&= ~gpu_unai.TextureWindow[3];
+
+       tmode = (tpage >> 7) & 3;  // 16bpp, 8bpp, or 4bpp texture colors?
+                                  // 0: 4bpp     1: 8bpp     2/3: 16bpp
 
-       TextureWindow[0]&= ~TextureWindow[2];
-       TextureWindow[1]&= ~TextureWindow[3];
+       // Nocash PSX docs state setting of 3 is same as setting of 2 (16bpp):
+       // Note: DrHell assumes 3 is same as 0.. TODO: verify which is correct?
+       if (tmode == 3) tmode = 2;
 
-       tp = (tpage >> 7) & 3;
        tx = (tpage & 0x0F) << 6;
        ty = (tpage & 0x10) << 4;
-       if (tp == 3) tp = 2;
 
-       tx += (TextureWindow[0] >> (2 - tp));
-       ty += TextureWindow[1];
+       tx += (gpu_unai.TextureWindow[0] >> (2 - tmode));
+       ty += gpu_unai.TextureWindow[1];
        
-       BLEND_MODE  = (((tpage>>5)&0x3)     ) << 3;
-       TEXT_MODE   = (((tpage>>7)&0x3) + 1 ) << 5; // +1 el cero no lo usamos
-
-       TBA = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(tx, ty)];
-
+       gpu_unai.BLEND_MODE  = ((tpage>>5) & 3) << 3;
+       gpu_unai.TEXT_MODE   = (tmode + 1) << 5; // gpu_unai.TEXT_MODE should be values 1..3, so add one
+       gpu_unai.TBA = &((u16*)gpu_unai.vram)[FRAME_OFFSET(tx, ty)];
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 INLINE void gpuSetCLUT(u16 clut)
 {
-       CBA = &((u16*)GPU_FrameBuffer)[(clut & 0x7FFF) << 4];
+       gpu_unai.CBA = &((u16*)gpu_unai.vram)[(clut & 0x7FFF) << 4];
 }
 
 #ifdef  ENABLE_GPU_NULL_SUPPORT
@@ -61,159 +66,305 @@ INLINE void gpuSetCLUT(u16 clut)
 #define DO_LOG(expr) {}
 #endif
 
-#define Blending (((PRIM&0x2)&&(blend))?(PRIM&0x2):0)
-#define Blending_Mode (((PRIM&0x2)&&(blend))?BLEND_MODE:0)
-#define Lighting (((~PRIM)&0x1)&&(light))
+#define Blending      (((PRIM&0x2) && BlendingEnabled()) ? (PRIM&0x2) : 0)
+#define Blending_Mode (((PRIM&0x2) && BlendingEnabled()) ? gpu_unai.BLEND_MODE : 0)
+#define Lighting      (((~PRIM)&0x1) && LightingEnabled())
+// Dithering applies only to Gouraud-shaded polys or texture-blended polys:
+#define Dithering     (((((~PRIM)&0x1) || (PRIM&0x10)) && DitheringEnabled()) ?            \
+                       (ForcedDitheringEnabled() ? (1<<9) : (gpu_unai.GPU_GP1 & (1 << 9))) \
+                       : 0)
+
+///////////////////////////////////////////////////////////////////////////////
+//Now handled by Rearmed's gpulib and gpu_unai/gpulib_if.cpp:
+///////////////////////////////////////////////////////////////////////////////
+#ifndef USE_GPULIB
+
+// Handles GP0 draw settings commands 0xE1...0xE6
+static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
+{
+       // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
+       u8 num = (cmd_word >> 24) & 7;
+       switch (num) {
+               case 1: {
+                       // GP0(E1h) - Draw Mode setting (aka "Texpage")
+                       DO_LOG(("GP0(0xE1) DrawMode TexPage(0x%x)\n", cmd_word));
+                       u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
+                       u32 new_texpage = cmd_word & 0x7FF;
+                       if (cur_texpage != new_texpage) {
+                               gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
+                               gpuSetTexture(gpu_unai.GPU_GP1);
+                       }
+               } break;
+
+               case 2: {
+                       // GP0(E2h) - Texture Window setting
+                       DO_LOG(("GP0(0xE2) TextureWindow(0x%x)\n", cmd_word));
+                       if (cmd_word != gpu_unai.TextureWindowCur) {
+                               static const u8 TextureMask[32] = {
+                                       255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
+                                       127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
+                               };
+                               gpu_unai.TextureWindowCur = cmd_word;
+                               gpu_unai.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
+                               gpu_unai.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
+                               gpu_unai.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
+                               gpu_unai.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
+                               gpu_unai.TextureWindow[0] &= ~gpu_unai.TextureWindow[2];
+                               gpu_unai.TextureWindow[1] &= ~gpu_unai.TextureWindow[3];
+
+                               // Inner loop vars must be updated whenever texture window is changed:
+                               const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
+                               gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
+                               gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
+
+                               gpuSetTexture(gpu_unai.GPU_GP1);
+                       }
+               } break;
+
+               case 3: {
+                       // GP0(E3h) - Set Drawing Area top left (X1,Y1)
+                       DO_LOG(("GP0(0xE3) DrawingArea Pos(0x%x)\n", cmd_word));
+                       gpu_unai.DrawingArea[0] = cmd_word         & 0x3FF;
+                       gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
+               } break;
+
+               case 4: {
+                       // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
+                       DO_LOG(("GP0(0xE4) DrawingArea Size(0x%x)\n", cmd_word));
+                       gpu_unai.DrawingArea[2] = (cmd_word         & 0x3FF) + 1;
+                       gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
+               } break;
+
+               case 5: {
+                       // GP0(E5h) - Set Drawing Offset (X,Y)
+                       DO_LOG(("GP0(0xE5) DrawingOffset(0x%x)\n", cmd_word));
+                       gpu_unai.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
+                       gpu_unai.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
+               } break;
+
+               case 6: {
+                       // GP0(E6h) - Mask Bit Setting
+                       DO_LOG(("GP0(0xE6) SetMask(0x%x)\n", cmd_word));
+                       gpu_unai.Masking  = (cmd_word & 0x2) <<  1;
+                       gpu_unai.PixelMSB = (cmd_word & 0x1) <<  8;
+               } break;
+       }
+}
 
 void gpuSendPacketFunction(const int PRIM)
 {
        //printf("0x%x\n",PRIM);
 
+       //senquack - TODO: optimize this (packet pointer union as prim draw parameter
+       // introduced as optimization for gpulib command-list processing)
+       PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
+
        switch (PRIM)
        {
-               case 0x02:
+               case 0x02: {
                        NULL_GPU();
-                       gpuClearImage();    //  prim handles updateLace && skip
+                       gpuClearImage(packet);    //  prim handles updateLace && skip
+                       gpu_unai.fb_dirty = true;
                        DO_LOG(("gpuClearImage(0x%x)\n",PRIM));
-                       break;
+               } break;
+
                case 0x20:
                case 0x21:
                case 0x22:
-               case 0x23:
-                       if (!isSkip)
+               case 0x23: {          // Monochrome 3-pt poly
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuDrawF3(gpuPolySpanDrivers [Blending_Mode | Masking | Blending | PixelMSB]);
-                               DO_LOG(("gpuDrawF3(0x%x)\n",PRIM));
+                               PP driver = gpuPolySpanDrivers[
+                                       (gpu_unai.blit_mask?1024:0) |
+                                       Blending_Mode |
+                                       gpu_unai.Masking | Blending | gpu_unai.PixelMSB
+                               ];
+                               gpuDrawPolyF(packet, driver, false);
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawPolyF(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x24:
                case 0x25:
                case 0x26:
-               case 0x27:
-                       if (!isSkip)
+               case 0x27: {          // Textured 3-pt poly
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-                               gpuSetTexture (PacketBuffer.U4[4] >> 16);
-                               if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-                                       gpuDrawFT3(gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | PixelMSB]);
-                               else
-                                       gpuDrawFT3(gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | PixelMSB]);
-                               DO_LOG(("gpuDrawFT3(0x%x)\n",PRIM));
+                               gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+                               gpuSetTexture (gpu_unai.PacketBuffer.U4[4] >> 16);
+
+                               u32 driver_idx =
+                                       (gpu_unai.blit_mask?1024:0) |
+                                       Dithering |
+                                       Blending_Mode | gpu_unai.TEXT_MODE |
+                                       gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
+
+                               if (!FastLightingEnabled()) {
+                                       driver_idx |= Lighting;
+                               } else {
+                                       if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
+                                               driver_idx |= Lighting;
+                               }
+
+                               PP driver = gpuPolySpanDrivers[driver_idx];
+                               gpuDrawPolyFT(packet, driver, false);
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawPolyFT(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x28:
                case 0x29:
                case 0x2A:
-               case 0x2B:
-                       if (!isSkip)
+               case 0x2B: {          // Monochrome 4-pt poly
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               const PP gpuPolySpanDriver  = gpuPolySpanDrivers [Blending_Mode | Masking | Blending | PixelMSB];
-                               //--PacketBuffer.S2[6];
-                               gpuDrawF3(gpuPolySpanDriver);
-                               PacketBuffer.U4[1] = PacketBuffer.U4[4];
-                               //--PacketBuffer.S2[2];
-                               gpuDrawF3(gpuPolySpanDriver);
-                               DO_LOG(("gpuDrawF4(0x%x)\n",PRIM));
+                               PP driver = gpuPolySpanDrivers[
+                                       (gpu_unai.blit_mask?1024:0) |
+                                       Blending_Mode |
+                                       gpu_unai.Masking | Blending | gpu_unai.PixelMSB
+                               ];
+                               gpuDrawPolyF(packet, driver, true); // is_quad = true
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawPolyF(0x%x) (4-pt QUAD)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x2C:
                case 0x2D:
                case 0x2E:
-               case 0x2F:
-                       if (!isSkip)
+               case 0x2F: {          // Textured 4-pt poly
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-                               gpuSetTexture (PacketBuffer.U4[4] >> 16);
-                               PP gpuPolySpanDriver;
-                               if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-                                       gpuPolySpanDriver = gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | PixelMSB];
-                               else
-                                       gpuPolySpanDriver = gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | PixelMSB];
-                               //--PacketBuffer.S2[6];
-                               gpuDrawFT3(gpuPolySpanDriver);
-                               PacketBuffer.U4[1] = PacketBuffer.U4[7];
-                               PacketBuffer.U4[2] = PacketBuffer.U4[8];
-                               //--PacketBuffer.S2[2];
-                               gpuDrawFT3(gpuPolySpanDriver);
-                               DO_LOG(("gpuDrawFT4(0x%x)\n",PRIM));
+                               gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+                               gpuSetTexture (gpu_unai.PacketBuffer.U4[4] >> 16);
+
+                               u32 driver_idx =
+                                       (gpu_unai.blit_mask?1024:0) |
+                                       Dithering |
+                                       Blending_Mode | gpu_unai.TEXT_MODE |
+                                       gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
+
+                               if (!FastLightingEnabled()) {
+                                       driver_idx |= Lighting;
+                               } else {
+                                       if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
+                                               driver_idx |= Lighting;
+                               }
+
+                               PP driver = gpuPolySpanDrivers[driver_idx];
+                               gpuDrawPolyFT(packet, driver, true); // is_quad = true
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawPolyFT(0x%x) (4-pt QUAD)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x30:
                case 0x31:
                case 0x32:
-               case 0x33:
-                       if (!isSkip)
+               case 0x33: {          // Gouraud-shaded 3-pt poly
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuDrawG3(gpuPolySpanDrivers [Blending_Mode | Masking | Blending | 129 | PixelMSB]);
-                               DO_LOG(("gpuDrawG3(0x%x)\n",PRIM));
+                               //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
+                               // this is an untextured poly, so CF_LIGHT (texture blend)
+                               // shouldn't apply. Until the original array of template
+                               // instantiation ptrs is fixed, we're stuck with this. (TODO)
+                               PP driver = gpuPolySpanDrivers[
+                                       (gpu_unai.blit_mask?1024:0) |
+                                       Dithering |
+                                       Blending_Mode |
+                                       gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
+                               ];
+                               gpuDrawPolyG(packet, driver, false);
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawPolyG(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x34:
                case 0x35:
                case 0x36:
-               case 0x37:
-                       if (!isSkip)
+               case 0x37: {          // Gouraud-shaded, textured 3-pt poly
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-                               gpuSetTexture (PacketBuffer.U4[5] >> 16);
-                               gpuDrawGT3(gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | ((Lighting)?129:0) | PixelMSB]);
-                               DO_LOG(("gpuDrawGT3(0x%x)\n",PRIM));
+                               gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+                               gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
+                               PP driver = gpuPolySpanDrivers[
+                                       (gpu_unai.blit_mask?1024:0) |
+                                       Dithering |
+                                       Blending_Mode | gpu_unai.TEXT_MODE |
+                                       gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
+                               ];
+                               gpuDrawPolyGT(packet, driver, false);
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawPolyGT(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x38:
                case 0x39:
                case 0x3A:
-               case 0x3B:
-                       if (!isSkip)
+               case 0x3B: {          // Gouraud-shaded 4-pt poly
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               const PP gpuPolySpanDriver  = gpuPolySpanDrivers [Blending_Mode | Masking | Blending | 129 | PixelMSB];
-                               //--PacketBuffer.S2[6];
-                               gpuDrawG3(gpuPolySpanDriver);
-                               PacketBuffer.U4[0] = PacketBuffer.U4[6];
-                               PacketBuffer.U4[1] = PacketBuffer.U4[7];
-                               //--PacketBuffer.S2[2];
-                               gpuDrawG3(gpuPolySpanDriver);
-                               DO_LOG(("gpuDrawG4(0x%x)\n",PRIM));
+                               // See notes regarding '129' for 0x30..0x33 further above -senquack
+                               PP driver = gpuPolySpanDrivers[
+                                       (gpu_unai.blit_mask?1024:0) |
+                                       Dithering |
+                                       Blending_Mode |
+                                       gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
+                               ];
+                               gpuDrawPolyG(packet, driver, true); // is_quad = true
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawPolyG(0x%x) (4-pt QUAD)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x3C:
                case 0x3D:
                case 0x3E:
-               case 0x3F:
-                       if (!isSkip)
+               case 0x3F: {          // Gouraud-shaded, textured 4-pt poly
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-                               gpuSetTexture (PacketBuffer.U4[5] >> 16);
-                               const PP gpuPolySpanDriver  = gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | ((Lighting)?129:0) | PixelMSB];
-                               //--PacketBuffer.S2[6];
-                               gpuDrawGT3(gpuPolySpanDriver);
-                               PacketBuffer.U4[0] = PacketBuffer.U4[9];
-                               PacketBuffer.U4[1] = PacketBuffer.U4[10];
-                               PacketBuffer.U4[2] = PacketBuffer.U4[11];
-                               //--PacketBuffer.S2[2];
-                               gpuDrawGT3(gpuPolySpanDriver);
-                               DO_LOG(("gpuDrawGT4(0x%x)\n",PRIM));
+                               gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+                               gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
+                               PP driver = gpuPolySpanDrivers[
+                                       (gpu_unai.blit_mask?1024:0) |
+                                       Dithering |
+                                       Blending_Mode | gpu_unai.TEXT_MODE |
+                                       gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
+                               ];
+                               gpuDrawPolyGT(packet, driver, true); // is_quad = true
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawPolyGT(0x%x) (4-pt QUAD)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x40:
                case 0x41:
                case 0x42:
-               case 0x43:
-                       if (!isSkip)
+               case 0x43: {          // Monochrome line
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuDrawLF(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
-                               DO_LOG(("gpuDrawLF(0x%x)\n",PRIM));
+                               // Shift index right by one, as untextured prims don't use lighting
+                               u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
+                               PSD driver = gpuPixelSpanDrivers[driver_idx];
+                               gpuDrawLineF(packet, driver);
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawLineF(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x48:
                case 0x49:
                case 0x4A:
@@ -221,32 +372,44 @@ void gpuSendPacketFunction(const int PRIM)
                case 0x4C:
                case 0x4D:
                case 0x4E:
-               case 0x4F:
-                       if (!isSkip)
+               case 0x4F: { // Monochrome line strip
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuDrawLF(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
-                               DO_LOG(("gpuDrawLF(0x%x)\n",PRIM));
+                               // Shift index right by one, as untextured prims don't use lighting
+                               u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
+                               PSD driver = gpuPixelSpanDrivers[driver_idx];
+                               gpuDrawLineF(packet, driver);
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawLineF(0x%x)\n",PRIM));
                        }
-                       if ((PacketBuffer.U4[3] & 0xF000F000) != 0x50005000)
+                       if ((gpu_unai.PacketBuffer.U4[3] & 0xF000F000) != 0x50005000)
                        {
-                               PacketBuffer.U4[1] = PacketBuffer.U4[2];
-                               PacketBuffer.U4[2] = PacketBuffer.U4[3];
-                               PacketCount = 1;
-                               PacketIndex = 3;
+                               gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
+                               gpu_unai.PacketBuffer.U4[2] = gpu_unai.PacketBuffer.U4[3];
+                               gpu_unai.PacketCount = 1;
+                               gpu_unai.PacketIndex = 3;
                        }
-                       break;
+               } break;
+
                case 0x50:
                case 0x51:
                case 0x52:
-               case 0x53:
-                       if (!isSkip)
+               case 0x53: {          // Gouraud-shaded line
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuDrawLG(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
-                               DO_LOG(("gpuDrawLG(0x%x)\n",PRIM));
+                               // Shift index right by one, as untextured prims don't use lighting
+                               u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
+                               // Index MSB selects Gouraud-shaded PixelSpanDriver:
+                               driver_idx |= (1 << 5);
+                               PSD driver = gpuPixelSpanDrivers[driver_idx];
+                               gpuDrawLineG(packet, driver);
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawLineG(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x58:
                case 0x59:
                case 0x5A:
@@ -254,204 +417,205 @@ void gpuSendPacketFunction(const int PRIM)
                case 0x5C:
                case 0x5D:
                case 0x5E:
-               case 0x5F:
-                       if (!isSkip)
+               case 0x5F: { // Gouraud-shaded line strip
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuDrawLG(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
-                               DO_LOG(("gpuDrawLG(0x%x)\n",PRIM));
+                               // Shift index right by one, as untextured prims don't use lighting
+                               u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
+                               // Index MSB selects Gouraud-shaded PixelSpanDriver:
+                               driver_idx |= (1 << 5);
+                               PSD driver = gpuPixelSpanDrivers[driver_idx];
+                               gpuDrawLineG(packet, driver);
+                               gpu_unai.fb_dirty = true;
+                               DO_LOG(("gpuDrawLineG(0x%x)\n",PRIM));
                        }
-                       if ((PacketBuffer.U4[4] & 0xF000F000) != 0x50005000)
+                       if ((gpu_unai.PacketBuffer.U4[4] & 0xF000F000) != 0x50005000)
                        {
-                               PacketBuffer.U1[3 + (2 * 4)] = PacketBuffer.U1[3 + (0 * 4)];
-                               PacketBuffer.U4[0] = PacketBuffer.U4[2];
-                               PacketBuffer.U4[1] = PacketBuffer.U4[3];
-                               PacketBuffer.U4[2] = PacketBuffer.U4[4];
-                               PacketCount = 2;
-                               PacketIndex = 3;
+                               gpu_unai.PacketBuffer.U1[3 + (2 * 4)] = gpu_unai.PacketBuffer.U1[3 + (0 * 4)];
+                               gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
+                               gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
+                               gpu_unai.PacketBuffer.U4[2] = gpu_unai.PacketBuffer.U4[4];
+                               gpu_unai.PacketCount = 2;
+                               gpu_unai.PacketIndex = 3;
                        }
-                       break;
+               } break;
+
                case 0x60:
                case 0x61:
                case 0x62:
-               case 0x63:
-                       if (!isSkip)
+               case 0x63: {          // Monochrome rectangle (variable size)
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuDrawT(gpuTileSpanDrivers [Blending_Mode | Masking | Blending | (PixelMSB>>3)]);
+                               PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
+                               gpuDrawT(packet, driver);
+                               gpu_unai.fb_dirty = true;
                                DO_LOG(("gpuDrawT(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x64:
                case 0x65:
                case 0x66:
-               case 0x67:
-                       if (!isSkip)
+               case 0x67: {          // Textured rectangle (variable size)
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-                               gpuSetTexture (GPU_GP1);
-                               if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-                                       gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | (enableAbbeyHack<<7)  | PixelMSB]);
-                               else
-                                       gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | (enableAbbeyHack<<7)  | PixelMSB]);
+                               gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+                               u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
+
+                               // This fixes Silent Hill running animation on loading screens:
+                               // (On PSX, color values 0x00-0x7F darken the source texture's color,
+                               //  0x81-FF lighten textures (ultimately clamped to 0x1F),
+                               //  0x80 leaves source texture color unchanged, HOWEVER,
+                               //   gpu_unai uses a simple lighting LUT whereby only the upper
+                               //   5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
+                               //   0x80.
+                               // 
+                               // NOTE: I've changed all textured sprite draw commands here and
+                               //  elsewhere to use proper behavior, but left poly commands
+                               //  alone, I don't want to slow rendering down too much. (TODO)
+                               //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
+                               // Strip lower 3 bits of each color and determine if lighting should be used:
+                               if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
+                                       driver_idx |= Lighting;
+                               PS driver = gpuSpriteSpanDrivers[driver_idx];
+                               gpuDrawS(packet, driver);
+                               gpu_unai.fb_dirty = true;
                                DO_LOG(("gpuDrawS(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x68:
                case 0x69:
                case 0x6A:
-               case 0x6B:
-                       if (!isSkip)
+               case 0x6B: {          // Monochrome rectangle (1x1 dot)
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               PacketBuffer.U4[2] = 0x00010001;
-                               gpuDrawT(gpuTileSpanDrivers [Blending_Mode | Masking | Blending | (PixelMSB>>3)]);
+                               gpu_unai.PacketBuffer.U4[2] = 0x00010001;
+                               PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
+                               gpuDrawT(packet, driver);
+                               gpu_unai.fb_dirty = true;
                                DO_LOG(("gpuDrawT(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x70:
                case 0x71:
                case 0x72:
-               case 0x73:
-                       if (!isSkip)
+               case 0x73: {          // Monochrome rectangle (8x8)
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               PacketBuffer.U4[2] = 0x00080008;
-                               gpuDrawT(gpuTileSpanDrivers [Blending_Mode | Masking | Blending | (PixelMSB>>3)]);
+                               gpu_unai.PacketBuffer.U4[2] = 0x00080008;
+                               PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
+                               gpuDrawT(packet, driver);
+                               gpu_unai.fb_dirty = true;
                                DO_LOG(("gpuDrawT(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x74:
                case 0x75:
                case 0x76:
-               case 0x77:
-                       if (!isSkip)
+               case 0x77: {          // Textured rectangle (8x8)
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               PacketBuffer.U4[3] = 0x00080008;
-                               gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-                               gpuSetTexture (GPU_GP1);
-                               if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-                                       gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | (enableAbbeyHack<<7)  | PixelMSB]);
-                               else
-                                       gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | (enableAbbeyHack<<7)  | PixelMSB]);
+                               gpu_unai.PacketBuffer.U4[3] = 0x00080008;
+                               gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+                               u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
+
+                               //senquack - Only color 808080h-878787h allows skipping lighting calculation:
+                               //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
+                               // Strip lower 3 bits of each color and determine if lighting should be used:
+                               if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
+                                       driver_idx |= Lighting;
+                               PS driver = gpuSpriteSpanDrivers[driver_idx];
+                               gpuDrawS(packet, driver);
+                               gpu_unai.fb_dirty = true;
                                DO_LOG(("gpuDrawS(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x78:
                case 0x79:
                case 0x7A:
-               case 0x7B:
-                       if (!isSkip)
+               case 0x7B: {          // Monochrome rectangle (16x16)
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               PacketBuffer.U4[2] = 0x00100010;
-                               gpuDrawT(gpuTileSpanDrivers [Blending_Mode | Masking | Blending | (PixelMSB>>3)]);
+                               gpu_unai.PacketBuffer.U4[2] = 0x00100010;
+                               PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
+                               gpuDrawT(packet, driver);
+                               gpu_unai.fb_dirty = true;
                                DO_LOG(("gpuDrawT(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x7C:
                case 0x7D:
-#ifdef __arm__
-                       if ((GPU_GP1 & 0x180) == 0 && (Masking | PixelMSB) == 0)
+                       #ifdef __arm__
+                       /* Notaz 4bit sprites optimization */
+                       if ((!gpu_unai.frameskip.skipGPU) && (!(gpu_unai.GPU_GP1&0x180)) && (!(gpu_unai.Masking|gpu_unai.PixelMSB)))
                        {
-                               gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-                               gpuSetTexture (GPU_GP1);
-                               gpuDrawS16();
+                               gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+                               gpuDrawS16(packet);
+                               gpu_unai.fb_dirty = true;
                                break;
                        }
-                       // fallthrough
-#endif
+                       #endif
                case 0x7E:
-               case 0x7F:
-                       if (!isSkip)
+               case 0x7F: {          // Textured rectangle (16x16)
+                       if (!gpu_unai.frameskip.skipGPU)
                        {
                                NULL_GPU();
-                               PacketBuffer.U4[3] = 0x00100010;
-                               gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-                               gpuSetTexture (GPU_GP1);
-                               if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-                                       gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | (enableAbbeyHack<<7)  | PixelMSB]);
-                               else
-                                       gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | (enableAbbeyHack<<7)  | PixelMSB]);
+                               gpu_unai.PacketBuffer.U4[3] = 0x00100010;
+                               gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+                               u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
+
+                               //senquack - Only color 808080h-878787h allows skipping lighting calculation:
+                               //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
+                               // Strip lower 3 bits of each color and determine if lighting should be used:
+                               if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
+                                       driver_idx |= Lighting;
+                               PS driver = gpuSpriteSpanDrivers[driver_idx];
+                               gpuDrawS(packet, driver);
+                               gpu_unai.fb_dirty = true;
                                DO_LOG(("gpuDrawS(0x%x)\n",PRIM));
                        }
-                       break;
+               } break;
+
                case 0x80:          //  vid -> vid
-                       gpuMoveImage();   //  prim handles updateLace && skip
+                       gpuMoveImage(packet);   //  prim handles updateLace && skip
+                       if ((!gpu_unai.frameskip.skipCount) && (gpu_unai.DisplayArea[3] == 480)) // Tekken 3 hack
+                       {
+                               if (!gpu_unai.frameskip.skipGPU) gpu_unai.fb_dirty = true;
+                       }
+                       else
+                       {
+                               gpu_unai.fb_dirty = true;
+                       }
                        DO_LOG(("gpuMoveImage(0x%x)\n",PRIM));
                        break;
                case 0xA0:          //  sys ->vid
-                       gpuLoadImage();   //  prim handles updateLace && skip
-#ifndef isSkip // not a define
-                       if (alt_fps) isSkip=false;
-#endif
+                       gpuLoadImage(packet);   //  prim handles updateLace && skip
                        DO_LOG(("gpuLoadImage(0x%x)\n",PRIM));
                        break;
                case 0xC0:          //  vid -> sys
-                       gpuStoreImage();  //  prim handles updateLace && skip
+                       gpuStoreImage(packet);  //  prim handles updateLace && skip
                        DO_LOG(("gpuStoreImage(0x%x)\n",PRIM));
                        break;
-               case 0xE1:
-                       {
-                               const u32 temp = PacketBuffer.U4[0];
-                               GPU_GP1 = (GPU_GP1 & ~0x000007FF) | (temp & 0x000007FF);
-                               gpuSetTexture(temp);
-                               DO_LOG(("gpuSetTexture(0x%x)\n",PRIM));
-                       }
-                       break;
-               case 0xE2:        
-                       {
-                               static const u8  TextureMask[32] = {
-                                       255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,        //
-                                       127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7   //
-                               };
-                               const u32 temp = PacketBuffer.U4[0];
-                               TextureWindow[0] = ((temp >> 10) & 0x1F) << 3;
-                               TextureWindow[1] = ((temp >> 15) & 0x1F) << 3;
-                               TextureWindow[2] = TextureMask[(temp >> 0) & 0x1F];
-                               TextureWindow[3] = TextureMask[(temp >> 5) & 0x1F];
-                               gpuSetTexture(GPU_GP1);
-                               //isSkip = false;
-                               DO_LOG(("TextureWindow(0x%x)\n",PRIM));
-                       }
-                       break;
-               case 0xE3:
-                       {
-                               const u32 temp = PacketBuffer.U4[0];
-                               DrawingArea[0] = temp         & 0x3FF;
-                               DrawingArea[1] = (temp >> 10) & 0x3FF;
-                               //isSkip = false;
-                               DO_LOG(("DrawingArea_Pos(0x%x)\n",PRIM));
-                       }
-                       break;
-               case 0xE4:
-                       {
-                               const u32 temp = PacketBuffer.U4[0];
-                               DrawingArea[2] = (temp         & 0x3FF) + 1;
-                               DrawingArea[3] = ((temp >> 10) & 0x3FF) + 1;
-                               //isSkip = false;
-                               DO_LOG(("DrawingArea_Size(0x%x)\n",PRIM));
-                       }
-                       break;
-               case 0xE5:
-                       {
-                               const u32 temp = PacketBuffer.U4[0];
-                               DrawingOffset[0] = ((s32)temp<<(32-11))>>(32-11);
-                               DrawingOffset[1] = ((s32)temp<<(32-22))>>(32-11);
-                               //isSkip = false;
-                               DO_LOG(("DrawingOffset(0x%x)\n",PRIM));
-                       }
-                       break;
-               case 0xE6:
-                       {
-                               const u32 temp = PacketBuffer.U4[0];
-                               //GPU_GP1 = (GPU_GP1 & ~0x00001800) | ((temp&3) << 11);
-                               Masking = (temp & 0x2) <<  1;
-                               PixelMSB =(temp & 0x1) <<  8;
-                               DO_LOG(("SetMask(0x%x)\n",PRIM));
-                       }
-                       break;
+               case 0xE1 ... 0xE6: { // Draw settings
+                       gpuGP0Cmd_0xEx(gpu_unai, gpu_unai.PacketBuffer.U4[0]);
+               } break;
        }
 }
+#endif //!USE_GPULIB
+///////////////////////////////////////////////////////////////////////////////
+// End of code specific to non-gpulib standalone version of gpu_unai
+///////////////////////////////////////////////////////////////////////////////
+
+#endif /* __GPU_UNAI_GPU_COMMAND_H__ */
index e72fda1..5df42cf 100644 (file)
 #ifndef FIXED_H
 #define FIXED_H
 
-#include "arm_features.h"
-
 typedef s32 fixed;
 
-#ifdef GPU_TABLE_10_BITS
-#define TABLE_BITS 10
-#else
-#define TABLE_BITS 16
-#endif
-
-#define FIXED_BITS 16
+//senquack - The gpu_drhell poly routines I adapted use 22.10 fixed point,
+//           while original Unai used 16.16: (see README_senquack.txt)
+//#define FIXED_BITS 16
+#define FIXED_BITS 10
 
 #define fixed_ZERO ((fixed)0)
 #define fixed_ONE  ((fixed)1<<FIXED_BITS)
 #define fixed_TWO  ((fixed)2<<FIXED_BITS)
 #define fixed_HALF ((fixed)((1<<FIXED_BITS)>>1))
 
-//  big precision inverse table.
-s32 s_invTable[(1<<TABLE_BITS)];
+#define fixed_LOMASK ((fixed)((1<<FIXED_BITS)-1))
+#define fixed_HIMASK ((fixed)(~fixed_LOMASK))
+
+// int<->fixed conversions:
+#define i2x(x) ((x)<<FIXED_BITS)
+#define x2i(x) ((x)>>FIXED_BITS)
+
+INLINE fixed FixedCeil(const fixed x)
+{
+       return (x + (fixed_ONE - 1)) & fixed_HIMASK;
+}
 
-INLINE  fixed i2x(const int   _x) { return  ((_x)<<FIXED_BITS); }
-INLINE  fixed x2i(const fixed _x) { return  ((_x)>>FIXED_BITS); }
+INLINE s32 FixedCeilToInt(const fixed x)
+{
+       return (x + (fixed_ONE - 1)) >> FIXED_BITS;
+}
 
-/*
-INLINE u32 Log2(u32 _a)
+//senquack - float<->fixed conversions:
+#define f2x(x) ((s32)((x) * (float)(1<<FIXED_BITS)))
+#define x2f(x) ((float)(x) / (float)(1<<FIXED_BITS))
+
+//senquack - floating point reciprocal:
+//NOTE: These assume x is always != 0 !!!
+#ifdef GPU_UNAI_USE_FLOATMATH
+#if defined(_MIPS_ARCH_MIPS32R2) || (__mips == 64)
+INLINE float FloatInv(const float x)
+{
+       float res;
+       asm("recip.s %0,%1" : "=f" (res) : "f" (x));
+       return res;
+}
+#else
+INLINE float FloatInv(const float x)
 {
-  u32 c = 0; // result of log2(v) will go here
-  if (_a & 0xFFFF0000) { _a >>= 16; c |= 16;  }
-  if (_a & 0xFF00) { _a >>= 8; c |= 8;  }
-  if (_a & 0xF0) { _a >>= 4; c |= 4;  }
-  if (_a & 0xC) { _a >>= 2; c |= 2;  }
-  if (_a & 0x2) { _a >>= 1; c |= 1;  }
-  return c;
+       return (1.0f / x);
 }
-*/
+#endif
+#endif
 
-#ifdef HAVE_ARMV5
+///////////////////////////////////////////////////////////////////////////
+// --- BEGIN INVERSE APPROXIMATION SECTION ---
+///////////////////////////////////////////////////////////////////////////
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+
+//  big precision inverse table.
+#define TABLE_BITS 16
+s32 s_invTable[(1<<TABLE_BITS)];
+
+//senquack - MIPS32 happens to have same instruction/format:
+#if defined(__arm__) || (__mips == 32)
 INLINE u32 Log2(u32 x) { u32 res; asm("clz %0,%1" : "=r" (res) : "r" (x)); return 32-res; }
 #else
 INLINE u32 Log2(u32 x) { u32 i = 0; for ( ; x > 0; ++i, x >>= 1); return i - 1; }
 #endif
 
-#ifdef GPU_TABLE_10_BITS
-INLINE  void  xInv (const fixed _b, s32& iFactor_, s32& iShift_)
-{
-    u32 uD   = (_b<0) ? -_b : _b ;
-    u32 uLog = Log2(uD);
-    uLog = uLog>(TABLE_BITS-1) ? uLog-(TABLE_BITS-1) : 0;
-    u32 uDen = uD>>uLog;
-    iFactor_ = s_invTable[uDen];
-    iFactor_ = (_b<0) ? -iFactor_ :iFactor_;
-    iShift_  = 15+uLog;
-}
-#else
 INLINE  void  xInv (const fixed _b, s32& iFactor_, s32& iShift_)
 {
   u32 uD = (_b<0) ? -_b : _b;
@@ -82,10 +95,12 @@ INLINE  void  xInv (const fixed _b, s32& iFactor_, s32& iShift_)
   {
        u32 uLog = Log2(uD);
     uLog = uLog>(TABLE_BITS-1) ? uLog-(TABLE_BITS-1) : 0;
-    u32 uDen = (uD>>uLog)-1;
+    u32 uDen = (uD>>uLog);
     iFactor_ = s_invTable[uDen];
     iFactor_ = (_b<0) ? -iFactor_ :iFactor_;
-    iShift_  = 15+uLog;
+    //senquack - Adapted to 22.10 fixed point (originally 16.16):
+    //iShift_  = 15+uLog;
+    iShift_  = 21+uLog;
   }
   else
   {
@@ -93,7 +108,6 @@ INLINE  void  xInv (const fixed _b, s32& iFactor_, s32& iShift_)
     iShift_ = 0;
   }
 }
-#endif
 
 INLINE  fixed xInvMulx  (const fixed _a, const s32 _iFact, const s32 _iShift)
 {
@@ -112,20 +126,9 @@ INLINE  fixed xLoDivx   (const fixed _a, const fixed _b)
   xInv(_b, iFact, iShift);
   return xInvMulx(_a, iFact, iShift);
 }
-
+#endif // GPU_UNAI_USE_INT_DIV_MULTINV
 ///////////////////////////////////////////////////////////////////////////
-template<typename T>
-INLINE  T Min2 (const T _a, const T _b)             { return (_a<_b)?_a:_b; }
-
-template<typename T>
-INLINE  T Min3 (const T _a, const T _b, const T _c) { return  Min2(Min2(_a,_b),_c); }
-
+// --- END INVERSE APPROXIMATION SECTION ---
 ///////////////////////////////////////////////////////////////////////////
-template<typename T>
-INLINE  T Max2 (const T _a, const T _b)             { return  (_a>_b)?_a:_b; }
 
-template<typename T>
-INLINE  T Max3 (const T _a, const T _b, const T _c) { return  Max2(Max2(_a,_b),_c); }
-
-///////////////////////////////////////////////////////////////////////////
 #endif  //FIXED_H
index 4cd7bff..4aab604 100644 (file)
@@ -1,6 +1,7 @@
 /***************************************************************************
 *   Copyright (C) 2010 PCSX4ALL Team                                      *
 *   Copyright (C) 2010 Unai                                               *
+*   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
 ***************************************************************************/
 
-///////////////////////////////////////////////////////////////////////////////
-//  Inner loop driver instanciation file
+#ifndef __GPU_UNAI_GPU_INNER_H__
+#define __GPU_UNAI_GPU_INNER_H__
 
 ///////////////////////////////////////////////////////////////////////////////
-//  Option Masks
-#define   L ((CF>>0)&1)
-#define   B ((CF>>1)&1)
-#define   M ((CF>>2)&1)
-#define  BM ((CF>>3)&3)
-#define  TM ((CF>>5)&3)
-#define   G ((CF>>7)&1)
+// Inner loop driver instantiation file
 
-#define  AH ((CF>>7)&1)
+///////////////////////////////////////////////////////////////////////////////
+//  Option Masks (CF template paramter)
+#define  CF_LIGHT     ((CF>> 0)&1) // Lighting
+#define  CF_BLEND     ((CF>> 1)&1) // Blending
+#define  CF_MASKCHECK ((CF>> 2)&1) // Mask bit check
+#define  CF_BLENDMODE ((CF>> 3)&3) // Blend mode   0..3
+#define  CF_TEXTMODE  ((CF>> 5)&3) // Texture mode 1..3 (0: texturing disabled)
+#define  CF_GOURAUD   ((CF>> 7)&1) // Gouraud shading
+#define  CF_MASKSET   ((CF>> 8)&1) // Mask bit set
+#define  CF_DITHER    ((CF>> 9)&1) // Dithering
+#define  CF_BLITMASK  ((CF>>10)&1) // blit_mask check (skip rendering pixels
+                                   //  that wouldn't end up displayed on
+                                   //  low-res screen using simple downscaler)
 
-#define  MB ((CF>>8)&1)
+//#ifdef __arm__
+//#ifndef ENABLE_GPU_ARMV7
+/* ARMv5 */
+//#include "gpu_inner_blend_arm5.h"
+//#else
+/* ARMv7 optimized */
+//#include "gpu_inner_blend_arm7.h"
+//#endif
+//#else
+//#include "gpu_inner_blend.h"
+//#endif
 
 #include "gpu_inner_blend.h"
+#include "gpu_inner_quantization.h"
 #include "gpu_inner_light.h"
 
+#ifdef __arm__
+#include "gpu_inner_blend_arm.h"
+#include "gpu_inner_light_arm.h"
+#define gpuBlending gpuBlendingARM
+#define gpuLightingRGB gpuLightingRGBARM
+#define gpuLightingTXT gpuLightingTXTARM
+#define gpuLightingTXTGouraud gpuLightingTXTGouraudARM
+// Non-dithering lighting and blending functions preserve uSrc
+// MSB. This saves a few operations and useless load/stores.
+#define MSB_PRESERVED (!CF_DITHER)
+#else
+#define gpuBlending gpuBlendingGeneric
+#define gpuLightingRGB gpuLightingRGBGeneric
+#define gpuLightingTXT gpuLightingTXTGeneric
+#define gpuLightingTXTGouraud gpuLightingTXTGouraudGeneric
+#define MSB_PRESERVED 0
+#endif
+
+
+// If defined, Gouraud colors are fixed-point 5.11, otherwise they are 8.16
+// This is only for debugging/verification of low-precision colors in C.
+// Low-precision Gouraud is intended for use by SIMD-optimized inner drivers
+// which get/use Gouraud colors in SIMD registers.
+//#define GPU_GOURAUD_LOW_PRECISION
+
+// How many bits of fixed-point precision GouraudColor uses
+#ifdef GPU_GOURAUD_LOW_PRECISION
+#define GPU_GOURAUD_FIXED_BITS 11
+#else
+#define GPU_GOURAUD_FIXED_BITS 16
+#endif
+
+// Used to pass Gouraud colors to gpuPixelSpanFn() (lines)
+struct GouraudColor {
+#ifdef GPU_GOURAUD_LOW_PRECISION
+       u16 r, g, b;
+       s16 r_incr, g_incr, b_incr;
+#else
+       u32 r, g, b;
+       s32 r_incr, g_incr, b_incr;
+#endif
+};
+
+static inline u16 gpuGouraudColor15bpp(u32 r, u32 g, u32 b)
+{
+       r >>= GPU_GOURAUD_FIXED_BITS;
+       g >>= GPU_GOURAUD_FIXED_BITS;
+       b >>= GPU_GOURAUD_FIXED_BITS;
+
+#ifndef GPU_GOURAUD_LOW_PRECISION
+       // High-precision Gouraud colors are 8-bit + fractional
+       r >>= 3;  g >>= 3;  b >>= 3;
+#endif
+
+       return r | (g << 5) | (b << 10);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
-//  GPU Pixel opperations generator
-template<const int CF>
-INLINE void gpuPixelFn(u16 *pixel,const u16 data)
+//  GPU Pixel span operations generator gpuPixelSpanFn<>
+//  Oct 2016: Created/adapted from old gpuPixelFn by senquack:
+//  Original gpuPixelFn was used to draw lines one pixel at a time. I wrote
+//  new line algorithms that draw lines using horizontal/vertical/diagonal
+//  spans of pixels, necessitating new pixel-drawing function that could
+//  not only render spans of pixels, but gouraud-shade them as well.
+//  This speeds up line rendering and would allow tile-rendering (untextured
+//  rectangles) to use the same set of functions. Since tiles are always
+//  monochrome, they simply wouldn't use the extra set of 32 gouraud-shaded
+//  gpuPixelSpanFn functions (TODO?).
+//
+// NOTE: While the PS1 framebuffer is 16 bit, we use 8-bit pointers here,
+//       so that pDst can be incremented directly by 'incr' parameter
+//       without having to shift it before use.
+template<int CF>
+static u8* gpuPixelSpanFn(u8* pDst, uintptr_t data, ptrdiff_t incr, size_t len)
 {
-       if ((!M)&&(!B))
-       {
-               if(MB) { *pixel = data | 0x8000; }
-               else   { *pixel = data; }
+       // Blend func can save an operation if it knows uSrc MSB is
+       //  unset. For untextured prims, this is always true.
+       const bool skip_uSrc_mask = true;
+
+       u16 col;
+       struct GouraudColor * gcPtr;
+       u32 r, g, b;
+       s32 r_incr, g_incr, b_incr;
+
+       if (CF_GOURAUD) {
+               gcPtr = (GouraudColor*)data;
+               r = gcPtr->r;  r_incr = gcPtr->r_incr;
+               g = gcPtr->g;  g_incr = gcPtr->g_incr;
+               b = gcPtr->b;  b_incr = gcPtr->b_incr;
+       } else {
+               col = (u16)data;
        }
-       else if ((M)&&(!B))
-       {
-               if (!(*pixel&0x8000))
-               {
-                       if(MB) { *pixel = data | 0x8000; }
-                       else   { *pixel = data; }
+
+       do {
+               if (!CF_GOURAUD)
+               {   // NO GOURAUD
+                       if (!CF_MASKCHECK && !CF_BLEND) {
+                               if (CF_MASKSET) { *(u16*)pDst = col | 0x8000; }
+                               else            { *(u16*)pDst = col;          }
+                       } else if (CF_MASKCHECK && !CF_BLEND) {
+                               if (!(*(u16*)pDst & 0x8000)) {
+                                       if (CF_MASKSET) { *(u16*)pDst = col | 0x8000; }
+                                       else            { *(u16*)pDst = col;          }
+                               }
+                       } else {
+                               uint_fast16_t uDst = *(u16*)pDst;
+                               if (CF_MASKCHECK) { if (uDst & 0x8000) goto endpixel; }
+
+                               uint_fast16_t uSrc = col;
+
+                               if (CF_BLEND)
+                                       uSrc = gpuBlending<CF_BLENDMODE, skip_uSrc_mask>(uSrc, uDst);
+
+                               if (CF_MASKSET) { *(u16*)pDst = uSrc | 0x8000; }
+                               else            { *(u16*)pDst = uSrc;          }
+                       }
+
+               } else
+               {   // GOURAUD
+
+                       if (!CF_MASKCHECK && !CF_BLEND) {
+                               col = gpuGouraudColor15bpp(r, g, b);
+                               if (CF_MASKSET) { *(u16*)pDst = col | 0x8000; }
+                               else            { *(u16*)pDst = col;          }
+                       } else if (CF_MASKCHECK && !CF_BLEND) {
+                               col = gpuGouraudColor15bpp(r, g, b);
+                               if (!(*(u16*)pDst & 0x8000)) {
+                                       if (CF_MASKSET) { *(u16*)pDst = col | 0x8000; }
+                                       else            { *(u16*)pDst = col;          }
+                               }
+                       } else {
+                               uint_fast16_t uDst = *(u16*)pDst;
+                               if (CF_MASKCHECK) { if (uDst & 0x8000) goto endpixel; }
+                               col = gpuGouraudColor15bpp(r, g, b);
+
+                               uint_fast16_t uSrc = col;
+
+                               // Blend func can save an operation if it knows uSrc MSB is
+                               //  unset. For untextured prims, this is always true.
+                               const bool skip_uSrc_mask = true;
+
+                               if (CF_BLEND)
+                                       uSrc = gpuBlending<CF_BLENDMODE, skip_uSrc_mask>(uSrc, uDst);
+
+                               if (CF_MASKSET) { *(u16*)pDst = uSrc | 0x8000; }
+                               else            { *(u16*)pDst = uSrc;          }
+                       }
                }
+
+endpixel:
+               if (CF_GOURAUD) {
+                       r += r_incr;
+                       g += g_incr;
+                       b += b_incr;
+               }
+               pDst += incr;
+       } while (len-- > 1);
+
+       // Note from senquack: Normally, I'd prefer to write a 'do {} while (--len)'
+       //  loop, or even a for() loop, however, on MIPS platforms anything but the
+       //  'do {} while (len-- > 1)' tends to generate very unoptimal asm, with
+       //  many unneeded MULs/ADDs/branches at the ends of these functions.
+       //  If you change the loop structure above, be sure to compare the quality
+       //  of the generated code!!
+
+       if (CF_GOURAUD) {
+               gcPtr->r = r;
+               gcPtr->g = g;
+               gcPtr->b = b;
        }
-       else
-       {
-               u16 uDst = *pixel;
-               if(M) { if (uDst&0x8000) return; }
-               u16 uSrc = data;
-               u32 uMsk; if (BM==0) uMsk=0x7BDE;
-               if (BM==0) gpuBlending00(uSrc, uDst);
-               if (BM==1) gpuBlending01(uSrc, uDst);
-               if (BM==2) gpuBlending02(uSrc, uDst);
-               if (BM==3) gpuBlending03(uSrc, uDst);
-               if(MB) { *pixel = uSrc | 0x8000; }
-               else   { *pixel = uSrc; }
-       }
+       return pDst;
+}
+
+static u8* PixelSpanNULL(u8* pDst, uintptr_t data, ptrdiff_t incr, size_t len)
+{
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"PixelSpanNULL()\n");
+       #endif
+       return pDst;
 }
-///////////////////////////////////////////////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////////
-//  Pixel drawing drivers, for lines (only blending)
-typedef void (*PD)(u16 *pixel,const u16 data);
-const PD  gpuPixelDrivers[32] =   //  We only generate pixel op for MASKING/BLEND_ENABLE/BLEND_MODE
+//  PixelSpan (lines) innerloops driver
+typedef u8* (*PSD)(u8* dst, uintptr_t data, ptrdiff_t incr, size_t len);
+
+const PSD gpuPixelSpanDrivers[64] =
 { 
-       gpuPixelFn<0x00<<1>,gpuPixelFn<0x01<<1>,gpuPixelFn<0x02<<1>,gpuPixelFn<0x03<<1>,  
-       NULL,gpuPixelFn<0x05<<1>,NULL,gpuPixelFn<0x07<<1>,
-       NULL,gpuPixelFn<0x09<<1>,NULL,gpuPixelFn<0x0B<<1>,
-       NULL,gpuPixelFn<0x0D<<1>,NULL,gpuPixelFn<0x0F<<1>,
-
-       gpuPixelFn<(0x00<<1)|256>,gpuPixelFn<(0x01<<1)|256>,gpuPixelFn<(0x02<<1)|256>,gpuPixelFn<(0x03<<1)|256>,  
-       NULL,gpuPixelFn<(0x05<<1)|256>,NULL,gpuPixelFn<(0x07<<1)|256>,
-       NULL,gpuPixelFn<(0x09<<1)|256>,NULL,gpuPixelFn<(0x0B<<1)|256>,
-       NULL,gpuPixelFn<(0x0D<<1)|256>,NULL,gpuPixelFn<(0x0F<<1)|256>
+       // Array index | 'CF' template field | Field value
+       // ------------+---------------------+----------------
+       // Bit 0       | CF_BLEND            | off (0), on (1)
+       // Bit 1       | CF_MASKCHECK        | off (0), on (1)
+       // Bit 3:2     | CF_BLENDMODE        | 0..3
+       // Bit 4       | CF_MASKSET          | off (0), on (1)
+       // Bit 5       | CF_GOURAUD          | off (0), on (1)
+       //
+       // NULL entries are ones for which blending is disabled and blend-mode
+       //  field is non-zero, which is obviously invalid.
+
+       // Flat-shaded
+       gpuPixelSpanFn<0x00<<1>,         gpuPixelSpanFn<0x01<<1>,         gpuPixelSpanFn<0x02<<1>,         gpuPixelSpanFn<0x03<<1>,
+       PixelSpanNULL,                   gpuPixelSpanFn<0x05<<1>,         PixelSpanNULL,                   gpuPixelSpanFn<0x07<<1>,
+       PixelSpanNULL,                   gpuPixelSpanFn<0x09<<1>,         PixelSpanNULL,                   gpuPixelSpanFn<0x0B<<1>,
+       PixelSpanNULL,                   gpuPixelSpanFn<0x0D<<1>,         PixelSpanNULL,                   gpuPixelSpanFn<0x0F<<1>,
+
+       // Flat-shaded + PixelMSB (CF_MASKSET)
+       gpuPixelSpanFn<(0x00<<1)|0x100>, gpuPixelSpanFn<(0x01<<1)|0x100>, gpuPixelSpanFn<(0x02<<1)|0x100>, gpuPixelSpanFn<(0x03<<1)|0x100>,
+       PixelSpanNULL,                   gpuPixelSpanFn<(0x05<<1)|0x100>, PixelSpanNULL,                   gpuPixelSpanFn<(0x07<<1)|0x100>,
+       PixelSpanNULL,                   gpuPixelSpanFn<(0x09<<1)|0x100>, PixelSpanNULL,                   gpuPixelSpanFn<(0x0B<<1)|0x100>,
+       PixelSpanNULL,                   gpuPixelSpanFn<(0x0D<<1)|0x100>, PixelSpanNULL,                   gpuPixelSpanFn<(0x0F<<1)|0x100>,
+
+       // Gouraud-shaded (CF_GOURAUD)
+       gpuPixelSpanFn<(0x00<<1)|0x80>,  gpuPixelSpanFn<(0x01<<1)|0x80>,  gpuPixelSpanFn<(0x02<<1)|0x80>,  gpuPixelSpanFn<(0x03<<1)|0x80>,
+       PixelSpanNULL,                   gpuPixelSpanFn<(0x05<<1)|0x80>,  PixelSpanNULL,                   gpuPixelSpanFn<(0x07<<1)|0x80>,
+       PixelSpanNULL,                   gpuPixelSpanFn<(0x09<<1)|0x80>,  PixelSpanNULL,                   gpuPixelSpanFn<(0x0B<<1)|0x80>,
+       PixelSpanNULL,                   gpuPixelSpanFn<(0x0D<<1)|0x80>,  PixelSpanNULL,                   gpuPixelSpanFn<(0x0F<<1)|0x80>,
+
+       // Gouraud-shaded (CF_GOURAUD) + PixelMSB (CF_MASKSET)
+       gpuPixelSpanFn<(0x00<<1)|0x180>, gpuPixelSpanFn<(0x01<<1)|0x180>, gpuPixelSpanFn<(0x02<<1)|0x180>, gpuPixelSpanFn<(0x03<<1)|0x180>,
+       PixelSpanNULL,                   gpuPixelSpanFn<(0x05<<1)|0x180>, PixelSpanNULL,                   gpuPixelSpanFn<(0x07<<1)|0x180>,
+       PixelSpanNULL,                   gpuPixelSpanFn<(0x09<<1)|0x180>, PixelSpanNULL,                   gpuPixelSpanFn<(0x0B<<1)|0x180>,
+       PixelSpanNULL,                   gpuPixelSpanFn<(0x0D<<1)|0x180>, PixelSpanNULL,                   gpuPixelSpanFn<(0x0F<<1)|0x180>
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 //  GPU Tiles innerloops generator
 
-template<const int CF>
-INLINE void  gpuTileSpanFn(u16 *pDst, u32 count, u16 data)
+template<int CF>
+static void gpuTileSpanFn(u16 *pDst, u32 count, u16 data)
 {
-       if ((!M)&&(!B))
-       {
-               if (MB) { data = data | 0x8000; }
+       if (!CF_MASKCHECK && !CF_BLEND) {
+               if (CF_MASKSET) { data = data | 0x8000; }
                do { *pDst++ = data; } while (--count);
-       }
-       else if ((M)&&(!B))
-       {
-               if (MB) { data = data | 0x8000; }
+       } else if (CF_MASKCHECK && !CF_BLEND) {
+               if (CF_MASKSET) { data = data | 0x8000; }
                do { if (!(*pDst&0x8000)) { *pDst = data; } pDst++; } while (--count);
-       }
-       else
+       } else
        {
-               u16 uSrc;
-               u16 uDst;
-               u32 uMsk; if (BM==0) uMsk=0x7BDE;
+               // Blend func can save an operation if it knows uSrc MSB is
+               //  unset. For untextured prims, this is always true.
+               const bool skip_uSrc_mask = true;
+
+               uint_fast16_t uSrc, uDst;
                do
                {
-                       //  MASKING
-                       uDst = *pDst;
-                       if(M) { if (uDst&0x8000) goto endtile;  }
+                       if (CF_MASKCHECK || CF_BLEND) { uDst = *pDst; }
+                       if (CF_MASKCHECK) { if (uDst&0x8000) goto endtile; }
+
                        uSrc = data;
 
-                       //  BLEND
-                       if (BM==0) gpuBlending00(uSrc, uDst);
-                       if (BM==1) gpuBlending01(uSrc, uDst);
-                       if (BM==2) gpuBlending02(uSrc, uDst);
-                       if (BM==3) gpuBlending03(uSrc, uDst);
+                       if (CF_BLEND)
+                               uSrc = gpuBlending<CF_BLENDMODE, skip_uSrc_mask>(uSrc, uDst);
 
-                       if (MB) { *pDst = uSrc | 0x8000; }
-                       else    { *pDst = uSrc; }
-                       endtile: pDst++;
+                       if (CF_MASKSET) { *pDst = uSrc | 0x8000; }
+                       else            { *pDst = uSrc;          }
+
+                       //senquack - Did not apply "Silent Hill" mask-bit fix to here.
+                       // It is hard to tell from scarce documentation available and
+                       //  lack of comments in code, but I believe the tile-span
+                       //  functions here should not bother to preserve any source MSB,
+                       //  as they are not drawing from a texture.
+endtile:
+                       pDst++;
                }
                while (--count);
        }
 }
 
+static void TileNULL(u16 *pDst, u32 count, u16 data)
+{
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"TileNULL()\n");
+       #endif
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 //  Tiles innerloops driver
 typedef void (*PT)(u16 *pDst, u32 count, u16 data);
-const PT gpuTileSpanDrivers[64] = 
-{
-       gpuTileSpanFn<0x00>,NULL,gpuTileSpanFn<0x02>,NULL,  gpuTileSpanFn<0x04>,NULL,gpuTileSpanFn<0x06>,NULL,  NULL,NULL,gpuTileSpanFn<0x0A>,NULL,  NULL,NULL,gpuTileSpanFn<0x0E>,NULL,
-       NULL,NULL,gpuTileSpanFn<0x12>,NULL,  NULL,NULL,gpuTileSpanFn<0x16>,NULL,  NULL,NULL,gpuTileSpanFn<0x1A>,NULL,  NULL,NULL,gpuTileSpanFn<0x1E>,NULL,
 
-       gpuTileSpanFn<0x100>,NULL,gpuTileSpanFn<0x102>,NULL,  gpuTileSpanFn<0x104>,NULL,gpuTileSpanFn<0x106>,NULL,  NULL,NULL,gpuTileSpanFn<0x10A>,NULL,  NULL,NULL,gpuTileSpanFn<0x10E>,NULL,
-       NULL,NULL,gpuTileSpanFn<0x112>,NULL,  NULL,NULL,gpuTileSpanFn<0x116>,NULL,  NULL,NULL,gpuTileSpanFn<0x11A>,NULL,  NULL,NULL,gpuTileSpanFn<0x11E>,NULL,
+// Template instantiation helper macros
+#define TI(cf) gpuTileSpanFn<(cf)>
+#define TN     TileNULL
+#define TIBLOCK(ub) \
+       TI((ub)|0x00), TI((ub)|0x02), TI((ub)|0x04), TI((ub)|0x06), \
+       TN,            TI((ub)|0x0a), TN,            TI((ub)|0x0e), \
+       TN,            TI((ub)|0x12), TN,            TI((ub)|0x16), \
+       TN,            TI((ub)|0x1a), TN,            TI((ub)|0x1e)
+
+const PT gpuTileSpanDrivers[32] = {
+       TIBLOCK(0<<8), TIBLOCK(1<<8)
 };
 
+#undef TI
+#undef TN
+#undef TIBLOCK
+
+
 ///////////////////////////////////////////////////////////////////////////////
 //  GPU Sprites innerloops generator
 
-template<const int CF>
-INLINE void  gpuSpriteSpanFn(u16 *pDst, u32 count, u32 u0, const u32 mask)
+template<int CF>
+static void gpuSpriteSpanFn(u16 *pDst, u32 count, u8* pTxt, u32 u0)
 {
-       u16 uSrc;
-       u16 uDst;
-       const u16* pTxt = TBA+(u0&~0x1ff); u0=u0&0x1ff;
-       const u16 *_CBA; if(TM!=3) _CBA=CBA;
-       u32 lCol; if(L)  { lCol = ((u32)(b4<< 2)&(0x03ff)) | ((u32)(g4<<13)&(0x07ff<<10)) | ((u32)(r4<<24)&(0x07ff<<21));  }
-       u8 rgb; if (TM==1) rgb = ((u8*)pTxt)[u0>>1];
-       u32 uMsk; if ((B)&&(BM==0)) uMsk=0x7BDE;
+       // Blend func can save an operation if it knows uSrc MSB is unset.
+       //  Untextured prims can always skip (source color always comes with MSB=0).
+       //  For textured prims, the generic lighting funcs always return it unset. (bonus!)
+       const bool skip_uSrc_mask = MSB_PRESERVED ? (!CF_TEXTMODE) : (!CF_TEXTMODE) || CF_LIGHT;
+
+       uint_fast16_t uSrc, uDst, srcMSB;
+       bool should_blend;
+       u32 u0_mask = gpu_unai.TextureWindow[2];
+
+       u8 r5, g5, b5;
+       if (CF_LIGHT) {
+               r5 = gpu_unai.r5;
+               g5 = gpu_unai.g5;
+               b5 = gpu_unai.b5;
+       }
+
+       if (CF_TEXTMODE==3) {
+               // Texture is accessed byte-wise, so adjust mask if 16bpp
+               u0_mask <<= 1;
+       }
+
+       const u16 *CBA_; if (CF_TEXTMODE!=3) CBA_ = gpu_unai.CBA;
 
        do
        {
-               //  MASKING
-               if(M)   { uDst = *pDst;   if (uDst&0x8000) { u0=(u0+1)&mask; goto endsprite; }  }
+               if (CF_MASKCHECK || CF_BLEND) { uDst = *pDst; }
+               if (CF_MASKCHECK) if (uDst&0x8000) { goto endsprite; }
 
-               //  TEXTURE MAPPING
-               if (TM==1) { if (!(u0&1)) rgb = ((u8*)pTxt)[u0>>1]; uSrc = _CBA[(rgb>>((u0&1)<<2))&0xf]; u0=(u0+1)&mask; }
-               if (TM==2) { uSrc = _CBA[((u8*)pTxt)[u0]]; u0=(u0+1)&mask; }
-               if (TM==3) { uSrc = pTxt[u0]; u0=(u0+1)&mask; }
-               if(!AH) { if (!uSrc) goto endsprite; }
-
-               //  BLEND
-               if(B)
-               {
-                       if(uSrc&0x8000)
-                       {
-                               //  LIGHTING CALCULATIONS
-                               if(L)  { gpuLightingTXT(uSrc, lCol);   }
-
-                               if(!M)    { uDst = *pDst; }
-                               if (BM==0) gpuBlending00(uSrc, uDst);
-                               if (BM==1) gpuBlending01(uSrc, uDst);
-                               if (BM==2) gpuBlending02(uSrc, uDst);
-                               if (BM==3) gpuBlending03(uSrc, uDst);
-                       }
-                       else
-                       {
-                               //  LIGHTING CALCULATIONS
-                               if(L)  { gpuLightingTXT(uSrc, lCol); }
-                       }
+               if (CF_TEXTMODE==1) {  //  4bpp (CLUT)
+                       u8 rgb = pTxt[(u0 & u0_mask)>>1];
+                       uSrc = CBA_[(rgb>>((u0&1)<<2))&0xf];
                }
-               else
-               {
-                       //  LIGHTING CALCULATIONS
-                       if(L)  { gpuLightingTXT(uSrc, lCol);   } else
-                       { if(!MB) uSrc&= 0x7fff;               }
+               if (CF_TEXTMODE==2) {  //  8bpp (CLUT)
+                       uSrc = CBA_[pTxt[u0 & u0_mask]];
+               }
+               if (CF_TEXTMODE==3) {  // 16bpp
+                       uSrc = *(u16*)(&pTxt[u0 & u0_mask]);
                }
 
-               if (MB) { *pDst = uSrc | 0x8000; }
-               else    { *pDst = uSrc; }
+               if (!uSrc) goto endsprite;
+
+               //senquack - save source MSB, as blending or lighting macros will not
+               //           (Silent Hill gray rectangles mask bit bug)
+               if (CF_BLEND || CF_LIGHT) srcMSB = uSrc & 0x8000;
                
-               endsprite: pDst++;
+               if (CF_LIGHT)
+                       uSrc = gpuLightingTXT(uSrc, r5, g5, b5);
+
+               should_blend = MSB_PRESERVED ? uSrc & 0x8000 : srcMSB;
+
+               if (CF_BLEND && should_blend)
+                       uSrc = gpuBlending<CF_BLENDMODE, skip_uSrc_mask>(uSrc, uDst);
+
+               if (CF_MASKSET)                                    { *pDst = uSrc | 0x8000; }
+               else if (!MSB_PRESERVED && (CF_BLEND || CF_LIGHT)) { *pDst = uSrc | srcMSB; }
+               else                                               { *pDst = uSrc;          }
+
+endsprite:
+               u0 += (CF_TEXTMODE==3) ? 2 : 1;
+               pDst++;
        }
        while (--count);
 }
+
+static void SpriteNULL(u16 *pDst, u32 count, u8* pTxt, u32 u0)
+{
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"SpriteNULL()\n");
+       #endif
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 ///////////////////////////////////////////////////////////////////////////////
 //  Sprite innerloops driver
-typedef void (*PS)(u16 *pDst, u32 count, u32 u0, const u32 mask);
-const PS gpuSpriteSpanDrivers[512] = 
-{
-       NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
-       NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
-       gpuSpriteSpanFn<0x20>,gpuSpriteSpanFn<0x21>,gpuSpriteSpanFn<0x22>,gpuSpriteSpanFn<0x23>,  gpuSpriteSpanFn<0x24>,gpuSpriteSpanFn<0x25>,gpuSpriteSpanFn<0x26>,gpuSpriteSpanFn<0x27>,  NULL,NULL,gpuSpriteSpanFn<0x2A>,gpuSpriteSpanFn<0x2B>,  NULL,NULL,gpuSpriteSpanFn<0x2E>,gpuSpriteSpanFn<0x2F>,
-       NULL,NULL,gpuSpriteSpanFn<0x32>,gpuSpriteSpanFn<0x33>,  NULL,NULL,gpuSpriteSpanFn<0x36>,gpuSpriteSpanFn<0x37>,  NULL,NULL,gpuSpriteSpanFn<0x3A>,gpuSpriteSpanFn<0x3B>,  NULL,NULL,gpuSpriteSpanFn<0x3E>,gpuSpriteSpanFn<0x3F>,
-       gpuSpriteSpanFn<0x40>,gpuSpriteSpanFn<0x41>,gpuSpriteSpanFn<0x42>,gpuSpriteSpanFn<0x43>,  gpuSpriteSpanFn<0x44>,gpuSpriteSpanFn<0x45>,gpuSpriteSpanFn<0x46>,gpuSpriteSpanFn<0x47>,  NULL,NULL,gpuSpriteSpanFn<0x4A>,gpuSpriteSpanFn<0x4B>,  NULL,NULL,gpuSpriteSpanFn<0x4E>,gpuSpriteSpanFn<0x4F>,
-       NULL,NULL,gpuSpriteSpanFn<0x52>,gpuSpriteSpanFn<0x53>,  NULL,NULL,gpuSpriteSpanFn<0x56>,gpuSpriteSpanFn<0x57>,  NULL,NULL,gpuSpriteSpanFn<0x5A>,gpuSpriteSpanFn<0x5B>,  NULL,NULL,gpuSpriteSpanFn<0x5E>,gpuSpriteSpanFn<0x5F>,
-       gpuSpriteSpanFn<0x60>,gpuSpriteSpanFn<0x61>,gpuSpriteSpanFn<0x62>,gpuSpriteSpanFn<0x63>,  gpuSpriteSpanFn<0x64>,gpuSpriteSpanFn<0x65>,gpuSpriteSpanFn<0x66>,gpuSpriteSpanFn<0x67>,  NULL,NULL,gpuSpriteSpanFn<0x6A>,gpuSpriteSpanFn<0x6B>,  NULL,NULL,gpuSpriteSpanFn<0x6E>,gpuSpriteSpanFn<0x6F>,
-       NULL,NULL,gpuSpriteSpanFn<0x72>,gpuSpriteSpanFn<0x73>,  NULL,NULL,gpuSpriteSpanFn<0x76>,gpuSpriteSpanFn<0x77>,  NULL,NULL,gpuSpriteSpanFn<0x7A>,gpuSpriteSpanFn<0x7B>,  NULL,NULL,gpuSpriteSpanFn<0x7E>,gpuSpriteSpanFn<0x7F>,
-
-       NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
-       NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
-       gpuSpriteSpanFn<0xa0>,gpuSpriteSpanFn<0xa1>,gpuSpriteSpanFn<0xa2>,gpuSpriteSpanFn<0xa3>,  gpuSpriteSpanFn<0xa4>,gpuSpriteSpanFn<0xa5>,gpuSpriteSpanFn<0xa6>,gpuSpriteSpanFn<0xa7>,  NULL,NULL,gpuSpriteSpanFn<0xaA>,gpuSpriteSpanFn<0xaB>,  NULL,NULL,gpuSpriteSpanFn<0xaE>,gpuSpriteSpanFn<0xaF>,
-       NULL,NULL,gpuSpriteSpanFn<0xb2>,gpuSpriteSpanFn<0xb3>,  NULL,NULL,gpuSpriteSpanFn<0xb6>,gpuSpriteSpanFn<0xb7>,  NULL,NULL,gpuSpriteSpanFn<0xbA>,gpuSpriteSpanFn<0xbB>,  NULL,NULL,gpuSpriteSpanFn<0xbE>,gpuSpriteSpanFn<0xbF>,
-       gpuSpriteSpanFn<0xc0>,gpuSpriteSpanFn<0xc1>,gpuSpriteSpanFn<0xc2>,gpuSpriteSpanFn<0xc3>,  gpuSpriteSpanFn<0xc4>,gpuSpriteSpanFn<0xc5>,gpuSpriteSpanFn<0xc6>,gpuSpriteSpanFn<0xc7>,  NULL,NULL,gpuSpriteSpanFn<0xcA>,gpuSpriteSpanFn<0xcB>,  NULL,NULL,gpuSpriteSpanFn<0xcE>,gpuSpriteSpanFn<0xcF>,
-       NULL,NULL,gpuSpriteSpanFn<0xd2>,gpuSpriteSpanFn<0xd3>,  NULL,NULL,gpuSpriteSpanFn<0xd6>,gpuSpriteSpanFn<0xd7>,  NULL,NULL,gpuSpriteSpanFn<0xdA>,gpuSpriteSpanFn<0xdB>,  NULL,NULL,gpuSpriteSpanFn<0xdE>,gpuSpriteSpanFn<0xdF>,
-       gpuSpriteSpanFn<0xe0>,gpuSpriteSpanFn<0xe1>,gpuSpriteSpanFn<0xe2>,gpuSpriteSpanFn<0xe3>,  gpuSpriteSpanFn<0xe4>,gpuSpriteSpanFn<0xe5>,gpuSpriteSpanFn<0xe6>,gpuSpriteSpanFn<0xe7>,  NULL,NULL,gpuSpriteSpanFn<0xeA>,gpuSpriteSpanFn<0xeB>,  NULL,NULL,gpuSpriteSpanFn<0xeE>,gpuSpriteSpanFn<0xeF>,
-       NULL,NULL,gpuSpriteSpanFn<0xf2>,gpuSpriteSpanFn<0xf3>,  NULL,NULL,gpuSpriteSpanFn<0xf6>,gpuSpriteSpanFn<0xf7>,  NULL,NULL,gpuSpriteSpanFn<0xfA>,gpuSpriteSpanFn<0xfB>,  NULL,NULL,gpuSpriteSpanFn<0xfE>,gpuSpriteSpanFn<0xfF>,
-
-       NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
-       NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
-       gpuSpriteSpanFn<0x120>,gpuSpriteSpanFn<0x121>,gpuSpriteSpanFn<0x122>,gpuSpriteSpanFn<0x123>,  gpuSpriteSpanFn<0x124>,gpuSpriteSpanFn<0x125>,gpuSpriteSpanFn<0x126>,gpuSpriteSpanFn<0x127>,  NULL,NULL,gpuSpriteSpanFn<0x12A>,gpuSpriteSpanFn<0x12B>,  NULL,NULL,gpuSpriteSpanFn<0x12E>,gpuSpriteSpanFn<0x12F>,
-       NULL,NULL,gpuSpriteSpanFn<0x132>,gpuSpriteSpanFn<0x133>,  NULL,NULL,gpuSpriteSpanFn<0x136>,gpuSpriteSpanFn<0x137>,  NULL,NULL,gpuSpriteSpanFn<0x13A>,gpuSpriteSpanFn<0x13B>,  NULL,NULL,gpuSpriteSpanFn<0x13E>,gpuSpriteSpanFn<0x13F>,
-       gpuSpriteSpanFn<0x140>,gpuSpriteSpanFn<0x141>,gpuSpriteSpanFn<0x142>,gpuSpriteSpanFn<0x143>,  gpuSpriteSpanFn<0x144>,gpuSpriteSpanFn<0x145>,gpuSpriteSpanFn<0x146>,gpuSpriteSpanFn<0x147>,  NULL,NULL,gpuSpriteSpanFn<0x14A>,gpuSpriteSpanFn<0x14B>,  NULL,NULL,gpuSpriteSpanFn<0x14E>,gpuSpriteSpanFn<0x14F>,
-       NULL,NULL,gpuSpriteSpanFn<0x152>,gpuSpriteSpanFn<0x153>,  NULL,NULL,gpuSpriteSpanFn<0x156>,gpuSpriteSpanFn<0x157>,  NULL,NULL,gpuSpriteSpanFn<0x15A>,gpuSpriteSpanFn<0x15B>,  NULL,NULL,gpuSpriteSpanFn<0x15E>,gpuSpriteSpanFn<0x15F>,
-       gpuSpriteSpanFn<0x160>,gpuSpriteSpanFn<0x161>,gpuSpriteSpanFn<0x162>,gpuSpriteSpanFn<0x163>,  gpuSpriteSpanFn<0x164>,gpuSpriteSpanFn<0x165>,gpuSpriteSpanFn<0x166>,gpuSpriteSpanFn<0x167>,  NULL,NULL,gpuSpriteSpanFn<0x16A>,gpuSpriteSpanFn<0x16B>,  NULL,NULL,gpuSpriteSpanFn<0x16E>,gpuSpriteSpanFn<0x16F>,
-       NULL,NULL,gpuSpriteSpanFn<0x172>,gpuSpriteSpanFn<0x173>,  NULL,NULL,gpuSpriteSpanFn<0x176>,gpuSpriteSpanFn<0x177>,  NULL,NULL,gpuSpriteSpanFn<0x17A>,gpuSpriteSpanFn<0x17B>,  NULL,NULL,gpuSpriteSpanFn<0x17E>,gpuSpriteSpanFn<0x17F>,
-                                                                                                                                                                                                                                                                                                                                                                                      
-       NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
-       NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
-       gpuSpriteSpanFn<0x1a0>,gpuSpriteSpanFn<0x1a1>,gpuSpriteSpanFn<0x1a2>,gpuSpriteSpanFn<0x1a3>,  gpuSpriteSpanFn<0x1a4>,gpuSpriteSpanFn<0x1a5>,gpuSpriteSpanFn<0x1a6>,gpuSpriteSpanFn<0x1a7>,  NULL,NULL,gpuSpriteSpanFn<0x1aA>,gpuSpriteSpanFn<0x1aB>,  NULL,NULL,gpuSpriteSpanFn<0x1aE>,gpuSpriteSpanFn<0x1aF>,
-       NULL,NULL,gpuSpriteSpanFn<0x1b2>,gpuSpriteSpanFn<0x1b3>,  NULL,NULL,gpuSpriteSpanFn<0x1b6>,gpuSpriteSpanFn<0x1b7>,  NULL,NULL,gpuSpriteSpanFn<0x1bA>,gpuSpriteSpanFn<0x1bB>,  NULL,NULL,gpuSpriteSpanFn<0x1bE>,gpuSpriteSpanFn<0x1bF>,
-       gpuSpriteSpanFn<0x1c0>,gpuSpriteSpanFn<0x1c1>,gpuSpriteSpanFn<0x1c2>,gpuSpriteSpanFn<0x1c3>,  gpuSpriteSpanFn<0x1c4>,gpuSpriteSpanFn<0x1c5>,gpuSpriteSpanFn<0x1c6>,gpuSpriteSpanFn<0x1c7>,  NULL,NULL,gpuSpriteSpanFn<0x1cA>,gpuSpriteSpanFn<0x1cB>,  NULL,NULL,gpuSpriteSpanFn<0x1cE>,gpuSpriteSpanFn<0x1cF>,
-       NULL,NULL,gpuSpriteSpanFn<0x1d2>,gpuSpriteSpanFn<0x1d3>,  NULL,NULL,gpuSpriteSpanFn<0x1d6>,gpuSpriteSpanFn<0x1d7>,  NULL,NULL,gpuSpriteSpanFn<0x1dA>,gpuSpriteSpanFn<0x1dB>,  NULL,NULL,gpuSpriteSpanFn<0x1dE>,gpuSpriteSpanFn<0x1dF>,
-       gpuSpriteSpanFn<0x1e0>,gpuSpriteSpanFn<0x1e1>,gpuSpriteSpanFn<0x1e2>,gpuSpriteSpanFn<0x1e3>,  gpuSpriteSpanFn<0x1e4>,gpuSpriteSpanFn<0x1e5>,gpuSpriteSpanFn<0x1e6>,gpuSpriteSpanFn<0x1e7>,  NULL,NULL,gpuSpriteSpanFn<0x1eA>,gpuSpriteSpanFn<0x1eB>,  NULL,NULL,gpuSpriteSpanFn<0x1eE>,gpuSpriteSpanFn<0x1eF>,
-       NULL,NULL,gpuSpriteSpanFn<0x1f2>,gpuSpriteSpanFn<0x1f3>,  NULL,NULL,gpuSpriteSpanFn<0x1f6>,gpuSpriteSpanFn<0x1f7>,  NULL,NULL,gpuSpriteSpanFn<0x1fA>,gpuSpriteSpanFn<0x1fB>,  NULL,NULL,gpuSpriteSpanFn<0x1fE>,gpuSpriteSpanFn<0x1fF>
+typedef void (*PS)(u16 *pDst, u32 count, u8* pTxt, u32 u0);
+
+// Template instantiation helper macros
+#define TI(cf) gpuSpriteSpanFn<(cf)>
+#define TN     SpriteNULL
+#define TIBLOCK(ub) \
+       TN,            TN,            TN,            TN,            TN,            TN,            TN,            TN,            \
+       TN,            TN,            TN,            TN,            TN,            TN,            TN,            TN,            \
+       TN,            TN,            TN,            TN,            TN,            TN,            TN,            TN,            \
+       TN,            TN,            TN,            TN,            TN,            TN,            TN,            TN,            \
+       TI((ub)|0x20), TI((ub)|0x21), TI((ub)|0x22), TI((ub)|0x23), TI((ub)|0x24), TI((ub)|0x25), TI((ub)|0x26), TI((ub)|0x27), \
+       TN,            TN,            TI((ub)|0x2a), TI((ub)|0x2b), TN,            TN,            TI((ub)|0x2e), TI((ub)|0x2f), \
+       TN,            TN,            TI((ub)|0x32), TI((ub)|0x33), TN,            TN,            TI((ub)|0x36), TI((ub)|0x37), \
+       TN,            TN,            TI((ub)|0x3a), TI((ub)|0x3b), TN,            TN,            TI((ub)|0x3e), TI((ub)|0x3f), \
+       TI((ub)|0x40), TI((ub)|0x41), TI((ub)|0x42), TI((ub)|0x43), TI((ub)|0x44), TI((ub)|0x45), TI((ub)|0x46), TI((ub)|0x47), \
+       TN,            TN,            TI((ub)|0x4a), TI((ub)|0x4b), TN,            TN,            TI((ub)|0x4e), TI((ub)|0x4f), \
+       TN,            TN,            TI((ub)|0x52), TI((ub)|0x53), TN,            TN,            TI((ub)|0x56), TI((ub)|0x57), \
+       TN,            TN,            TI((ub)|0x5a), TI((ub)|0x5b), TN,            TN,            TI((ub)|0x5e), TI((ub)|0x5f), \
+       TI((ub)|0x60), TI((ub)|0x61), TI((ub)|0x62), TI((ub)|0x63), TI((ub)|0x64), TI((ub)|0x65), TI((ub)|0x66), TI((ub)|0x67), \
+       TN,            TN,            TI((ub)|0x6a), TI((ub)|0x6b), TN,            TN,            TI((ub)|0x6e), TI((ub)|0x6f), \
+       TN,            TN,            TI((ub)|0x72), TI((ub)|0x73), TN,            TN,            TI((ub)|0x76), TI((ub)|0x77), \
+       TN,            TN,            TI((ub)|0x7a), TI((ub)|0x7b), TN,            TN,            TI((ub)|0x7e), TI((ub)|0x7f)
+
+const PS gpuSpriteSpanDrivers[256] = {
+       TIBLOCK(0<<8), TIBLOCK(1<<8)
 };
 
+#undef TI
+#undef TN
+#undef TIBLOCK
+
 ///////////////////////////////////////////////////////////////////////////////
 //  GPU Polygon innerloops generator
-template<const int CF>
-INLINE void  gpuPolySpanFn(u16 *pDst, u32 count)
+
+//senquack - Newer version with following changes:
+//           * Adapted to work with new poly routings in gpu_raster_polygon.h
+//             adapted from DrHell GPU. They are less glitchy and use 22.10
+//             fixed-point instead of original UNAI's 16.16.
+//           * Texture coordinates are no longer packed together into one
+//             unsigned int. This seems to lose too much accuracy (they each
+//             end up being only 8.7 fixed-point that way) and pixel-droupouts
+//             were noticeable both with original code and current DrHell
+//             adaptations. An example would be the sky in NFS3. Now, they are
+//             stored in separate ints, using separate masks.
+//           * Function is no longer INLINE, as it was always called
+//             through a function pointer.
+//           * Function now ensures the mask bit of source texture is preserved
+//             across calls to blending functions (Silent Hill rectangles fix)
+//           * November 2016: Large refactoring of blending/lighting when
+//             JohnnyF added dithering. See gpu_inner_quantization.h and
+//             relevant blend/light headers.
+// (see README_senquack.txt)
+template<int CF>
+static void gpuPolySpanFn(const gpu_unai_t &gpu_unai, u16 *pDst, u32 count)
 {
-       if (!TM)
-       {       
-               // NO TEXTURE
-               if (!G)
+       // Blend func can save an operation if it knows uSrc MSB is unset.
+       //  Untextured prims can always skip this (src color MSB is always 0).
+       //  For textured prims, the generic lighting funcs always return it unset. (bonus!)
+       const bool skip_uSrc_mask = MSB_PRESERVED ? (!CF_TEXTMODE) : (!CF_TEXTMODE) || CF_LIGHT;
+       bool should_blend;
+
+       u32 bMsk; if (CF_BLITMASK) bMsk = gpu_unai.blit_mask;
+
+       if (!CF_TEXTMODE)
+       {
+               if (!CF_GOURAUD)
                {
-                       // NO GOURAUD
-                       u16 data;
-                       if (L) { u32 lCol=((u32)(b4<< 2)&(0x03ff)) | ((u32)(g4<<13)&(0x07ff<<10)) | ((u32)(r4<<24)&(0x07ff<<21)); gpuLightingRGB(data,lCol); }
-                       else data=PixelData;
-                       if ((!M)&&(!B))
-                       {
-                               if (MB) { data = data | 0x8000; }
-                               do { *pDst++ = data; } while (--count);
-                       }
-                       else if ((M)&&(!B))
-                       {
-                               if (MB) { data = data | 0x8000; }
-                               do { if (!(*pDst&0x8000)) { *pDst = data; } pDst++; } while (--count);
-                       }
-                       else
-                       {
-                               u16 uSrc;
-                               u16 uDst;
-                               u32 uMsk; if (BM==0) uMsk=0x7BDE;
-                               do
-                               {
-                                       //  masking
-                                       uDst = *pDst;
-                                       if(M) { if (uDst&0x8000) goto endtile;  }
-                                       uSrc = data;
-                                       //  blend
-                                       if (BM==0) gpuBlending00(uSrc, uDst);
-                                       if (BM==1) gpuBlending01(uSrc, uDst);
-                                       if (BM==2) gpuBlending02(uSrc, uDst);
-                                       if (BM==3) gpuBlending03(uSrc, uDst);
-                                       if (MB) { *pDst = uSrc | 0x8000; }
-                                       else    { *pDst = uSrc; }
-                                       endtile: pDst++;
-                               }
-                               while (--count);
-                       }
+                       // UNTEXTURED, NO GOURAUD
+                       const u16 pix15 = gpu_unai.PixelData;
+                       do {
+                               uint_fast16_t uSrc, uDst;
+
+                               // NOTE: Don't enable CF_BLITMASK  pixel skipping (speed hack)
+                               //  on untextured polys. It seems to do more harm than good: see
+                               //  gravestone text at end of Medieval intro sequence. -senquack
+                               //if (CF_BLITMASK) { if ((bMsk>>((((uintptr_t)pDst)>>1)&7))&1) { goto endpolynotextnogou; } }
+
+                               if (CF_BLEND || CF_MASKCHECK) uDst = *pDst;
+                               if (CF_MASKCHECK) { if (uDst&0x8000) { goto endpolynotextnogou; } }
+
+                               uSrc = pix15;
+
+                               if (CF_BLEND)
+                                       uSrc = gpuBlending<CF_BLENDMODE, skip_uSrc_mask>(uSrc, uDst);
+
+                               if (CF_MASKSET) { *pDst = uSrc | 0x8000; }
+                               else            { *pDst = uSrc;          }
+
+endpolynotextnogou:
+                               pDst++;
+                       } while(--count);
                }
                else
                {
-                       // GOURAUD
-                       u16 uDst;
-                       u16 uSrc;
-                       u32 linc=lInc;
-                       u32 lCol=((u32)(b4>>14)&(0x03ff)) | ((u32)(g4>>3)&(0x07ff<<10)) | ((u32)(r4<<8)&(0x07ff<<21));
-                       u32 uMsk; if ((B)&&(BM==0)) uMsk=0x7BDE;
-                       do
-                       {
-                               //  masking
-                               if(M) { uDst = *pDst;  if (uDst&0x8000) goto endgou;  }
-                               //  blend
-                               if(B)
-                               {
-                                       //  light
-                                       gpuLightingRGB(uSrc,lCol);
-                                       if(!M)    { uDst = *pDst; }
-                                       if (BM==0) gpuBlending00(uSrc, uDst);
-                                       if (BM==1) gpuBlending01(uSrc, uDst);
-                                       if (BM==2) gpuBlending02(uSrc, uDst);
-                                       if (BM==3) gpuBlending03(uSrc, uDst);
-                               }
-                               else
-                               {
-                                       //  light
-                                       gpuLightingRGB(uSrc,lCol);
+                       // UNTEXTURED, GOURAUD
+                       u32 l_gCol = gpu_unai.gCol;
+                       u32 l_gInc = gpu_unai.gInc;
+
+                       do {
+                               uint_fast16_t uDst, uSrc;
+
+                               // See note in above loop regarding CF_BLITMASK
+                               //if (CF_BLITMASK) { if ((bMsk>>((((uintptr_t)pDst)>>1)&7))&1) goto endpolynotextgou; }
+
+                               if (CF_BLEND || CF_MASKCHECK) uDst = *pDst;
+                               if (CF_MASKCHECK) { if (uDst&0x8000) goto endpolynotextgou; }
+
+                               if (CF_DITHER) {
+                                       // GOURAUD, DITHER
+
+                                       u32 uSrc24 = gpuLightingRGB24(l_gCol);
+                                       if (CF_BLEND)
+                                               uSrc24 = gpuBlending24<CF_BLENDMODE>(uSrc24, uDst);
+                                       uSrc = gpuColorQuantization24<CF_DITHER>(uSrc24, pDst);
+                               } else {
+                                       // GOURAUD, NO DITHER
+
+                                       uSrc = gpuLightingRGB(l_gCol);
+
+                                       if (CF_BLEND)
+                                               uSrc = gpuBlending<CF_BLENDMODE, skip_uSrc_mask>(uSrc, uDst);
                                }
-                               if (MB) { *pDst = uSrc | 0x8000; }
-                               else    { *pDst = uSrc; }
-                               endgou: pDst++; lCol=(lCol+linc);
+
+                               if (CF_MASKSET) { *pDst = uSrc | 0x8000; }
+                               else            { *pDst = uSrc;          }
+
+endpolynotextgou:
+                               pDst++;
+                               l_gCol += l_gInc;
                        }
                        while (--count);
                }
        }
        else
        {
-               // TEXTURE
-               u16 uDst;
-               u16 uSrc;
-               u32 linc; if (L&&G) linc=lInc;
-               u32 tinc=tInc;
-               u32 tmsk=tMsk;
-               u32 tCor = ((u32)( u4<<7)&0x7fff0000) | ((u32)( v4>>9)&0x00007fff); tCor&= tmsk;
-               const u16* _TBA=TBA;
-               const u16* _CBA; if (TM!=3) _CBA=CBA;
-               u32 lCol;
-               if(L && !G) { lCol = ((u32)(b4<< 2)&(0x03ff)) | ((u32)(g4<<13)&(0x07ff<<10)) | ((u32)(r4<<24)&(0x07ff<<21)); }
-               else if(L && G) { lCol = ((u32)(b4>>14)&(0x03ff)) | ((u32)(g4>>3)&(0x07ff<<10)) | ((u32)(r4<<8)&(0x07ff<<21));  }
-               u32 uMsk; if ((B)&&(BM==0)) uMsk=0x7BDE;
+               // TEXTURED
+
+               uint_fast16_t uDst, uSrc, srcMSB;
+
+               //senquack - note: original UNAI code had gpu_unai.{u4/v4} packed into
+               // one 32-bit unsigned int, but this proved to lose too much accuracy
+               // (pixel drouputs noticeable in NFS3 sky), so now are separate vars.
+               u32 l_u_msk = gpu_unai.u_msk;     u32 l_v_msk = gpu_unai.v_msk;
+               u32 l_u = gpu_unai.u & l_u_msk;   u32 l_v = gpu_unai.v & l_v_msk;
+               s32 l_u_inc = gpu_unai.u_inc;     s32 l_v_inc = gpu_unai.v_inc;
+
+               const u16* TBA_ = gpu_unai.TBA;
+               const u16* CBA_; if (CF_TEXTMODE!=3) CBA_ = gpu_unai.CBA;
+
+               u8 r5, g5, b5;
+               u8 r8, g8, b8;
+
+               u32 l_gInc, l_gCol;
+
+               if (CF_LIGHT) {
+                       if (CF_GOURAUD) {
+                               l_gInc = gpu_unai.gInc;
+                               l_gCol = gpu_unai.gCol;
+                       } else {
+                               if (CF_DITHER) {
+                                       r8 = gpu_unai.r8;
+                                       g8 = gpu_unai.g8;
+                                       b8 = gpu_unai.b8;
+                               } else {
+                                       r5 = gpu_unai.r5;
+                                       g5 = gpu_unai.g5;
+                                       b5 = gpu_unai.b5;
+                               }
+                       }
+               }
+
                do
                {
-                       //  masking
-                       if(M) { uDst = *pDst;  if (uDst&0x8000) goto endpoly;  }
-                       //  texture
-                       if (TM==1) { u32 tu=(tCor>>23); u32 tv=(tCor<<4)&(0xff<<11); u8 rgb=((u8*)_TBA)[tv+(tu>>1)]; uSrc=_CBA[(rgb>>((tu&1)<<2))&0xf]; if(!uSrc) goto endpoly; }
-                       if (TM==2) { uSrc = _CBA[(((u8*)_TBA)[(tCor>>23)+((tCor<<4)&(0xff<<11))])]; if(!uSrc)  goto endpoly; }
-                       if (TM==3) { uSrc = _TBA[(tCor>>23)+((tCor<<3)&(0xff<<10))]; if(!uSrc)  goto endpoly; }
-                       //  blend
-                       if(B)
-                       {
-                               if (uSrc&0x8000)
-                               {
-                                       //  light
-                                       if(L) gpuLightingTXT(uSrc, lCol);
-                                       if(!M)    { uDst = *pDst; }
-                                       if (BM==0) gpuBlending00(uSrc, uDst);
-                                       if (BM==1) gpuBlending01(uSrc, uDst);
-                                       if (BM==2) gpuBlending02(uSrc, uDst);
-                                       if (BM==3) gpuBlending03(uSrc, uDst);
-                               }
-                               else
-                               {
-                                       // light
-                                       if(L) gpuLightingTXT(uSrc, lCol);
-                               }
+                       if (CF_BLITMASK) { if ((bMsk>>((((uintptr_t)pDst)>>1)&7))&1) goto endpolytext; }
+                       if (CF_MASKCHECK || CF_BLEND) { uDst = *pDst; }
+                       if (CF_MASKCHECK) if (uDst&0x8000) { goto endpolytext; }
+
+                       //senquack - adapted to work with new 22.10 fixed point routines:
+                       //           (UNAI originally used 16.16)
+                       if (CF_TEXTMODE==1) {  //  4bpp (CLUT)
+                               u32 tu=(l_u>>10);
+                               u32 tv=(l_v<<1)&(0xff<<11);
+                               u8 rgb=((u8*)TBA_)[tv+(tu>>1)];
+                               uSrc=CBA_[(rgb>>((tu&1)<<2))&0xf];
+                               if (!uSrc) goto endpolytext;
+                       }
+                       if (CF_TEXTMODE==2) {  //  8bpp (CLUT)
+                               uSrc = CBA_[(((u8*)TBA_)[(l_u>>10)+((l_v<<1)&(0xff<<11))])];
+                               if (!uSrc) goto endpolytext;
+                       }
+                       if (CF_TEXTMODE==3) {  // 16bpp
+                               uSrc = TBA_[(l_u>>10)+((l_v)&(0xff<<10))];
+                               if (!uSrc) goto endpolytext;
                        }
-                       else
+
+                       // Save source MSB, as blending or lighting will not (Silent Hill)
+                       if (CF_BLEND || CF_LIGHT) srcMSB = uSrc & 0x8000;
+
+                       // When textured, only dither when LIGHT (texture blend) is enabled
+                       // LIGHT &&  BLEND => dither
+                       // LIGHT && !BLEND => dither
+                       //!LIGHT &&  BLEND => no dither
+                       //!LIGHT && !BLEND => no dither
+
+                       if (CF_DITHER && CF_LIGHT) {
+                               u32 uSrc24;
+                               if ( CF_GOURAUD)
+                                       uSrc24 = gpuLightingTXT24Gouraud(uSrc, l_gCol);
+                               if (!CF_GOURAUD)
+                                       uSrc24 = gpuLightingTXT24(uSrc, r8, g8, b8);
+
+                               if (CF_BLEND && srcMSB)
+                                       uSrc24 = gpuBlending24<CF_BLENDMODE>(uSrc24, uDst);
+
+                               uSrc = gpuColorQuantization24<CF_DITHER>(uSrc24, pDst);
+                       } else
                        {
-                               //  light
-                               if(L)  { gpuLightingTXT(uSrc, lCol); } else if(!MB) { uSrc&= 0x7fff; }
+                               if (CF_LIGHT) {
+                                       if ( CF_GOURAUD)
+                                               uSrc = gpuLightingTXTGouraud(uSrc, l_gCol);
+                                       if (!CF_GOURAUD)
+                                               uSrc = gpuLightingTXT(uSrc, r5, g5, b5);
+                               }
+
+                               should_blend = MSB_PRESERVED ? uSrc & 0x8000 : srcMSB;
+                               if (CF_BLEND && should_blend)
+                                       uSrc = gpuBlending<CF_BLENDMODE, skip_uSrc_mask>(uSrc, uDst);
                        }
-                       if (MB) { *pDst = uSrc | 0x8000; }
-                       else    { *pDst = uSrc; }
-                       endpoly: pDst++;
-                       tCor=(tCor+tinc)&tmsk;
-                       if (L&&G) lCol=(lCol+linc);
+
+                       if (CF_MASKSET)                                    { *pDst = uSrc | 0x8000; }
+                       else if (!MSB_PRESERVED && (CF_BLEND || CF_LIGHT)) { *pDst = uSrc | srcMSB; }
+                       else                                               { *pDst = uSrc;          }
+endpolytext:
+                       pDst++;
+                       l_u = (l_u + l_u_inc) & l_u_msk;
+                       l_v = (l_v + l_v_inc) & l_v_msk;
+                       if (CF_LIGHT && CF_GOURAUD) l_gCol += l_gInc;
                }
                while (--count);
        }
 }
 
-// supposedly shouldn't be called?
-static void gpuPolySpanFn_NULL_(u16 *pDst, u32 count)
+static void PolyNULL(const gpu_unai_t &gpu_unai, u16 *pDst, u32 count)
 {
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"PolyNULL()\n");
+       #endif
 }
 
-///////////////////////////////////////////////////////////////////////////////
-
 ///////////////////////////////////////////////////////////////////////////////
 //  Polygon innerloops driver
-typedef void (*PP)(u16 *pDst, u32 count);
-const PP gpuPolySpanDrivers[512] =
-{
-       gpuPolySpanFn<0x00>,gpuPolySpanFn<0x01>,gpuPolySpanFn<0x02>,gpuPolySpanFn<0x03>,  gpuPolySpanFn<0x04>,gpuPolySpanFn<0x05>,gpuPolySpanFn<0x06>,gpuPolySpanFn<0x07>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x0A>,gpuPolySpanFn<0x0B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x0E>,gpuPolySpanFn<0x0F>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x12>,gpuPolySpanFn<0x13>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x16>,gpuPolySpanFn<0x17>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1A>,gpuPolySpanFn<0x1B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1E>,gpuPolySpanFn<0x1F>,
-       gpuPolySpanFn<0x20>,gpuPolySpanFn<0x21>,gpuPolySpanFn<0x22>,gpuPolySpanFn<0x23>,  gpuPolySpanFn<0x24>,gpuPolySpanFn<0x25>,gpuPolySpanFn<0x26>,gpuPolySpanFn<0x27>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x2A>,gpuPolySpanFn<0x2B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x2E>,gpuPolySpanFn<0x2F>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x32>,gpuPolySpanFn<0x33>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x36>,gpuPolySpanFn<0x37>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x3A>,gpuPolySpanFn<0x3B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x3E>,gpuPolySpanFn<0x3F>,
-       gpuPolySpanFn<0x40>,gpuPolySpanFn<0x41>,gpuPolySpanFn<0x42>,gpuPolySpanFn<0x43>,  gpuPolySpanFn<0x44>,gpuPolySpanFn<0x45>,gpuPolySpanFn<0x46>,gpuPolySpanFn<0x47>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x4A>,gpuPolySpanFn<0x4B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x4E>,gpuPolySpanFn<0x4F>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x52>,gpuPolySpanFn<0x53>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x56>,gpuPolySpanFn<0x57>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x5A>,gpuPolySpanFn<0x5B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x5E>,gpuPolySpanFn<0x5F>,
-       gpuPolySpanFn<0x60>,gpuPolySpanFn<0x61>,gpuPolySpanFn<0x62>,gpuPolySpanFn<0x63>,  gpuPolySpanFn<0x64>,gpuPolySpanFn<0x65>,gpuPolySpanFn<0x66>,gpuPolySpanFn<0x67>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x6A>,gpuPolySpanFn<0x6B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x6E>,gpuPolySpanFn<0x6F>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x72>,gpuPolySpanFn<0x73>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x76>,gpuPolySpanFn<0x77>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x7A>,gpuPolySpanFn<0x7B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x7E>,gpuPolySpanFn<0x7F>,
-
-       gpuPolySpanFn_NULL_,gpuPolySpanFn<0x81>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x83>,  gpuPolySpanFn_NULL_,gpuPolySpanFn<0x85>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x87>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x8B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x8F>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x93>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x97>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x9B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x9F>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn<0xa1>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xa3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn<0xa5>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xa7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xaB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xaF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xb3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xb7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xbB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xbF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn<0xc1>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xc3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn<0xc5>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xc7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xcB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xcF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xd3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xd7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xdB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xdF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn<0xe1>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xe3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn<0xe5>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xe7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xeB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xeF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xf3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xf7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xfB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0xfF>,
-
-       gpuPolySpanFn<0x100>,gpuPolySpanFn<0x101>,gpuPolySpanFn<0x102>,gpuPolySpanFn<0x103>,  gpuPolySpanFn<0x104>,gpuPolySpanFn<0x105>,gpuPolySpanFn<0x106>,gpuPolySpanFn<0x107>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x10A>,gpuPolySpanFn<0x10B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x10E>,gpuPolySpanFn<0x10F>,
-       gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_, gpuPolySpanFn<0x112>,gpuPolySpanFn<0x113>,  gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_, gpuPolySpanFn<0x116>,gpuPolySpanFn<0x117>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x11A>,gpuPolySpanFn<0x11B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x11E>,gpuPolySpanFn<0x11F>,
-       gpuPolySpanFn<0x120>,gpuPolySpanFn<0x121>,gpuPolySpanFn<0x122>,gpuPolySpanFn<0x123>,  gpuPolySpanFn<0x124>,gpuPolySpanFn<0x125>,gpuPolySpanFn<0x126>,gpuPolySpanFn<0x127>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x12A>,gpuPolySpanFn<0x12B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x12E>,gpuPolySpanFn<0x12F>,
-       gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_, gpuPolySpanFn<0x132>,gpuPolySpanFn<0x133>,  gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_, gpuPolySpanFn<0x136>,gpuPolySpanFn<0x137>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x13A>,gpuPolySpanFn<0x13B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x13E>,gpuPolySpanFn<0x13F>,
-       gpuPolySpanFn<0x140>,gpuPolySpanFn<0x141>,gpuPolySpanFn<0x142>,gpuPolySpanFn<0x143>,  gpuPolySpanFn<0x144>,gpuPolySpanFn<0x145>,gpuPolySpanFn<0x146>,gpuPolySpanFn<0x147>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x14A>,gpuPolySpanFn<0x14B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x14E>,gpuPolySpanFn<0x14F>,
-       gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_, gpuPolySpanFn<0x152>,gpuPolySpanFn<0x153>,  gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_, gpuPolySpanFn<0x156>,gpuPolySpanFn<0x157>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x15A>,gpuPolySpanFn<0x15B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x15E>,gpuPolySpanFn<0x15F>,
-       gpuPolySpanFn<0x160>,gpuPolySpanFn<0x161>,gpuPolySpanFn<0x162>,gpuPolySpanFn<0x163>,  gpuPolySpanFn<0x164>,gpuPolySpanFn<0x165>,gpuPolySpanFn<0x166>,gpuPolySpanFn<0x167>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x16A>,gpuPolySpanFn<0x16B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x16E>,gpuPolySpanFn<0x16F>,
-       gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_, gpuPolySpanFn<0x172>,gpuPolySpanFn<0x173>,  gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_, gpuPolySpanFn<0x176>,gpuPolySpanFn<0x177>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x17A>,gpuPolySpanFn<0x17B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x17E>,gpuPolySpanFn<0x17F>,
-                                                                                                                                                                                                                                                                                                                                                                                      
-       gpuPolySpanFn_NULL_,gpuPolySpanFn<0x181>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x183>,  gpuPolySpanFn_NULL_,gpuPolySpanFn<0x185>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x187>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x18B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x18F>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_,gpuPolySpanFn<0x193>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_,gpuPolySpanFn<0x197>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x19B>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x19F>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1a1>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1a3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1a5>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1a7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1aB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1aF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1b3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1b7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1bB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1bF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1c1>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1c3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1c5>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1c7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1cB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1cF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1d3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1d7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1dB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1dF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1e1>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1e3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1e5>,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1e7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1eB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1eF>,
-       gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1f3>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_, gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1f7>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1fB>,  gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn_NULL_,gpuPolySpanFn<0x1fF>
+typedef void (*PP)(const gpu_unai_t &gpu_unai, u16 *pDst, u32 count);
+
+// Template instantiation helper macros
+#define TI(cf) gpuPolySpanFn<(cf)>
+#define TN     PolyNULL
+#define TIBLOCK(ub) \
+       TI((ub)|0x00), TI((ub)|0x01), TI((ub)|0x02), TI((ub)|0x03), TI((ub)|0x04), TI((ub)|0x05), TI((ub)|0x06), TI((ub)|0x07), \
+       TN,            TN,            TI((ub)|0x0a), TI((ub)|0x0b), TN,            TN,            TI((ub)|0x0e), TI((ub)|0x0f), \
+       TN,            TN,            TI((ub)|0x12), TI((ub)|0x13), TN,            TN,            TI((ub)|0x16), TI((ub)|0x17), \
+       TN,            TN,            TI((ub)|0x1a), TI((ub)|0x1b), TN,            TN,            TI((ub)|0x1e), TI((ub)|0x1f), \
+       TI((ub)|0x20), TI((ub)|0x21), TI((ub)|0x22), TI((ub)|0x23), TI((ub)|0x24), TI((ub)|0x25), TI((ub)|0x26), TI((ub)|0x27), \
+       TN,            TN,            TI((ub)|0x2a), TI((ub)|0x2b), TN,            TN,            TI((ub)|0x2e), TI((ub)|0x2f), \
+       TN,            TN,            TI((ub)|0x32), TI((ub)|0x33), TN,            TN,            TI((ub)|0x36), TI((ub)|0x37), \
+       TN,            TN,            TI((ub)|0x3a), TI((ub)|0x3b), TN,            TN,            TI((ub)|0x3e), TI((ub)|0x3f), \
+       TI((ub)|0x40), TI((ub)|0x41), TI((ub)|0x42), TI((ub)|0x43), TI((ub)|0x44), TI((ub)|0x45), TI((ub)|0x46), TI((ub)|0x47), \
+       TN,            TN,            TI((ub)|0x4a), TI((ub)|0x4b), TN,            TN,            TI((ub)|0x4e), TI((ub)|0x4f), \
+       TN,            TN,            TI((ub)|0x52), TI((ub)|0x53), TN,            TN,            TI((ub)|0x56), TI((ub)|0x57), \
+       TN,            TN,            TI((ub)|0x5a), TI((ub)|0x5b), TN,            TN,            TI((ub)|0x5e), TI((ub)|0x5f), \
+       TI((ub)|0x60), TI((ub)|0x61), TI((ub)|0x62), TI((ub)|0x63), TI((ub)|0x64), TI((ub)|0x65), TI((ub)|0x66), TI((ub)|0x67), \
+       TN,            TN,            TI((ub)|0x6a), TI((ub)|0x6b), TN,            TN,            TI((ub)|0x6e), TI((ub)|0x6f), \
+       TN,            TN,            TI((ub)|0x72), TI((ub)|0x73), TN,            TN,            TI((ub)|0x76), TI((ub)|0x77), \
+       TN,            TN,            TI((ub)|0x7a), TI((ub)|0x7b), TN,            TN,            TI((ub)|0x7e), TI((ub)|0x7f), \
+       TN,            TI((ub)|0x81), TN,            TI((ub)|0x83), TN,            TI((ub)|0x85), TN,            TI((ub)|0x87), \
+       TN,            TN,            TN,            TI((ub)|0x8b), TN,            TN,            TN,            TI((ub)|0x8f), \
+       TN,            TN,            TN,            TI((ub)|0x93), TN,            TN,            TN,            TI((ub)|0x97), \
+       TN,            TN,            TN,            TI((ub)|0x9b), TN,            TN,            TN,            TI((ub)|0x9f), \
+       TN,            TI((ub)|0xa1), TN,            TI((ub)|0xa3), TN,            TI((ub)|0xa5), TN,            TI((ub)|0xa7), \
+       TN,            TN,            TN,            TI((ub)|0xab), TN,            TN,            TN,            TI((ub)|0xaf), \
+       TN,            TN,            TN,            TI((ub)|0xb3), TN,            TN,            TN,            TI((ub)|0xb7), \
+       TN,            TN,            TN,            TI((ub)|0xbb), TN,            TN,            TN,            TI((ub)|0xbf), \
+       TN,            TI((ub)|0xc1), TN,            TI((ub)|0xc3), TN,            TI((ub)|0xc5), TN,            TI((ub)|0xc7), \
+       TN,            TN,            TN,            TI((ub)|0xcb), TN,            TN,            TN,            TI((ub)|0xcf), \
+       TN,            TN,            TN,            TI((ub)|0xd3), TN,            TN,            TN,            TI((ub)|0xd7), \
+       TN,            TN,            TN,            TI((ub)|0xdb), TN,            TN,            TN,            TI((ub)|0xdf), \
+       TN,            TI((ub)|0xe1), TN,            TI((ub)|0xe3), TN,            TI((ub)|0xe5), TN,            TI((ub)|0xe7), \
+       TN,            TN,            TN,            TI((ub)|0xeb), TN,            TN,            TN,            TI((ub)|0xef), \
+       TN,            TN,            TN,            TI((ub)|0xf3), TN,            TN,            TN,            TI((ub)|0xf7), \
+       TN,            TN,            TN,            TI((ub)|0xfb), TN,            TN,            TN,            TI((ub)|0xff)
+
+const PP gpuPolySpanDrivers[2048] = {
+       TIBLOCK(0<<8), TIBLOCK(1<<8), TIBLOCK(2<<8), TIBLOCK(3<<8),
+       TIBLOCK(4<<8), TIBLOCK(5<<8), TIBLOCK(6<<8), TIBLOCK(7<<8)
 };
+
+#undef TI
+#undef TN
+#undef TIBLOCK
+
+#endif /* __GPU_UNAI_GPU_INNER_H__ */
index ce439d3..febc7ed 100644 (file)
 
 //  GPU Blending operations functions
 
-#ifdef __arm__
-#define gpuBlending00(uSrc,uDst) \
-{ \
-       asm ("and  %[src], %[src], %[msk]\n" \
-            "and  %[dst], %[dst], %[msk]\n" \
-            "add  %[src], %[dst], %[src]\n" \
-            "mov  %[src], %[src], lsr #1\n" \
-        : [src] "=&r" (uSrc), [dst] "=&r" (uDst) : "0" (uSrc), "1" (uDst), [msk] "r" (uMsk)); \
-}
-#else
-#define gpuBlending00(uSrc,uDst) \
-{ \
-       uSrc = (((uDst & uMsk) + (uSrc & uMsk)) >> 1); \
-}
-#endif
+////////////////////////////////////////////////////////////////////////////////
+// Blend bgr555 color in 'uSrc' (foreground) with bgr555 color
+//  in 'uDst' (background), returning resulting color.
+//
+// INPUT:
+//  'uSrc','uDst' input: -bbbbbgggggrrrrr
+//                       ^ bit 16
+// OUTPUT:
+//           u16 output: 0bbbbbgggggrrrrr
+//                       ^ bit 16
+// RETURNS:
+// Where '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+template <int BLENDMODE, bool SKIP_USRC_MSB_MASK>
+GPU_INLINE uint_fast16_t gpuBlendingGeneric(uint_fast16_t uSrc, uint_fast16_t uDst)
+{
+       // These use Blargg's bitwise modulo-clamping:
+       //  http://blargg.8bitalley.com/info/rgb_mixing.html
+       //  http://blargg.8bitalley.com/info/rgb_clamped_add.html
+       //  http://blargg.8bitalley.com/info/rgb_clamped_sub.html
 
-//     1.0 x Back + 1.0 x Forward
-#ifdef __arm__
-#define gpuBlending01(uSrc,uDst) \
-{ \
-       u32 st,dt,out; \
-       asm ("and    %[dt],  %[dst],   #0x7C00\n" \
-            "and    %[st],  %[src],   #0x7C00\n" \
-            "add    %[out], %[dt],    %[st]  \n" \
-            "cmp    %[out], #0x7C00          \n" \
-            "movhi  %[out], #0x7C00          \n" \
-            "and    %[dt],  %[dst],   #0x03E0\n" \
-            "and    %[st],  %[src],   #0x03E0\n" \
-            "add    %[dt],  %[dt],    %[st]  \n" \
-            "cmp    %[dt],  #0x03E0          \n" \
-            "movhi  %[dt],  #0x03E0          \n" \
-            "orr    %[out], %[out],   %[dt]  \n" \
-            "and    %[dt],  %[dst],   #0x001F\n" \
-            "and    %[st],  %[src],   #0x001F\n" \
-            "add    %[dt],  %[dt],    %[st]  \n" \
-            "cmp    %[dt],  #0x001F          \n" \
-            "movhi  %[dt],  #0x001F          \n" \
-            "orr    %[src], %[out],  %[dt]  \n" \
-        : [src] "=r" (uSrc), [st] "=&r" (st), [dt] "=&r" (dt), [out] "=&r" (out) \
-        : [dst] "r" (uDst), "0" (uSrc) : "cc"); \
-}
+       uint_fast16_t mix;
+
+       // 0.5 x Back + 0.5 x Forward
+       if (BLENDMODE==0) {
+#ifdef GPU_UNAI_USE_ACCURATE_BLENDING
+               // Slower, but more accurate (doesn't lose LSB data)
+               uDst &= 0x7fff;
+               if (!SKIP_USRC_MSB_MASK)
+                       uSrc &= 0x7fff;
+               mix = ((uSrc + uDst) - ((uSrc ^ uDst) & 0x0421)) >> 1;
 #else
-#define gpuBlending01(uSrc,uDst) \
-{ \
-       u16 rr, gg, bb; \
-       bb = (uDst & 0x7C00) + (uSrc & 0x7C00);   if (bb > 0x7C00)  bb = 0x7C00; \
-       gg = (uDst & 0x03E0) + (uSrc & 0x03E0);   if (gg > 0x03E0)  gg = 0x03E0;  bb |= gg; \
-       rr = (uDst & 0x001F) + (uSrc & 0x001F);   if (rr > 0x001F)  rr = 0x001F;  bb |= rr; \
-       uSrc = bb; \
-}
+               mix = ((uDst & 0x7bde) + (uSrc & 0x7bde)) >> 1;
 #endif
+       }
+
+       // 1.0 x Back + 1.0 x Forward
+       if (BLENDMODE==1) {
+               uDst &= 0x7fff;
+               if (!SKIP_USRC_MSB_MASK)
+                       uSrc &= 0x7fff;
+               u32 sum      = uSrc + uDst;
+               u32 low_bits = (uSrc ^ uDst) & 0x0421;
+               u32 carries  = (sum - low_bits) & 0x8420;
+               u32 modulo   = sum - carries;
+               u32 clamp    = carries - (carries >> 5);
+               mix = modulo | clamp;
+       }
+
+       // 1.0 x Back - 1.0 x Forward
+       if (BLENDMODE==2) {
+               uDst &= 0x7fff;
+               if (!SKIP_USRC_MSB_MASK)
+                       uSrc &= 0x7fff;
+               u32 diff     = uDst - uSrc + 0x8420;
+               u32 low_bits = (uDst ^ uSrc) & 0x8420;
+               u32 borrows  = (diff - low_bits) & 0x8420;
+               u32 modulo   = diff - borrows;
+               u32 clamp    = borrows - (borrows >> 5);
+               mix = modulo & clamp;
+       }
 
-//     1.0 x Back - 1.0 x Forward      */
-#ifdef __arm__
-#define gpuBlending02(uSrc,uDst) \
-{ \
-       u32 st,dt,out; \
-       asm ("and    %[dt],  %[dst],   #0x7C00\n" \
-            "and    %[st],  %[src],   #0x7C00\n" \
-            "subs   %[out], %[dt],    %[st]  \n" \
-            "movmi  %[out], #0x0000          \n" \
-            "and    %[dt],  %[dst],   #0x03E0\n" \
-            "and    %[st],  %[src],   #0x03E0\n" \
-            "subs   %[dt],  %[dt],    %[st]  \n" \
-            "orrpl  %[out], %[out],   %[dt]  \n" \
-            "and    %[dt],  %[dst],   #0x001F\n" \
-            "and    %[st],  %[src],   #0x001F\n" \
-            "subs   %[dt],  %[dt],    %[st]  \n" \
-            "orrpl  %[out], %[out],   %[dt]  \n" \
-            "mov    %[src], %[out]           \n" \
-        : [src] "=r" (uSrc), [st] "=&r" (st), [dt] "=&r" (dt), [out] "=&r" (out) \
-        : [dst] "r" (uDst), "0" (uSrc) : "cc"); \
+       // 1.0 x Back + 0.25 x Forward
+       if (BLENDMODE==3) {
+               uDst &= 0x7fff;
+               uSrc = ((uSrc >> 2) & 0x1ce7);
+               u32 sum      = uSrc + uDst;
+               u32 low_bits = (uSrc ^ uDst) & 0x0421;
+               u32 carries  = (sum - low_bits) & 0x8420;
+               u32 modulo   = sum - carries;
+               u32 clamp    = carries - (carries >> 5);
+               mix = modulo | clamp;
+       }
+
+       return mix;
 }
 
-int btest(int s, int d)
+
+////////////////////////////////////////////////////////////////////////////////
+// Convert bgr555 color in uSrc to padded u32 5.4:5.4:5.4 bgr fixed-pt
+//  color triplet suitable for use with HQ 24-bit quantization.
+//
+// INPUT:
+//       'uDst' input: -bbbbbgggggrrrrr
+//                     ^ bit 16
+// RETURNS:
+//         u32 output: 000bbbbbXXXX0gggggXXXX0rrrrrXXXX
+//                     ^ bit 31
+// Where 'X' are fixed-pt bits, '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE u32 gpuGetRGB24(uint_fast16_t uSrc)
 {
-       gpuBlending02(s, d);
-       return s;
-}
-#else
-#define gpuBlending02(uSrc,uDst) \
-{ \
-       s32 rr, gg, bb; \
-       bb = (uDst & 0x7C00) - (uSrc & 0x7C00);   if (bb < 0)  bb  =  0; \
-       gg = (uDst & 0x03E0) - (uSrc & 0x03E0);   if (gg > 0)  bb |= gg; \
-       rr = (uDst & 0x001F) - (uSrc & 0x001F);   if (rr > 0)  bb |= rr; \
-       uSrc = bb; \
+       return ((uSrc & 0x7C00)<<14)
+            | ((uSrc & 0x03E0)<< 9)
+            | ((uSrc & 0x001F)<< 4);
 }
-#endif
 
-//     1.0 x Back + 0.25 x Forward     */
-#ifdef __arm__
-#define gpuBlending03(uSrc,uDst) \
-{ \
-       u32 st,dt,out; \
-       asm ("mov    %[src], %[src],   lsr #2 \n" \
-            "and    %[dt],  %[dst],   #0x7C00\n" \
-            "and    %[st],  %[src],   #0x1C00\n" \
-            "add    %[out], %[dt],    %[st]  \n" \
-            "cmp    %[out], #0x7C00          \n" \
-            "movhi  %[out], #0x7C00          \n" \
-            "and    %[dt],  %[dst],   #0x03E0\n" \
-            "and    %[st],  %[src],   #0x00E0\n" \
-            "add    %[dt],  %[dt],    %[st]  \n" \
-            "cmp    %[dt],  #0x03E0          \n" \
-            "movhi  %[dt],  #0x03E0          \n" \
-            "orr    %[out], %[out],   %[dt]  \n" \
-            "and    %[dt],  %[dst],   #0x001F\n" \
-            "and    %[st],  %[src],   #0x0007\n" \
-            "add    %[dt],  %[dt],    %[st]  \n" \
-            "cmp    %[dt],  #0x001F          \n" \
-            "movhi  %[dt],  #0x001F          \n" \
-            "orr    %[src], %[out],   %[dt]  \n" \
-        : [src] "=r" (uSrc), [st] "=&r" (st), [dt] "=&r" (dt), [out] "=&r" (out) \
-        : [dst] "r" (uDst), "0" (uSrc) : "cc"); \
-}
-#else
-#define gpuBlending03(uSrc,uDst) \
-{ \
-       u16 rr, gg, bb; \
-       uSrc >>= 2; \
-       bb = (uDst & 0x7C00) + (uSrc & 0x1C00);   if (bb > 0x7C00)  bb = 0x7C00; \
-       gg = (uDst & 0x03E0) + (uSrc & 0x00E0);   if (gg > 0x03E0)  gg = 0x03E0;  bb |= gg; \
-       rr = (uDst & 0x001F) + (uSrc & 0x0007);   if (rr > 0x001F)  rr = 0x001F;  bb |= rr; \
-       uSrc = bb; \
+
+////////////////////////////////////////////////////////////////////////////////
+// Blend padded u32 5.4:5.4:5.4 bgr fixed-pt color triplet in 'uSrc24'
+//  (foreground color) with bgr555 color in 'uDst' (background color),
+//  returning the resulting u32 5.4:5.4:5.4 color.
+//
+// INPUT:
+//     'uSrc24' input: 000bbbbbXXXX0gggggXXXX0rrrrrXXXX
+//                     ^ bit 31
+//       'uDst' input: -bbbbbgggggrrrrr
+//                     ^ bit 16
+// RETURNS:
+//         u32 output: 000bbbbbXXXX0gggggXXXX0rrrrrXXXX
+//                     ^ bit 31
+// Where 'X' are fixed-pt bits, '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+template <int BLENDMODE>
+GPU_INLINE u32 gpuBlending24(u32 uSrc24, uint_fast16_t uDst)
+{
+       // These use techniques adapted from Blargg's techniques mentioned in
+       //  in gpuBlending() comments above. Not as much bitwise trickery is
+       //  necessary because of presence of 0 padding in uSrc24 format.
+
+       u32 uDst24 = gpuGetRGB24(uDst);
+       u32 mix;
+
+       // 0.5 x Back + 0.5 x Forward
+       if (BLENDMODE==0) {
+               const u32 uMsk = 0x1FE7F9FE;
+               // Only need to mask LSBs of uSrc24, uDst24's LSBs are 0 already
+               mix = (uDst24 + (uSrc24 & uMsk)) >> 1;
+       }
+
+       // 1.0 x Back + 1.0 x Forward
+       if (BLENDMODE==1) {
+               u32 sum     = uSrc24 + uDst24;
+               u32 carries = sum & 0x20080200;
+               u32 modulo  = sum - carries;
+               u32 clamp   = carries - (carries >> 9);
+               mix = modulo | clamp;
+       }
+
+       // 1.0 x Back - 1.0 x Forward
+       if (BLENDMODE==2) {
+               // Insert ones in 0-padded borrow slot of color to be subtracted from
+               uDst24 |= 0x20080200;
+               u32 diff    = uDst24 - uSrc24;
+               u32 borrows = diff & 0x20080200;
+               u32 clamp   = borrows - (borrows >> 9);
+               mix = diff & clamp;
+       }
+
+       // 1.0 x Back + 0.25 x Forward
+       if (BLENDMODE==3) {
+               uSrc24 = (uSrc24 & 0x1FC7F1FC) >> 2;
+               u32 sum     = uSrc24 + uDst24;
+               u32 carries = sum & 0x20080200;
+               u32 modulo  = sum - carries;
+               u32 clamp   = carries - (carries >> 9);
+               mix = modulo | clamp;
+       }
+
+       return mix;
 }
-#endif
 
 #endif  //_OP_BLEND_H_
diff --git a/plugins/gpu_unai/gpu_inner_blend_arm.h b/plugins/gpu_unai/gpu_inner_blend_arm.h
new file mode 100644 (file)
index 0000000..6413527
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef _OP_BLEND_ARM_H_
+#define _OP_BLEND_ARM_H_
+
+////////////////////////////////////////////////////////////////////////////////
+// Blend bgr555 color in 'uSrc' (foreground) with bgr555 color
+//  in 'uDst' (background), returning resulting color.
+//
+// INPUT:
+//  'uSrc','uDst' input: -bbbbbgggggrrrrr
+//                       ^ bit 16
+// OUTPUT:
+//           u16 output: 0bbbbbgggggrrrrr
+//                       ^ bit 16
+// RETURNS:
+// Where '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+template <int BLENDMODE, bool SKIP_USRC_MSB_MASK>
+GPU_INLINE uint_fast16_t gpuBlendingARM(uint_fast16_t uSrc, uint_fast16_t uDst)
+{
+       // These use Blargg's bitwise modulo-clamping:
+       //  http://blargg.8bitalley.com/info/rgb_mixing.html
+       //  http://blargg.8bitalley.com/info/rgb_clamped_add.html
+       //  http://blargg.8bitalley.com/info/rgb_clamped_sub.html
+
+       uint_fast16_t mix;
+
+       // Clear preserved msb
+       asm ("bic %[uDst], %[uDst], #0x8000" : [uDst] "+r" (uDst));
+
+       if (BLENDMODE == 3) {
+               // Prepare uSrc for blending ((0.25 * uSrc) & (0.25 * mask))
+               asm ("and %[uSrc], %[mask], %[uSrc], lsr #0x2" : [uSrc] "+r" (uSrc) : [mask] "r" (0x1ce7));
+       } else if (!SKIP_USRC_MSB_MASK) {
+               asm ("bic %[uSrc], %[uSrc], #0x8000" : [uSrc] "+r" (uSrc));
+       }
+
+
+       // 0.5 x Back + 0.5 x Forward
+       if (BLENDMODE==0) {
+               // mix = ((uSrc + uDst) - ((uSrc ^ uDst) & 0x0421)) >> 1;
+               asm ("eor %[mix], %[uSrc], %[uDst]\n\t" // uSrc ^ uDst
+                    "and %[mix], %[mix], %[mask]\n\t"  // ... & 0x0421
+                    "sub %[mix], %[uDst], %[mix]\n\t"  // uDst - ...
+                    "add %[mix], %[uSrc], %[mix]\n\t"  // uSrc + ...
+                    "mov %[mix], %[mix], lsr #0x1\n\t" // ... >> 1
+                    : [mix] "=&r" (mix)
+                    : [uSrc] "r" (uSrc), [uDst] "r" (uDst), [mask] "r" (0x0421));
+       }
+
+       if (BLENDMODE == 1 || BLENDMODE == 3) {
+               // u32 sum      = uSrc + uDst;
+               // u32 low_bits = (uSrc ^ uDst) & 0x0421;
+               // u32 carries  = (sum - low_bits) & 0x8420;
+               // u32 modulo   = sum - carries;
+               // u32 clamp    = carries - (carries >> 5);
+               // mix = modulo | clamp;
+
+               u32 sum;
+
+               asm ("add %[sum], %[uSrc], %[uDst]\n\t" // sum = uSrc + uDst
+                    "eor %[mix], %[uSrc], %[uDst]\n\t" // uSrc ^ uDst
+                    "and %[mix], %[mix], %[mask]\n\t"  // low_bits = (... & 0x0421)
+                    "sub %[mix], %[sum], %[mix]\n\t"   // sum - low_bits
+                    "and %[mix], %[mix], %[mask], lsl #0x05\n\t"  // carries = ... & 0x8420
+                    "sub %[sum], %[sum], %[mix] \n\t"  // modulo = sum - carries
+                    "sub %[mix], %[mix], %[mix], lsr #0x05\n\t" // clamp = carries - (carries >> 5)
+                    "orr %[mix], %[sum], %[mix]"       // mix = modulo | clamp
+                    : [sum] "=&r" (sum), [mix] "=&r" (mix)
+                    : [uSrc] "r" (uSrc), [uDst] "r" (uDst), [mask] "r" (0x0421));
+       }
+    
+       // 1.0 x Back - 1.0 x Forward
+       if (BLENDMODE==2) {
+               u32 diff;
+               // u32 diff     = uDst - uSrc + 0x8420;
+               // u32 low_bits = (uDst ^ uSrc) & 0x8420;
+               // u32 borrows  = (diff - low_bits) & 0x8420;
+               // u32 modulo   = diff - borrows;
+               // u32 clamp    = borrows - (borrows >> 5);
+               // mix = modulo & clamp;
+               asm ("sub %[diff], %[uDst], %[uSrc]\n\t"  // uDst - uSrc
+                    "add %[diff], %[diff], %[mask]\n\t"  // diff = ... + 0x8420
+                    "eor %[mix], %[uDst], %[uSrc]\n\t"   // uDst ^ uSrc
+                    "and %[mix], %[mix], %[mask]\n\t"    // low_bits = ... & 0x8420
+                    "sub %[mix], %[diff], %[mix]\n\t"    // diff - low_bits
+                    "and %[mix], %[mix], %[mask]\n\t"    // borrows = ... & 0x8420
+                    "sub %[diff], %[diff], %[mix]\n\t"   // modulo = diff - borrows
+                    "sub %[mix], %[mix], %[mix], lsr #0x05\n\t"  // clamp = borrows - (borrows >> 5)
+                    "and %[mix], %[diff], %[mix]"        // mix = modulo & clamp
+                    : [diff] "=&r" (diff), [mix] "=&r" (mix)
+                    : [uSrc] "r" (uSrc), [uDst] "r" (uDst), [mask] "r" (0x8420));
+       }
+
+       // There's not a case where we can get into this function,
+       // SKIP_USRC_MSB_MASK is false, and the msb of uSrc is unset.
+       if (!SKIP_USRC_MSB_MASK) {
+               asm ("orr %[mix], %[mix], #0x8000" : [mix] "+r" (mix));
+       }
+  
+       return mix;
+}
+
+#endif  //_OP_BLEND_ARM_H_
diff --git a/plugins/gpu_unai/gpu_inner_blend_arm5.h b/plugins/gpu_unai/gpu_inner_blend_arm5.h
new file mode 100644 (file)
index 0000000..0e9b74f
--- /dev/null
@@ -0,0 +1,100 @@
+/***************************************************************************
+*   Copyright (C) 2010 PCSX4ALL Team                                      *
+*   Copyright (C) 2010 Unai                                               *
+*                                                                         *
+*   This program is free software; you can redistribute it and/or modify  *
+*   it under the terms of the GNU General Public License as published by  *
+*   the Free Software Foundation; either version 2 of the License, or     *
+*   (at your option) any later version.                                   *
+*                                                                         *
+*   This program is distributed in the hope that it will be useful,       *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+*   GNU General Public License for more details.                          *
+*                                                                         *
+*   You should have received a copy of the GNU General Public License     *
+*   along with this program; if not, write to the                         *
+*   Free Software Foundation, Inc.,                                       *
+*   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
+***************************************************************************/
+
+#ifndef _OP_BLEND_H_
+#define _OP_BLEND_H_
+
+//  GPU Blending operations functions
+
+#define gpuBlending00(uSrc,uDst) \
+{ \
+       asm ("and  %[src], %[src], %[msk]  " : [src] "=r" (uSrc) : "0" (uSrc), [msk] "r" (uMsk)                  ); \
+       asm ("and  %[dst], %[dst], %[msk]  " : [dst] "=r" (uDst) : "0" (uDst), [msk] "r" (uMsk)                  ); \
+       asm ("add  %[src], %[dst], %[src]  " : [src] "=r" (uSrc) :             [dst] "r" (uDst), "0" (uSrc)      ); \
+       asm ("mov  %[src], %[src], lsr #1  " : [src] "=r" (uSrc) : "0" (uSrc)                                    ); \
+}
+
+//     1.0 x Back + 1.0 x Forward
+#define gpuBlending01(uSrc,uDst) \
+{ \
+       u16 st,dt,out; \
+       asm ("and    %[dt],  %[dst],   #0x7C00  " : [dt]  "=r" (dt)   :             [dst] "r" (uDst)                    ); \
+       asm ("and    %[st],  %[src],   #0x7C00  " : [st]  "=r" (st)   :             [src] "r" (uSrc)                    ); \
+       asm ("add    %[out], %[dt],    %[st]    " : [out] "=r" (out)  :             [dt]  "r" (dt),   [st]  "r" (st)    ); \
+       asm ("cmp    %[out], #0x7C00            " :                   :             [out] "r" (out) : "cc"              ); \
+       asm ("movhi  %[out], #0x7C00            " : [out] "=r" (out)  : "0" (out)                                       ); \
+       asm ("and    %[dt],  %[dst],   #0x03E0  " : [dt]  "=r" (dt)   :             [dst] "r" (uDst)                    ); \
+       asm ("and    %[st],  %[src],   #0x03E0  " : [st]  "=r" (st)   :             [src] "r" (uSrc)                    ); \
+       asm ("add    %[dt],  %[dt],    %[st]    " : [dt]  "=r" (dt)   : "0" (dt),   [st]  "r" (st)                      ); \
+       asm ("cmp    %[dt],  #0x03E0            " :                   :             [dt]  "r" (dt) : "cc"               ); \
+       asm ("movhi  %[dt],  #0x03E0            " : [dt]  "=r" (dt)   : "0" (dt)                                        ); \
+       asm ("orr    %[out], %[out],   %[dt]    " : [out] "=r" (out)  : "0" (out),  [dt]  "r" (dt)                      ); \
+       asm ("and    %[dt],  %[dst],   #0x001F  " : [dt]  "=r" (dt)   :             [dst] "r" (uDst)                    ); \
+       asm ("and    %[st],  %[src],   #0x001F  " : [st]  "=r" (st)   :             [src] "r" (uSrc)                    ); \
+       asm ("add    %[dt],  %[dt],    %[st]    " : [dt]  "=r" (dt)   : "0" (dt),   [st]  "r" (st)                      ); \
+       asm ("cmp    %[dt],  #0x001F            " :                   :             [dt]  "r" (dt) : "cc"               ); \
+       asm ("movhi  %[dt],  #0x001F            " : [dt]  "=r" (dt)   : "0" (dt)                                        ); \
+       asm ("orr    %[uSrc], %[out],   %[dt]   " : [uSrc] "=r" (uSrc)  : [out] "r" (out),  [dt]  "r" (dt)              ); \
+}
+
+//     1.0 x Back - 1.0 x Forward      */
+#define gpuBlending02(uSrc,uDst) \
+{ \
+       u16 st,dt,out; \
+       asm ("and    %[dt],  %[dst],   #0x7C00  " : [dt]  "=r" (dt)   :             [dst] "r" (uDst)                    ); \
+       asm ("and    %[st],  %[src],   #0x7C00  " : [st]  "=r" (st)   :             [src] "r" (uSrc)                    ); \
+       asm ("subs   %[out], %[dt],    %[st]    " : [out] "=r" (out)  : [dt]  "r" (dt),   [st]  "r" (st) : "cc"         ); \
+       asm ("movmi  %[out], #0x0000            " : [out] "=r" (out)  : "0" (out)                                       ); \
+       asm ("and    %[dt],  %[dst],   #0x03E0  " : [dt]  "=r" (dt)   :             [dst] "r" (uDst)                    ); \
+       asm ("and    %[st],  %[src],   #0x03E0  " : [st]  "=r" (st)   :             [src] "r" (uSrc)                    ); \
+       asm ("subs   %[dt],  %[dt],    %[st]    " : [dt]  "=r" (dt)   : "0" (dt),   [st]  "r" (st) : "cc"               ); \
+       asm ("orrpl  %[out], %[out],   %[dt]    " : [out] "=r" (out)  : "0" (out),  [dt]  "r" (dt)                      ); \
+       asm ("and    %[dt],  %[dst],   #0x001F  " : [dt]  "=r" (dt)   :             [dst] "r" (uDst)                    ); \
+       asm ("and    %[st],  %[src],   #0x001F  " : [st]  "=r" (st)   :             [src] "r" (uSrc)                    ); \
+       asm ("subs   %[dt],  %[dt],    %[st]    " : [dt]  "=r" (dt)   : "0" (dt),   [st]  "r" (st) : "cc"               ); \
+       asm ("orrpl  %[out], %[out],   %[dt]    " : [out] "=r" (out)  : "0" (out),  [dt]  "r" (dt)                      ); \
+       asm ("mov %[uSrc], %[out]" : [uSrc] "=r" (uSrc) : [out] "r" (out) ); \
+}
+
+//     1.0 x Back + 0.25 x Forward     */
+#define gpuBlending03(uSrc,uDst) \
+{ \
+               u16 st,dt,out; \
+               asm ("mov    %[src], %[src],   lsr #2   " : [src] "=r" (uSrc) : "0" (uSrc)                                      ); \
+               asm ("and    %[dt],  %[dst],   #0x7C00  " : [dt]  "=r" (dt)   :             [dst] "r" (uDst)                    ); \
+               asm ("and    %[st],  %[src],   #0x1C00  " : [st]  "=r" (st)   :             [src] "r" (uSrc)                    ); \
+               asm ("add    %[out], %[dt],    %[st]    " : [out] "=r" (out)  :             [dt]  "r" (dt),   [st]  "r" (st)    ); \
+               asm ("cmp    %[out], #0x7C00            " :                   :             [out] "r" (out) : "cc"              ); \
+               asm ("movhi  %[out], #0x7C00            " : [out] "=r" (out)  : "0" (out)                                       ); \
+               asm ("and    %[dt],  %[dst],   #0x03E0  " : [dt]  "=r" (dt)   :             [dst] "r" (uDst)                    ); \
+               asm ("and    %[st],  %[src],   #0x00E0  " : [st]  "=r" (st)   :             [src] "r" (uSrc)                    ); \
+               asm ("add    %[dt],  %[dt],    %[st]    " : [dt]  "=r" (dt)   : "0" (dt),   [st]  "r" (st)                      ); \
+               asm ("cmp    %[dt],  #0x03E0            " :                   :             [dt]  "r" (dt) : "cc"               ); \
+               asm ("movhi  %[dt],  #0x03E0            " : [dt]  "=r" (dt)   : "0" (dt)                                        ); \
+               asm ("orr    %[out], %[out],   %[dt]    " : [out] "=r" (out)  : "0" (out),  [dt]  "r" (dt)                      ); \
+               asm ("and    %[dt],  %[dst],   #0x001F  " : [dt]  "=r" (dt)   :             [dst] "r" (uDst)                    ); \
+               asm ("and    %[st],  %[src],   #0x0007  " : [st]  "=r" (st)   :             [src] "r" (uSrc)                    ); \
+               asm ("add    %[dt],  %[dt],    %[st]    " : [dt]  "=r" (dt)   : "0" (dt),   [st]  "r" (st)                      ); \
+               asm ("cmp    %[dt],  #0x001F            " :                   :             [dt]  "r" (dt) : "cc"               ); \
+               asm ("movhi  %[dt],  #0x001F            " : [dt]  "=r" (dt)   : "0" (dt)                                        ); \
+               asm ("orr    %[uSrc], %[out],   %[dt]   " : [uSrc] "=r" (uSrc)  : [out] "r" (out),  [dt]  "r" (dt)              ); \
+}
+
+#endif  //_OP_BLEND_H_
diff --git a/plugins/gpu_unai/gpu_inner_blend_arm7.h b/plugins/gpu_unai/gpu_inner_blend_arm7.h
new file mode 100644 (file)
index 0000000..083e62d
--- /dev/null
@@ -0,0 +1,107 @@
+/***************************************************************************
+*   Copyright (C) 2010 PCSX4ALL Team                                      *
+*   Copyright (C) 2010 Unai                                               *
+*                                                                         *
+*   This program is free software; you can redistribute it and/or modify  *
+*   it under the terms of the GNU General Public License as published by  *
+*   the Free Software Foundation; either version 2 of the License, or     *
+*   (at your option) any later version.                                   *
+*                                                                         *
+*   This program is distributed in the hope that it will be useful,       *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+*   GNU General Public License for more details.                          *
+*                                                                         *
+*   You should have received a copy of the GNU General Public License     *
+*   along with this program; if not, write to the                         *
+*   Free Software Foundation, Inc.,                                       *
+*   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
+***************************************************************************/
+
+#ifndef _OP_BLEND_H_
+#define _OP_BLEND_H_
+
+//  GPU Blending operations functions
+
+#define gpuBlending00(uSrc,uDst) \
+{ \
+       asm ("and  %[src], %[src], %[msk]\n" \
+            "and  %[dst], %[dst], %[msk]\n" \
+            "add  %[src], %[dst], %[src]\n" \
+            "mov  %[src], %[src], lsr #1\n" \
+        : [src] "=&r" (uSrc), [dst] "=&r" (uDst) : "0" (uSrc), "1" (uDst), [msk] "r" (uMsk)); \
+}
+
+//     1.0 x Back + 1.0 x Forward
+#define gpuBlending01(uSrc,uDst) \
+{ \
+       u32 st,dt,out; \
+       asm ("and    %[dt],  %[dst],   #0x7C00\n" \
+            "and    %[st],  %[src],   #0x7C00\n" \
+            "add    %[out], %[dt],    %[st]  \n" \
+            "cmp    %[out], #0x7C00          \n" \
+            "movhi  %[out], #0x7C00          \n" \
+            "and    %[dt],  %[dst],   #0x03E0\n" \
+            "and    %[st],  %[src],   #0x03E0\n" \
+            "add    %[dt],  %[dt],    %[st]  \n" \
+            "cmp    %[dt],  #0x03E0          \n" \
+            "movhi  %[dt],  #0x03E0          \n" \
+            "orr    %[out], %[out],   %[dt]  \n" \
+            "and    %[dt],  %[dst],   #0x001F\n" \
+            "and    %[st],  %[src],   #0x001F\n" \
+            "add    %[dt],  %[dt],    %[st]  \n" \
+            "cmp    %[dt],  #0x001F          \n" \
+            "movhi  %[dt],  #0x001F          \n" \
+            "orr    %[src], %[out],  %[dt]  \n" \
+        : [src] "=r" (uSrc), [st] "=&r" (st), [dt] "=&r" (dt), [out] "=&r" (out) \
+        : [dst] "r" (uDst), "0" (uSrc) : "cc"); \
+}
+
+//     1.0 x Back - 1.0 x Forward      */
+#define gpuBlending02(uSrc,uDst) \
+{ \
+       u32 st,dt,out; \
+       asm ("and    %[dt],  %[dst],   #0x7C00\n" \
+            "and    %[st],  %[src],   #0x7C00\n" \
+            "subs   %[out], %[dt],    %[st]  \n" \
+            "movmi  %[out], #0x0000          \n" \
+            "and    %[dt],  %[dst],   #0x03E0\n" \
+            "and    %[st],  %[src],   #0x03E0\n" \
+            "subs   %[dt],  %[dt],    %[st]  \n" \
+            "orrpl  %[out], %[out],   %[dt]  \n" \
+            "and    %[dt],  %[dst],   #0x001F\n" \
+            "and    %[st],  %[src],   #0x001F\n" \
+            "subs   %[dt],  %[dt],    %[st]  \n" \
+            "orrpl  %[out], %[out],   %[dt]  \n" \
+            "mov    %[src], %[out]           \n" \
+        : [src] "=r" (uSrc), [st] "=&r" (st), [dt] "=&r" (dt), [out] "=&r" (out) \
+        : [dst] "r" (uDst), "0" (uSrc) : "cc"); \
+}
+
+//     1.0 x Back + 0.25 x Forward     */
+#define gpuBlending03(uSrc,uDst) \
+{ \
+       u32 st,dt,out; \
+       asm ("mov    %[src], %[src],   lsr #2 \n" \
+            "and    %[dt],  %[dst],   #0x7C00\n" \
+            "and    %[st],  %[src],   #0x1C00\n" \
+            "add    %[out], %[dt],    %[st]  \n" \
+            "cmp    %[out], #0x7C00          \n" \
+            "movhi  %[out], #0x7C00          \n" \
+            "and    %[dt],  %[dst],   #0x03E0\n" \
+            "and    %[st],  %[src],   #0x00E0\n" \
+            "add    %[dt],  %[dt],    %[st]  \n" \
+            "cmp    %[dt],  #0x03E0          \n" \
+            "movhi  %[dt],  #0x03E0          \n" \
+            "orr    %[out], %[out],   %[dt]  \n" \
+            "and    %[dt],  %[dst],   #0x001F\n" \
+            "and    %[st],  %[src],   #0x0007\n" \
+            "add    %[dt],  %[dt],    %[st]  \n" \
+            "cmp    %[dt],  #0x001F          \n" \
+            "movhi  %[dt],  #0x001F          \n" \
+            "orr    %[src], %[out],   %[dt]  \n" \
+        : [src] "=r" (uSrc), [st] "=&r" (st), [dt] "=&r" (dt), [out] "=&r" (out) \
+        : [dst] "r" (uDst), "0" (uSrc) : "cc"); \
+}
+
+#endif  //_OP_BLEND_H_
index d291418..f90e8ec 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
-*   Copyright (C) 2010 PCSX4ALL Team                                      *
+*   Copyright (C) 2016 PCSX4ALL Team                                      *
 *   Copyright (C) 2010 Unai                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 
 //  GPU color operations for lighting calculations
 
-#ifdef __arm__
-#define gpuLightingRGB(uSrc,lCol) \
-{ \
-       u32 cb,cg; \
-       asm ("and %[cb],  %[lCol], #0x7C00/32      \n" \
-            "and %[cg],  %[lCol], #0x03E0*2048    \n" \
-            "mov %[res], %[lCol],          lsr #27\n" \
-            "orr %[res], %[res], %[cb],    lsl #5 \n" \
-            "orr %[res], %[res], %[cg],    lsr #11\n" \
-        : [res] "=&r" (uSrc), [cb] "=&r" (cb), [cg] "=&r" (cg) \
-        : [lCol] "r" (lCol)); \
+static void SetupLightLUT()
+{
+       // 1024-entry lookup table that modulates 5-bit texture + 5-bit light value.
+       // A light value of 15 does not modify the incoming texture color.
+       // LightLUT[32*32] array is initialized to following values:
+       //  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       //  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       //  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+       //  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+       //  0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+       //  0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9,
+       //  0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9,10,10,10,11,11,
+       //  0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9,10,10,10,11,11,12,12,13,13,
+       //  0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13,13,14,14,15,15,
+       //  0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9,10,10,11,11,12,12,13,14,14,15,15,16,16,17,
+       //  0, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9,10,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19,
+       //  0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,19,20,21,
+       //  0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9,10,11,12,12,13,14,15,15,16,17,18,18,19,20,21,21,22,23,
+       //  0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 9,10,11,12,13,13,14,15,16,17,17,18,19,20,21,21,22,23,24,25,
+       //  0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9,10,11,12,13,14,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27,
+       //  0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,
+       //  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
+       //  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,31,
+       //  0, 1, 2, 3, 4, 5, 6, 7, 9,10,11,12,13,14,15,16,18,19,20,21,22,23,24,25,27,28,29,30,31,31,31,31,
+       //  0, 1, 2, 3, 4, 5, 7, 8, 9,10,11,13,14,15,16,17,19,20,21,22,23,24,26,27,28,29,30,31,31,31,31,31,
+       //  0, 1, 2, 3, 5, 6, 7, 8,10,11,12,13,15,16,17,18,20,21,22,23,25,26,27,28,30,31,31,31,31,31,31,31,
+       //  0, 1, 2, 3, 5, 6, 7, 9,10,11,13,14,15,17,18,19,21,22,23,24,26,27,28,30,31,31,31,31,31,31,31,31,
+       //  0, 1, 2, 4, 5, 6, 8, 9,11,12,13,15,16,17,19,20,22,23,24,26,27,28,30,31,31,31,31,31,31,31,31,31,
+       //  0, 1, 2, 4, 5, 7, 8,10,11,12,14,15,17,18,20,21,23,24,25,27,28,30,31,31,31,31,31,31,31,31,31,31,
+       //  0, 1, 3, 4, 6, 7, 9,10,12,13,15,16,18,19,21,22,24,25,27,28,30,31,31,31,31,31,31,31,31,31,31,31,
+       //  0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23,25,26,28,29,31,31,31,31,31,31,31,31,31,31,31,31,
+       //  0, 1, 3, 4, 6, 8, 9,11,13,14,16,17,19,21,22,24,26,27,29,30,31,31,31,31,31,31,31,31,31,31,31,31,
+       //  0, 1, 3, 5, 6, 8,10,11,13,15,16,18,20,21,23,25,27,28,30,31,31,31,31,31,31,31,31,31,31,31,31,31,
+       //  0, 1, 3, 5, 7, 8,10,12,14,15,17,19,21,22,24,26,28,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
+       //  0, 1, 3, 5, 7, 9,10,12,14,16,18,19,21,23,25,27,29,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
+       //  0, 1, 3, 5, 7, 9,11,13,15,16,18,20,22,24,26,28,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
+       //  0, 1, 3, 5, 7, 9,11,13,15,17,19,21,23,25,27,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
+
+       for (int j=0; j < 32; ++j) {
+               for (int i=0; i < 32; ++i) {
+                       int val = i * j / 16;
+                       if (val > 31) val = 31;
+                       gpu_unai.LightLUT[(j*32) + i] = val;
+               }
+       }
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Create packed Gouraud fixed-pt 8.3:8.3:8.2 rgb triplet
+//
+// INPUT:
+// 'r','g','b' are 8.10 fixed-pt color components (r shown here)
+//     'r' input:  --------------rrrrrrrrXXXXXXXXXX
+//                 ^ bit 31
+// RETURNS:
+//    u32 output:  rrrrrrrrXXXggggggggXXXbbbbbbbbXX
+//                 ^ bit 31
+// Where 'r,g,b' are integer bits of colors, 'X' fixed-pt, and '-' don't care
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE u32 gpuPackGouraudCol(u32 r, u32 g, u32 b)
+{
+       return ((u32)(b>> 8)&(0x03ff    ))
+            | ((u32)(g<< 3)&(0x07ff<<10))
+            | ((u32)(r<<14)&(0x07ff<<21));
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Create packed increment for Gouraud fixed-pt 8.3:8.3:8.2 rgb triplet
+//
+// INPUT:
+//  Sign-extended 8.10 fixed-pt r,g,b color increment values (only dr is shown)
+//   'dr' input:  ssssssssssssssrrrrrrrrXXXXXXXXXX
+//                ^ bit 31
+// RETURNS:
+//   u32 output:  rrrrrrrrXXXggggggggXXXbbbbbbbbXX
+//                ^ bit 31
+// Where 'r,g,b' are integer bits of colors, 'X' fixed-pt, and 's' sign bits
+//
+// NOTE: The correctness of this code/method has not been fully verified,
+//       having been merely factored out from original code in
+//       poly-drawing functions. Feel free to check/improve it -senquack
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE u32 gpuPackGouraudColInc(s32 dr, s32 dg, s32 db)
+{
+       u32 dr_tmp = (u32)(dr << 14)&(0xffffffff<<21);  if (dr < 0) dr_tmp += 1<<21;
+       u32 dg_tmp = (u32)(dg <<  3)&(0xffffffff<<10);  if (dg < 0) dg_tmp += 1<<10;
+       u32 db_tmp = (u32)(db >>  8)&(0xffffffff    );  if (db < 0) db_tmp += 1<< 0;
+       return db_tmp + dg_tmp + dr_tmp;
 }
-#else
-#define gpuLightingRGB(uSrc,lCol) uSrc=((lCol<<5)&0x7C00) | ((lCol>>11)&0x3E0) | (lCol>>27)
-#endif
 
-INLINE void gpuLightingTXT(u16 &uSrc, u32 &lCol)
+
+////////////////////////////////////////////////////////////////////////////////
+// Extract bgr555 color from Gouraud u32 fixed-pt 8.3:8.3:8.2 rgb triplet
+//
+// INPUT:
+//  'gCol' input:  rrrrrrrrXXXggggggggXXXbbbbbbbbXX
+//                 ^ bit 31
+// RETURNS:
+//    u16 output:  0bbbbbgggggrrrrr
+//                 ^ bit 16
+// Where 'r,g,b' are integer bits of colors, 'X' fixed-pt, and '0' zero
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE uint_fast16_t gpuLightingRGBGeneric(u32 gCol)
+{
+       return ((gCol<< 5)&0x7C00) |
+              ((gCol>>11)&0x03E0) |
+               (gCol>>27);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Convert packed Gouraud u32 fixed-pt 8.3:8.3:8.2 rgb triplet in 'gCol'
+//  to padded u32 5.4:5.4:5.4 bgr fixed-pt triplet, suitable for use
+//  with HQ 24-bit lighting/quantization.
+//
+// INPUT:
+//       'gCol' input:  rrrrrrrrXXXggggggggXXXbbbbbbbbXX
+//                      ^ bit 31
+// RETURNS:
+//         u32 output:  000bbbbbXXXX0gggggXXXX0rrrrrXXXX
+//                      ^ bit 31
+//  Where 'X' are fixed-pt bits, '0' zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE u32 gpuLightingRGB24(u32 gCol)
+{
+       return ((gCol<<19) & (0x1FF<<20)) |
+              ((gCol>> 2) & (0x1FF<<10)) |
+               (gCol>>23);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Apply fast (low-precision) 5-bit lighting to bgr555 texture color:
+//
+// INPUT:
+//        'r5','g5','b5' are unsigned 5-bit color values, value of 15
+//          is midpoint that doesn't modify that component of texture
+//        'uSrc' input:  -bbbbbgggggrrrrr
+//                       ^ bit 16
+// RETURNS:
+//          u16 output:  0bbbbbgggggrrrrr
+// Where 'X' are fixed-pt bits, '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE uint_fast16_t gpuLightingTXTGeneric(uint_fast16_t uSrc, u8 r5, u8 g5, u8 b5)
 {
-       //  Pixelops Table
-       static const u8 _gpuLitT[32*32] = {
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-                0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
-                0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
-                0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
-                0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9,
-                0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 9, 9, 9,10,10,10,11,11,
-                0, 0, 0, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9,10,10,10,11,11,12,12,13,13,
-                0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,11,11,12,12,13,13,14,14,15,15,
-                0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 8, 9, 9,10,10,11,11,12,12,13,14,14,15,15,16,16,17,
-                0, 0, 1, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 8, 8, 9,10,10,11,11,12,13,13,14,15,15,16,16,17,18,18,19,
-                0, 0, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 8, 9,10,11,11,12,13,13,14,15,15,16,17,17,18,19,19,20,21,
-                0, 0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9, 9,10,11,12,12,13,14,15,15,16,17,18,18,19,20,21,21,22,23,
-                0, 0, 1, 2, 3, 4, 4, 5, 6, 7, 8, 8, 9,10,11,12,13,13,14,15,16,17,17,18,19,20,21,21,22,23,24,25,
-                0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9,10,11,12,13,14,14,15,16,17,18,19,20,21,21,22,23,24,25,26,27,
-                0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,
-                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
-                0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,31,
-                0, 1, 2, 3, 4, 5, 6, 7, 9,10,11,12,13,14,15,16,18,19,20,21,22,23,24,25,27,28,29,30,31,31,31,31,
-                0, 1, 2, 3, 4, 5, 7, 8, 9,10,11,13,14,15,16,17,19,20,21,22,23,24,26,27,28,29,30,31,31,31,31,31,
-                0, 1, 2, 3, 5, 6, 7, 8,10,11,12,13,15,16,17,18,20,21,22,23,25,26,27,28,30,31,31,31,31,31,31,31,
-                0, 1, 2, 3, 5, 6, 7, 9,10,11,13,14,15,17,18,19,21,22,23,24,26,27,28,30,31,31,31,31,31,31,31,31,
-                0, 1, 2, 4, 5, 6, 8, 9,11,12,13,15,16,17,19,20,22,23,24,26,27,28,30,31,31,31,31,31,31,31,31,31,
-                0, 1, 2, 4, 5, 7, 8,10,11,12,14,15,17,18,20,21,23,24,25,27,28,30,31,31,31,31,31,31,31,31,31,31,
-                0, 1, 3, 4, 6, 7, 9,10,12,13,15,16,18,19,21,22,24,25,27,28,30,31,31,31,31,31,31,31,31,31,31,31,
-                0, 1, 3, 4, 6, 7, 9,10,12,14,15,17,18,20,21,23,25,26,28,29,31,31,31,31,31,31,31,31,31,31,31,31,
-                0, 1, 3, 4, 6, 8, 9,11,13,14,16,17,19,21,22,24,26,27,29,30,31,31,31,31,31,31,31,31,31,31,31,31,
-                0, 1, 3, 5, 6, 8,10,11,13,15,16,18,20,21,23,25,27,28,30,31,31,31,31,31,31,31,31,31,31,31,31,31,
-                0, 1, 3, 5, 7, 8,10,12,14,15,17,19,21,22,24,26,28,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
-                0, 1, 3, 5, 7, 9,10,12,14,16,18,19,21,23,25,27,29,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
-                0, 1, 3, 5, 7, 9,11,13,15,16,18,20,22,24,26,28,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,
-                0, 1, 3, 5, 7, 9,11,13,15,17,19,21,23,25,27,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31
-       };
-       uSrc  = (_gpuLitT[((uSrc&0x7C00)>>5)|((lCol>>5)&0x1f)]<<10)|(_gpuLitT[(uSrc&0x03E0)|((lCol>>16)&0x1f)]<<5)|(_gpuLitT[((uSrc&0x001F)<<5)|(lCol>>27)]);
+       return (gpu_unai.LightLUT[((uSrc&0x7C00)>>5) | b5] << 10) |
+              (gpu_unai.LightLUT[ (uSrc&0x03E0)     | g5] <<  5) |
+              (gpu_unai.LightLUT[((uSrc&0x001F)<<5) | r5]      );
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Apply fast (low-precision) 5-bit Gouraud lighting to bgr555 texture color:
+//
+// INPUT:
+//  'gCol' is a packed Gouraud u32 fixed-pt 8.3:8.3:8.2 rgb triplet, value of
+//     15.0 is midpoint that does not modify color of texture
+//         gCol input :  rrrrrXXXXXXgggggXXXXXXbbbbbXXXXX
+//                       ^ bit 31
+//        'uSrc' input:  -bbbbbgggggrrrrr
+//                       ^ bit 16
+// RETURNS:
+//          u16 output:  0bbbbbgggggrrrrr
+// Where 'X' are fixed-pt bits, '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE uint_fast16_t gpuLightingTXTGouraudGeneric(uint_fast16_t uSrc, u32 gCol)
+{
+       return (gpu_unai.LightLUT[((uSrc&0x7C00)>>5) | ((gCol>> 5)&0x1F)]<<10) |
+              (gpu_unai.LightLUT[ (uSrc&0x03E0)     | ((gCol>>16)&0x1F)]<< 5) |
+              (gpu_unai.LightLUT[((uSrc&0x001F)<<5) |  (gCol>>27)      ]    );
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Apply high-precision 8-bit lighting to bgr555 texture color,
+//  returning a padded u32 5.4:5.4:5.4 bgr fixed-pt triplet
+//  suitable for use with HQ 24-bit lighting/quantization.
+//
+// INPUT:
+//        'r8','g8','b8' are unsigned 8-bit color component values, value of
+//          127 is midpoint that doesn't modify that component of texture
+//
+//         uSrc input: -bbbbbgggggrrrrr
+//                     ^ bit 16
+// RETURNS:
+//         u32 output: 000bbbbbXXXX0gggggXXXX0rrrrrXXXX
+//                     ^ bit 31
+// Where 'X' are fixed-pt bits, '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE u32 gpuLightingTXT24(uint_fast16_t uSrc, u8 r8, u8 g8, u8 b8)
+{
+       uint_fast16_t r1 = uSrc&0x001F;
+       uint_fast16_t g1 = uSrc&0x03E0;
+       uint_fast16_t b1 = uSrc&0x7C00;
+
+       uint_fast16_t r2 = r8;
+       uint_fast16_t g2 = g8;
+       uint_fast16_t b2 = b8;
+
+       u32 r3 = r1 * r2; if (r3 & 0xFFFFF000) r3 = ~0xFFFFF000;
+       u32 g3 = g1 * g2; if (g3 & 0xFFFE0000) g3 = ~0xFFFE0000;
+       u32 b3 = b1 * b2; if (b3 & 0xFFC00000) b3 = ~0xFFC00000;
+
+       return ((r3>> 3)    ) |
+              ((g3>> 8)<<10) |
+              ((b3>>13)<<20);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Apply high-precision 8-bit lighting to bgr555 texture color in 'uSrc',
+//  returning a padded u32 5.4:5.4:5.4 bgr fixed-pt triplet
+//  suitable for use with HQ 24-bit lighting/quantization.
+//
+// INPUT:
+//       'uSrc' input: -bbbbbgggggrrrrr
+//                     ^ bit 16
+//       'gCol' input: rrrrrrrrXXXggggggggXXXbbbbbbbbXX
+//                     ^ bit 31
+// RETURNS:
+//         u32 output: 000bbbbbXXXX0gggggXXXX0rrrrrXXXX
+//                     ^ bit 31
+// Where 'X' are fixed-pt bits, '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE u32 gpuLightingTXT24Gouraud(uint_fast16_t uSrc, u32 gCol)
+{
+       uint_fast16_t r1 = uSrc&0x001F;
+       uint_fast16_t g1 = uSrc&0x03E0;
+       uint_fast16_t b1 = uSrc&0x7C00;
+
+       uint_fast16_t r2 = (gCol>>24) & 0xFF;
+       uint_fast16_t g2 = (gCol>>13) & 0xFF;
+       uint_fast16_t b2 = (gCol>> 2) & 0xFF;
+
+       u32 r3 = r1 * r2; if (r3 & 0xFFFFF000) r3 = ~0xFFFFF000;
+       u32 g3 = g1 * g2; if (g3 & 0xFFFE0000) g3 = ~0xFFFE0000;
+       u32 b3 = b1 * b2; if (b3 & 0xFFC00000) b3 = ~0xFFC00000;
+
+       return ((r3>> 3)    ) |
+              ((g3>> 8)<<10) |
+              ((b3>>13)<<20);
 }
 
 #endif  //_OP_LIGHT_H_
diff --git a/plugins/gpu_unai/gpu_inner_light_arm.h b/plugins/gpu_unai/gpu_inner_light_arm.h
new file mode 100644 (file)
index 0000000..7bd5890
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef _OP_LIGHT_ARM_H_
+#define _OP_LIGHT_ARM_H_
+
+////////////////////////////////////////////////////////////////////////////////
+// Extract bgr555 color from Gouraud u32 fixed-pt 8.3:8.3:8.2 rgb triplet
+//
+// INPUT:
+//  'gCol' input:  rrrrrrrrXXXggggggggXXXbbbbbbbbXX
+//                 ^ bit 31
+// RETURNS:
+//    u16 output:  0bbbbbgggggrrrrr
+//                 ^ bit 16
+// Where 'r,g,b' are integer bits of colors, 'X' fixed-pt, and '0' zero
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE uint_fast16_t gpuLightingRGBARM(u32 gCol)
+{
+       uint_fast16_t out = 0x03E0; // don't need the mask after starting to write output
+       u32 tmp;
+  
+       asm ("and %[tmp], %[gCol], %[out]\n\t"              // tmp holds 0x000000bbbbb00000
+            "and %[out], %[out],  %[gCol], lsr #0x0B\n\t"  // out holds 0x000000ggggg00000
+            "orr %[tmp], %[out],  %[tmp],  lsl #0x05\n\t"  // tmp holds 0x0bbbbbggggg00000
+            "orr %[out], %[tmp],  %[gCol], lsr #0x1B\n\t"  // out holds 0x0bbbbbgggggrrrrr
+            : [out] "+&r" (out), [tmp] "=&r" (tmp)
+            : [gCol] "r"  (gCol)
+            );
+
+       return out;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Apply fast (low-precision) 5-bit lighting to bgr555 texture color:
+//
+// INPUT:
+//       'r5','g5','b5' are unsigned 5-bit color values, value of 15
+//         is midpoint that doesn't modify that component of texture
+//       'uSrc' input:  mbbbbbgggggrrrrr
+//                      ^ bit 16
+// RETURNS:
+//         u16 output:  mbbbbbgggggrrrrr
+// Where 'X' are fixed-pt bits.
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE uint_fast16_t gpuLightingTXTARM(uint_fast16_t uSrc, u8 r5, u8 g5, u8 b5)
+{
+       uint_fast16_t out = 0x03E0;
+       u32 db, dg;
+
+       // Using `g` for src, `G` for dest
+       asm ("and    %[dg],  %[out],    %[src]  \n\t"             // dg holds 0x000000ggggg00000
+            "orr    %[dg],  %[dg],     %[g5]   \n\t"             // dg holds 0x000000gggggGGGGG
+            "and    %[db],  %[out],    %[src], lsr #0x05 \n\t"   // db holds 0x000000bbbbb00000
+            "ldrb   %[dg],  [%[lut],   %[dg]]  \n\t"             // dg holds result 0x00000000000ggggg
+            "and    %[out], %[out],    %[src], lsl #0x05 \n\t"   // out holds 0x000000rrrrr00000
+            "orr    %[out], %[out],    %[r5]   \n\t"             // out holds 0x000000rrrrrRRRRR
+            "orr    %[db],  %[db],     %[b5]   \n\t"             // db holds 0x000000bbbbbBBBBB
+            "ldrb   %[out], [%[lut],   %[out]] \n\t"             // out holds result 0x00000000000rrrrr
+            "ldrb   %[db],  [%[lut],   %[db]]  \n\t"             // db holds result 0x00000000000bbbbb
+            "tst    %[src], #0x8000\n\t"                         // check whether msb was set on uSrc
+            "orr    %[out], %[out],    %[dg],  lsl #0x05   \n\t" // out holds 0x000000gggggrrrrr
+            "orrne  %[out], %[out],    #0x8000\n\t"              // add msb to out if set on uSrc
+            "orr    %[out], %[out],    %[db],  lsl #0x0A   \n\t" // out holds 0xmbbbbbgggggrrrrr
+            : [out] "=&r" (out), [db] "=&r" (db), [dg] "=&r" (dg)
+            : [r5] "r" (r5), [g5] "r" (g5),  [b5] "r" (b5),
+              [lut] "r" (gpu_unai.LightLUT), [src] "r" (uSrc), "0" (out)
+            : "cc");
+       return out;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Apply fast (low-precision) 5-bit Gouraud lighting to bgr555 texture color:
+//
+// INPUT:
+//  'gCol' is a packed Gouraud u32 fixed-pt 8.3:8.3:8.2 rgb triplet, value of
+//     15.0 is midpoint that does not modify color of texture
+//        gCol input :  rrrrrXXXXXXgggggXXXXXXbbbbbXXXXX
+//                      ^ bit 31
+//       'uSrc' input:  mbbbbbgggggrrrrr
+//                      ^ bit 16
+// RETURNS:
+//         u16 output:  mbbbbbgggggrrrrr
+// Where 'X' are fixed-pt bits, '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+GPU_INLINE uint_fast16_t gpuLightingTXTGouraudARM(uint_fast16_t uSrc, u32 gCol)
+{
+       uint_fast16_t out = 0x03E0; // don't need the mask after starting to write output
+       u32 db,dg,gtmp;
+
+       // Using `g` for src, `G` for dest
+       asm ("and    %[dg],  %[out],  %[src]   \n\t"           // dg holds 0x000000ggggg00000
+            "and    %[gtmp],%[out],  %[gCol], lsr #0x0B \n\t" // gtmp holds 0x000000GGGGG00000
+            "and    %[db],  %[out],  %[src],  lsr #0x05 \n\t" // db holds 0x000000bbbbb00000
+            "orr    %[dg],  %[dg],   %[gtmp], lsr #0x05 \n\t" // dg holds 0x000000gggggGGGGG
+            "and    %[gtmp],%[out],  %[gCol]  \n\t"           // gtmp holds 0x000000BBBBB00000
+            "ldrb   %[dg],  [%[lut], %[dg]]   \n\t"           // dg holds result 0x00000000000ggggg
+            "and    %[out], %[out],  %[src],  lsl #0x05 \n\t" // out holds 0x000000rrrrr00000
+            "orr    %[out], %[out],  %[gCol], lsr #0x1B \n\t" // out holds 0x000000rrrrrRRRRR
+            "orr    %[db],  %[db],   %[gtmp], lsr #0x05 \n\t" // db holds 0x000000bbbbbBBBBB
+            "ldrb   %[out], [%[lut], %[out]]  \n\t"           // out holds result 0x00000000000rrrrr
+            "ldrb   %[db],  [%[lut], %[db]]   \n\t"           // db holds result 0x00000000000bbbbb
+            "tst    %[src], #0x8000\n\t"                      // check whether msb was set on uSrc
+            "orr    %[out], %[out],  %[dg],   lsl #0x05 \n\t" // out holds 0x000000gggggrrrrr
+            "orrne  %[out], %[out],  #0x8000\n\t"             // add msb to out if set on uSrc
+            "orr    %[out], %[out],  %[db],   lsl #0x0A \n\t" // out holds 0xmbbbbbgggggrrrrr
+            : [out] "=&r" (out), [db] "=&r" (db), [dg] "=&r" (dg),
+              [gtmp] "=&r" (gtmp) \
+            : [gCol] "r" (gCol), [lut] "r" (gpu_unai.LightLUT), "0" (out), [src] "r" (uSrc)
+            : "cc");
+
+       return out;
+}
+
+#endif  //_OP_LIGHT_ARM_H_
diff --git a/plugins/gpu_unai/gpu_inner_quantization.h b/plugins/gpu_unai/gpu_inner_quantization.h
new file mode 100644 (file)
index 0000000..0e7e3e8
--- /dev/null
@@ -0,0 +1,108 @@
+/***************************************************************************
+*   Copyright (C) 2016 PCSX4ALL Team                                      *
+*                                                                         *
+*   This program is free software; you can redistribute it and/or modify  *
+*   it under the terms of the GNU General Public License as published by  *
+*   the Free Software Foundation; either version 2 of the License, or     *
+*   (at your option) any later version.                                   *
+*                                                                         *
+*   This program is distributed in the hope that it will be useful,       *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+*   GNU General Public License for more details.                          *
+*                                                                         *
+*   You should have received a copy of the GNU General Public License     *
+*   along with this program; if not, write to the                         *
+*   Free Software Foundation, Inc.,                                       *
+*   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
+***************************************************************************/
+
+#ifndef _OP_DITHER_H_
+#define _OP_DITHER_H_
+
+static void SetupDitheringConstants()
+{
+       // Initialize Dithering Constants
+       // The screen is divided into 8x8 chunks and sub-unitary noise is applied
+       // using the following matrix. This ensures that data lost in color
+       // quantization will be added back to the image 'by chance' in predictable
+       // patterns that are naturally 'smoothed' by your sight when viewed from a
+       // certain distance.
+       //
+       // http://caca.zoy.org/study/index.html
+       //
+       // Shading colors are encoded in 4.5, and then are quantitized to 5.0,
+       // DitherMatrix constants reflect that.
+
+       static const u8 DitherMatrix[] = {
+                0, 32,  8, 40,  2, 34, 10, 42,
+               48, 16, 56, 24, 50, 18, 58, 26,
+               12, 44,  4, 36, 14, 46,  6, 38,
+               60, 28, 52, 20, 62, 30, 54, 22,
+                3, 35, 11, 43,  1, 33,  9, 41,
+               51, 19, 59, 27, 49, 17, 57, 25,
+               15, 47,  7, 39, 13, 45,  5, 37,
+               63, 31, 55, 23, 61, 29, 53, 21
+       };
+
+       int i, j;
+       for (i = 0; i < 8; i++)
+       {
+               for (j = 0; j < 8; j++)
+               {
+                       u16 offset = (i << 3) | j;
+
+                       u32 component = ((DitherMatrix[offset] + 1) << 4) / 65; //[5.5] -> [5]
+
+                       // XXX - senquack - hack Dec 2016
+                       //  Until JohnnyF gets the time to work further on dithering,
+                       //   force lower bit of component to 0. This fixes grid pattern
+                       //   affecting quality of dithered image, as well as loss of
+                       //   detail in dark areas. With lower bit unset like this, existing
+                       //   27-bit accuracy of dithering math is unneeded, could be 24-bit.
+                       //   Is 8x8 matrix overkill as a result, can we use 4x4?
+                       component &= ~1;
+
+                       gpu_unai.DitherMatrix[offset] = (component)
+                                                     | (component << 10)
+                                                     | (component << 20);
+               }
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Convert padded u32 5.4:5.4:5.4 bgr fixed-pt triplet to final bgr555 color,
+//  applying dithering if specified by template parameter.
+//
+// INPUT:
+//     'uSrc24' input: 000bbbbbXXXX0gggggXXXX0rrrrrXXXX
+//                     ^ bit 31
+//       'pDst' is a pointer to destination framebuffer pixel, used
+//         to determine which DitherMatrix[] entry to apply.
+// RETURNS:
+//         u16 output: 0bbbbbgggggrrrrr
+//                     ^ bit 16
+// Where 'X' are fixed-pt bits, '0' is zero-padding, and '-' is don't care
+////////////////////////////////////////////////////////////////////////////////
+template <int DITHER>
+GPU_INLINE u16 gpuColorQuantization24(u32 uSrc24, const u16 *pDst)
+{
+       if (DITHER)
+       {
+               u16 fbpos  = (u32)(pDst - gpu_unai.vram);
+               u16 offset = ((fbpos & (0x7 << 10)) >> 7) | (fbpos & 0x7);
+
+               //clean overflow flags and add
+               uSrc24 = (uSrc24 & 0x1FF7FDFF) + gpu_unai.DitherMatrix[offset];
+
+               if (uSrc24 & (1<< 9)) uSrc24 |= (0x1FF    );
+               if (uSrc24 & (1<<19)) uSrc24 |= (0x1FF<<10);
+               if (uSrc24 & (1<<29)) uSrc24 |= (0x1FF<<20);
+       }
+
+       return ((uSrc24>> 4) & (0x1F    ))
+            | ((uSrc24>> 9) & (0x1F<<5 ))
+            | ((uSrc24>>14) & (0x1F<<10));
+}
+
+#endif //_OP_DITHER_H_
index 0c82aa9..2d34b34 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
  ***************************************************************************/
 
+#ifndef __GPU_UNAI_GPU_RASTER_IMAGE_H__
+#define __GPU_UNAI_GPU_RASTER_IMAGE_H__
+
 ///////////////////////////////////////////////////////////////////////////////
-INLINE void gpuLoadImage(void)
+#ifndef USE_GPULIB
+void gpuLoadImage(PtrUnion packet)
 {
        u16 x0, y0, w0, h0;
-       x0 = PacketBuffer.U2[2] & 1023;
-       y0 = PacketBuffer.U2[3] & 511;
-       w0 = PacketBuffer.U2[4];
-       h0 = PacketBuffer.U2[5];
+       x0 = packet.U2[2] & 1023;
+       y0 = packet.U2[3] & 511;
+       w0 = packet.U2[4];
+       h0 = packet.U2[5];
 
        if ((y0 + h0) > FRAME_HEIGHT)
        {
                h0 = FRAME_HEIGHT - y0;
        }
 
-       FrameToWrite = ((w0)&&(h0));
+       gpu_unai.dma.FrameToWrite = ((w0)&&(h0));
 
-       px = 0;
-       py = 0;
-       x_end = w0;
-       y_end = h0;
-       pvram = &((u16*)GPU_FrameBuffer)[x0+(y0*1024)];
+       gpu_unai.dma.px = 0;
+       gpu_unai.dma.py = 0;
+       gpu_unai.dma.x_end = w0;
+       gpu_unai.dma.y_end = h0;
+       gpu_unai.dma.pvram = &((u16*)gpu_unai.vram)[x0+(y0*1024)];
 
-       GPU_GP1 |= 0x08000000;
+       gpu_unai.GPU_GP1 |= 0x08000000;
 }
+#endif // !USE_GPULIB
 
 ///////////////////////////////////////////////////////////////////////////////
-INLINE void gpuStoreImage(void)
+#ifndef USE_GPULIB
+void gpuStoreImage(PtrUnion packet)
 {
        u16 x0, y0, w0, h0;
-       x0 = PacketBuffer.U2[2] & 1023;
-       y0 = PacketBuffer.U2[3] & 511;
-       w0 = PacketBuffer.U2[4];
-       h0 = PacketBuffer.U2[5];
+       x0 = packet.U2[2] & 1023;
+       y0 = packet.U2[3] & 511;
+       w0 = packet.U2[4];
+       h0 = packet.U2[5];
 
        if ((y0 + h0) > FRAME_HEIGHT)
        {
                h0 = FRAME_HEIGHT - y0;
        }
-       FrameToRead = ((w0)&&(h0));
+       gpu_unai.dma.FrameToRead = ((w0)&&(h0));
 
-       px = 0;
-       py = 0;
-       x_end = w0;
-       y_end = h0;
-       pvram = &((u16*)GPU_FrameBuffer)[x0+(y0*1024)];
+       gpu_unai.dma.px = 0;
+       gpu_unai.dma.py = 0;
+       gpu_unai.dma.x_end = w0;
+       gpu_unai.dma.y_end = h0;
+       gpu_unai.dma.pvram = &((u16*)gpu_unai.vram)[x0+(y0*1024)];
        
-       GPU_GP1 |= 0x08000000;
+       gpu_unai.GPU_GP1 |= 0x08000000;
 }
+#endif // !USE_GPULIB
 
-INLINE void gpuMoveImage(void)
+void gpuMoveImage(PtrUnion packet)
 {
        u32 x0, y0, x1, y1;
        s32 w0, h0;
-       x0 = PacketBuffer.U2[2] & 1023;
-       y0 = PacketBuffer.U2[3] & 511;
-       x1 = PacketBuffer.U2[4] & 1023;
-       y1 = PacketBuffer.U2[5] & 511;
-       w0 = PacketBuffer.U2[6];
-       h0 = PacketBuffer.U2[7];
+       x0 = packet.U2[2] & 1023;
+       y0 = packet.U2[3] & 511;
+       x1 = packet.U2[4] & 1023;
+       y1 = packet.U2[5] & 511;
+       w0 = packet.U2[6];
+       h0 = packet.U2[7];
 
        if( (x0==x1) && (y0==y1) ) return;
        if ((w0<=0) || (h0<=0)) return;
        
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"gpuMoveImage(x0=%u,y0=%u,x1=%u,y1=%u,w0=%d,h0=%d)\n",x0,y0,x1,y1,w0,h0);
+       #endif
+       
        if (((y0+h0)>512)||((x0+w0)>1024)||((y1+h0)>512)||((x1+w0)>1024))
        {
-               u16 *psxVuw=GPU_FrameBuffer;
+               u16 *psxVuw=gpu_unai.vram;
                s32 i,j;
            for(j=0;j<h0;j++)
                 for(i=0;i<w0;i++)
@@ -93,7 +104,7 @@ INLINE void gpuMoveImage(void)
        else if ((x0&1)||(x1&1))
        {
                u16 *lpDst, *lpSrc;
-               lpDst = lpSrc = (u16*)GPU_FrameBuffer;
+               lpDst = lpSrc = (u16*)gpu_unai.vram;
                lpSrc += FRAME_OFFSET(x0, y0);
                lpDst += FRAME_OFFSET(x1, y1);
                x1 = FRAME_WIDTH - w0;
@@ -107,7 +118,7 @@ INLINE void gpuMoveImage(void)
        else
        {
                u32 *lpDst, *lpSrc;
-               lpDst = lpSrc = (u32*)(void*)GPU_FrameBuffer;
+               lpDst = lpSrc = (u32*)(void*)gpu_unai.vram;
                lpSrc += ((FRAME_OFFSET(x0, y0))>>1);
                lpDst += ((FRAME_OFFSET(x1, y1))>>1);
                if (w0&1)
@@ -143,13 +154,13 @@ INLINE void gpuMoveImage(void)
        }
 }
 
-INLINE void gpuClearImage(void)
+void gpuClearImage(PtrUnion packet)
 {
        s32   x0, y0, w0, h0;
-       x0 = PacketBuffer.S2[2];
-       y0 = PacketBuffer.S2[3];
-       w0 = PacketBuffer.S2[4] & 0x3ff;
-       h0 = PacketBuffer.S2[5] & 0x3ff;
+       x0 = packet.S2[2];
+       y0 = packet.S2[3];
+       w0 = packet.S2[4] & 0x3ff;
+       h0 = packet.S2[5] & 0x3ff;
         
        w0 += x0;
        if (x0 < 0) x0 = 0;
@@ -162,10 +173,14 @@ INLINE void gpuClearImage(void)
        h0 -= y0;
        if (h0 <= 0) return;
 
+       #ifdef ENABLE_GPU_LOG_SUPPORT
+               fprintf(stdout,"gpuClearImage(x0=%d,y0=%d,w0=%d,h0=%d)\n",x0,y0,w0,h0);
+       #endif
+       
        if (x0&1)
        {
-               u16* pixel = (u16*)GPU_FrameBuffer + FRAME_OFFSET(x0, y0);
-               u16 rgb = GPU_RGB16(PacketBuffer.S4[0]);
+               u16* pixel = (u16*)gpu_unai.vram + FRAME_OFFSET(x0, y0);
+               u16 rgb = GPU_RGB16(packet.U4[0]);
                y0 = FRAME_WIDTH - w0;
                do {
                        x0=w0;
@@ -175,8 +190,8 @@ INLINE void gpuClearImage(void)
        }
        else
        {
-               u32* pixel = (u32*)(void*)GPU_FrameBuffer + ((FRAME_OFFSET(x0, y0))>>1);
-               u32 rgb = GPU_RGB16(PacketBuffer.S4[0]);
+               u32* pixel = (u32*)gpu_unai.vram + ((FRAME_OFFSET(x0, y0))>>1);
+               u32 rgb = GPU_RGB16(packet.U4[0]);
                rgb |= (rgb<<16);
                if (w0&1)
                {
@@ -201,3 +216,5 @@ INLINE void gpuClearImage(void)
                }
        }
 }
+
+#endif /* __GPU_UNAI_GPU_RASTER_IMAGE_H__ */
index fc59b79..2a7b422 100644 (file)
@@ -1,6 +1,7 @@
 /***************************************************************************
 *   Copyright (C) 2010 PCSX4ALL Team                                      *
 *   Copyright (C) 2010 Unai                                               *
+*   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
 ***************************************************************************/
 
-#define        GPU_TESTRANGE(x)      { if((u32)(x+1024) > 2047) return; }
+#ifndef __GPU_UNAI_GPU_RASTER_LINE_H__
+#define __GPU_UNAI_GPU_RASTER_LINE_H__
 
 ///////////////////////////////////////////////////////////////////////////////
 //  GPU internal line drawing functions
+//
+// Rewritten October 2016 by senquack:
+//  Instead of one pixel at a time, lines are now drawn in runs of pixels,
+//  whether vertical, horizontal, or diagonal. A new inner driver
+//  'gpuPixelSpanFn' is used, as well as an enhanced Bresenham run-slice
+//  algorithm. For more information, see the following:
+//
+//  Michael Abrash - Graphics Programming Black Book
+//  Chapters 35 - 36 (does not implement diagonal runs)
+//  http://www.drdobbs.com/parallel/graphics-programming-black-book/184404919
+//  http://www.jagregory.com/abrash-black-book/
+//
+//  Article by Andrew Delong (does not implement diagonal runs)
+//  http://timetraces.ca/nw/drawline.htm
+//
+//  'Run-Based Multi-Point Line Drawing' by Eun Jae Lee & Larry F. Hodges
+//  https://smartech.gatech.edu/bitstream/handle/1853/3632/93-22.pdf
+//  Provided the idea of doing a half-octant transform allowing lines with
+//  slopes between 0.5 and 2.0 (diagonal runs of pixels) to be handled
+//  identically to the traditional horizontal/vertical run-slice method.
 
-#define GPU_DIGITS  16
-#define GPU_DIGITSC (GPU_DIGITS+3)
+// Use 16.16 fixed point precision for line math.
+// NOTE: Gouraud colors used by gpuPixelSpanFn can use a different precision.
+#define GPU_LINE_FIXED_BITS 16
 
-INLINE s32 GPU_DIV(s32 rs, s32 rt)
-{
-       return rt ? (rs / rt) : (0);
-}
+// If defined, Gouraud lines will use fixed-point multiply-by-inverse to
+// do most divisions. With enough accuracy, this should be OK.
+#define USE_LINES_ALL_FIXED_PT_MATH
 
-///////////////////////////////////////////////////////////////////////////////
-void gpuDrawLF(const PD gpuPixelDriver)
+//////////////////////
+// Flat-shaded line //
+//////////////////////
+void gpuDrawLineF(PtrUnion packet, const PSD gpuPixelSpanDriver)
 {
-       s32 temp;
-       s32 xmin, xmax;
-       s32 ymin, ymax;
-       s32 x0, x1, dx;
-       s32 y0, y1, dy;
-
-       x0 = PacketBuffer.S2[2] + DrawingOffset[0];     GPU_TESTRANGE(x0);
-       y0 = PacketBuffer.S2[3] + DrawingOffset[1];     GPU_TESTRANGE(y0);
-       x1 = PacketBuffer.S2[4] + DrawingOffset[0];     GPU_TESTRANGE(x1);
-       y1 = PacketBuffer.S2[5] + DrawingOffset[1];     GPU_TESTRANGE(y1);
-
-       xmin = DrawingArea[0];  xmax = DrawingArea[2];
-       ymin = DrawingArea[1];  ymax = DrawingArea[3];
-       const u16 pixeldata = GPU_RGB16(PacketBuffer.U4[0]);
-
-       dy = (y1 - y0);
-       if (dy < 0) dy = -dy;
-       dx = (x1 - x0);
-       if (dx < 0) dx = -dx;
-       if (dx > dy) {
-               if (x0 > x1) {
-                       GPU_SWAP(x0, x1, temp);
-                       GPU_SWAP(y0, y1, temp);
+       int x0, y0, x1, y1;
+       int dx, dy;
+
+       // All three of these variables should be signed (so multiplication works)
+       ptrdiff_t sx;  // Sign of x delta, positive when x0 < x1
+       const ptrdiff_t dst_depth  = FRAME_BYTES_PER_PIXEL; // PSX: 2 bytes per pixel
+       const ptrdiff_t dst_stride = FRAME_BYTE_STRIDE;     // PSX: 2048 bytes per framebuffer line
+
+       // Clip region: xmax/ymax seem to normally be one *past* the rightmost/
+       //  bottommost pixels of the draw area. Since we render every pixel between
+       //  and including both line endpoints, subtract one from xmax/ymax.
+       const int xmin = gpu_unai.DrawingArea[0];
+       const int ymin = gpu_unai.DrawingArea[1];
+       const int xmax = gpu_unai.DrawingArea[2] - 1;
+       const int ymax = gpu_unai.DrawingArea[3] - 1;
+
+       x0 = GPU_EXPANDSIGN(packet.S2[2]) + gpu_unai.DrawingOffset[0];
+       y0 = GPU_EXPANDSIGN(packet.S2[3]) + gpu_unai.DrawingOffset[1];
+       x1 = GPU_EXPANDSIGN(packet.S2[4]) + gpu_unai.DrawingOffset[0];
+       y1 = GPU_EXPANDSIGN(packet.S2[5]) + gpu_unai.DrawingOffset[1];
+
+       // Always draw top to bottom, so ensure y0 <= y1
+       if (y0 > y1) {
+               SwapValues(y0, y1);
+               SwapValues(x0, x1);
+       }
+
+       // Is line totally outside Y clipping range?
+       if (y0 > ymax || y1 < ymin) return;
+
+       dx = x1 - x0;
+       dy = y1 - y0;
+
+       // X-axis range check : max distance between any two X coords is 1023
+       // (PSX hardware will not render anything violating this rule)
+       // NOTE: We'll check y coord range further below
+       if (dx >= CHKMAX_X || dx <= -CHKMAX_X)
+               return;
+
+       // Y-axis range check and clipping
+       if (dy) {
+               // Y-axis range check : max distance between any two Y coords is 511
+               // (PSX hardware will not render anything violating this rule)
+               if (dy >= CHKMAX_Y)
+                       return;
+
+               // We already know y0 < y1
+               if (y0 < ymin) {
+                       x0 += GPU_FAST_DIV(((ymin - y0) * dx), dy);
+                       y0 = ymin;
                }
-               y1 = GPU_DIV((y1 - y0) << GPU_DIGITS, dx);
-               y0 <<= GPU_DIGITS;
-               temp = xmin - x0;
-               if (temp > 0) {
-                       x0 = xmin;
-                       y0 += (y1 * temp);
+               if (y1 > ymax) {
+                       x1 += GPU_FAST_DIV(((ymax - y1) * dx), dy);
+                       y1 = ymax;
                }
-               if (x1 > xmax) x1 = xmax;
-               x1 -= x0;
-               if (x1 < 0) x1 = 0;
-
-               const int li=linesInterlace;
-               for (; x1; x1--) {
-                       temp = y0 >> GPU_DIGITS;
-                       if( 0 == (temp&li) )  {
-                               if ((u32) (temp - ymin) < (u32) (ymax - ymin)) {
-                                       gpuPixelDriver(&((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0, temp)],pixeldata);
-                               }
+
+               // Recompute in case clipping occurred:
+               dx = x1 - x0;
+               dy = y1 - y0;
+       }
+
+       // Check X clipping range, set 'sx' x-direction variable
+       if (dx == 0) {
+               // Is vertical line totally outside X clipping range?
+               if (x0 < xmin || x0 > xmax)
+                       return;
+               sx = 0;
+       } else {
+               if (dx > 0) {
+                       // x0 is leftmost coordinate
+                       if (x0 > xmax) return; // Both points outside X clip range
+
+                       if (x0 < xmin) {
+                               if (x1 < xmin) return; // Both points outside X clip range
+                               y0 += GPU_FAST_DIV(((xmin - x0) * dy), dx);
+                               x0 = xmin;
                        }
-                       x0++;
-                       y0 += y1;
+
+                       if (x1 > xmax) {
+                               y1 += GPU_FAST_DIV(((xmax - x1) * dy), dx);
+                               x1 = xmax;
+                       }
+
+                       sx = +1;
+                       dx = x1 - x0; // Get final value, which should also be absolute value
+               } else {
+                       // x1 is leftmost coordinate
+                       if (x1 > xmax) return; // Both points outside X clip range
+
+                       if (x1 < xmin) {
+                               if (x0 < xmin) return; // Both points outside X clip range
+
+                               y1 += GPU_FAST_DIV(((xmin - x1) * dy), dx);
+                               x1 = xmin;
+                       }
+
+                       if (x0 > xmax) {
+                               y0 += GPU_FAST_DIV(((xmax - x0) * dy), dx);
+                               x0 = xmax;
+                       }
+
+                       sx = -1;
+                       dx = x0 - x1; // Get final value, which should also be absolute value
+               }
+
+               // Recompute in case clipping occurred:
+               dy = y1 - y0;
+       }
+
+       // IMPORTANT: dx,dy should now contain their absolute values
+
+       int min_length,    // Minimum length of a pixel run
+           start_length,  // Length of first run
+           end_length,    // Length of last run
+           err_term,      // Cumulative error to determine when to draw longer run
+           err_adjup,     // Increment to err_term for each run drawn
+           err_adjdown;   // Subract this from err_term after drawing longer run
+
+       // Color to draw with (16 bits, highest of which is unset mask bit)
+       uintptr_t col16 = GPU_RGB16(packet.U4[0]);
+
+       // We use u8 pointers even though PS1 has u16 framebuffer.
+       //  This allows pixel-drawing functions to increment dst pointer
+       //  directly by the passed 'incr' value, not having to shift it first.
+       u8 *dst = (u8*)gpu_unai.vram + y0 * dst_stride + x0 * dst_depth;
+
+       // SPECIAL CASE: Vertical line
+       if (dx == 0) {
+               gpuPixelSpanDriver(dst, col16, dst_stride, dy+1);
+               return;
+       }
+
+       // SPECIAL CASE: Horizontal line
+       if (dy == 0) {
+               gpuPixelSpanDriver(dst, col16, sx * dst_depth, dx+1);
+               return;
+       }
+
+       // SPECIAL CASE: Diagonal line
+       if (dx == dy) {
+               gpuPixelSpanDriver(dst, col16, dst_stride + (sx * dst_depth), dy+1);
+               return;
+       }
+
+       int       major, minor;             // Major axis, minor axis
+       ptrdiff_t incr_major, incr_minor;   // Ptr increment for each step along axis
+
+       if (dx > dy) {
+               major = dx;
+               minor = dy;
+       } else {
+               major = dy;
+               minor = dx;
+       }
+
+       // Determine if diagonal or horizontal runs
+       if (major < (2 * minor)) {
+               // Diagonal runs, so perform half-octant transformation
+               minor = major - minor;
+
+               // Advance diagonally when drawing runs
+               incr_major = dst_stride + (sx * dst_depth);
+
+               // After drawing each run, correct for over-advance along minor axis
+               if (dx > dy)
+                       incr_minor = -dst_stride;
+               else
+                       incr_minor = -sx * dst_depth;
+       } else {
+               // Horizontal or vertical runs
+               if (dx > dy) {
+                       incr_major = sx * dst_depth;
+                       incr_minor = dst_stride;
+               } else {
+                       incr_major = dst_stride;
+                       incr_minor = sx * dst_depth;
                }
-       } else if (dy) {
-               if (y0 > y1) {
-                       GPU_SWAP(x0, x1, temp);
-                       GPU_SWAP(y0, y1, temp);
+       }
+
+       if (minor > 1) {
+               // Minimum number of pixels each run
+               min_length = major / minor;
+
+               // Initial error term; reflects an initial step of 0.5 along minor axis
+               err_term = (major % minor) - (minor * 2);
+
+               // Increment err_term this much each step along minor axis; when
+               //  err_term crosses zero, draw longer pixel run.
+               err_adjup = (major % minor) * 2;
+       } else {
+               min_length = major;
+               err_term = 0;
+               err_adjup = 0;
+       }
+
+       // Error term adjustment when err_term turns over; used to factor
+       //  out the major-axis step made at that time
+       err_adjdown = minor * 2;
+
+       // The initial and last runs are partial, because minor axis advances
+       //  only 0.5 for these runs, rather than 1. Each is half a full run,
+       //  plus the initial pixel.
+       start_length = end_length = (min_length / 2) + 1;
+
+       if (min_length & 1) {
+               // If there're an odd number of pixels per run, we have 1 pixel that
+               //  can't be allocated to either the initial or last partial run, so
+               //  we'll add 0.5 to err_term so that this pixel will be handled
+               //  by the normal full-run loop
+               err_term += minor;
+       } else {
+               // If the minimum run length is even and there's no fractional advance,
+               // we have one pixel that could go to either the initial or last
+               // partial run, which we arbitrarily allocate to the last run
+               if (err_adjup == 0)
+                       start_length--; // Leave out the extra pixel at the start
+       }
+
+       // First run of pixels
+       dst = gpuPixelSpanDriver(dst, col16, incr_major, start_length);
+       dst += incr_minor;
+
+       // Middle runs of pixels
+       while (--minor > 0) {
+               int run_length = min_length;
+               err_term += err_adjup;
+
+               // If err_term passed 0, reset it and draw longer run
+               if (err_term > 0) {
+                       err_term -= err_adjdown;
+                       run_length++;
                }
-               x1 = GPU_DIV((x1 - x0) << GPU_DIGITS, dy);
-               x0 <<= GPU_DIGITS;
-               temp = ymin - y0;
-               if (temp > 0) {
+
+               dst = gpuPixelSpanDriver(dst, col16, incr_major, run_length);
+               dst += incr_minor;
+       }
+
+       // Final run of pixels
+       gpuPixelSpanDriver(dst, col16, incr_major, end_length);
+}
+
+/////////////////////////
+// Gouraud-shaded line //
+/////////////////////////
+void gpuDrawLineG(PtrUnion packet, const PSD gpuPixelSpanDriver)
+{
+       int x0, y0, x1, y1;
+       int dx, dy, dr, dg, db;
+       u32 r0, g0, b0, r1, g1, b1;
+
+       // All three of these variables should be signed (so multiplication works)
+       ptrdiff_t sx;  // Sign of x delta, positive when x0 < x1
+       const ptrdiff_t dst_depth  = FRAME_BYTES_PER_PIXEL; // PSX: 2 bytes per pixel
+       const ptrdiff_t dst_stride = FRAME_BYTE_STRIDE;     // PSX: 2048 bytes per framebuffer line
+
+       // Clip region: xmax/ymax seem to normally be one *past* the rightmost/
+       //  bottommost pixels of the draw area. We'll render every pixel between
+       //  and including both line endpoints, so subtract one from xmax/ymax.
+       const int xmin = gpu_unai.DrawingArea[0];
+       const int ymin = gpu_unai.DrawingArea[1];
+       const int xmax = gpu_unai.DrawingArea[2] - 1;
+       const int ymax = gpu_unai.DrawingArea[3] - 1;
+
+       x0 = GPU_EXPANDSIGN(packet.S2[2]) + gpu_unai.DrawingOffset[0];
+       y0 = GPU_EXPANDSIGN(packet.S2[3]) + gpu_unai.DrawingOffset[1];
+       x1 = GPU_EXPANDSIGN(packet.S2[6]) + gpu_unai.DrawingOffset[0];
+       y1 = GPU_EXPANDSIGN(packet.S2[7]) + gpu_unai.DrawingOffset[1];
+
+       u32 col0 = packet.U4[0];
+       u32 col1 = packet.U4[2];
+
+       // Always draw top to bottom, so ensure y0 <= y1
+       if (y0 > y1) {
+               SwapValues(y0, y1);
+               SwapValues(x0, x1);
+               SwapValues(col0, col1);
+       }
+
+       // Is line totally outside Y clipping range?
+       if (y0 > ymax || y1 < ymin) return;
+
+       // If defined, Gouraud colors are fixed-point 5.11, otherwise they are 8.16
+       // (This is only beneficial if using SIMD-optimized pixel driver)
+#ifdef GPU_GOURAUD_LOW_PRECISION
+       r0 = (col0 >> 3) & 0x1f;  g0 = (col0 >> 11) & 0x1f;  b0 = (col0 >> 19) & 0x1f;
+       r1 = (col1 >> 3) & 0x1f;  g1 = (col1 >> 11) & 0x1f;  b1 = (col1 >> 19) & 0x1f;
+#else
+       r0 = col0 & 0xff;  g0 = (col0 >> 8) & 0xff;  b0 = (col0 >> 16) & 0xff;
+       r1 = col1 & 0xff;  g1 = (col1 >> 8) & 0xff;  b1 = (col1 >> 16) & 0xff;
+#endif
+
+       dx = x1 - x0;
+       dy = y1 - y0;
+       dr = r1 - r0;
+       dg = g1 - g0;
+       db = b1 - b0;
+
+       // X-axis range check : max distance between any two X coords is 1023
+       // (PSX hardware will not render anything violating this rule)
+       // NOTE: We'll check y coord range further below
+       if (dx >= CHKMAX_X || dx <= -CHKMAX_X)
+               return;
+
+       // Y-axis range check and clipping
+       if (dy) {
+               // Y-axis range check : max distance between any two Y coords is 511
+               // (PSX hardware will not render anything violating this rule)
+               if (dy >= CHKMAX_Y)
+                       return;
+
+               // We already know y0 < y1
+               if (y0 < ymin) {
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+                       s32 factor = GPU_FAST_DIV(((ymin - y0) << GPU_LINE_FIXED_BITS), dy);
+                       x0 += (dx * factor) >> GPU_LINE_FIXED_BITS;
+                       r0 += (dr * factor) >> GPU_LINE_FIXED_BITS;
+                       g0 += (dg * factor) >> GPU_LINE_FIXED_BITS;
+                       b0 += (db * factor) >> GPU_LINE_FIXED_BITS;
+#else
+                       x0 += (ymin - y0) * dx / dy;
+                       r0 += (ymin - y0) * dr / dy;
+                       g0 += (ymin - y0) * dg / dy;
+                       b0 += (ymin - y0) * db / dy;
+#endif
                        y0 = ymin;
-                       x0 += (x1 * temp);
                }
-               if (y1 > ymax) y1 = ymax;
-               y1 -= y0;
-               if (y1 < 0) y1 = 0;
-               
-               const int li=linesInterlace;
-               for (; y1; y1--) {
-                       if( 0 == (y0&li) )  {
-                               temp = x0 >> GPU_DIGITS;
-                               if ((u32) (temp - xmin) < (u32) (xmax - xmin)) {
-                                       gpuPixelDriver(&((u16*)GPU_FrameBuffer)[FRAME_OFFSET(temp, y0)],pixeldata);
-                               }
-                       }
-                       y0++;
-                       x0 += x1;
+
+               if (y1 > ymax) {
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+                       s32 factor = GPU_FAST_DIV(((ymax - y1) << GPU_LINE_FIXED_BITS), dy);
+                       x1 += (dx * factor) >> GPU_LINE_FIXED_BITS;
+                       r1 += (dr * factor) >> GPU_LINE_FIXED_BITS;
+                       g1 += (dg * factor) >> GPU_LINE_FIXED_BITS;
+                       b1 += (db * factor) >> GPU_LINE_FIXED_BITS;
+#else
+                       x1 += (ymax - y1) * dx / dy;
+                       r1 += (ymax - y1) * dr / dy;
+                       g1 += (ymax - y1) * dg / dy;
+                       b1 += (ymax - y1) * db / dy;
+#endif
+                       y1 = ymax;
                }
-               
+
+               // Recompute in case clipping occurred:
+               dx = x1 - x0;
+               dy = y1 - y0;
+               dr = r1 - r0;
+               dg = g1 - g0;
+               db = b1 - b0;
+       }
+
+       // Check X clipping range, set 'sx' x-direction variable
+       if (dx == 0) {
+               // Is vertical line totally outside X clipping range?
+               if (x0 < xmin || x0 > xmax)
+                       return;
+               sx = 0;
        } else {
-               if( 0 == (y0&linesInterlace) )  {
-                       if ((u32) (x0 - xmin) < (u32) (xmax - xmin)) {
-                               if ((u32) (y0 - ymin) < (u32) (ymax - ymin)) {
-                                       gpuPixelDriver(&((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0, y0)],pixeldata);
-                               }
+               if (dx > 0) {
+                       // x0 is leftmost coordinate
+                       if (x0 > xmax) return; // Both points outside X clip range
+
+                       if (x0 < xmin) {
+                               if (x1 < xmin) return; // Both points outside X clip range
+
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+                               s32 factor = GPU_FAST_DIV(((xmin - x0) << GPU_LINE_FIXED_BITS), dx);
+                               y0 += (dy * factor) >> GPU_LINE_FIXED_BITS;
+                               r0 += (dr * factor) >> GPU_LINE_FIXED_BITS;
+                               g0 += (dg * factor) >> GPU_LINE_FIXED_BITS;
+                               b0 += (db * factor) >> GPU_LINE_FIXED_BITS;
+#else
+                               y0 += (xmin - x0) * dy / dx;
+                               r0 += (xmin - x0) * dr / dx;
+                               g0 += (xmin - x0) * dg / dx;
+                               b0 += (xmin - x0) * db / dx;
+#endif
+                               x0 = xmin;
+                       }
+
+                       if (x1 > xmax) {
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+                               s32 factor = GPU_FAST_DIV(((xmax - x1) << GPU_LINE_FIXED_BITS), dx);
+                               y1 += (dy * factor) >> GPU_LINE_FIXED_BITS;
+                               r1 += (dr * factor) >> GPU_LINE_FIXED_BITS;
+                               g1 += (dg * factor) >> GPU_LINE_FIXED_BITS;
+                               b1 += (db * factor) >> GPU_LINE_FIXED_BITS;
+#else
+                               y1 += (xmax - x1) * dy / dx;
+                               r1 += (xmax - x1) * dr / dx;
+                               g1 += (xmax - x1) * dg / dx;
+                               b1 += (xmax - x1) * db / dx;
+#endif
+                               x1 = xmax;
+                       }
+
+                       sx = +1;
+                       dx = x1 - x0; // Get final value, which should also be absolute value
+               } else {
+                       // x1 is leftmost coordinate
+                       if (x1 > xmax) return; // Both points outside X clip range
+
+                       if (x1 < xmin) {
+                               if (x0 < xmin) return; // Both points outside X clip range
+
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+                               s32 factor = GPU_FAST_DIV(((xmin - x1) << GPU_LINE_FIXED_BITS), dx);
+                               y1 += (dy * factor) >> GPU_LINE_FIXED_BITS;
+                               r1 += (dr * factor) >> GPU_LINE_FIXED_BITS;
+                               g1 += (dg * factor) >> GPU_LINE_FIXED_BITS;
+                               b1 += (db * factor) >> GPU_LINE_FIXED_BITS;
+#else
+                               y1 += (xmin - x1) * dy / dx;
+                               r1 += (xmin - x1) * dr / dx;
+                               g1 += (xmin - x1) * dg / dx;
+                               b1 += (xmin - x1) * db / dx;
+#endif
+                               x1 = xmin;
                        }
+
+                       if (x0 > xmax) {
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+                               s32 factor = GPU_FAST_DIV(((xmax - x0) << GPU_LINE_FIXED_BITS), dx);
+                               y0 += (dy * factor) >> GPU_LINE_FIXED_BITS;
+                               r0 += (dr * factor) >> GPU_LINE_FIXED_BITS;
+                               g0 += (dg * factor) >> GPU_LINE_FIXED_BITS;
+                               b0 += (db * factor) >> GPU_LINE_FIXED_BITS;
+#else
+                               y0 += (xmax - x0) * dy / dx;
+                               r0 += (xmax - x0) * dr / dx;
+                               g0 += (xmax - x0) * dg / dx;
+                               b0 += (xmax - x0) * db / dx;
+#endif
+                               x0 = xmax;
+                       }
+
+                       sx = -1;
+                       dx = x0 - x1; // Get final value, which should also be absolute value
                }
+
+               // Recompute in case clipping occurred:
+               dy = y1 - y0;
+               dr = r1 - r0;
+               dg = g1 - g0;
+               db = b1 - b0;
        }
-}
 
-/*----------------------------------------------------------------------
-GF
-----------------------------------------------------------------------*/
+       // IMPORTANT: dx,dy should now contain their absolute values
 
-///////////////////////////////////////////////////////////////////////////////
-void gpuDrawLG(const PD gpuPixelDriver)
-{
-       s32 temp;
-       s32 xmin, xmax;
-       s32 ymin, ymax;
-       s32 x0, x1, dx;
-       s32 y0, y1, dy;
-       s32 r0, r1;
-       s32 g0, g1;
-       s32 b0, b1;
-
-       x0 = PacketBuffer.S2[2] + DrawingOffset[0];     GPU_TESTRANGE(x0);
-       y0 = PacketBuffer.S2[3] + DrawingOffset[1];     GPU_TESTRANGE(y0);
-       x1 = PacketBuffer.S2[6] + DrawingOffset[0];     GPU_TESTRANGE(x1);
-       y1 = PacketBuffer.S2[7] + DrawingOffset[1];     GPU_TESTRANGE(y1);
-
-       r0 = PacketBuffer.U1[0];  g0 = PacketBuffer.U1[1];  b0 = PacketBuffer.U1[2];
-       r1 = PacketBuffer.U1[8];  g1 = PacketBuffer.U1[9];      b1 = PacketBuffer.U1[10];
-
-       xmin = DrawingArea[0];  xmax = DrawingArea[2];
-       ymin = DrawingArea[1];  ymax = DrawingArea[3];
-
-       dy = (y1 - y0);
-       if (dy < 0)
-       dy = -dy;
-       dx = (x1 - x0);
-       if (dx < 0)
-       dx = -dx;
-       if (dx > dy) {
-               if (x0 > x1) {
-                       GPU_SWAP(x0, x1, temp);
-                       GPU_SWAP(y0, y1, temp);
-                       GPU_SWAP(r0, r1, temp);
-                       GPU_SWAP(g0, g1, temp);
-                       GPU_SWAP(b0, b1, temp);
-               }
-               y1 = GPU_DIV((y1 - y0) << GPU_DIGITS, dx);
-               r1 = GPU_DIV((r1 - r0) << GPU_DIGITS, dx);
-               g1 = GPU_DIV((g1 - g0) << GPU_DIGITS, dx);
-               b1 = GPU_DIV((b1 - b0) << GPU_DIGITS, dx);
-               y0 <<= GPU_DIGITS;
-               r0 <<= GPU_DIGITS;
-               g0 <<= GPU_DIGITS;
-               b0 <<= GPU_DIGITS;
-               temp = xmin - x0;
-               if (temp > 0) {
-                       x0 = xmin;
-                       y0 += (y1 * temp);
-                       r0 += (r1 * temp);
-                       g0 += (g1 * temp);
-                       b0 += (b1 * temp);
+       int min_length,    // Minimum length of a pixel run
+           start_length,  // Length of first run
+           end_length,    // Length of last run
+           err_term,      // Cumulative error to determine when to draw longer run
+           err_adjup,     // Increment to err_term for each run drawn
+           err_adjdown;   // Subract this from err_term after drawing longer run
+
+       GouraudColor gcol;
+       gcol.r = r0 << GPU_GOURAUD_FIXED_BITS;
+       gcol.g = g0 << GPU_GOURAUD_FIXED_BITS;
+       gcol.b = b0 << GPU_GOURAUD_FIXED_BITS;
+
+       // We use u8 pointers even though PS1 has u16 framebuffer.
+       //  This allows pixel-drawing functions to increment dst pointer
+       //  directly by the passed 'incr' value, not having to shift it first.
+       u8 *dst = (u8*)gpu_unai.vram + y0 * dst_stride + x0 * dst_depth;
+
+       // SPECIAL CASE: Vertical line
+       if (dx == 0) {
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+               // Get dy fixed-point inverse
+               s32 inv_factor = 1 << GPU_GOURAUD_FIXED_BITS;
+               if (dy > 1) inv_factor = GPU_FAST_DIV(inv_factor, dy);
+
+               // Simultaneously divide and convert integer to Gouraud fixed point:
+               gcol.r_incr = dr * inv_factor;
+               gcol.g_incr = dg * inv_factor;
+               gcol.b_incr = db * inv_factor;
+#else
+               // First, convert to Gouraud fixed point
+               gcol.r_incr = dr << GPU_GOURAUD_FIXED_BITS;
+               gcol.g_incr = dg << GPU_GOURAUD_FIXED_BITS;
+               gcol.b_incr = db << GPU_GOURAUD_FIXED_BITS;
+
+               if (dy > 1) {
+                       if (dr) gcol.r_incr /= dy;
+                       if (dg) gcol.g_incr /= dy;
+                       if (db) gcol.b_incr /= dy;
                }
-               if (x1 > xmax) x1 = xmax;
-               x1 -= x0;
-               if (x1 < 0) x1 = 0;
+#endif
                
-               const int li=linesInterlace;
-               for (; x1; x1--) {
-                       temp = y0 >> GPU_DIGITS;
-                       if( 0 == (temp&li) )  {
-                               if ((u32) (temp - ymin) < (u32) (ymax - ymin)) {
-                                       gpuPixelDriver (
-                                               &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0, temp)],
-                                               (((b0>>GPU_DIGITSC)&0x1F)<<10) | (((g0>>GPU_DIGITSC)&0x1F)<< 5) | ((r0>>GPU_DIGITSC)&0x1F)
-                                       );
-                               }
-                       }
-                       x0++;
-                       y0 += y1;
-                       r0 += r1;
-                       g0 += g1;
-                       b0 += b1;
-               }
-       } else if (dy) {
-               if (y0 > y1) {
-                       GPU_SWAP(x0, x1, temp);
-                       GPU_SWAP(y0, y1, temp);
-                       GPU_SWAP(r0, r1, temp);
-                       GPU_SWAP(g0, g1, temp);
-                       GPU_SWAP(b0, b1, temp);
+               gpuPixelSpanDriver(dst, (uintptr_t)&gcol, dst_stride, dy+1);
+               return;
+       }
+
+       // SPECIAL CASE: Horizontal line
+       if (dy == 0) {
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+               // Get dx fixed-point inverse
+               s32 inv_factor = (1 << GPU_GOURAUD_FIXED_BITS);
+               if (dx > 1) inv_factor = GPU_FAST_DIV(inv_factor, dx);
+
+               // Simultaneously divide and convert integer to Gouraud fixed point:
+               gcol.r_incr = dr * inv_factor;
+               gcol.g_incr = dg * inv_factor;
+               gcol.b_incr = db * inv_factor;
+#else
+               gcol.r_incr = dr << GPU_GOURAUD_FIXED_BITS;
+               gcol.g_incr = dg << GPU_GOURAUD_FIXED_BITS;
+               gcol.b_incr = db << GPU_GOURAUD_FIXED_BITS;
+
+               if (dx > 1) {
+                       if (dr) gcol.r_incr /= dx;
+                       if (dg) gcol.g_incr /= dx;
+                       if (db) gcol.b_incr /= dx;
                }
-               x1 = GPU_DIV((x1 - x0) << GPU_DIGITS, dy);
-               r1 = GPU_DIV((r1 - r0) << GPU_DIGITS, dy);
-               g1 = GPU_DIV((g1 - g0) << GPU_DIGITS, dy);
-               b1 = GPU_DIV((b1 - b0) << GPU_DIGITS, dy);
-               x0 <<= GPU_DIGITS;
-               r0 <<= GPU_DIGITS;
-               g0 <<= GPU_DIGITS;
-               b0 <<= GPU_DIGITS;
-               temp = ymin - y0;
-               if (temp > 0) {
-                       y0 = ymin;
-                       x0 += (x1 * temp);
-                       r0 += (r1 * temp);
-                       g0 += (g1 * temp);
-                       b0 += (b1 * temp);
+#endif
+
+               gpuPixelSpanDriver(dst, (uintptr_t)&gcol, sx * dst_depth, dx+1);
+               return;
+       }
+
+       // SPECIAL CASE: Diagonal line
+       if (dx == dy) {
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+               // Get dx fixed-point inverse
+               s32 inv_factor = (1 << GPU_GOURAUD_FIXED_BITS);
+               if (dx > 1) inv_factor = GPU_FAST_DIV(inv_factor, dx);
+
+               // Simultaneously divide and convert integer to Gouraud fixed point:
+               gcol.r_incr = dr * inv_factor;
+               gcol.g_incr = dg * inv_factor;
+               gcol.b_incr = db * inv_factor;
+#else
+               // First, convert to Gouraud fixed point
+               gcol.r_incr = dr << GPU_GOURAUD_FIXED_BITS;
+               gcol.g_incr = dg << GPU_GOURAUD_FIXED_BITS;
+               gcol.b_incr = db << GPU_GOURAUD_FIXED_BITS;
+
+               if (dx > 1) {
+                       if (dr) gcol.r_incr /= dx;
+                       if (dg) gcol.g_incr /= dx;
+                       if (db) gcol.b_incr /= dx;
                }
-               if (y1 > ymax) y1 = ymax;
-               y1 -= y0;
-               if (y1 < 0) y1 = 0;
-               
-               const int li=linesInterlace;
-               for (; y1; y1--) {
-                       if( 0 == (y0&li) )  {
-                               temp = x0 >> GPU_DIGITS;
-                               if ((u32) (temp - xmin) < (u32) (xmax - xmin)) {
-                                       gpuPixelDriver (
-                                               &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(temp, y0)],
-                                               (((b0>>GPU_DIGITSC)&0x1F)<<10) | (((g0>>GPU_DIGITSC)&0x1F)<< 5) | ((r0>>GPU_DIGITSC)&0x1F)
-                                       );
-                               }
-                       }
-                       y0++;
-                       x0 += x1;
-                       r0 += r1;
-                       g0 += g1;
-                       b0 += b1;
+#endif
+
+               gpuPixelSpanDriver(dst, (uintptr_t)&gcol, dst_stride + (sx * dst_depth), dy+1);
+               return;
+       }
+
+       int       major, minor;             // Absolute val of major,minor axis delta
+       ptrdiff_t incr_major, incr_minor;   // Ptr increment for each step along axis
+
+       if (dx > dy) {
+               major = dx;
+               minor = dy;
+       } else {
+               major = dy;
+               minor = dx;
+       }
+
+       // Determine if diagonal or horizontal runs
+       if (major < (2 * minor)) {
+               // Diagonal runs, so perform half-octant transformation
+               minor = major - minor;
+
+               // Advance diagonally when drawing runs
+               incr_major = dst_stride + (sx * dst_depth);
+
+               // After drawing each run, correct for over-advance along minor axis
+               if (dx > dy)
+                       incr_minor = -dst_stride;
+               else
+                       incr_minor = -sx * dst_depth;
+       } else {
+               // Horizontal or vertical runs
+               if (dx > dy) {
+                       incr_major = sx * dst_depth;
+                       incr_minor = dst_stride;
+               } else {
+                       incr_major = dst_stride;
+                       incr_minor = sx * dst_depth;
                }
+       }
+
+#ifdef USE_LINES_ALL_FIXED_PT_MATH
+       s32 major_inv = GPU_FAST_DIV((1 << GPU_GOURAUD_FIXED_BITS), major);
+
+       // Simultaneously divide and convert from integer to Gouraud fixed point:
+       gcol.r_incr = dr * major_inv;
+       gcol.g_incr = dg * major_inv;
+       gcol.b_incr = db * major_inv;
+#else
+       gcol.r_incr = dr ? ((dr << GPU_GOURAUD_FIXED_BITS) / major) : 0;
+       gcol.g_incr = dg ? ((dg << GPU_GOURAUD_FIXED_BITS) / major) : 0;
+       gcol.b_incr = db ? ((db << GPU_GOURAUD_FIXED_BITS) / major) : 0;
+#endif
+
+       if (minor > 1) {
+               // Minimum number of pixels each run
+               min_length = major / minor;
+
+               // Initial error term; reflects an initial step of 0.5 along minor axis
+               err_term = (major % minor) - (minor * 2);
+
+               // Increment err_term this much each step along minor axis; when
+               //  err_term crosses zero, draw longer pixel run.
+               err_adjup = (major % minor) * 2;
        } else {
-               if( 0 == (y0&linesInterlace) )  {
-                       if ((u32) (x0 - xmin) < (u32) (xmax - xmin)) {
-                               if ((u32) (y0 - ymin) < (u32) (ymax - ymin)) {
-                                       gpuPixelDriver (
-                                               &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0, y0)],
-                                               (((b0>>GPU_DIGITSC)&0x1F)<<10) | (((g0>>GPU_DIGITSC)&0x1F)<< 5) | ((r0>>GPU_DIGITSC)&0x1F)
-                                       );
-                               }
-                       }
+               min_length = major;
+               err_term = 0;
+               err_adjup = 0;
+       }
+
+       // Error term adjustment when err_term turns over; used to factor
+       //  out the major-axis step made at that time
+       err_adjdown = minor * 2;
+
+       // The initial and last runs are partial, because minor axis advances
+       //  only 0.5 for these runs, rather than 1. Each is half a full run,
+       //  plus the initial pixel.
+       start_length = end_length = (min_length / 2) + 1;
+
+       if (min_length & 1) {
+               // If there're an odd number of pixels per run, we have 1 pixel that
+               //  can't be allocated to either the initial or last partial run, so
+               //  we'll add 0.5 to err_term so that this pixel will be handled
+               //  by the normal full-run loop
+               err_term += minor;
+       } else {
+               // If the minimum run length is even and there's no fractional advance,
+               // we have one pixel that could go to either the initial or last
+               // partial run, which we'll arbitrarily allocate to the last run
+               if (err_adjup == 0)
+                       start_length--; // Leave out the extra pixel at the start
+       }
+
+       // First run of pixels
+       dst = gpuPixelSpanDriver(dst, (uintptr_t)&gcol, incr_major, start_length);
+       dst += incr_minor;
+
+       // Middle runs of pixels
+       while (--minor > 0) {
+               int run_length = min_length;
+               err_term += err_adjup;
+
+               // If err_term passed 0, reset it and draw longer run
+               if (err_term > 0) {
+                       err_term -= err_adjdown;
+                       run_length++;
                }
+
+               dst = gpuPixelSpanDriver(dst, (uintptr_t)&gcol, incr_major, run_length);
+               dst += incr_minor;
        }
+
+       // Final run of pixels
+       gpuPixelSpanDriver(dst, (uintptr_t)&gcol, incr_major, end_length);
 }
+
+#endif /* __GPU_UNAI_GPU_RASTER_LINE_H__ */
index c4b0350..b30286d 100644 (file)
 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
 ***************************************************************************/
 
-#define GPU_TESTRANGE3() \
-{ \
-       if(x0<0) { if((x1-x0)>CHKMAX_X) return; if((x2-x0)>CHKMAX_X) return; } \
-       if(x1<0) { if((x0-x1)>CHKMAX_X) return; if((x2-x1)>CHKMAX_X) return; } \
-       if(x2<0) { if((x0-x2)>CHKMAX_X) return; if((x1-x2)>CHKMAX_X) return; } \
-       if(y0<0) { if((y1-y0)>CHKMAX_Y) return; if((y2-y0)>CHKMAX_Y) return; } \
-       if(y1<0) { if((y0-y1)>CHKMAX_Y) return; if((y2-y1)>CHKMAX_Y) return; } \
-       if(y2<0) { if((y0-y2)>CHKMAX_Y) return; if((y1-y2)>CHKMAX_Y) return; } \
-}
+#ifndef __GPU_UNAI_GPU_RASTER_POLYGON_H__
+#define __GPU_UNAI_GPU_RASTER_POLYGON_H__
+
+//senquack - NOTE: GPU Unai poly routines have been rewritten/adapted
+// from DrHell routines to fix multiple issues. See README_senquack.txt
 
 ///////////////////////////////////////////////////////////////////////////////
-//  GPU internal polygon drawing functions
+// Shared poly vertex buffer, able to handle 3 or 4-pt polys of any type.
+///////////////////////////////////////////////////////////////////////////////
+
+struct PolyVertex {
+       s32 x, y; // Sign-extended 11-bit X,Y coords
+       union {
+               struct { u8 u, v, pad[2]; } tex; // Texture coords (if used)
+               u32 tex_word;
+       };
+       union {
+               struct { u8 r, g, b, pad; } col; // 24-bit RGB color (if used)
+               u32 col_word;
+       };
+};
+
+enum PolyAttribute {
+       POLYATTR_TEXTURE = (1 << 0),
+       POLYATTR_GOURAUD = (1 << 1)
+};
+
+enum PolyType {
+       POLYTYPE_F  = 0,
+       POLYTYPE_FT = (POLYATTR_TEXTURE),
+       POLYTYPE_G  = (POLYATTR_GOURAUD),
+       POLYTYPE_GT = (POLYATTR_TEXTURE | POLYATTR_GOURAUD)
+};
 
 ///////////////////////////////////////////////////////////////////////////////
-void gpuDrawF3(const PP gpuPolySpanDriver)
+// polyInitVertexBuffer()
+// Fills vbuf[] array with data from any type of poly draw-command packet.
+///////////////////////////////////////////////////////////////////////////////
+static void polyInitVertexBuffer(PolyVertex *vbuf, const PtrUnion packet, PolyType ptype, u32 is_quad)
 {
-       const int li=linesInterlace;
-       s32 temp;
-       s32 xa, xb, xmin, xmax;
-       s32 ya, yb, ymin, ymax;
-       s32 x0, x1, x2, x3, dx3=0, x4, dx4=0, dx;
-       s32 y0, y1, y2;
+       bool texturing = ptype & POLYATTR_TEXTURE;
+       bool gouraud   = ptype & POLYATTR_GOURAUD;
+
+       int vert_stride = 1; // Stride of vertices in cmd packet, in 32-bit words
+       if (texturing)
+               vert_stride++;
+       if (gouraud)
+               vert_stride++;
+
+       int num_verts = (is_quad) ? 4 : 3;
+       u32 *ptr;
+
+       // X,Y coords, adjusted by draw offsets
+       s32 x_off = gpu_unai.DrawingOffset[0];
+       s32 y_off = gpu_unai.DrawingOffset[1];
+       ptr = &packet.U4[1];
+       for (int i=0;  i < num_verts; ++i, ptr += vert_stride) {
+               s16* coord_ptr = (s16*)ptr;
+               vbuf[i].x = GPU_EXPANDSIGN(coord_ptr[0]) + x_off;
+               vbuf[i].y = GPU_EXPANDSIGN(coord_ptr[1]) + y_off;
+       }
 
-       x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2]);
-       y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3]);
-       x1 = GPU_EXPANDSIGN(PacketBuffer.S2[4]);
-       y1 = GPU_EXPANDSIGN(PacketBuffer.S2[5]);
-       x2 = GPU_EXPANDSIGN(PacketBuffer.S2[6]);
-       y2 = GPU_EXPANDSIGN(PacketBuffer.S2[7]);
+       // U,V texture coords (if applicable)
+       if (texturing) {
+               ptr = &packet.U4[2];
+               for (int i=0;  i < num_verts; ++i, ptr += vert_stride)
+                       vbuf[i].tex_word = *ptr;
+       }
 
-       GPU_TESTRANGE3();
+       // Colors (if applicable)
+       if (gouraud) {
+               ptr = &packet.U4[0];
+               for (int i=0;  i < num_verts; ++i, ptr += vert_stride)
+                       vbuf[i].col_word = *ptr;
+       }
+}
 
-       x0 += DrawingOffset[0];   x1 += DrawingOffset[0];   x2 += DrawingOffset[0];
-       y0 += DrawingOffset[1];   y1 += DrawingOffset[1];   y2 += DrawingOffset[1];
+///////////////////////////////////////////////////////////////////////////////
+//  Helper functions to determine which vertex in a 2 or 3 vertex array
+//   has the highest/lowest X/Y coordinate.
+//   Note: the comparison logic is such that, given a set of vertices with
+//    identical values for a given coordinate, a different index will be
+//    returned from vertIdxOfLeast..() than a call to vertIdxOfHighest..().
+//    This ensures that, during the vertex-ordering phase of rasterization,
+//    all three vertices remain unique.
+///////////////////////////////////////////////////////////////////////////////
 
-       xmin = DrawingArea[0];  xmax = DrawingArea[2];
-       ymin = DrawingArea[1];  ymax = DrawingArea[3];
+template<typename T>
+static inline int vertIdxOfLeastXCoord2(const T *Tptr)
+{
+       return (Tptr[0].x <= Tptr[1].x) ? 0 : 1;
+}
 
-       {
-               int rx0 = Max2(xmin,Min3(x0,x1,x2));
-               int ry0 = Max2(ymin,Min3(y0,y1,y2));
-               int rx1 = Min2(xmax,Max3(x0,x1,x2));
-               int ry1 = Min2(ymax,Max3(y0,y1,y2));
-               if( rx0>=rx1 || ry0>=ry1) return;
-       }
-       
-       PixelData = GPU_RGB16(PacketBuffer.U4[0]);
+template<typename T>
+static inline int vertIdxOfLeastXCoord3(const T *Tptr)
+{
+       int least_of_v0_v1 = vertIdxOfLeastXCoord2(Tptr);
+       return (Tptr[least_of_v0_v1].x <= Tptr[2].x) ? least_of_v0_v1 : 2;
+}
 
-       if (y0 >= y1)
-       {
-               if( y0!=y1 || x0>x1 )
-               {
-                       GPU_SWAP(x0, x1, temp);
-                       GPU_SWAP(y0, y1, temp);
-               }
-       }
-       if (y1 >= y2)
-       {
-               if( y1!=y2 || x1>x2 )
-               {
-                       GPU_SWAP(x1, x2, temp);
-                       GPU_SWAP(y1, y2, temp);
-               }
-       }
-       if (y0 >= y1)
-       {
-               if( y0!=y1 || x0>x1 )
-               {
-                       GPU_SWAP(x0, x1, temp);
-                       GPU_SWAP(y0, y1, temp);
-               }
-       }
+template<typename T>
+static inline int vertIdxOfLeastYCoord2(const T *Tptr)
+{
+       return (Tptr[0].y <= Tptr[1].y) ? 0 : 1;
+}
+
+template<typename T>
+static inline int vertIdxOfLeastYCoord3(const T *Tptr)
+{
+       int least_of_v0_v1 = vertIdxOfLeastYCoord2(Tptr);
+       return (Tptr[least_of_v0_v1].y <= Tptr[2].y) ? least_of_v0_v1 : 2;
+}
+
+template<typename T>
+static inline int vertIdxOfHighestXCoord2(const T *Tptr)
+{
+       return (Tptr[1].x >= Tptr[0].x) ? 1 : 0;
+}
+
+template<typename T>
+static inline int vertIdxOfHighestXCoord3(const T *Tptr)
+{
+       int highest_of_v0_v1 = vertIdxOfHighestXCoord2(Tptr);
+       return (Tptr[2].x >= Tptr[highest_of_v0_v1].x) ? 2 : highest_of_v0_v1;
+}
+
+template<typename T>
+static inline int vertIdxOfHighestYCoord2(const T *Tptr)
+{
+       return (Tptr[1].y >= Tptr[0].y) ? 1 : 0;
+}
+
+template<typename T>
+static inline int vertIdxOfHighestYCoord3(const T *Tptr)
+{
+       int highest_of_v0_v1 = vertIdxOfHighestYCoord2(Tptr);
+       return (Tptr[2].y >= Tptr[highest_of_v0_v1].y) ? 2 : highest_of_v0_v1;
+}
 
-       ya = y2 - y0;
-       yb = y2 - y1;
-       dx =(x2 - x1) * ya - (x2 - x0) * yb;
+///////////////////////////////////////////////////////////////////////////////
+// polyUseTriangle()
+//  Determines if the specified triangle should be rendered. If so, it
+//  fills the given array of vertex pointers, vert_ptrs, in order of
+//  increasing Y coordinate values, as required by rasterization algorithm.
+//  Parameter 'tri_num' is 0 for first triangle (idx 0,1,2 of vbuf[]),
+//   or 1 for second triangle of a quad (idx 1,2,3 of vbuf[]).
+//  Returns true if triangle should be rendered, false if not.
+///////////////////////////////////////////////////////////////////////////////
+static bool polyUseTriangle(const PolyVertex *vbuf, int tri_num, const PolyVertex **vert_ptrs)
+{
+       // Using verts 0,1,2 or is this the 2nd pass of a quad (verts 1,2,3)?
+       const PolyVertex *tri_ptr = &vbuf[(tri_num == 0) ? 0 : 1];
+
+       // Get indices of highest/lowest X,Y coords within triangle
+       int idx_lowest_x  = vertIdxOfLeastXCoord3(tri_ptr);
+       int idx_highest_x = vertIdxOfHighestXCoord3(tri_ptr);
+       int idx_lowest_y  = vertIdxOfLeastYCoord3(tri_ptr);
+       int idx_highest_y = vertIdxOfHighestYCoord3(tri_ptr);
+
+       // Maximum absolute distance between any two X coordinates is 1023,
+       //  and for Y coordinates is 511 (PS1 hardware limitation)
+       int lowest_x  = tri_ptr[idx_lowest_x].x;
+       int highest_x = tri_ptr[idx_highest_x].x;
+       int lowest_y  = tri_ptr[idx_lowest_y].y;
+       int highest_y = tri_ptr[idx_highest_y].y;
+       if ((highest_x - lowest_x) >= CHKMAX_X ||
+           (highest_y - lowest_y) >= CHKMAX_Y)
+               return false;
+
+       // Determine if triangle is completely outside clipping range
+       int xmin, xmax, ymin, ymax;
+       xmin = gpu_unai.DrawingArea[0];  xmax = gpu_unai.DrawingArea[2];
+       ymin = gpu_unai.DrawingArea[1];  ymax = gpu_unai.DrawingArea[3];
+       int clipped_lowest_x  = Max2(xmin,lowest_x);
+       int clipped_lowest_y  = Max2(ymin,lowest_y);
+       int clipped_highest_x = Min2(xmax,highest_x);
+       int clipped_highest_y = Min2(ymax,highest_y);
+       if (clipped_lowest_x >= clipped_highest_x ||
+           clipped_lowest_y >= clipped_highest_y)
+               return false;
+
+       // Order vertex ptrs by increasing y value (draw routines need this).
+       // The middle index is deduced by a binary math trick that depends
+       //  on index range always being between 0..2
+       vert_ptrs[0] = tri_ptr + idx_lowest_y;
+       vert_ptrs[1] = tri_ptr + ((idx_lowest_y + idx_highest_y) ^ 3);
+       vert_ptrs[2] = tri_ptr + idx_highest_y;
+       return true;
+}
 
-       for (s32 loop0 = 2; loop0; --loop0)
+///////////////////////////////////////////////////////////////////////////////
+//  GPU internal polygon drawing functions
+///////////////////////////////////////////////////////////////////////////////
+
+/*----------------------------------------------------------------------
+gpuDrawPolyF - Flat-shaded, untextured poly
+----------------------------------------------------------------------*/
+void gpuDrawPolyF(const PtrUnion packet, const PP gpuPolySpanDriver, u32 is_quad)
+{
+       // Set up bgr555 color to be used across calls in inner driver
+       gpu_unai.PixelData = GPU_RGB16(packet.U4[0]);
+
+       PolyVertex vbuf[4];
+       polyInitVertexBuffer(vbuf, packet, POLYTYPE_F, is_quad);
+
+       int total_passes = is_quad ? 2 : 1;
+       int cur_pass = 0;
+       do
        {
-               if (loop0 == 2)
-               {
-                       ya = y0;
-                       yb = y1;
-                       x3 = i2x(x0);
-                       x4 = y0!=y1 ? x3 : i2x(x1);
-                       if (dx < 0)
-                       {
-                               dx3 = xLoDivx((x2 - x0), (y2 - y0));
-                               dx4 = xLoDivx((x1 - x0), (y1 - y0));
+               const PolyVertex* vptrs[3];
+               if (polyUseTriangle(vbuf, cur_pass, vptrs) == false)
+                       continue;
+
+               s32 xa, xb, ya, yb;
+               s32 x3, dx3, x4, dx4, dx;
+               s32 x0, x1, x2, y0, y1, y2;
+
+               x0 = vptrs[0]->x;  y0 = vptrs[0]->y;
+               x1 = vptrs[1]->x;  y1 = vptrs[1]->y;
+               x2 = vptrs[2]->x;  y2 = vptrs[2]->y;
+
+               ya = y2 - y0;
+               yb = y2 - y1;
+               dx = (x2 - x1) * ya - (x2 - x0) * yb;
+
+               for (int loop0 = 2; loop0; loop0--) {
+                       if (loop0 == 2) {
+                               ya = y0;  yb = y1;
+                               x3 = x4 = i2x(x0);
+                               if (dx < 0) {
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       dx3 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) * FloatInv(y2 - y0)) : 0;
+                                       dx4 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) * FloatInv(y1 - y0)) : 0;
+#else
+                                       dx3 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) / (float)(y2 - y0)) : 0;
+                                       dx4 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) / (float)(y1 - y0)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       dx3 = ((y2 - y0) != 0) ? xLoDivx((x2 - x0), (y2 - y0)) : 0;
+                                       dx4 = ((y1 - y0) != 0) ? xLoDivx((x1 - x0), (y1 - y0)) : 0;
+#else
+                                       dx3 = ((y2 - y0) != 0) ? GPU_FAST_DIV((x2 - x0) << FIXED_BITS, (y2 - y0)) : 0;
+                                       dx4 = ((y1 - y0) != 0) ? GPU_FAST_DIV((x1 - x0) << FIXED_BITS, (y1 - y0)) : 0;
+#endif
+#endif
+                               } else {
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       dx3 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) * FloatInv(y1 - y0)) : 0;
+                                       dx4 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) * FloatInv(y2 - y0)) : 0;
+#else
+                                       dx3 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) / (float)(y1 - y0)) : 0;
+                                       dx4 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) / (float)(y2 - y0)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       dx3 = ((y1 - y0) != 0) ? xLoDivx((x1 - x0), (y1 - y0)) : 0;
+                                       dx4 = ((y2 - y0) != 0) ? xLoDivx((x2 - x0), (y2 - y0)) : 0;
+#else
+                                       dx3 = ((y1 - y0) != 0) ? GPU_FAST_DIV((x1 - x0) << FIXED_BITS, (y1 - y0)) : 0;
+                                       dx4 = ((y2 - y0) != 0) ? GPU_FAST_DIV((x2 - x0) << FIXED_BITS, (y2 - y0)) : 0;
+#endif
+#endif
+                               }
+                       } else {
+                               //senquack - break out of final loop if nothing to be drawn (1st loop
+                               //           must always be taken to setup dx3/dx4)
+                               if (y1 == y2) break;
+
+                               ya = y1;  yb = y2;
+
+                               if (dx < 0) {
+                                       x3 = i2x(x0) + (dx3 * (y1 - y0));
+                                       x4 = i2x(x1);
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       dx4 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) * FloatInv(y2 - y1)) : 0;
+#else
+                                       dx4 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) / (float)(y2 - y1)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       dx4 = ((y2 - y1) != 0) ? xLoDivx ((x2 - x1), (y2 - y1)) : 0;
+#else
+                                       dx4 = ((y2 - y1) != 0) ? GPU_FAST_DIV((x2 - x1) << FIXED_BITS, (y2 - y1)) : 0;
+#endif
+#endif
+                               } else {
+                                       x3 = i2x(x1);
+                                       x4 = i2x(x0) + (dx4 * (y1 - y0));
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       dx3 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) * FloatInv(y2 - y1)) : 0;
+#else
+                                       dx3 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) / (float)(y2 - y1)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       dx3 = ((y2 - y1) != 0) ? xLoDivx ((x2 - x1), (y2 - y1)) : 0;
+#else
+                                       dx3 = ((y2 - y1) != 0) ? GPU_FAST_DIV((x2 - x1) << FIXED_BITS, (y2 - y1)) : 0;
+#endif
+#endif
+                               }
                        }
-                       else
-                       {
-                               dx3 = xLoDivx((x1 - x0), (y1 - y0));
-                               dx4 = xLoDivx((x2 - x0), (y2 - y0));
-                       }
-               }
-               else
-               {
-                       ya = y1;
-                       yb = y2;
-                       if (dx < 0)
-                       {
-                               x4  = i2x(x1);
-                               x3  = i2x(x0) + (dx3 * (y1 - y0));
-                               dx4 = xLoDivx((x2 - x1), (y2 - y1));
+
+                       s32 xmin, xmax, ymin, ymax;
+                       xmin = gpu_unai.DrawingArea[0];  xmax = gpu_unai.DrawingArea[2];
+                       ymin = gpu_unai.DrawingArea[1];  ymax = gpu_unai.DrawingArea[3];
+
+                       if ((ymin - ya) > 0) {
+                               x3 += (dx3 * (ymin - ya));
+                               x4 += (dx4 * (ymin - ya));
+                               ya = ymin;
                        }
-                       else
+
+                       if (yb > ymax) yb = ymax;
+
+                       int loop1 = yb - ya;
+                       if (loop1 <= 0)
+                               continue;
+
+                       u16* PixelBase = &((u16*)gpu_unai.vram)[FRAME_OFFSET(0, ya)];
+                       int li=gpu_unai.ilace_mask;
+                       int pi=(ProgressiveInterlaceEnabled()?(gpu_unai.ilace_mask+1):0);
+                       int pif=(ProgressiveInterlaceEnabled()?(gpu_unai.prog_ilace_flag?(gpu_unai.ilace_mask+1):0):1);
+
+                       for (; loop1; --loop1, ya++, PixelBase += FRAME_WIDTH,
+                                       x3 += dx3, x4 += dx4 )
                        {
-                               x3  = i2x(x1);
-                               x4  = i2x(x0) + (dx4 * (y1 - y0));
-                               dx3 = xLoDivx((x2 - x1), (y2 - y1));
+                               if (ya&li) continue;
+                               if ((ya&pi)==pif) continue;
+
+                               xa = FixedCeilToInt(x3);  xb = FixedCeilToInt(x4);
+                               if ((xmin - xa) > 0) xa = xmin;
+                               if (xb > xmax) xb = xmax;
+                               if ((xb - xa) > 0)
+                                       gpuPolySpanDriver(gpu_unai, PixelBase + xa, (xb - xa));
                        }
                }
-
-               temp = ymin - ya;
-               if (temp > 0)
-               {
-                       ya  = ymin;
-                       x3 += dx3*temp;
-                       x4 += dx4*temp;
-               }
-               if (yb > ymax) yb = ymax;
-               if (ya>=yb) continue;
-
-               x3+= fixed_HALF;
-               x4+= fixed_HALF;
-
-               u16* PixelBase  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(0, ya)];
-               
-               for(;ya<yb;++ya, PixelBase += FRAME_WIDTH, x3+=dx3, x4+=dx4)
-               {
-                       if (ya&li) continue;
-                       xa = x2i(x3);
-                       xb = x2i(x4);
-                       if( (xa>xmax) || (xb<xmin) ) continue;
-                       if(xa < xmin) xa = xmin;
-                       if(xb > xmax) xb = xmax;
-                       xb-=xa;
-                       if(xb>0) gpuPolySpanDriver(PixelBase + xa,xb);
-               }
-       }
+       } while (++cur_pass < total_passes);
 }
 
 /*----------------------------------------------------------------------
-FT3
+gpuDrawPolyFT - Flat-shaded, textured poly
 ----------------------------------------------------------------------*/
-
-void gpuDrawFT3(const PP gpuPolySpanDriver)
+void gpuDrawPolyFT(const PtrUnion packet, const PP gpuPolySpanDriver, u32 is_quad)
 {
-       const int li=linesInterlace;
-       s32 temp;
-       s32 xa, xb, xmin, xmax;
-       s32 ya, yb, ymin, ymax;
-       s32 x0, x1, x2, x3, dx3=0, x4, dx4=0, dx;
-       s32 y0, y1, y2;
-       s32 u0, u1, u2, u3, du3=0;
-       s32 v0, v1, v2, v3, dv3=0;
-
-       x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2] );
-       y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3] );
-       x1 = GPU_EXPANDSIGN(PacketBuffer.S2[6] );
-       y1 = GPU_EXPANDSIGN(PacketBuffer.S2[7] );
-       x2 = GPU_EXPANDSIGN(PacketBuffer.S2[10]);
-       y2 = GPU_EXPANDSIGN(PacketBuffer.S2[11]);
-
-       GPU_TESTRANGE3();
-
-       x0 += DrawingOffset[0];   x1 += DrawingOffset[0];   x2 += DrawingOffset[0];
-       y0 += DrawingOffset[1];   y1 += DrawingOffset[1];   y2 += DrawingOffset[1];
-
-       xmin = DrawingArea[0];  xmax = DrawingArea[2];
-       ymin = DrawingArea[1];  ymax = DrawingArea[3];
-
+       // r8/g8/b8 used if texture-blending & dithering is applied (24-bit light)
+       gpu_unai.r8 = packet.U1[0];
+       gpu_unai.g8 = packet.U1[1];
+       gpu_unai.b8 = packet.U1[2];
+       // r5/g5/b5 used if just texture-blending is applied (15-bit light)
+       gpu_unai.r5 = packet.U1[0] >> 3;
+       gpu_unai.g5 = packet.U1[1] >> 3;
+       gpu_unai.b5 = packet.U1[2] >> 3;
+
+       PolyVertex vbuf[4];
+       polyInitVertexBuffer(vbuf, packet, POLYTYPE_FT, is_quad);
+
+       int total_passes = is_quad ? 2 : 1;
+       int cur_pass = 0;
+       do
        {
-               int rx0 = Max2(xmin,Min3(x0,x1,x2));
-               int ry0 = Max2(ymin,Min3(y0,y1,y2));
-               int rx1 = Min2(xmax,Max3(x0,x1,x2));
-               int ry1 = Min2(ymax,Max3(y0,y1,y2));
-               if( rx0>=rx1 || ry0>=ry1) return;
-       }
-       
-       u0 = PacketBuffer.U1[8];  v0 = PacketBuffer.U1[9];
-       u1 = PacketBuffer.U1[16]; v1 = PacketBuffer.U1[17];
-       u2 = PacketBuffer.U1[24]; v2 = PacketBuffer.U1[25];
-
-       r4 = s32(PacketBuffer.U1[0]);
-       g4 = s32(PacketBuffer.U1[1]);
-       b4 = s32(PacketBuffer.U1[2]);
-       dr4 = dg4 = db4 = 0;
+               const PolyVertex* vptrs[3];
+               if (polyUseTriangle(vbuf, cur_pass, vptrs) == false)
+                       continue;
+
+               s32 xa, xb, ya, yb;
+               s32 x3, dx3, x4, dx4, dx;
+               s32 u3, du3, v3, dv3;
+               s32 x0, x1, x2, y0, y1, y2;
+               s32 u0, u1, u2, v0, v1, v2;
+               s32 du4, dv4;
+
+               x0 = vptrs[0]->x;      y0 = vptrs[0]->y;
+               u0 = vptrs[0]->tex.u;  v0 = vptrs[0]->tex.v;
+               x1 = vptrs[1]->x;      y1 = vptrs[1]->y;
+               u1 = vptrs[1]->tex.u;  v1 = vptrs[1]->tex.v;
+               x2 = vptrs[2]->x;      y2 = vptrs[2]->y;
+               u2 = vptrs[2]->tex.u;  v2 = vptrs[2]->tex.v;
+
+               ya = y2 - y0;
+               yb = y2 - y1;
+               dx4 = (x2 - x1) * ya - (x2 - x0) * yb;
+               du4 = (u2 - u1) * ya - (u2 - u0) * yb;
+               dv4 = (v2 - v1) * ya - (v2 - v0) * yb;
+               dx = dx4;
+               if (dx4 < 0) {
+                       dx4 = -dx4;
+                       du4 = -du4;
+                       dv4 = -dv4;
+               }
 
-       if (y0 >= y1)
-       {
-               if( y0!=y1 || x0>x1 )
-               {
-                       GPU_SWAP(x0, x1, temp);
-                       GPU_SWAP(y0, y1, temp);
-                       GPU_SWAP(u0, u1, temp);
-                       GPU_SWAP(v0, v1, temp);
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+               if (dx4 != 0) {
+                       float finv = FloatInv(dx4);
+                       du4 = (fixed)((du4 << FIXED_BITS) * finv);
+                       dv4 = (fixed)((dv4 << FIXED_BITS) * finv);
+               } else {
+                       du4 = dv4 = 0;
                }
-       }
-       if (y1 >= y2)
-       {
-               if( y1!=y2 || x1>x2 )
-               {
-                       GPU_SWAP(x1, x2, temp);
-                       GPU_SWAP(y1, y2, temp);
-                       GPU_SWAP(u1, u2, temp);
-                       GPU_SWAP(v1, v2, temp);
+#else
+               if (dx4 != 0) {
+                       float fdiv = dx4;
+                       du4 = (fixed)((du4 << FIXED_BITS) / fdiv);
+                       dv4 = (fixed)((dv4 << FIXED_BITS) / fdiv);
+               } else {
+                       du4 = dv4 = 0;
                }
-       }
-       if (y0 >= y1)
-       {
-               if( y0!=y1 || x0>x1 )
-               {
-                       GPU_SWAP(x0, x1, temp);
-                       GPU_SWAP(y0, y1, temp);
-                       GPU_SWAP(u0, u1, temp);
-                       GPU_SWAP(v0, v1, temp);
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+               if (dx4 != 0) {
+                       int iF, iS;
+                       xInv(dx4, iF, iS);
+                       du4 = xInvMulx(du4, iF, iS);
+                       dv4 = xInvMulx(dv4, iF, iS);
+               } else {
+                       du4 = dv4 = 0;
                }
-       }
-
-       ya  = y2 - y0;
-       yb  = y2 - y1;
-       dx  = (x2 - x1) * ya - (x2 - x0) * yb;
-       du4 = (u2 - u1) * ya - (u2 - u0) * yb;
-       dv4 = (v2 - v1) * ya - (v2 - v0) * yb;
+#else
+               if (dx4 != 0) {
+                       du4 = GPU_FAST_DIV(du4 << FIXED_BITS, dx4);
+                       dv4 = GPU_FAST_DIV(dv4 << FIXED_BITS, dx4);
+               } else {
+                       du4 = dv4 = 0;
+               }
+#endif
+#endif
+               // Set u,v increments for inner driver
+               gpu_unai.u_inc = du4;
+               gpu_unai.v_inc = dv4;
+
+               //senquack - TODO: why is it always going through 2 iterations when sometimes one would suffice here?
+               //                       (SAME ISSUE ELSEWHERE)
+               for (s32 loop0 = 2; loop0; loop0--) {
+                       if (loop0 == 2) {
+                               ya = y0;  yb = y1;
+                               x3 = x4 = i2x(x0);
+                               u3 = i2x(u0);  v3 = i2x(v0);
+                               if (dx < 0) {
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       if ((y2 - y0) != 0) {
+                                               float finv = FloatInv(y2 - y0);
+                                               dx3 = (fixed)(((x2 - x0) << FIXED_BITS) * finv);
+                                               du3 = (fixed)(((u2 - u0) << FIXED_BITS) * finv);
+                                               dv3 = (fixed)(((v2 - v0) << FIXED_BITS) * finv);
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) * FloatInv(y1 - y0)) : 0;
+#else
+                                       if ((y2 - y0) != 0) {
+                                               float fdiv = y2 - y0;
+                                               dx3 = (fixed)(((x2 - x0) << FIXED_BITS) / fdiv);
+                                               du3 = (fixed)(((u2 - u0) << FIXED_BITS) / fdiv);
+                                               dv3 = (fixed)(((v2 - v0) << FIXED_BITS) / fdiv);
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) / (float)(y1 - y0)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       if ((y2 - y0) != 0) {
+                                               int iF, iS;
+                                               xInv((y2 - y0), iF, iS);
+                                               dx3 = xInvMulx((x2 - x0), iF, iS);
+                                               du3 = xInvMulx((u2 - u0), iF, iS);
+                                               dv3 = xInvMulx((v2 - v0), iF, iS);
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? xLoDivx((x1 - x0), (y1 - y0)) : 0;
+#else
+                                       if ((y2 - y0) != 0) {
+                                               dx3 = GPU_FAST_DIV((x2 - x0) << FIXED_BITS, (y2 - y0));
+                                               du3 = GPU_FAST_DIV((u2 - u0) << FIXED_BITS, (y2 - y0));
+                                               dv3 = GPU_FAST_DIV((v2 - v0) << FIXED_BITS, (y2 - y0));
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? GPU_FAST_DIV((x1 - x0) << FIXED_BITS, (y1 - y0)) : 0;
+#endif
+#endif
+                               } else {
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       if ((y1 - y0) != 0) {
+                                               float finv = FloatInv(y1 - y0);
+                                               dx3 = (fixed)(((x1 - x0) << FIXED_BITS) * finv);
+                                               du3 = (fixed)(((u1 - u0) << FIXED_BITS) * finv);
+                                               dv3 = (fixed)(((v1 - v0) << FIXED_BITS) * finv);
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) * FloatInv(y2 - y0)) : 0;
+#else
+                                       if ((y1 - y0) != 0) {
+                                               float fdiv = y1 - y0;
+                                               dx3 = (fixed)(((x1 - x0) << FIXED_BITS) / fdiv);
+                                               du3 = (fixed)(((u1 - u0) << FIXED_BITS) / fdiv);
+                                               dv3 = (fixed)(((v1 - v0) << FIXED_BITS) / fdiv);
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) / (float)(y2 - y0)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       if ((y1 - y0) != 0) {
+                                               int iF, iS;
+                                               xInv((y1 - y0), iF, iS);
+                                               dx3 = xInvMulx((x1 - x0), iF, iS);
+                                               du3 = xInvMulx((u1 - u0), iF, iS);
+                                               dv3 = xInvMulx((v1 - v0), iF, iS);
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? xLoDivx((x2 - x0), (y2 - y0)) : 0;
+#else
+                                       if ((y1 - y0) != 0) {
+                                               dx3 = GPU_FAST_DIV((x1 - x0) << FIXED_BITS, (y1 - y0));
+                                               du3 = GPU_FAST_DIV((u1 - u0) << FIXED_BITS, (y1 - y0));
+                                               dv3 = GPU_FAST_DIV((v1 - v0) << FIXED_BITS, (y1 - y0));
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? GPU_FAST_DIV((x2 - x0) << FIXED_BITS, (y2 - y0)) : 0;
+#endif
+#endif
+                               }
+                       } else {
+                               //senquack - break out of final loop if nothing to be drawn (1st loop
+                               //           must always be taken to setup dx3/dx4)
+                               if (y1 == y2) break;
+
+                               ya = y1;  yb = y2;
+
+                               if (dx < 0) {
+                                       x3 = i2x(x0);
+                                       x4 = i2x(x1);
+                                       u3 = i2x(u0);
+                                       v3 = i2x(v0);
+                                       if ((y1 - y0) != 0) {
+                                               x3 += (dx3 * (y1 - y0));
+                                               u3 += (du3 * (y1 - y0));
+                                               v3 += (dv3 * (y1 - y0));
+                                       }
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       dx4 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) * FloatInv(y2 - y1)) : 0;
+#else
+                                       dx4 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) / (float)(y2 - y1)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       dx4 = ((y2 - y1) != 0) ? xLoDivx((x2 - x1), (y2 - y1)) : 0;
+#else
+                                       dx4 = ((y2 - y1) != 0) ? GPU_FAST_DIV((x2 - x1) << FIXED_BITS, (y2 - y1)) : 0;
+#endif
+#endif
+                               } else {
+                                       x3 = i2x(x1);
+                                       x4 = i2x(x0) + (dx4 * (y1 - y0));
+                                       u3 = i2x(u1);
+                                       v3 = i2x(v1);
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       if ((y2 - y1) != 0) {
+                                               float finv = FloatInv(y2 - y1);
+                                               dx3 = (fixed)(((x2 - x1) << FIXED_BITS) * finv);
+                                               du3 = (fixed)(((u2 - u1) << FIXED_BITS) * finv);
+                                               dv3 = (fixed)(((v2 - v1) << FIXED_BITS) * finv);
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+#else
+                                       if ((y2 - y1) != 0) {
+                                               float fdiv = y2 - y1;
+                                               dx3 = (fixed)(((x2 - x1) << FIXED_BITS) / fdiv);
+                                               du3 = (fixed)(((u2 - u1) << FIXED_BITS) / fdiv);
+                                               dv3 = (fixed)(((v2 - v1) << FIXED_BITS) / fdiv);
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       if ((y2 - y1) != 0) {
+                                               int iF, iS;
+                                               xInv((y2 - y1), iF, iS);
+                                               dx3 = xInvMulx((x2 - x1), iF, iS);
+                                               du3 = xInvMulx((u2 - u1), iF, iS);
+                                               dv3 = xInvMulx((v2 - v1), iF, iS);
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+#else 
+                                       if ((y2 - y1) != 0) {
+                                               dx3 = GPU_FAST_DIV((x2 - x1) << FIXED_BITS, (y2 - y1));
+                                               du3 = GPU_FAST_DIV((u2 - u1) << FIXED_BITS, (y2 - y1));
+                                               dv3 = GPU_FAST_DIV((v2 - v1) << FIXED_BITS, (y2 - y1));
+                                       } else {
+                                               dx3 = du3 = dv3 = 0;
+                                       }
+#endif
+#endif
+                               }
+                       }
 
-       s32 iF,iS;
-       xInv( dx, iF, iS);
-       du4 = xInvMulx( du4, iF, iS);
-       dv4 = xInvMulx( dv4, iF, iS);
-       tInc = ((u32)(du4<<7)&0x7fff0000) | ((u32)(dv4>>9)&0x00007fff);
-       tMsk = (TextureWindow[2]<<23) | (TextureWindow[3]<<7) | 0x00ff00ff;
+                       s32 xmin, xmax, ymin, ymax;
+                       xmin = gpu_unai.DrawingArea[0];  xmax = gpu_unai.DrawingArea[2];
+                       ymin = gpu_unai.DrawingArea[1];  ymax = gpu_unai.DrawingArea[3];
 
-       for (s32 loop0 = 2; loop0; --loop0)
-       {
-               if (loop0 == 2)
-               {
-                       ya = y0;
-                       yb = y1;
-                       u3 = i2x(u0);
-                       v3 = i2x(v0);
-                       x3 = i2x(x0);
-                       x4 = y0!=y1 ? x3 : i2x(x1);
-                       if (dx < 0)
-                       {
-                               xInv( (y2 - y0), iF, iS);
-                               dx3 = xInvMulx( (x2 - x0), iF, iS);
-                               du3 = xInvMulx( (u2 - u0), iF, iS);
-                               dv3 = xInvMulx( (v2 - v0), iF, iS);
-                               dx4 = xLoDivx ( (x1 - x0), (y1 - y0));
-                       }
-                       else
-                       {
-                               xInv( (y1 - y0), iF, iS);
-                               dx3 = xInvMulx( (x1 - x0), iF, iS);
-                               du3 = xInvMulx( (u1 - u0), iF, iS);
-                               dv3 = xInvMulx( (v1 - v0), iF, iS);
-                               dx4 = xLoDivx ( (x2 - x0), (y2 - y0));
+                       if ((ymin - ya) > 0) {
+                               x3 += dx3 * (ymin - ya);
+                               x4 += dx4 * (ymin - ya);
+                               u3 += du3 * (ymin - ya);
+                               v3 += dv3 * (ymin - ya);
+                               ya = ymin;
                        }
-               }
-               else
-               {
-                       ya = y1;
-                       yb = y2;
-                       if (dx < 0)
-                       {
-                               temp = y1 - y0;
-                               u3 = i2x(u0) + (du3 * temp);
-                               v3 = i2x(v0) + (dv3 * temp);
-                               x3 = i2x(x0) + (dx3 * temp);
-                               x4 = i2x(x1);
-                               dx4 = xLoDivx((x2 - x1), (y2 - y1));
-                       }
-                       else
+
+                       if (yb > ymax) yb = ymax;
+
+                       int loop1 = yb - ya;
+                       if (loop1 <= 0)
+                               continue;
+
+                       u16* PixelBase = &((u16*)gpu_unai.vram)[FRAME_OFFSET(0, ya)];
+                       int li=gpu_unai.ilace_mask;
+                       int pi=(ProgressiveInterlaceEnabled()?(gpu_unai.ilace_mask+1):0);
+                       int pif=(ProgressiveInterlaceEnabled()?(gpu_unai.prog_ilace_flag?(gpu_unai.ilace_mask+1):0):1);
+
+                       for (; loop1; --loop1, ++ya, PixelBase += FRAME_WIDTH,
+                                       x3 += dx3, x4 += dx4,
+                                       u3 += du3, v3 += dv3 )
                        {
-                               u3 = i2x(u1);
-                               v3 = i2x(v1);
-                               x3 = i2x(x1);
-                               x4 = i2x(x0) + (dx4 * (y1 - y0));
-                               xInv( (y2 - y1), iF, iS);
-                               dx3 = xInvMulx( (x2 - x1), iF, iS);
-                               du3 = xInvMulx( (u2 - u1), iF, iS);
-                               dv3 = xInvMulx( (v2 - v1), iF, iS);
-                       }
-               }
+                               if (ya&li) continue;
+                               if ((ya&pi)==pif) continue;
 
-               temp = ymin - ya;
-               if (temp > 0)
-               {
-                       ya  = ymin;
-                       x3 += dx3*temp;
-                       x4 += dx4*temp;
-                       u3 += du3*temp;
-                       v3 += dv3*temp;
-               }
-               if (yb > ymax) yb = ymax;
-               if (ya>=yb) continue;
+                               u32 u4, v4;
 
-               x3+= fixed_HALF;
-               x4+= fixed_HALF;
-               u3+= fixed_HALF;
-               v4+= fixed_HALF;
+                               xa = FixedCeilToInt(x3);  xb = FixedCeilToInt(x4);
+                               u4 = u3;  v4 = v3;
 
-               u16* PixelBase  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(0, ya)];
+                               fixed itmp = i2x(xa) - x3;
+                               if (itmp != 0) {
+                                       u4 += (du4 * itmp) >> FIXED_BITS;
+                                       v4 += (dv4 * itmp) >> FIXED_BITS;
+                               }
 
-               for(;ya<yb;++ya, PixelBase += FRAME_WIDTH, x3+=dx3, x4+=dx4, u3+=du3, v3+=dv3)
-               {
-                       if (ya&li) continue;
-                       xa = x2i(x3);
-                       xb = x2i(x4);
-                       if( (xa>xmax) || (xb<xmin) ) continue;
+                               u4 += fixed_HALF;
+                               v4 += fixed_HALF;
 
-                       temp = xmin - xa;
-                       if(temp > 0)
-                       {
-                               xa  = xmin;
-                               u4 = u3 + du4*temp;
-                               v4 = v3 + dv4*temp;
-                       }
-                       else
-                       {
-                               u4 = u3;
-                               v4 = v3;
+                               if ((xmin - xa) > 0) {
+                                       u4 += du4 * (xmin - xa);
+                                       v4 += dv4 * (xmin - xa);
+                                       xa = xmin;
+                               }
+
+                               // Set u,v coords for inner driver
+                               gpu_unai.u = u4;
+                               gpu_unai.v = v4;
+
+                               if (xb > xmax) xb = xmax;
+                               if ((xb - xa) > 0)
+                                       gpuPolySpanDriver(gpu_unai, PixelBase + xa, (xb - xa));
                        }
-                       if(xb > xmax) xb = xmax;
-                       xb-=xa;
-                       if(xb>0) gpuPolySpanDriver(PixelBase + xa,xb);
                }
-       }
+       } while (++cur_pass < total_passes);
 }
 
 /*----------------------------------------------------------------------
-G3
+gpuDrawPolyG - Gouraud-shaded, untextured poly
 ----------------------------------------------------------------------*/
-
-void gpuDrawG3(const PP gpuPolySpanDriver)
+void gpuDrawPolyG(const PtrUnion packet, const PP gpuPolySpanDriver, u32 is_quad)
 {
-       const int li=linesInterlace;
-       s32 temp;
-       s32 xa, xb, xmin, xmax;
-       s32 ya, yb, ymin, ymax;
-       s32 x0, x1, x2, x3, dx3=0, x4, dx4=0, dx;
-       s32 y0, y1, y2;
-       s32 r0, r1, r2, r3, dr3=0;
-       s32 g0, g1, g2, g3, dg3=0;
-       s32 b0, b1, b2, b3, db3=0;
-
-       x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2] );
-       y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3] );
-       x1 = GPU_EXPANDSIGN(PacketBuffer.S2[6] );
-       y1 = GPU_EXPANDSIGN(PacketBuffer.S2[7] );
-       x2 = GPU_EXPANDSIGN(PacketBuffer.S2[10]);
-       y2 = GPU_EXPANDSIGN(PacketBuffer.S2[11]);
-
-       GPU_TESTRANGE3();
-
-       x0 += DrawingOffset[0];   x1 += DrawingOffset[0];   x2 += DrawingOffset[0];
-       y0 += DrawingOffset[1];   y1 += DrawingOffset[1];   y2 += DrawingOffset[1];
-
-       xmin = DrawingArea[0];  xmax = DrawingArea[2];
-       ymin = DrawingArea[1];  ymax = DrawingArea[3];
+       PolyVertex vbuf[4];
+       polyInitVertexBuffer(vbuf, packet, POLYTYPE_G, is_quad);
 
+       int total_passes = is_quad ? 2 : 1;
+       int cur_pass = 0;
+       do
        {
-               int rx0 = Max2(xmin,Min3(x0,x1,x2));
-               int ry0 = Max2(ymin,Min3(y0,y1,y2));
-               int rx1 = Min2(xmax,Max3(x0,x1,x2));
-               int ry1 = Min2(ymax,Max3(y0,y1,y2));
-               if( rx0>=rx1 || ry0>=ry1) return;
-       }
-       
-       r0 = PacketBuffer.U1[0];        g0 = PacketBuffer.U1[1];        b0 = PacketBuffer.U1[2];
-       r1 = PacketBuffer.U1[8];        g1 = PacketBuffer.U1[9];        b1 = PacketBuffer.U1[10];
-       r2 = PacketBuffer.U1[16];       g2 = PacketBuffer.U1[17];       b2 = PacketBuffer.U1[18];
+               const PolyVertex* vptrs[3];
+               if (polyUseTriangle(vbuf, cur_pass, vptrs) == false)
+                       continue;
+
+               s32 xa, xb, ya, yb;
+               s32 x3, dx3, x4, dx4, dx;
+               s32 r3, dr3, g3, dg3, b3, db3;
+               s32 x0, x1, x2, y0, y1, y2;
+               s32 r0, r1, r2, g0, g1, g2, b0, b1, b2;
+               s32 dr4, dg4, db4;
+
+               x0 = vptrs[0]->x;      y0 = vptrs[0]->y;
+               r0 = vptrs[0]->col.r;  g0 = vptrs[0]->col.g;  b0 = vptrs[0]->col.b;
+               x1 = vptrs[1]->x;      y1 = vptrs[1]->y;
+               r1 = vptrs[1]->col.r;  g1 = vptrs[1]->col.g;  b1 = vptrs[1]->col.b;
+               x2 = vptrs[2]->x;      y2 = vptrs[2]->y;
+               r2 = vptrs[2]->col.r;  g2 = vptrs[2]->col.g;  b2 = vptrs[2]->col.b;
+
+               ya = y2 - y0;
+               yb = y2 - y1;
+               dx4 = (x2 - x1) * ya - (x2 - x0) * yb;
+               dr4 = (r2 - r1) * ya - (r2 - r0) * yb;
+               dg4 = (g2 - g1) * ya - (g2 - g0) * yb;
+               db4 = (b2 - b1) * ya - (b2 - b0) * yb;
+               dx = dx4;
+               if (dx4 < 0) {
+                       dx4 = -dx4;
+                       dr4 = -dr4;
+                       dg4 = -dg4;
+                       db4 = -db4;
+               }
 
-       if (y0 >= y1)
-       {
-               if( y0!=y1 || x0>x1 )
-               {
-                       GPU_SWAP(x0, x1, temp);         GPU_SWAP(y0, y1, temp);
-                       GPU_SWAP(r0, r1, temp);         GPU_SWAP(g0, g1, temp);         GPU_SWAP(b0, b1, temp);
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+               if (dx4 != 0) {
+                       float finv = FloatInv(dx4);
+                       dr4 = (fixed)((dr4 << FIXED_BITS) * finv);
+                       dg4 = (fixed)((dg4 << FIXED_BITS) * finv);
+                       db4 = (fixed)((db4 << FIXED_BITS) * finv);
+               } else {
+                       dr4 = dg4 = db4 = 0;
                }
-       }
-       if (y1 >= y2)
-       {
-               if( y1!=y2 || x1>x2 )
-               {
-                       GPU_SWAP(x1, x2, temp);         GPU_SWAP(y1, y2, temp);
-                       GPU_SWAP(r1, r2, temp);         GPU_SWAP(g1, g2, temp);   GPU_SWAP(b1, b2, temp);
+#else
+               if (dx4 != 0) {
+                       float fdiv = dx4;
+                       dr4 = (fixed)((dr4 << FIXED_BITS) / fdiv);
+                       dg4 = (fixed)((dg4 << FIXED_BITS) / fdiv);
+                       db4 = (fixed)((db4 << FIXED_BITS) / fdiv);
+               } else {
+                       dr4 = dg4 = db4 = 0;
                }
-       }
-       if (y0 >= y1)
-       {
-               if( y0!=y1 || x0>x1 )
-               {
-                       GPU_SWAP(x0, x1, temp);         GPU_SWAP(y0, y1, temp);
-                       GPU_SWAP(r0, r1, temp);   GPU_SWAP(g0, g1, temp);               GPU_SWAP(b0, b1, temp);
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+               if (dx4 != 0) {
+                       int iF, iS;
+                       xInv(dx4, iF, iS);
+                       dr4 = xInvMulx(dr4, iF, iS);
+                       dg4 = xInvMulx(dg4, iF, iS);
+                       db4 = xInvMulx(db4, iF, iS);
+               } else {
+                       dr4 = dg4 = db4 = 0;
                }
-       }
-
-       ya  = y2 - y0;
-       yb  = y2 - y1;
-       dx  = (x2 - x1) * ya - (x2 - x0) * yb;
-       dr4 = (r2 - r1) * ya - (r2 - r0) * yb;
-       dg4 = (g2 - g1) * ya - (g2 - g0) * yb;
-       db4 = (b2 - b1) * ya - (b2 - b0) * yb;
-
-       s32 iF,iS;
-       xInv(            dx, iF, iS);
-       dr4 = xInvMulx( dr4, iF, iS);
-       dg4 = xInvMulx( dg4, iF, iS);
-       db4 = xInvMulx( db4, iF, iS);
-       u32 dr = (u32)(dr4<< 8)&(0xffffffff<<21);   if(dr4<0) dr+= 1<<21;
-       u32 dg = (u32)(dg4>> 3)&(0xffffffff<<10);   if(dg4<0) dg+= 1<<10;
-       u32 db = (u32)(db4>>14)&(0xffffffff    );   if(db4<0) db+= 1<< 0;
-       lInc = db + dg + dr;
-
-       for (s32 loop0 = 2; loop0; --loop0)
-       {
-               if (loop0 == 2)
-               {
-                       ya = y0;
-                       yb = y1;
-                       r3 = i2x(r0);
-                       g3 = i2x(g0);
-                       b3 = i2x(b0);
-                       x3 = i2x(x0);
-                       x4 = y0!=y1 ? x3 : i2x(x1);
-                       if (dx < 0)
-                       {
-                               xInv(           (y2 - y0), iF, iS);
-                               dx3 = xInvMulx( (x2 - x0), iF, iS);
-                               dr3 = xInvMulx( (r2 - r0), iF, iS);
-                               dg3 = xInvMulx( (g2 - g0), iF, iS);
-                               db3 = xInvMulx( (b2 - b0), iF, iS);
-                               dx4 = xLoDivx ( (x1 - x0), (y1 - y0));
-                       }
-                       else
-                       {
-                               xInv(           (y1 - y0), iF, iS);
-                               dx3 = xInvMulx( (x1 - x0), iF, iS);
-                               dr3 = xInvMulx( (r1 - r0), iF, iS);
-                               dg3 = xInvMulx( (g1 - g0), iF, iS);
-                               db3 = xInvMulx( (b1 - b0), iF, iS);
-                               dx4 = xLoDivx ( (x2 - x0), (y2 - y0));
-                       }
+#else
+               if (dx4 != 0) {
+                       dr4 = GPU_FAST_DIV(dr4 << FIXED_BITS, dx4);
+                       dg4 = GPU_FAST_DIV(dg4 << FIXED_BITS, dx4);
+                       db4 = GPU_FAST_DIV(db4 << FIXED_BITS, dx4);
+               } else {
+                       dr4 = dg4 = db4 = 0;
                }
-               else
-               {
-                       ya = y1;
-                       yb = y2;
-                       if (dx < 0)
-                       {
-                               temp = y1 - y0;
-                               r3  = i2x(r0) + (dr3 * temp);
-                               g3  = i2x(g0) + (dg3 * temp);
-                               b3  = i2x(b0) + (db3 * temp);
-                               x3  = i2x(x0) + (dx3 * temp);
-                               x4  = i2x(x1);
-                               dx4 = xLoDivx((x2 - x1), (y2 - y1));
+#endif
+#endif
+               // Setup packed Gouraud increment for inner driver
+               gpu_unai.gInc = gpuPackGouraudColInc(dr4, dg4, db4);
+
+               for (s32 loop0 = 2; loop0; loop0--) {
+                       if (loop0 == 2) {
+                               ya = y0;
+                               yb = y1;
+                               x3 = x4 = i2x(x0);
+                               r3 = i2x(r0);
+                               g3 = i2x(g0);
+                               b3 = i2x(b0);
+                               if (dx < 0) {
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       if ((y2 - y0) != 0) {
+                                               float finv = FloatInv(y2 - y0);
+                                               dx3 = (fixed)(((x2 - x0) << FIXED_BITS) * finv);
+                                               dr3 = (fixed)(((r2 - r0) << FIXED_BITS) * finv);
+                                               dg3 = (fixed)(((g2 - g0) << FIXED_BITS) * finv);
+                                               db3 = (fixed)(((b2 - b0) << FIXED_BITS) * finv);
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) * FloatInv(y1 - y0)) : 0;
+#else
+                                       if ((y2 - y0) != 0) {
+                                               float fdiv = y2 - y0;
+                                               dx3 = (fixed)(((x2 - x0) << FIXED_BITS) / fdiv);
+                                               dr3 = (fixed)(((r2 - r0) << FIXED_BITS) / fdiv);
+                                               dg3 = (fixed)(((g2 - g0) << FIXED_BITS) / fdiv);
+                                               db3 = (fixed)(((b2 - b0) << FIXED_BITS) / fdiv);
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) / (float)(y1 - y0)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       if ((y2 - y0) != 0) {
+                                               int iF, iS;
+                                               xInv((y2 - y0), iF, iS);
+                                               dx3 = xInvMulx((x2 - x0), iF, iS);
+                                               dr3 = xInvMulx((r2 - r0), iF, iS);
+                                               dg3 = xInvMulx((g2 - g0), iF, iS);
+                                               db3 = xInvMulx((b2 - b0), iF, iS);
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? xLoDivx((x1 - x0), (y1 - y0)) : 0;
+#else
+                                       if ((y2 - y0) != 0) {
+                                               dx3 = GPU_FAST_DIV((x2 - x0) << FIXED_BITS, (y2 - y0));
+                                               dr3 = GPU_FAST_DIV((r2 - r0) << FIXED_BITS, (y2 - y0));
+                                               dg3 = GPU_FAST_DIV((g2 - g0) << FIXED_BITS, (y2 - y0));
+                                               db3 = GPU_FAST_DIV((b2 - b0) << FIXED_BITS, (y2 - y0));
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? GPU_FAST_DIV((x1 - x0) << FIXED_BITS, (y1 - y0)) : 0;
+#endif
+#endif
+                               } else {
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       if ((y1 - y0) != 0) {
+                                               float finv = FloatInv(y1 - y0);
+                                               dx3 = (fixed)(((x1 - x0) << FIXED_BITS) * finv);
+                                               dr3 = (fixed)(((r1 - r0) << FIXED_BITS) * finv);
+                                               dg3 = (fixed)(((g1 - g0) << FIXED_BITS) * finv);
+                                               db3 = (fixed)(((b1 - b0) << FIXED_BITS) * finv);
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) * FloatInv(y2 - y0)) : 0;
+#else
+                                       if ((y1 - y0) != 0) {
+                                               float fdiv = y1 - y0;
+                                               dx3 = (fixed)(((x1 - x0) << FIXED_BITS) / fdiv);
+                                               dr3 = (fixed)(((r1 - r0) << FIXED_BITS) / fdiv);
+                                               dg3 = (fixed)(((g1 - g0) << FIXED_BITS) / fdiv);
+                                               db3 = (fixed)(((b1 - b0) << FIXED_BITS) / fdiv);
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) / (float)(y2 - y0)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       if ((y1 - y0) != 0) {
+                                               int iF, iS;
+                                               xInv((y1 - y0), iF, iS);
+                                               dx3 = xInvMulx((x1 - x0), iF, iS);
+                                               dr3 = xInvMulx((r1 - r0), iF, iS);
+                                               dg3 = xInvMulx((g1 - g0), iF, iS);
+                                               db3 = xInvMulx((b1 - b0), iF, iS);
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? xLoDivx((x2 - x0), (y2 - y0)) : 0;
+#else
+                                       if ((y1 - y0) != 0) {
+                                               dx3 = GPU_FAST_DIV((x1 - x0) << FIXED_BITS, (y1 - y0));
+                                               dr3 = GPU_FAST_DIV((r1 - r0) << FIXED_BITS, (y1 - y0));
+                                               dg3 = GPU_FAST_DIV((g1 - g0) << FIXED_BITS, (y1 - y0));
+                                               db3 = GPU_FAST_DIV((b1 - b0) << FIXED_BITS, (y1 - y0));
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? GPU_FAST_DIV((x2 - x0) << FIXED_BITS, (y2 - y0)) : 0;
+#endif
+#endif
+                               }
+                       } else {
+                               //senquack - break out of final loop if nothing to be drawn (1st loop
+                               //           must always be taken to setup dx3/dx4)
+                               if (y1 == y2) break;
+
+                               ya = y1;  yb = y2;
+
+                               if (dx < 0) {
+                                       x3 = i2x(x0);  x4 = i2x(x1);
+                                       r3 = i2x(r0);  g3 = i2x(g0);  b3 = i2x(b0);
+
+                                       if ((y1 - y0) != 0) {
+                                               x3 += (dx3 * (y1 - y0));
+                                               r3 += (dr3 * (y1 - y0));
+                                               g3 += (dg3 * (y1 - y0));
+                                               b3 += (db3 * (y1 - y0));
+                                       }
+
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       dx4 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) * FloatInv(y2 - y1)) : 0;
+#else
+                                       dx4 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) / (float)(y2 - y1)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       dx4 = ((y2 - y1) != 0) ? xLoDivx((x2 - x1), (y2 - y1)) : 0;
+#else
+                                       dx4 = ((y2 - y1) != 0) ? GPU_FAST_DIV((x2 - x1) << FIXED_BITS, (y2 - y1)) : 0;
+#endif
+#endif
+                               } else {
+                                       x3 = i2x(x1);
+                                       x4 = i2x(x0) + (dx4 * (y1 - y0));
+
+                                       r3 = i2x(r1);  g3 = i2x(g1);  b3 = i2x(b1);
+
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       if ((y2 - y1) != 0) {
+                                               float finv = FloatInv(y2 - y1);
+                                               dx3 = (fixed)(((x2 - x1) << FIXED_BITS) * finv);
+                                               dr3 = (fixed)(((r2 - r1) << FIXED_BITS) * finv);
+                                               dg3 = (fixed)(((g2 - g1) << FIXED_BITS) * finv);
+                                               db3 = (fixed)(((b2 - b1) << FIXED_BITS) * finv);
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+#else
+                                       if ((y2 - y1) != 0) {
+                                               float fdiv = y2 - y1;
+                                               dx3 = (fixed)(((x2 - x1) << FIXED_BITS) / fdiv);
+                                               dr3 = (fixed)(((r2 - r1) << FIXED_BITS) / fdiv);
+                                               dg3 = (fixed)(((g2 - g1) << FIXED_BITS) / fdiv);
+                                               db3 = (fixed)(((b2 - b1) << FIXED_BITS) / fdiv);
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       if ((y2 - y1) != 0) {
+                                               int iF, iS;
+                                               xInv((y2 - y1), iF, iS);
+                                               dx3 = xInvMulx((x2 - x1), iF, iS);
+                                               dr3 = xInvMulx((r2 - r1), iF, iS);
+                                               dg3 = xInvMulx((g2 - g1), iF, iS);
+                                               db3 = xInvMulx((b2 - b1), iF, iS);
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+#else
+                                       if ((y2 - y1) != 0) {
+                                               dx3 = GPU_FAST_DIV((x2 - x1) << FIXED_BITS, (y2 - y1));
+                                               dr3 = GPU_FAST_DIV((r2 - r1) << FIXED_BITS, (y2 - y1));
+                                               dg3 = GPU_FAST_DIV((g2 - g1) << FIXED_BITS, (y2 - y1));
+                                               db3 = GPU_FAST_DIV((b2 - b1) << FIXED_BITS, (y2 - y1));
+                                       } else {
+                                               dx3 = dr3 = dg3 = db3 = 0;
+                                       }
+#endif
+#endif
+                               }
                        }
-                       else
-                       {
-                               r3 = i2x(r1);
-                               g3 = i2x(g1);
-                               b3 = i2x(b1);
-                               x3 = i2x(x1);
-                               x4 = i2x(x0) + (dx4 * (y1 - y0));
-
-                               xInv(           (y2 - y1), iF, iS);
-                               dx3 = xInvMulx( (x2 - x1), iF, iS);
-                               dr3 = xInvMulx( (r2 - r1), iF, iS);
-                               dg3 = xInvMulx( (g2 - g1), iF, iS);
-                               db3 = xInvMulx( (b2 - b1), iF, iS);
-                       }
-               }
 
-               temp = ymin - ya;
-               if (temp > 0)
-               {
-                       ya  = ymin;
-                       x3 += dx3*temp;   x4 += dx4*temp;
-                       r3 += dr3*temp;   g3 += dg3*temp;   b3 += db3*temp;
-               }
-               if (yb > ymax) yb = ymax;
-               if (ya>=yb) continue;
-
-               x3+= fixed_HALF;  x4+= fixed_HALF;
-               r3+= fixed_HALF;  g3+= fixed_HALF;  b3+= fixed_HALF;
-
-               u16* PixelBase  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(0, ya)];
-               
-               for(;ya<yb;++ya, PixelBase += FRAME_WIDTH, x3+=dx3, x4+=dx4, r3+=dr3, g3+=dg3, b3+=db3)
-               {
-                       if (ya&li) continue;
-                       xa = x2i(x3);
-                       xb = x2i(x4);
-                       if( (xa>xmax) || (xb<xmin) ) continue;
-
-                       temp = xmin - xa;
-                       if(temp > 0)
-                       {
-                               xa  = xmin;
-                               r4 = r3 + dr4*temp;   g4 = g3 + dg4*temp;   b4 = b3 + db4*temp;
+                       s32 xmin, xmax, ymin, ymax;
+                       xmin = gpu_unai.DrawingArea[0];  xmax = gpu_unai.DrawingArea[2];
+                       ymin = gpu_unai.DrawingArea[1];  ymax = gpu_unai.DrawingArea[3];
+
+                       if ((ymin - ya) > 0) {
+                               x3 += (dx3 * (ymin - ya));
+                               x4 += (dx4 * (ymin - ya));
+                               r3 += (dr3 * (ymin - ya));
+                               g3 += (dg3 * (ymin - ya));
+                               b3 += (db3 * (ymin - ya));
+                               ya = ymin;
                        }
-                       else
+
+                       if (yb > ymax) yb = ymax;
+
+                       int loop1 = yb - ya;
+                       if (loop1 <= 0)
+                               continue;
+
+                       u16* PixelBase = &((u16*)gpu_unai.vram)[FRAME_OFFSET(0, ya)];
+                       int li=gpu_unai.ilace_mask;
+                       int pi=(ProgressiveInterlaceEnabled()?(gpu_unai.ilace_mask+1):0);
+                       int pif=(ProgressiveInterlaceEnabled()?(gpu_unai.prog_ilace_flag?(gpu_unai.ilace_mask+1):0):1);
+
+                       for (; loop1; --loop1, ++ya, PixelBase += FRAME_WIDTH,
+                                       x3 += dx3, x4 += dx4,
+                                       r3 += dr3, g3 += dg3, b3 += db3 )
                        {
+                               if (ya&li) continue;
+                               if ((ya&pi)==pif) continue;
+
+                               u32 r4, g4, b4;
+
+                               xa = FixedCeilToInt(x3);
+                               xb = FixedCeilToInt(x4);
                                r4 = r3;  g4 = g3;  b4 = b3;
+
+                               fixed itmp = i2x(xa) - x3;
+                               if (itmp != 0) {
+                                       r4 += (dr4 * itmp) >> FIXED_BITS;
+                                       g4 += (dg4 * itmp) >> FIXED_BITS;
+                                       b4 += (db4 * itmp) >> FIXED_BITS;
+                               }
+
+                               r4 += fixed_HALF;
+                               g4 += fixed_HALF;
+                               b4 += fixed_HALF;
+
+                               if ((xmin - xa) > 0) {
+                                       r4 += (dr4 * (xmin - xa));
+                                       g4 += (dg4 * (xmin - xa));
+                                       b4 += (db4 * (xmin - xa));
+                                       xa = xmin;
+                               }
+
+                               // Setup packed Gouraud color for inner driver
+                               gpu_unai.gCol = gpuPackGouraudCol(r4, g4, b4);
+
+                               if (xb > xmax) xb = xmax;
+                               if ((xb - xa) > 0)
+                                       gpuPolySpanDriver(gpu_unai, PixelBase + xa, (xb - xa));
                        }
-                       if(xb > xmax) xb = xmax;
-                       xb-=xa;
-                       if(xb>0) gpuPolySpanDriver(PixelBase + xa,xb);
                }
-       }
+       } while (++cur_pass < total_passes);
 }
 
 /*----------------------------------------------------------------------
-GT3
+gpuDrawPolyGT - Gouraud-shaded, textured poly
 ----------------------------------------------------------------------*/
-
-void gpuDrawGT3(const PP gpuPolySpanDriver)
+void gpuDrawPolyGT(const PtrUnion packet, const PP gpuPolySpanDriver, u32 is_quad)
 {
-       const int li=linesInterlace;
-       s32 temp;
-       s32 xa, xb, xmin, xmax;
-       s32 ya, yb, ymin, ymax;
-       s32 x0, x1, x2, x3, dx3=0, x4, dx4=0, dx;
-       s32 y0, y1, y2;
-       s32 u0, u1, u2, u3, du3=0;
-       s32 v0, v1, v2, v3, dv3=0;
-       s32 r0, r1, r2, r3, dr3=0;
-       s32 g0, g1, g2, g3, dg3=0;
-       s32 b0, b1, b2, b3, db3=0;
-
-       x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2] );
-       y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3] );
-       x1 = GPU_EXPANDSIGN(PacketBuffer.S2[8] );
-       y1 = GPU_EXPANDSIGN(PacketBuffer.S2[9] );
-       x2 = GPU_EXPANDSIGN(PacketBuffer.S2[14]);
-       y2 = GPU_EXPANDSIGN(PacketBuffer.S2[15]);
-
-       GPU_TESTRANGE3();
-
-       x0 += DrawingOffset[0];   x1 += DrawingOffset[0];   x2 += DrawingOffset[0];
-       y0 += DrawingOffset[1];   y1 += DrawingOffset[1];   y2 += DrawingOffset[1];
-
-       xmin = DrawingArea[0];  xmax = DrawingArea[2];
-       ymin = DrawingArea[1];  ymax = DrawingArea[3];
+       PolyVertex vbuf[4];
+       polyInitVertexBuffer(vbuf, packet, POLYTYPE_GT, is_quad);
 
+       int total_passes = is_quad ? 2 : 1;
+       int cur_pass = 0;
+       do
        {
-               int rx0 = Max2(xmin,Min3(x0,x1,x2));
-               int ry0 = Max2(ymin,Min3(y0,y1,y2));
-               int rx1 = Min2(xmax,Max3(x0,x1,x2));
-               int ry1 = Min2(ymax,Max3(y0,y1,y2));
-               if( rx0>=rx1 || ry0>=ry1) return;
-       }
-
-       r0 = PacketBuffer.U1[0];        g0 = PacketBuffer.U1[1];        b0 = PacketBuffer.U1[2];
-       u0 = PacketBuffer.U1[8];        v0 = PacketBuffer.U1[9];
-       r1 = PacketBuffer.U1[12];       g1 = PacketBuffer.U1[13];       b1 = PacketBuffer.U1[14];
-       u1 = PacketBuffer.U1[20];       v1 = PacketBuffer.U1[21];
-       r2 = PacketBuffer.U1[24];       g2 = PacketBuffer.U1[25];       b2 = PacketBuffer.U1[26];
-       u2 = PacketBuffer.U1[32];       v2 = PacketBuffer.U1[33];
+               const PolyVertex* vptrs[3];
+               if (polyUseTriangle(vbuf, cur_pass, vptrs) == false)
+                       continue;
+
+               s32 xa, xb, ya, yb;
+               s32 x3, dx3, x4, dx4, dx;
+               s32 u3, du3, v3, dv3;
+               s32 r3, dr3, g3, dg3, b3, db3;
+               s32 x0, x1, x2, y0, y1, y2;
+               s32 u0, u1, u2, v0, v1, v2;
+               s32 r0, r1, r2, g0, g1, g2, b0, b1, b2;
+               s32 du4, dv4;
+               s32 dr4, dg4, db4;
+
+               x0 = vptrs[0]->x;      y0 = vptrs[0]->y;
+               u0 = vptrs[0]->tex.u;  v0 = vptrs[0]->tex.v;
+               r0 = vptrs[0]->col.r;  g0 = vptrs[0]->col.g;  b0 = vptrs[0]->col.b;
+               x1 = vptrs[1]->x;      y1 = vptrs[1]->y;
+               u1 = vptrs[1]->tex.u;  v1 = vptrs[1]->tex.v;
+               r1 = vptrs[1]->col.r;  g1 = vptrs[1]->col.g;  b1 = vptrs[1]->col.b;
+               x2 = vptrs[2]->x;      y2 = vptrs[2]->y;
+               u2 = vptrs[2]->tex.u;  v2 = vptrs[2]->tex.v;
+               r2 = vptrs[2]->col.r;  g2 = vptrs[2]->col.g;  b2 = vptrs[2]->col.b;
+
+               ya = y2 - y0;
+               yb = y2 - y1;
+               dx4 = (x2 - x1) * ya - (x2 - x0) * yb;
+               du4 = (u2 - u1) * ya - (u2 - u0) * yb;
+               dv4 = (v2 - v1) * ya - (v2 - v0) * yb;
+               dr4 = (r2 - r1) * ya - (r2 - r0) * yb;
+               dg4 = (g2 - g1) * ya - (g2 - g0) * yb;
+               db4 = (b2 - b1) * ya - (b2 - b0) * yb;
+               dx = dx4;
+               if (dx4 < 0) {
+                       dx4 = -dx4;
+                       du4 = -du4;
+                       dv4 = -dv4;
+                       dr4 = -dr4;
+                       dg4 = -dg4;
+                       db4 = -db4;
+               }
 
-       if (y0 >= y1)
-       {
-               if( y0!=y1 || x0>x1 )
-               {
-                       GPU_SWAP(x0, x1, temp);         GPU_SWAP(y0, y1, temp);
-                       GPU_SWAP(u0, u1, temp);         GPU_SWAP(v0, v1, temp);
-                       GPU_SWAP(r0, r1, temp);         GPU_SWAP(g0, g1, temp);   GPU_SWAP(b0, b1, temp);
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+               if (dx4 != 0) {
+                       float finv = FloatInv(dx4);
+                       du4 = (fixed)((du4 << FIXED_BITS) * finv);
+                       dv4 = (fixed)((dv4 << FIXED_BITS) * finv);
+                       dr4 = (fixed)((dr4 << FIXED_BITS) * finv);
+                       dg4 = (fixed)((dg4 << FIXED_BITS) * finv);
+                       db4 = (fixed)((db4 << FIXED_BITS) * finv);
+               } else {
+                       du4 = dv4 = dr4 = dg4 = db4 = 0;
                }
-       }
-       if (y1 >= y2)
-       {
-               if( y1!=y2 || x1>x2 )
-               {
-                       GPU_SWAP(x1, x2, temp);         GPU_SWAP(y1, y2, temp);
-                       GPU_SWAP(u1, u2, temp);         GPU_SWAP(v1, v2, temp);
-                       GPU_SWAP(r1, r2, temp);   GPU_SWAP(g1, g2, temp);               GPU_SWAP(b1, b2, temp);
+#else
+               if (dx4 != 0) {
+                       float fdiv = dx4;
+                       du4 = (fixed)((du4 << FIXED_BITS) / fdiv);
+                       dv4 = (fixed)((dv4 << FIXED_BITS) / fdiv);
+                       dr4 = (fixed)((dr4 << FIXED_BITS) / fdiv);
+                       dg4 = (fixed)((dg4 << FIXED_BITS) / fdiv);
+                       db4 = (fixed)((db4 << FIXED_BITS) / fdiv);
+               } else {
+                       du4 = dv4 = dr4 = dg4 = db4 = 0;
                }
-       }
-       if (y0 >= y1)
-       {
-               if( y0!=y1 || x0>x1 )
-               {
-                       GPU_SWAP(x0, x1, temp);         GPU_SWAP(y0, y1, temp);
-                       GPU_SWAP(u0, u1, temp);         GPU_SWAP(v0, v1, temp);
-                       GPU_SWAP(r0, r1, temp);         GPU_SWAP(g0, g1, temp);         GPU_SWAP(b0, b1, temp);
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+               if (dx4 != 0) {
+                       int iF, iS;
+                       xInv(dx4, iF, iS);
+                       du4 = xInvMulx(du4, iF, iS);
+                       dv4 = xInvMulx(dv4, iF, iS);
+                       dr4 = xInvMulx(dr4, iF, iS);
+                       dg4 = xInvMulx(dg4, iF, iS);
+                       db4 = xInvMulx(db4, iF, iS);
+               } else {
+                       du4 = dv4 = dr4 = dg4 = db4 = 0;
                }
-       }
-
-       ya  = y2 - y0;
-       yb  = y2 - y1;
-       dx  = (x2 - x1) * ya - (x2 - x0) * yb;
-       du4 = (u2 - u1) * ya - (u2 - u0) * yb;
-       dv4 = (v2 - v1) * ya - (v2 - v0) * yb;
-       dr4 = (r2 - r1) * ya - (r2 - r0) * yb;
-       dg4 = (g2 - g1) * ya - (g2 - g0) * yb;
-       db4 = (b2 - b1) * ya - (b2 - b0) * yb;
-
-       s32 iF,iS;
-
-       xInv(            dx, iF, iS);
-       du4 = xInvMulx( du4, iF, iS);
-       dv4 = xInvMulx( dv4, iF, iS);
-       dr4 = xInvMulx( dr4, iF, iS);
-       dg4 = xInvMulx( dg4, iF, iS);
-       db4 = xInvMulx( db4, iF, iS);
-       u32 dr = (u32)(dr4<< 8)&(0xffffffff<<21);   if(dr4<0) dr+= 1<<21;
-       u32 dg = (u32)(dg4>> 3)&(0xffffffff<<10);   if(dg4<0) dg+= 1<<10;
-       u32 db = (u32)(db4>>14)&(0xffffffff    );   if(db4<0) db+= 1<< 0;
-       lInc = db + dg + dr;
-       tInc = ((u32)(du4<<7)&0x7fff0000) | ((u32)(dv4>>9)&0x00007fff);
-       tMsk = (TextureWindow[2]<<23) | (TextureWindow[3]<<7) | 0x00ff00ff;
-
-       for (s32 loop0 = 2; loop0; --loop0)
-       {
-               if (loop0 == 2)
-               {
-                       ya = y0;
-                       yb = y1;
-                       u3 = i2x(u0);
-                       v3 = i2x(v0);
-                       r3 = i2x(r0);
-                       g3 = i2x(g0);
-                       b3 = i2x(b0);
-                       x3 = i2x(x0);
-                       x4 = y0!=y1 ? x3 : i2x(x1);
-                       if (dx < 0)
-                       {
-                               xInv(           (y2 - y0), iF, iS);
-                               dx3 = xInvMulx( (x2 - x0), iF, iS);
-                               du3 = xInvMulx( (u2 - u0), iF, iS);
-                               dv3 = xInvMulx( (v2 - v0), iF, iS);
-                               dr3 = xInvMulx( (r2 - r0), iF, iS);
-                               dg3 = xInvMulx( (g2 - g0), iF, iS);
-                               db3 = xInvMulx( (b2 - b0), iF, iS);
-                               dx4 = xLoDivx ( (x1 - x0), (y1 - y0));
-                       }
-                       else
-                       {
-                               xInv(           (y1 - y0), iF, iS);
-                               dx3 = xInvMulx( (x1 - x0), iF, iS);
-                               du3 = xInvMulx( (u1 - u0), iF, iS);
-                               dv3 = xInvMulx( (v1 - v0), iF, iS);
-                               dr3 = xInvMulx( (r1 - r0), iF, iS);
-                               dg3 = xInvMulx( (g1 - g0), iF, iS);
-                               db3 = xInvMulx( (b1 - b0), iF, iS);
-                               dx4 = xLoDivx ( (x2 - x0), (y2 - y0));
-                       }
+#else
+               if (dx4 != 0) {
+                       du4 = GPU_FAST_DIV(du4 << FIXED_BITS, dx4);
+                       dv4 = GPU_FAST_DIV(dv4 << FIXED_BITS, dx4);
+                       dr4 = GPU_FAST_DIV(dr4 << FIXED_BITS, dx4);
+                       dg4 = GPU_FAST_DIV(dg4 << FIXED_BITS, dx4);
+                       db4 = GPU_FAST_DIV(db4 << FIXED_BITS, dx4);
+               } else {
+                       du4 = dv4 = dr4 = dg4 = db4 = 0;
                }
-               else
-               {
-                       ya = y1;
-                       yb = y2;
-                       if (dx < 0)
-                       {
-                               temp = y1 - y0;
-                               u3  = i2x(u0) + (du3 * temp);
-                               v3  = i2x(v0) + (dv3 * temp);
-                               r3  = i2x(r0) + (dr3 * temp);
-                               g3  = i2x(g0) + (dg3 * temp);
-                               b3  = i2x(b0) + (db3 * temp);
-                               x3  = i2x(x0) + (dx3 * temp);
-                               x4  = i2x(x1);
-                               dx4 = xLoDivx((x2 - x1), (y2 - y1));
-                       }
-                       else
-                       {
-                               u3 = i2x(u1);
-                               v3 = i2x(v1);
-                               r3 = i2x(r1);
-                               g3 = i2x(g1);
-                               b3 = i2x(b1);
-                               x3 = i2x(x1);
-                               x4 = i2x(x0) + (dx4 * (y1 - y0));
-
-                               xInv(           (y2 - y1), iF, iS);
-                               dx3 = xInvMulx( (x2 - x1), iF, iS);
-                               du3 = xInvMulx( (u2 - u1), iF, iS);
-                               dv3 = xInvMulx( (v2 - v1), iF, iS);
-                               dr3 = xInvMulx( (r2 - r1), iF, iS);
-                               dg3 = xInvMulx( (g2 - g1), iF, iS);
-                               db3 = xInvMulx( (b2 - b1), iF, iS);
+#endif
+#endif
+               // Set u,v increments and packed Gouraud increment for inner driver
+               gpu_unai.u_inc = du4;
+               gpu_unai.v_inc = dv4;
+               gpu_unai.gInc = gpuPackGouraudColInc(dr4, dg4, db4);
+
+               for (s32 loop0 = 2; loop0; loop0--) {
+                       if (loop0 == 2) {
+                               ya = y0;  yb = y1;
+                               x3 = x4 = i2x(x0);
+                               u3 = i2x(u0);  v3 = i2x(v0);
+                               r3 = i2x(r0);  g3 = i2x(g0);  b3 = i2x(b0);
+                               if (dx < 0) {
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       if ((y2 - y0) != 0) {
+                                               float finv = FloatInv(y2 - y0);
+                                               dx3 = (fixed)(((x2 - x0) << FIXED_BITS) * finv);
+                                               du3 = (fixed)(((u2 - u0) << FIXED_BITS) * finv);
+                                               dv3 = (fixed)(((v2 - v0) << FIXED_BITS) * finv);
+                                               dr3 = (fixed)(((r2 - r0) << FIXED_BITS) * finv);
+                                               dg3 = (fixed)(((g2 - g0) << FIXED_BITS) * finv);
+                                               db3 = (fixed)(((b2 - b0) << FIXED_BITS) * finv);
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) * FloatInv(y1 - y0)) : 0;
+#else
+                                       if ((y2 - y0) != 0) {
+                                               float fdiv = y2 - y0;
+                                               dx3 = (fixed)(((x2 - x0) << FIXED_BITS) / fdiv);
+                                               du3 = (fixed)(((u2 - u0) << FIXED_BITS) / fdiv);
+                                               dv3 = (fixed)(((v2 - v0) << FIXED_BITS) / fdiv);
+                                               dr3 = (fixed)(((r2 - r0) << FIXED_BITS) / fdiv);
+                                               dg3 = (fixed)(((g2 - g0) << FIXED_BITS) / fdiv);
+                                               db3 = (fixed)(((b2 - b0) << FIXED_BITS) / fdiv);
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? (fixed)(((x1 - x0) << FIXED_BITS) / (float)(y1 - y0)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       if ((y2 - y0) != 0) {
+                                               int iF, iS;
+                                               xInv((y2 - y0), iF, iS);
+                                               dx3 = xInvMulx((x2 - x0), iF, iS);
+                                               du3 = xInvMulx((u2 - u0), iF, iS);
+                                               dv3 = xInvMulx((v2 - v0), iF, iS);
+                                               dr3 = xInvMulx((r2 - r0), iF, iS);
+                                               dg3 = xInvMulx((g2 - g0), iF, iS);
+                                               db3 = xInvMulx((b2 - b0), iF, iS);
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? xLoDivx((x1 - x0), (y1 - y0)) : 0;
+#else
+                                       if ((y2 - y0) != 0) {
+                                               dx3 = GPU_FAST_DIV((x2 - x0) << FIXED_BITS, (y2 - y0));
+                                               du3 = GPU_FAST_DIV((u2 - u0) << FIXED_BITS, (y2 - y0));
+                                               dv3 = GPU_FAST_DIV((v2 - v0) << FIXED_BITS, (y2 - y0));
+                                               dr3 = GPU_FAST_DIV((r2 - r0) << FIXED_BITS, (y2 - y0));
+                                               dg3 = GPU_FAST_DIV((g2 - g0) << FIXED_BITS, (y2 - y0));
+                                               db3 = GPU_FAST_DIV((b2 - b0) << FIXED_BITS, (y2 - y0));
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y1 - y0) != 0) ? GPU_FAST_DIV((x1 - x0) << FIXED_BITS, (y1 - y0)) : 0;
+#endif
+#endif
+                               } else {
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       if ((y1 - y0) != 0) {
+                                               float finv = FloatInv(y1 - y0);
+                                               dx3 = (fixed)(((x1 - x0) << FIXED_BITS) * finv);
+                                               du3 = (fixed)(((u1 - u0) << FIXED_BITS) * finv);
+                                               dv3 = (fixed)(((v1 - v0) << FIXED_BITS) * finv);
+                                               dr3 = (fixed)(((r1 - r0) << FIXED_BITS) * finv);
+                                               dg3 = (fixed)(((g1 - g0) << FIXED_BITS) * finv);
+                                               db3 = (fixed)(((b1 - b0) << FIXED_BITS) * finv);
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) * FloatInv(y2 - y0)) : 0;
+#else
+                                       if ((y1 - y0) != 0) {
+                                               float fdiv = y1 - y0;
+                                               dx3 = (fixed)(((x1 - x0) << FIXED_BITS) / fdiv);
+                                               du3 = (fixed)(((u1 - u0) << FIXED_BITS) / fdiv);
+                                               dv3 = (fixed)(((v1 - v0) << FIXED_BITS) / fdiv);
+                                               dr3 = (fixed)(((r1 - r0) << FIXED_BITS) / fdiv);
+                                               dg3 = (fixed)(((g1 - g0) << FIXED_BITS) / fdiv);
+                                               db3 = (fixed)(((b1 - b0) << FIXED_BITS) / fdiv);
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? (fixed)(((x2 - x0) << FIXED_BITS) / float(y2 - y0)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       if ((y1 - y0) != 0) {
+                                               int iF, iS;
+                                               xInv((y1 - y0), iF, iS);
+                                               dx3 = xInvMulx((x1 - x0), iF, iS);
+                                               du3 = xInvMulx((u1 - u0), iF, iS);
+                                               dv3 = xInvMulx((v1 - v0), iF, iS);
+                                               dr3 = xInvMulx((r1 - r0), iF, iS);
+                                               dg3 = xInvMulx((g1 - g0), iF, iS);
+                                               db3 = xInvMulx((b1 - b0), iF, iS);
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? xLoDivx((x2 - x0), (y2 - y0)) : 0;
+#else
+                                       if ((y1 - y0) != 0) {
+                                               dx3 = GPU_FAST_DIV((x1 - x0) << FIXED_BITS, (y1 - y0));
+                                               du3 = GPU_FAST_DIV((u1 - u0) << FIXED_BITS, (y1 - y0));
+                                               dv3 = GPU_FAST_DIV((v1 - v0) << FIXED_BITS, (y1 - y0));
+                                               dr3 = GPU_FAST_DIV((r1 - r0) << FIXED_BITS, (y1 - y0));
+                                               dg3 = GPU_FAST_DIV((g1 - g0) << FIXED_BITS, (y1 - y0));
+                                               db3 = GPU_FAST_DIV((b1 - b0) << FIXED_BITS, (y1 - y0));
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+                                       dx4 = ((y2 - y0) != 0) ? GPU_FAST_DIV((x2 - x0) << FIXED_BITS, (y2 - y0)) : 0;
+#endif
+#endif
+                               }
+                       } else {
+                               //senquack - break out of final loop if nothing to be drawn (1st loop
+                               //           must always be taken to setup dx3/dx4)
+                               if (y1 == y2) break;
+
+                               ya = y1;  yb = y2;
+
+                               if (dx < 0) {
+                                       x3 = i2x(x0);  x4 = i2x(x1);
+                                       u3 = i2x(u0);  v3 = i2x(v0);
+                                       r3 = i2x(r0);  g3 = i2x(g0);  b3 = i2x(b0);
+
+                                       if ((y1 - y0) != 0) {
+                                               x3 += (dx3 * (y1 - y0));
+                                               u3 += (du3 * (y1 - y0));
+                                               v3 += (dv3 * (y1 - y0));
+                                               r3 += (dr3 * (y1 - y0));
+                                               g3 += (dg3 * (y1 - y0));
+                                               b3 += (db3 * (y1 - y0));
+                                       }
+
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       dx4 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) * FloatInv(y2 - y1)) : 0;
+#else
+                                       dx4 = ((y2 - y1) != 0) ? (fixed)(((x2 - x1) << FIXED_BITS) / (float)(y2 - y1)) : 0;
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       dx4 = ((y2 - y1) != 0) ? xLoDivx((x2 - x1), (y2 - y1)) : 0;
+#else
+                                       dx4 = ((y2 - y1) != 0) ? GPU_FAST_DIV((x2 - x1) << FIXED_BITS, (y2 - y1)) : 0;
+#endif
+#endif
+                               } else {
+                                       x3 = i2x(x1);
+                                       x4 = i2x(x0) + (dx4 * (y1 - y0));
+
+                                       u3 = i2x(u1);  v3 = i2x(v1);
+                                       r3 = i2x(r1);  g3 = i2x(g1);  b3 = i2x(b1);
+#ifdef GPU_UNAI_USE_FLOATMATH
+#ifdef GPU_UNAI_USE_FLOAT_DIV_MULTINV
+                                       if ((y2 - y1) != 0) {
+                                               float finv = FloatInv(y2 - y1);
+                                               dx3 = (fixed)(((x2 - x1) << FIXED_BITS) * finv);
+                                               du3 = (fixed)(((u2 - u1) << FIXED_BITS) * finv);
+                                               dv3 = (fixed)(((v2 - v1) << FIXED_BITS) * finv);
+                                               dr3 = (fixed)(((r2 - r1) << FIXED_BITS) * finv);
+                                               dg3 = (fixed)(((g2 - g1) << FIXED_BITS) * finv);
+                                               db3 = (fixed)(((b2 - b1) << FIXED_BITS) * finv);
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+#else
+                                       if ((y2 - y1) != 0) {
+                                               float fdiv = y2 - y1;
+                                               dx3 = (fixed)(((x2 - x1) << FIXED_BITS) / fdiv);
+                                               du3 = (fixed)(((u2 - u1) << FIXED_BITS) / fdiv);
+                                               dv3 = (fixed)(((v2 - v1) << FIXED_BITS) / fdiv);
+                                               dr3 = (fixed)(((r2 - r1) << FIXED_BITS) / fdiv);
+                                               dg3 = (fixed)(((g2 - g1) << FIXED_BITS) / fdiv);
+                                               db3 = (fixed)(((b2 - b1) << FIXED_BITS) / fdiv);
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+#endif
+#else  // Integer Division:
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+                                       if ((y2 - y1) != 0) {
+                                               int iF, iS;
+                                               xInv((y2 - y1), iF, iS);
+                                               dx3 = xInvMulx((x2 - x1), iF, iS);
+                                               du3 = xInvMulx((u2 - u1), iF, iS);
+                                               dv3 = xInvMulx((v2 - v1), iF, iS);
+                                               dr3 = xInvMulx((r2 - r1), iF, iS);
+                                               dg3 = xInvMulx((g2 - g1), iF, iS);
+                                               db3 = xInvMulx((b2 - b1), iF, iS);
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+#else
+                                       if ((y2 - y1) != 0) {
+                                               dx3 = GPU_FAST_DIV((x2 - x1) << FIXED_BITS, (y2 - y1));
+                                               du3 = GPU_FAST_DIV((u2 - u1) << FIXED_BITS, (y2 - y1));
+                                               dv3 = GPU_FAST_DIV((v2 - v1) << FIXED_BITS, (y2 - y1));
+                                               dr3 = GPU_FAST_DIV((r2 - r1) << FIXED_BITS, (y2 - y1));
+                                               dg3 = GPU_FAST_DIV((g2 - g1) << FIXED_BITS, (y2 - y1));
+                                               db3 = GPU_FAST_DIV((b2 - b1) << FIXED_BITS, (y2 - y1));
+                                       } else {
+                                               dx3 = du3 = dv3 = dr3 = dg3 = db3 = 0;
+                                       }
+#endif
+#endif
+                               }
                        }
-               }
 
-               temp = ymin - ya;
-               if (temp > 0)
-               {
-                       ya  = ymin;
-                       x3 += dx3*temp;   x4 += dx4*temp;
-                       u3 += du3*temp;   v3 += dv3*temp;
-                       r3 += dr3*temp;   g3 += dg3*temp;   b3 += db3*temp;
-               }
-               if (yb > ymax) yb = ymax;
-               if (ya>=yb) continue;
-
-               x3+= fixed_HALF;  x4+= fixed_HALF;
-               u3+= fixed_HALF;  v4+= fixed_HALF;
-               r3+= fixed_HALF;  g3+= fixed_HALF;  b3+= fixed_HALF;
-               u16* PixelBase  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(0, ya)];
-               
-               for(;ya<yb;++ya, PixelBase += FRAME_WIDTH, x3+=dx3, x4+=dx4, u3+=du3, v3+=dv3, r3+=dr3, g3+=dg3,        b3+=db3)
-               {
-                       if (ya&li) continue;
-                       xa = x2i(x3);
-                       xb = x2i(x4);
-                       if( (xa>xmax) || (xb<xmin))     continue;
-
-                       temp = xmin - xa;
-                       if(temp > 0)
-                       {
-                               xa  = xmin;
-                               u4 = u3 + du4*temp;   v4 = v3 + dv4*temp;
-                               r4 = r3 + dr4*temp;   g4 = g3 + dg4*temp;   b4 = b3 + db4*temp;
+                       s32 xmin, xmax, ymin, ymax;
+                       xmin = gpu_unai.DrawingArea[0];  xmax = gpu_unai.DrawingArea[2];
+                       ymin = gpu_unai.DrawingArea[1];  ymax = gpu_unai.DrawingArea[3];
+
+                       if ((ymin - ya) > 0) {
+                               x3 += (dx3 * (ymin - ya));
+                               x4 += (dx4 * (ymin - ya));
+                               u3 += (du3 * (ymin - ya));
+                               v3 += (dv3 * (ymin - ya));
+                               r3 += (dr3 * (ymin - ya));
+                               g3 += (dg3 * (ymin - ya));
+                               b3 += (db3 * (ymin - ya));
+                               ya = ymin;
                        }
-                       else
+
+                       if (yb > ymax) yb = ymax;
+
+                       int loop1 = yb - ya;
+                       if (loop1 <= 0)
+                               continue;
+
+                       u16* PixelBase = &((u16*)gpu_unai.vram)[FRAME_OFFSET(0, ya)];
+                       int li=gpu_unai.ilace_mask;
+                       int pi=(ProgressiveInterlaceEnabled()?(gpu_unai.ilace_mask+1):0);
+                       int pif=(ProgressiveInterlaceEnabled()?(gpu_unai.prog_ilace_flag?(gpu_unai.ilace_mask+1):0):1);
+
+                       for (; loop1; --loop1, ++ya, PixelBase += FRAME_WIDTH,
+                                       x3 += dx3, x4 += dx4,
+                                       u3 += du3, v3 += dv3,
+                                       r3 += dr3, g3 += dg3, b3 += db3 )
                        {
+                               if (ya&li) continue;
+                               if ((ya&pi)==pif) continue;
+
+                               u32 u4, v4;
+                               u32 r4, g4, b4;
+
+                               xa = FixedCeilToInt(x3);
+                               xb = FixedCeilToInt(x4);
                                u4 = u3;  v4 = v3;
                                r4 = r3;  g4 = g3;  b4 = b3;
+
+                               fixed itmp = i2x(xa) - x3;
+                               if (itmp != 0) {
+                                       u4 += (du4 * itmp) >> FIXED_BITS;
+                                       v4 += (dv4 * itmp) >> FIXED_BITS;
+                                       r4 += (dr4 * itmp) >> FIXED_BITS;
+                                       g4 += (dg4 * itmp) >> FIXED_BITS;
+                                       b4 += (db4 * itmp) >> FIXED_BITS;
+                               }
+
+                               u4 += fixed_HALF;
+                               v4 += fixed_HALF;
+                               r4 += fixed_HALF;
+                               g4 += fixed_HALF;
+                               b4 += fixed_HALF;
+
+                               if ((xmin - xa) > 0) {
+                                       u4 += du4 * (xmin - xa);
+                                       v4 += dv4 * (xmin - xa);
+                                       r4 += dr4 * (xmin - xa);
+                                       g4 += dg4 * (xmin - xa);
+                                       b4 += db4 * (xmin - xa);
+                                       xa = xmin;
+                               }
+
+                               // Set packed Gouraud color and u,v coords for inner driver
+                               gpu_unai.u = u4;
+                               gpu_unai.v = v4;
+                               gpu_unai.gCol = gpuPackGouraudCol(r4, g4, b4);
+
+                               if (xb > xmax) xb = xmax;
+                               if ((xb - xa) > 0)
+                                       gpuPolySpanDriver(gpu_unai, PixelBase + xa, (xb - xa));
                        }
-                       if(xb > xmax) xb = xmax;
-                       xb-=xa;
-                       if(xb>0) gpuPolySpanDriver(PixelBase + xa,xb);
                }
-       }
+       } while (++cur_pass < total_passes);
 }
+
+#endif /* __GPU_UNAI_GPU_RASTER_POLYGON_H__ */
index a700db3..91f7bc0 100644 (file)
 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
 ***************************************************************************/
 
+#ifndef __GPU_UNAI_GPU_RASTER_SPRITE_H__
+#define __GPU_UNAI_GPU_RASTER_SPRITE_H__
+
 ///////////////////////////////////////////////////////////////////////////////
 //  GPU internal sprite drawing functions
 
-///////////////////////////////////////////////////////////////////////////////
-void gpuDrawS(const PS gpuSpriteSpanDriver)
+void gpuDrawS(PtrUnion packet, const PS gpuSpriteSpanDriver)
 {
-       s32 x0, x1;
-       s32 y0, y1;
-       s32 u0;
-       s32 v0;
-
-       x1 = x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2]) + DrawingOffset[0];
-       y1 = y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3]) + DrawingOffset[1];
-       x1+= PacketBuffer.S2[6];
-       y1+= PacketBuffer.S2[7];
-
-       {
-               s32 xmin, xmax;
-               s32 ymin, ymax;
-               xmin = DrawingArea[0];  xmax = DrawingArea[2];
-               ymin = DrawingArea[1];  ymax = DrawingArea[3];
-
-               {
-                       int rx0 = Max2(xmin,Min2(x0,x1));
-                       int ry0 = Max2(ymin,Min2(y0,y1));
-                       int rx1 = Min2(xmax,Max2(x0,x1));
-                       int ry1 = Min2(ymax,Max2(y0,y1));
-                       if( rx0>=rx1 || ry0>=ry1) return;
-               }
-
-               u0 = PacketBuffer.U1[8];
-               v0 = PacketBuffer.U1[9];
-
-               r4 = s32(PacketBuffer.U1[0]);
-               g4 = s32(PacketBuffer.U1[1]);
-               b4 = s32(PacketBuffer.U1[2]);
-
-               {
-                       s32 temp;
-                       temp = ymin - y0;
-                       if (temp > 0) { y0 = ymin; v0 += temp; }
-                       if (y1 > ymax) y1 = ymax;
-                       if (y1 <= y0) return;
-                       
-                       temp = xmin - x0;
-                       if (temp > 0) { x0 = xmin; u0 += temp; }
-                       if (x1 > xmax) x1 = xmax;
-                       x1 -= x0;
-                       if (x1 <= 0) return;
-               }
-       }
-
-       {
-               u16 *Pixel = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0, y0)];
-               const int li=linesInterlace;
-               const u32 masku=TextureWindow[2];
-               const u32 maskv=TextureWindow[3];
-
-               for (;y0<y1;++y0) {
-                       if( 0 == (y0&li) ) gpuSpriteSpanDriver(Pixel,x1,FRAME_OFFSET(u0,v0),masku);
-                       Pixel += FRAME_WIDTH;
-                       v0 = (v0+1)&maskv;
-               }
+       s32 x0, x1, y0, y1;
+       u32 u0, v0;
+
+       //NOTE: Must 11-bit sign-extend the whole sum here, not just packet X/Y,
+       // or sprites in 1st level of SkullMonkeys disappear when walking right.
+       // This now matches behavior of Mednafen and PCSX Rearmed's gpu_neon:
+       x0 = GPU_EXPANDSIGN(packet.S2[2] + gpu_unai.DrawingOffset[0]);
+       y0 = GPU_EXPANDSIGN(packet.S2[3] + gpu_unai.DrawingOffset[1]);
+
+       u32 w = packet.U2[6] & 0x3ff; // Max width is 1023
+       u32 h = packet.U2[7] & 0x1ff; // Max height is 511
+       x1 = x0 + w;
+       y1 = y0 + h;
+
+       s32 xmin, xmax, ymin, ymax;
+       xmin = gpu_unai.DrawingArea[0]; xmax = gpu_unai.DrawingArea[2];
+       ymin = gpu_unai.DrawingArea[1]; ymax = gpu_unai.DrawingArea[3];
+
+       u0 = packet.U1[8];
+       v0 = packet.U1[9];
+
+       s32 temp;
+       temp = ymin - y0;
+       if (temp > 0) { y0 = ymin; v0 += temp; }
+       if (y1 > ymax) y1 = ymax;
+       if (y1 <= y0) return;
+
+       temp = xmin - x0;
+       if (temp > 0) { x0 = xmin; u0 += temp; }
+       if (x1 > xmax) x1 = xmax;
+       x1 -= x0;
+       if (x1 <= 0) return;
+
+       gpu_unai.r5 = packet.U1[0] >> 3;
+       gpu_unai.g5 = packet.U1[1] >> 3;
+       gpu_unai.b5 = packet.U1[2] >> 3;
+
+       u16 *Pixel = &((u16*)gpu_unai.vram)[FRAME_OFFSET(x0, y0)];
+       const int li=gpu_unai.ilace_mask;
+       const int pi=(ProgressiveInterlaceEnabled()?(gpu_unai.ilace_mask+1):0);
+       const int pif=(ProgressiveInterlaceEnabled()?(gpu_unai.prog_ilace_flag?(gpu_unai.ilace_mask+1):0):1);
+       unsigned int tmode = gpu_unai.TEXT_MODE >> 5;
+       const u32 v0_mask = gpu_unai.TextureWindow[3];
+       u8* pTxt_base = (u8*)gpu_unai.TBA;
+
+       // Texture is accessed byte-wise, so adjust idx if 16bpp
+       if (tmode == 3) u0 <<= 1;
+
+       for (; y0<y1; ++y0) {
+               u8* pTxt = pTxt_base + ((v0 & v0_mask) * 2048);
+               if (!(y0&li) && (y0&pi)!=pif)
+                       gpuSpriteSpanDriver(Pixel, x1, pTxt, u0);
+               Pixel += FRAME_WIDTH;
+               v0++;
        }
 }
 
 #ifdef __arm__
 #include "gpu_arm.h"
 
-void gpuDrawS16(void)
+/* Notaz 4bit sprites optimization */
+void gpuDrawS16(PtrUnion packet)
 {
        s32 x0, y0;
        s32 u0, v0;
@@ -95,19 +95,22 @@ void gpuDrawS16(void)
        s32 ymin, ymax;
        u32 h = 16;
 
-       x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2]) + DrawingOffset[0];
-       y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3]) + DrawingOffset[1];
+       //NOTE: Must 11-bit sign-extend the whole sum here, not just packet X/Y,
+       // or sprites in 1st level of SkullMonkeys disappear when walking right.
+       // This now matches behavior of Mednafen and PCSX Rearmed's gpu_neon:
+       x0 = GPU_EXPANDSIGN(packet.S2[2] + gpu_unai.DrawingOffset[0]);
+       y0 = GPU_EXPANDSIGN(packet.S2[3] + gpu_unai.DrawingOffset[1]);
 
-       xmin = DrawingArea[0];  xmax = DrawingArea[2];
-       ymin = DrawingArea[1];  ymax = DrawingArea[3];
-       u0 = PacketBuffer.U1[8];
-       v0 = PacketBuffer.U1[9];
+       xmin = gpu_unai.DrawingArea[0]; xmax = gpu_unai.DrawingArea[2];
+       ymin = gpu_unai.DrawingArea[1]; ymax = gpu_unai.DrawingArea[3];
+       u0 = packet.U1[8];
+       v0 = packet.U1[9];
 
        if (x0 > xmax - 16 || x0 < xmin ||
-           ((u0 | v0) & 15) || !(TextureWindow[2] & TextureWindow[3] & 8)) {
+           ((u0 | v0) & 15) || !(gpu_unai.TextureWindow[2] & gpu_unai.TextureWindow[3] & 8)) {
                // send corner cases to general handler
-               PacketBuffer.U4[3] = 0x00100010;
-               gpuDrawS(gpuSpriteSpanFn<0x20>);
+               packet.U4[3] = 0x00100010;
+               gpuDrawS(packet, gpuSpriteSpanFn<0x20>);
                return;
        }
 
@@ -121,54 +124,47 @@ void gpuDrawS16(void)
        else if (ymax - y0 < 16)
                h = ymax - y0;
 
-       draw_spr16_full(&GPU_FrameBuffer[FRAME_OFFSET(x0, y0)], &TBA[FRAME_OFFSET(u0/4, v0)], CBA, h);
+       draw_spr16_full(&gpu_unai.vram[FRAME_OFFSET(x0, y0)], &gpu_unai.TBA[FRAME_OFFSET(u0/4, v0)], gpu_unai.CBA, h);
 }
 #endif // __arm__
 
-///////////////////////////////////////////////////////////////////////////////
-void gpuDrawT(const PT gpuTileSpanDriver)
+void gpuDrawT(PtrUnion packet, const PT gpuTileSpanDriver)
 {
-       s32 x0, y0;
-       s32 x1, y1;
-
-       x1 = x0 = GPU_EXPANDSIGN(PacketBuffer.S2[2]) + DrawingOffset[0];
-       y1 = y0 = GPU_EXPANDSIGN(PacketBuffer.S2[3]) + DrawingOffset[1];
-       x1+= PacketBuffer.S2[4];
-       y1+= PacketBuffer.S2[5];
-
-       {
-               s32 xmin, xmax;
-               s32 ymin, ymax;
-               xmin = DrawingArea[0];  xmax = DrawingArea[2];
-               ymin = DrawingArea[1];  ymax = DrawingArea[3];
-
-               {
-                       int rx0 = Max2(xmin,Min2(x0,x1));
-                       int ry0 = Max2(ymin,Min2(y0,y1));
-                       int rx1 = Min2(xmax,Max2(x0,x1));
-                       int ry1 = Min2(ymax,Max2(y0,y1));
-                       if(rx0>=rx1 || ry0>=ry1) return;
-               }
-
-               if (y0 < ymin) y0 = ymin;
-               if (y1 > ymax) y1 = ymax;
-               if (y1 <= y0) return;
-
-               if (x0 < xmin) x0 = xmin;
-               if (x1 > xmax) x1 = xmax;
-               x1 -= x0;
-               if (x1 <= 0) return;
-       }
-       
-       {
-               u16 *Pixel = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0, y0)];
-               const u16 Data = GPU_RGB16(PacketBuffer.U4[0]);
-               const int li=linesInterlace;
-
-               for (; y0<y1; ++y0)
-               {
-                       if( 0 == (y0&li) ) gpuTileSpanDriver(Pixel,x1,Data);
-                       Pixel += FRAME_WIDTH;
-               }
+       s32 x0, x1, y0, y1;
+
+       // This now matches behavior of Mednafen and PCSX Rearmed's gpu_neon:
+       x0 = GPU_EXPANDSIGN(packet.S2[2] + gpu_unai.DrawingOffset[0]);
+       y0 = GPU_EXPANDSIGN(packet.S2[3] + gpu_unai.DrawingOffset[1]);
+
+       u32 w = packet.U2[4] & 0x3ff; // Max width is 1023
+       u32 h = packet.U2[5] & 0x1ff; // Max height is 511
+       x1 = x0 + w;
+       y1 = y0 + h;
+
+       s32 xmin, xmax, ymin, ymax;
+       xmin = gpu_unai.DrawingArea[0]; xmax = gpu_unai.DrawingArea[2];
+       ymin = gpu_unai.DrawingArea[1]; ymax = gpu_unai.DrawingArea[3];
+
+       if (y0 < ymin) y0 = ymin;
+       if (y1 > ymax) y1 = ymax;
+       if (y1 <= y0) return;
+
+       if (x0 < xmin) x0 = xmin;
+       if (x1 > xmax) x1 = xmax;
+       x1 -= x0;
+       if (x1 <= 0) return;
+
+       const u16 Data = GPU_RGB16(packet.U4[0]);
+       u16 *Pixel = &((u16*)gpu_unai.vram)[FRAME_OFFSET(x0, y0)];
+       const int li=gpu_unai.ilace_mask;
+       const int pi=(ProgressiveInterlaceEnabled()?(gpu_unai.ilace_mask+1):0);
+       const int pif=(ProgressiveInterlaceEnabled()?(gpu_unai.prog_ilace_flag?(gpu_unai.ilace_mask+1):0):1);
+
+       for (; y0<y1; ++y0) {
+               if (!(y0&li) && (y0&pi)!=pif)
+                       gpuTileSpanDriver(Pixel,x1,Data);
+               Pixel += FRAME_WIDTH;
        }
 }
+
+#endif /* __GPU_UNAI_GPU_RASTER_SPRITE_H__ */
diff --git a/plugins/gpu_unai/gpu_unai.h b/plugins/gpu_unai/gpu_unai.h
new file mode 100644 (file)
index 0000000..6886eb8
--- /dev/null
@@ -0,0 +1,321 @@
+/***************************************************************************
+*   Copyright (C) 2010 PCSX4ALL Team                                      *
+*   Copyright (C) 2010 Unai                                               *
+*   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
+*                                                                         *
+*   This program is free software; you can redistribute it and/or modify  *
+*   it under the terms of the GNU General Public License as published by  *
+*   the Free Software Foundation; either version 2 of the License, or     *
+*   (at your option) any later version.                                   *
+*                                                                         *
+*   This program is distributed in the hope that it will be useful,       *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+*   GNU General Public License for more details.                          *
+*                                                                         *
+*   You should have received a copy of the GNU General Public License     *
+*   along with this program; if not, write to the                         *
+*   Free Software Foundation, Inc.,                                       *
+*   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
+***************************************************************************/
+
+#ifndef GPU_UNAI_H
+#define GPU_UNAI_H
+
+#include "gpu.h"
+
+// Header shared between both standalone gpu_unai (gpu.cpp) and new
+// gpulib-compatible gpu_unai (gpulib_if.cpp)
+// -> Anything here should be for gpu_unai's private use. <-
+
+///////////////////////////////////////////////////////////////////////////////
+//  Compile Options
+
+//#define ENABLE_GPU_NULL_SUPPORT   // Enables NullGPU support
+//#define ENABLE_GPU_LOG_SUPPORT    // Enables gpu logger, very slow only for windows debugging
+//#define ENABLE_GPU_ARMV7                     // Enables ARMv7 optimized assembly
+
+//Poly routine options (default is integer math and accurate division)
+//#define GPU_UNAI_USE_FLOATMATH         // Use float math in poly routines
+//#define GPU_UNAI_USE_FLOAT_DIV_MULTINV // If GPU_UNAI_USE_FLOATMATH is defined,
+                                         //  use multiply-by-inverse for division
+//#define GPU_UNAI_USE_INT_DIV_MULTINV   // If GPU_UNAI_USE_FLOATMATH is *not*
+                                         //  defined, use old inaccurate division
+
+
+#define GPU_INLINE static inline __attribute__((always_inline))
+#define INLINE     static inline __attribute__((always_inline))
+
+#define u8  uint8_t
+#define s8  int8_t
+#define u16 uint16_t
+#define s16 int16_t
+#define u32 uint32_t
+#define s32 int32_t
+#define s64 int64_t
+
+union PtrUnion
+{
+       u32  *U4;
+       s32  *S4;
+       u16  *U2;
+       s16  *S2;
+       u8   *U1;
+       s8   *S1;
+       void *ptr;
+};
+
+union GPUPacket
+{
+       u32 U4[16];
+       s32 S4[16];
+       u16 U2[32];
+       s16 S2[32];
+       u8  U1[64];
+       s8  S1[64];
+};
+
+template<class T> static inline void SwapValues(T &x, T &y)
+{
+       T tmp(x);  x = y;  y = tmp;
+}
+
+template<typename T>
+static inline T Min2 (const T a, const T b)
+{
+       return (a<b)?a:b;
+}
+
+template<typename T>
+static inline T Min3 (const T a, const T b, const T c)
+{
+       return  Min2(Min2(a,b),c);
+}
+
+template<typename T>
+static inline T Max2 (const T a, const T b)
+{
+       return  (a>b)?a:b;
+}
+
+template<typename T>
+static inline T Max3 (const T a, const T b, const T c)
+{
+       return  Max2(Max2(a,b),c);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+//  GPU Raster Macros
+
+// Convert 24bpp color parameter of GPU command to 16bpp (15bpp + mask bit)
+#define        GPU_RGB16(rgb) ((((rgb)&0xF80000)>>9)|(((rgb)&0xF800)>>6)|(((rgb)&0xF8)>>3))
+
+// Sign-extend 11-bit coordinate command param
+#define GPU_EXPANDSIGN(x) (((s32)(x)<<(32-11))>>(32-11))
+
+// Max difference between any two X or Y primitive coordinates
+#define CHKMAX_X 1024
+#define CHKMAX_Y 512
+
+#define        FRAME_BUFFER_SIZE       (1024*512*2)
+#define        FRAME_WIDTH                       1024
+#define        FRAME_HEIGHT              512
+#define        FRAME_OFFSET(x,y)       (((y)<<10)+(x))
+#define FRAME_BYTE_STRIDE     2048
+#define FRAME_BYTES_PER_PIXEL 2
+
+static inline s32 GPU_DIV(s32 rs, s32 rt)
+{
+       return rt ? (rs / rt) : (0);
+}
+
+// 'Unsafe' version of above that doesn't check for div-by-zero
+#define GPU_FAST_DIV(rs, rt) ((signed)(rs) / (signed)(rt))
+
+struct gpu_unai_t {
+       u32 GPU_GP1;
+       GPUPacket PacketBuffer;
+       u16 *vram;
+
+#ifdef USE_GPULIB
+       u16 *downscale_vram;
+#endif
+       ////////////////////////////////////////////////////////////////////////////
+       // Variables used only by older standalone version of gpu_unai (gpu.cpp)
+#ifndef USE_GPULIB
+       u32  GPU_GP0;
+       u32  tex_window;       // Current texture window vals (set by GP0(E2h) cmd)
+       s32  PacketCount;
+       s32  PacketIndex;
+       bool fb_dirty;         // Framebuffer is dirty (according to GPU)
+
+       //  Display status
+       //  NOTE: Standalone older gpu_unai didn't care about horiz display range
+       u16  DisplayArea[6];   // [0] : Start of display area (in VRAM) X
+                              // [1] : Start of display area (in VRAM) Y
+                              // [2] : Display mode resolution HORIZONTAL
+                              // [3] : Display mode resolution VERTICAL
+                              // [4] : Vertical display range (on TV) START
+                              // [5] : Vertical display range (on TV) END
+
+       ////////////////////////////////////////////////////////////////////////////
+       //  Dma Transfers info
+       struct {
+               s32  px,py;
+               s32  x_end,y_end;
+               u16* pvram;
+               u32 *last_dma;     // Last dma pointer
+               bool FrameToRead;  // Load image in progress
+               bool FrameToWrite; // Store image in progress
+       } dma;
+
+       ////////////////////////////////////////////////////////////////////////////
+       //  Frameskip
+       struct {
+               int  skipCount;    // Frame skip (0,1,2,3...)
+               bool isSkip;       // Skip frame (according to GPU)
+               bool skipFrame;    // Skip this frame (according to frame skip)
+               bool wasSkip;      // Skip frame old value (according to GPU)
+               bool skipGPU;      // Skip GPU primitives
+       } frameskip;
+#endif
+       // END of standalone gpu_unai variables
+       ////////////////////////////////////////////////////////////////////////////
+
+       u32 TextureWindowCur;  // Current setting from last GP0(0xE2) cmd (raw form)
+       u8  TextureWindow[4];  // [0] : Texture window offset X
+                              // [1] : Texture window offset Y
+                              // [2] : Texture window mask X
+                              // [3] : Texture window mask Y
+
+       u16 DrawingArea[4];    // [0] : Drawing area top left X
+                              // [1] : Drawing area top left Y
+                              // [2] : Drawing area bottom right X
+                              // [3] : Drawing area bottom right Y
+
+       s16 DrawingOffset[2];  // [0] : Drawing offset X (signed)
+                              // [1] : Drawing offset Y (signed)
+
+       u16* TBA;              // Ptr to current texture in VRAM
+       u16* CBA;              // Ptr to current CLUT in VRAM
+
+       ////////////////////////////////////////////////////////////////////////////
+       //  Inner Loop parameters
+
+       // 22.10 Fixed-pt texture coords, mask, scanline advance
+       // NOTE: U,V are no longer packed together into one u32, this proved to be
+       //  too imprecise, leading to pixel dropouts.  Example: NFS3's skybox.
+       u32 u, v;
+       u32 u_msk, v_msk;
+       s32 u_inc, v_inc;
+
+       // Color for Gouraud-shaded prims
+       // Packed fixed-pt 8.3:8.3:8.2 rgb triplet
+       //  layout:  rrrrrrrrXXXggggggggXXXbbbbbbbbXX
+       //           ^ bit 31                       ^ bit 0
+       u32 gCol;
+       u32 gInc;          // Increment along scanline for gCol
+
+       // Color for flat-shaded, texture-blended prims
+       u8  r5, g5, b5;    // 5-bit light for undithered prims
+       u8  r8, g8, b8;    // 8-bit light for dithered prims
+
+       // Color for flat-shaded, untextured prims
+       u16 PixelData;      // bgr555 color for untextured flat-shaded polys
+
+       // End of inner Loop parameters
+       ////////////////////////////////////////////////////////////////////////////
+
+
+       u8 blit_mask;           // Determines what pixels to skip when rendering.
+                               //  Only useful on low-resolution devices using
+                               //  a simple pixel-dropping downscaler for PS1
+                               //  high-res modes. See 'pixel_skip' option.
+
+       u8 ilace_mask;          // Determines what lines to skip when rendering.
+                               //  Normally 0 when PS1 240 vertical res is in
+                               //  use and ilace_force is 0. When running in
+                               //  PS1 480 vertical res on a low-resolution
+                               //  device (320x240), will usually be set to 1
+                               //  so odd lines are not rendered. (Unless future
+                               //  full-screen scaling option is in use ..TODO)
+
+       bool prog_ilace_flag;   // Tracks successive frames for 'prog_ilace' option
+
+       u8 BLEND_MODE;
+       u8 TEXT_MODE;
+       u8 Masking;
+
+       u16 PixelMSB;
+
+       gpu_unai_config_t config;
+
+       u8  LightLUT[32*32];    // 5-bit lighting LUT (gpu_inner_light.h)
+       u32 DitherMatrix[64];   // Matrix of dither coefficients
+};
+
+static gpu_unai_t gpu_unai;
+
+// Global config that frontend can alter.. Values are read in GPU_init().
+// TODO: if frontend menu modifies a setting, add a function that can notify
+// GPU plugin to use new setting.
+gpu_unai_config_t gpu_unai_config_ext;
+
+///////////////////////////////////////////////////////////////////////////////
+// Internal inline funcs to get option status: (Allows flexibility)
+static inline bool LightingEnabled()
+{
+       return gpu_unai.config.lighting;
+}
+
+static inline bool FastLightingEnabled()
+{
+       return gpu_unai.config.fast_lighting;
+}
+
+static inline bool BlendingEnabled()
+{
+       return gpu_unai.config.blending;
+}
+
+static inline bool DitheringEnabled()
+{
+       return gpu_unai.config.dithering;
+}
+
+// For now, this is just for development/experimentation purposes..
+// If modified to return true, it will allow ignoring the status register
+//  bit 9 setting (dither enable). It will still restrict dithering only
+//  to Gouraud-shaded or texture-blended polys.
+static inline bool ForcedDitheringEnabled()
+{
+       return false;
+}
+
+static inline bool ProgressiveInterlaceEnabled()
+{
+#ifdef USE_GPULIB
+       // Using this old option greatly decreases quality of image. Disabled
+       //  for now when using new gpulib, since it also adds more work in loops.
+       return false;
+#else
+       return gpu_unai.config.prog_ilace;
+#endif
+}
+
+// For now, 320x240 output resolution is assumed, using simple line-skipping
+//  and pixel-skipping downscaler.
+// TODO: Flesh these out so they return useful values based on whether
+//       running on higher-res device or a resampling downscaler is enabled.
+static inline bool PixelSkipEnabled()
+{
+       return gpu_unai.config.pixel_skip || gpu_unai.config.scale_hires;
+}
+
+static inline bool LineSkipEnabled()
+{
+       return true;
+}
+
+#endif // GPU_UNAI_H
index 2dedbf8..588134d 100644 (file)
@@ -2,6 +2,7 @@
 *   Copyright (C) 2010 PCSX4ALL Team                                      *
 *   Copyright (C) 2010 Unai                                               *
 *   Copyright (C) 2011 notaz                                              *
+*   Copyright (C) 2016 Senquack (dansilsby <AT> gmail <DOT> com)          *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
 ***************************************************************************/
 
+#include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include "../gpulib/gpu.h"
-#include "arm_features.h"
-
-#define u8 uint8_t
-#define s8 int8_t
-#define u16 uint16_t
-#define s16 int16_t
-#define u32 uint32_t
-#define s32 int32_t
-#define s64 int64_t
-
-#define INLINE static
-
-#define        FRAME_BUFFER_SIZE  (1024*512*2)
-#define        FRAME_WIDTH        1024
-#define        FRAME_HEIGHT       512
-#define        FRAME_OFFSET(x,y)  (((y)<<10)+(x))
-
-#define isSkip 0 /* skip frame (info coming from GPU) */
-#define alt_fps 0
-static int linesInterlace;  /* internal lines interlace */
-static int force_interlace;
-
-static bool light = true; /* lighting */
-static bool blend = true; /* blending */
-static bool FrameToRead = false; /* load image in progress */
-static bool FrameToWrite = false; /* store image in progress */
-
-static bool enableAbbeyHack = false; /* Abe's Odyssey hack */
-
-static u8 BLEND_MODE;
-static u8 TEXT_MODE;
-static u8 Masking;
-
-static u16 PixelMSB;
-static u16 PixelData;
-
-///////////////////////////////////////////////////////////////////////////////
-//  GPU Global data
-///////////////////////////////////////////////////////////////////////////////
-
-//  Dma Transfers info
-static s32             px,py;
-static s32             x_end,y_end;
-static u16*  pvram;
-
-static s32 PacketCount;
-static s32 PacketIndex;
-
-//  Rasterizer status
-static u32 TextureWindow [4];
-static u32 DrawingArea   [4];
-static u32 DrawingOffset [2];
-
-static u16* TBA;
-static u16* CBA;
-
-//  Inner Loops
-static s32   u4, du4;
-static s32   v4, dv4;
-static s32   r4, dr4;
-static s32   g4, dg4;
-static s32   b4, db4;
-static u32   lInc;
-static u32   tInc, tMsk;
-
-union GPUPacket
-{
-       u32 U4[16];
-       s32 S4[16];
-       u16 U2[32];
-       s16 S2[32];
-       u8  U1[64];
-       s8  S1[64];
-};
-
-static GPUPacket PacketBuffer;
-static u16  *GPU_FrameBuffer;
-static u32   GPU_GP1;
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include "../gpu_unai/gpu_fixedpoint.h"
-
-//  Inner loop driver instanciation file
-#include "../gpu_unai/gpu_inner.h"
 
-//  GPU Raster Macros
-#define        GPU_RGB16(rgb)        ((((rgb)&0xF80000)>>9)|(((rgb)&0xF800)>>6)|(((rgb)&0xF8)>>3))
+#ifdef THREAD_RENDERING
+#include "../gpulib/gpulib_thread_if.h"
+#define do_cmd_list real_do_cmd_list
+#define renderer_init real_renderer_init
+#define renderer_finish real_renderer_finish
+#define renderer_sync_ecmds real_renderer_sync_ecmds
+#define renderer_update_caches real_renderer_update_caches
+#define renderer_flush_queues real_renderer_flush_queues
+#define renderer_set_interlace real_renderer_set_interlace
+#define renderer_set_config real_renderer_set_config
+#define renderer_notify_res_change real_renderer_notify_res_change
+#define renderer_notify_update_lace real_renderer_notify_update_lace
+#define renderer_sync real_renderer_sync
+#define ex_regs scratch_ex_regs
+#endif
 
-#define GPU_EXPANDSIGN(x)  (((s32)(x)<<21)>>21)
+//#include "port.h"
+#include "gpu_unai.h"
 
-#define CHKMAX_X 1024
-#define CHKMAX_Y 512
+// GPU fixed point math
+#include "gpu_fixedpoint.h"
 
-#define        GPU_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
+// Inner loop driver instantiation file
+#include "gpu_inner.h"
 
 // GPU internal image drawing functions
-#include "../gpu_unai/gpu_raster_image.h"
+#include "gpu_raster_image.h"
 
 // GPU internal line drawing functions
-#include "../gpu_unai/gpu_raster_line.h"
+#include "gpu_raster_line.h"
 
 // GPU internal polygon drawing functions
-#include "../gpu_unai/gpu_raster_polygon.h"
+#include "gpu_raster_polygon.h"
 
 // GPU internal sprite drawing functions
-#include "../gpu_unai/gpu_raster_sprite.h"
+#include "gpu_raster_sprite.h"
 
 // GPU command buffer execution/store
-#include "../gpu_unai/gpu_command.h"
+#include "gpu_command.h"
 
 /////////////////////////////////////////////////////////////////////////////
 
+#define DOWNSCALE_VRAM_SIZE (1024 * 512 * 2 * 2 + 4096)
+
+INLINE void scale_640_to_320(uint16_t *dest, const uint16_t *src, bool isRGB24) {
+  size_t uCount = 320;
+
+  if(isRGB24) {
+    const uint8_t* src8 = (const uint8_t *)src;
+    uint8_t* dst8 = (uint8_t *)dest;
+
+    do {
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8;
+      src8 += 4;
+    } while(--uCount);
+  } else {
+    const uint16_t* src16 = src;
+    uint16_t* dst16 = dest;
+
+    do {
+      *dst16++ = *src16;
+      src16 += 2;
+    } while(--uCount);
+  }
+}
+
+INLINE void scale_512_to_320(uint16_t *dest, const uint16_t *src, bool isRGB24) {
+  size_t uCount = 64;
+
+  if(isRGB24) {
+    const uint8_t* src8 = (const uint8_t *)src;
+    uint8_t* dst8 = (uint8_t *)dest;
+
+    do {
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8;
+      src8 += 4;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8;
+      src8 += 4;
+      *dst8++ = *src8++;
+      *dst8++ = *src8++;
+      *dst8++ = *src8;
+      src8 += 4;
+    } while(--uCount);
+  } else {
+    const uint16_t* src16 = src;
+    uint16_t* dst16 = dest;
+
+    do {
+      *dst16++ = *src16++;
+      *dst16++ = *src16;
+      src16 += 2;
+      *dst16++ = *src16++;
+      *dst16++ = *src16;
+      src16 += 2;
+      *dst16++ = *src16;
+      src16 += 2;
+    } while(--uCount);
+  }
+}
+
+static uint16_t *get_downscale_buffer(int *x, int *y, int *w, int *h, int *vram_h)
+{
+  uint16_t *dest = gpu_unai.downscale_vram;
+  const uint16_t *src = gpu_unai.vram;
+  bool isRGB24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false);
+  int stride = 1024, dstride = 1024, lines = *h, orig_w = *w;
+
+  // PS1 fb read wraps around (fixes black screen in 'Tobal no. 1')
+  unsigned int fb_mask = 1024 * 512 - 1;
+
+  if (*h > 240) {
+    *h /= 2;
+    stride *= 2;
+    lines = *h;
+
+    // Ensure start at a non-skipped line
+    while (*y & gpu_unai.ilace_mask) ++*y;
+  }
+
+  unsigned int fb_offset_src = (*y * dstride + *x) & fb_mask;
+  unsigned int fb_offset_dest = fb_offset_src;
+
+  if (*w == 512 || *w == 640) {
+    *w = 320;
+  }
+
+  switch(orig_w) {
+  case 640:
+    do {
+      scale_640_to_320(dest + fb_offset_dest, src + fb_offset_src, isRGB24);
+      fb_offset_src = (fb_offset_src + stride) & fb_mask;
+      fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
+    } while(--lines);
+
+    break;
+  case 512:
+    do {
+      scale_512_to_320(dest + fb_offset_dest, src + fb_offset_src, isRGB24);
+      fb_offset_src = (fb_offset_src + stride) & fb_mask;
+      fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
+    } while(--lines);
+    break;
+  default:
+    size_t size = isRGB24 ? *w * 3 : *w * 2;
+
+    do {
+      memcpy(dest + fb_offset_dest, src + fb_offset_src, size);
+      fb_offset_src = (fb_offset_src + stride) & fb_mask;
+      fb_offset_dest = (fb_offset_dest + dstride) & fb_mask;
+    } while(--lines);
+    break;
+  }
+
+  return gpu_unai.downscale_vram;
+}
+
+static void map_downscale_buffer(void)
+{
+  if (gpu_unai.downscale_vram)
+    return;
+
+  gpu_unai.downscale_vram = (uint16_t*)gpu.mmap(DOWNSCALE_VRAM_SIZE);
+
+  if (gpu_unai.downscale_vram == NULL) {
+    fprintf(stderr, "failed to map downscale buffer\n");
+    gpu.get_downscale_buffer = NULL;
+  }
+  else {
+    gpu.get_downscale_buffer = get_downscale_buffer;
+  }
+}
+
+static void unmap_downscale_buffer(void)
+{
+  if (gpu_unai.downscale_vram == NULL)
+    return;
+
+  gpu.munmap(gpu_unai.downscale_vram, DOWNSCALE_VRAM_SIZE);
+  gpu_unai.downscale_vram = NULL;
+  gpu.get_downscale_buffer = NULL;
+}
+
 int renderer_init(void)
 {
-       GPU_FrameBuffer = (u16 *)gpu.vram;
-
-       // s_invTable
-       for(int i=1;i<=(1<<TABLE_BITS);++i)
-       {
-               double v = 1.0 / double(i);
-               #ifdef GPU_TABLE_10_BITS
-               v *= double(0xffffffff>>1);
-               #else
-               v *= double(0x80000000);
-               #endif
-               s_invTable[i-1]=s32(v);
-       }
-
-       return 0;
+  memset((void*)&gpu_unai, 0, sizeof(gpu_unai));
+  gpu_unai.vram = (u16*)gpu.vram;
+
+  // Original standalone gpu_unai initialized TextureWindow[]. I added the
+  //  same behavior here, since it seems unsafe to leave [2],[3] unset when
+  //  using HLE and Rearmed gpu_neon sets this similarly on init. -senquack
+  gpu_unai.TextureWindow[0] = 0;
+  gpu_unai.TextureWindow[1] = 0;
+  gpu_unai.TextureWindow[2] = 255;
+  gpu_unai.TextureWindow[3] = 255;
+  //senquack - new vars must be updated whenever texture window is changed:
+  //           (used for polygon-drawing in gpu_inner.h, gpu_raster_polygon.h)
+  const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
+  gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
+  gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
+
+  // Configuration options
+  gpu_unai.config = gpu_unai_config_ext;
+  //senquack - disabled, not sure this is needed and would require modifying
+  // sprite-span functions, perhaps unnecessarily. No Abe Oddysey hack was
+  // present in latest PCSX4ALL sources we were using.
+  //gpu_unai.config.enableAbbeyHack = gpu_unai_config_ext.abe_hack;
+  gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
+
+#ifdef GPU_UNAI_USE_INT_DIV_MULTINV
+  // s_invTable
+  for(int i=1;i<=(1<<TABLE_BITS);++i)
+  {
+    double v = 1.0 / double(i);
+#ifdef GPU_TABLE_10_BITS
+    v *= double(0xffffffff>>1);
+#else
+    v *= double(0x80000000);
+#endif
+    s_invTable[i-1]=s32(v);
+  }
+#endif
+
+  SetupLightLUT();
+  SetupDitheringConstants();
+
+  if (gpu_unai.config.scale_hires) {
+    map_downscale_buffer();
+  }
+
+  return 0;
 }
 
 void renderer_finish(void)
 {
+  unmap_downscale_buffer();
 }
 
 void renderer_notify_res_change(void)
 {
+  if (PixelSkipEnabled()) {
+    // Set blit_mask for high horizontal resolutions. This allows skipping
+    //  rendering pixels that would never get displayed on low-resolution
+    //  platforms that use simple pixel-dropping scaler.
+
+    switch (gpu.screen.hres)
+    {
+      case 512: gpu_unai.blit_mask = 0xa4; break; // GPU_BlitWWSWWSWS
+      case 640: gpu_unai.blit_mask = 0xaa; break; // GPU_BlitWS
+      default:  gpu_unai.blit_mask = 0;    break;
+    }
+  } else {
+    gpu_unai.blit_mask = 0;
+  }
+
+  if (LineSkipEnabled()) {
+    // Set rendering line-skip (only render every other line in high-res
+    //  480 vertical mode, or, optionally, force it for all video modes)
+
+    if (gpu.screen.vres == 480) {
+      if (gpu_unai.config.ilace_force) {
+        gpu_unai.ilace_mask = 3; // Only need 1/4 of lines
+      } else {
+        gpu_unai.ilace_mask = 1; // Only need 1/2 of lines
+      }
+    } else {
+      // Vert resolution changed from 480 to lower one
+      gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
+    }
+  } else {
+    gpu_unai.ilace_mask = 0;
+  }
+
+  /*
+  printf("res change hres: %d   vres: %d   depth: %d   ilace_mask: %d\n",
+      gpu.screen.hres, gpu.screen.vres, gpu.status.rgb24 ? 24 : 15,
+      gpu_unai.ilace_mask);
+  */
 }
 
+#ifdef USE_GPULIB
+// Handles GP0 draw settings commands 0xE1...0xE6
+static void gpuGP0Cmd_0xEx(gpu_unai_t &gpu_unai, u32 cmd_word)
+{
+  // Assume incoming GP0 command is 0xE1..0xE6, convert to 1..6
+  u8 num = (cmd_word >> 24) & 7;
+  gpu.ex_regs[num] = cmd_word; // Update gpulib register
+  switch (num) {
+    case 1: {
+      // GP0(E1h) - Draw Mode setting (aka "Texpage")
+      u32 cur_texpage = gpu_unai.GPU_GP1 & 0x7FF;
+      u32 new_texpage = cmd_word & 0x7FF;
+      if (cur_texpage != new_texpage) {
+        gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x7FF) | new_texpage;
+        gpuSetTexture(gpu_unai.GPU_GP1);
+      }
+    } break;
+
+    case 2: {
+      // GP0(E2h) - Texture Window setting
+      if (cmd_word != gpu_unai.TextureWindowCur) {
+        static const u8 TextureMask[32] = {
+          255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
+          127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
+        };
+        gpu_unai.TextureWindowCur = cmd_word;
+        gpu_unai.TextureWindow[0] = ((cmd_word >> 10) & 0x1F) << 3;
+        gpu_unai.TextureWindow[1] = ((cmd_word >> 15) & 0x1F) << 3;
+        gpu_unai.TextureWindow[2] = TextureMask[(cmd_word >> 0) & 0x1F];
+        gpu_unai.TextureWindow[3] = TextureMask[(cmd_word >> 5) & 0x1F];
+        gpu_unai.TextureWindow[0] &= ~gpu_unai.TextureWindow[2];
+        gpu_unai.TextureWindow[1] &= ~gpu_unai.TextureWindow[3];
+
+        // Inner loop vars must be updated whenever texture window is changed:
+        const u32 fb = FIXED_BITS;  // # of fractional fixed-pt bits of u4/v4
+        gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1);
+        gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1);
+
+        gpuSetTexture(gpu_unai.GPU_GP1);
+      }
+    } break;
+
+    case 3: {
+      // GP0(E3h) - Set Drawing Area top left (X1,Y1)
+      gpu_unai.DrawingArea[0] = cmd_word         & 0x3FF;
+      gpu_unai.DrawingArea[1] = (cmd_word >> 10) & 0x3FF;
+    } break;
+
+    case 4: {
+      // GP0(E4h) - Set Drawing Area bottom right (X2,Y2)
+      gpu_unai.DrawingArea[2] = (cmd_word         & 0x3FF) + 1;
+      gpu_unai.DrawingArea[3] = ((cmd_word >> 10) & 0x3FF) + 1;
+    } break;
+
+    case 5: {
+      // GP0(E5h) - Set Drawing Offset (X,Y)
+      gpu_unai.DrawingOffset[0] = ((s32)cmd_word<<(32-11))>>(32-11);
+      gpu_unai.DrawingOffset[1] = ((s32)cmd_word<<(32-22))>>(32-11);
+    } break;
+
+    case 6: {
+      // GP0(E6h) - Mask Bit Setting
+      gpu_unai.Masking  = (cmd_word & 0x2) <<  1;
+      gpu_unai.PixelMSB = (cmd_word & 0x1) <<  8;
+    } break;
+  }
+}
+#endif
+
 extern const unsigned char cmd_lengths[256];
 
-int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
+int do_cmd_list(u32 *list, int list_len, int *last_cmd)
 {
-  unsigned int cmd = 0, len, i;
-  unsigned int *list_start = list;
-  unsigned int *list_end = list + list_len;
+  u32 cmd = 0, len, i;
+  u32 *list_start = list;
+  u32 *list_end = list + list_len;
+
+  //TODO: set ilace_mask when resolution changes instead of every time,
+  // eliminate #ifdef below.
+  gpu_unai.ilace_mask = gpu_unai.config.ilace_force;
 
-  linesInterlace = force_interlace;
 #ifdef HAVE_PRE_ARMV7 /* XXX */
-  linesInterlace |= gpu.status.interlace;
+  gpu_unai.ilace_mask |= gpu.status.interlace;
 #endif
+  if (gpu_unai.config.scale_hires) {
+    gpu_unai.ilace_mask |= gpu.status.interlace;
+  }
 
   for (; list < list_end; list += 1 + len)
   {
@@ -186,126 +415,175 @@ int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
     }
 
     #define PRIM cmd
-    PacketBuffer.U4[0] = list[0];
+    gpu_unai.PacketBuffer.U4[0] = list[0];
     for (i = 1; i <= len; i++)
-      PacketBuffer.U4[i] = list[i];
+      gpu_unai.PacketBuffer.U4[i] = list[i];
+
+    PtrUnion packet = { .ptr = (void*)&gpu_unai.PacketBuffer };
 
     switch (cmd)
     {
       case 0x02:
-        gpuClearImage();
+        gpuClearImage(packet);
         break;
 
       case 0x20:
       case 0x21:
       case 0x22:
-      case 0x23:
-        gpuDrawF3(gpuPolySpanDrivers [Blending_Mode | Masking | Blending | PixelMSB]);
-        break;
+      case 0x23: {          // Monochrome 3-pt poly
+        PP driver = gpuPolySpanDrivers[
+          (gpu_unai.blit_mask?1024:0) |
+          Blending_Mode |
+          gpu_unai.Masking | Blending | gpu_unai.PixelMSB
+        ];
+        gpuDrawPolyF(packet, driver, false);
+      } break;
 
       case 0x24:
       case 0x25:
       case 0x26:
-      case 0x27:
-        gpuSetCLUT   (PacketBuffer.U4[2] >> 16);
-        gpuSetTexture(PacketBuffer.U4[4] >> 16);
-        if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-          gpuDrawFT3(gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | PixelMSB]);
-        else
-          gpuDrawFT3(gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | PixelMSB]);
-        break;
+      case 0x27: {          // Textured 3-pt poly
+        gpuSetCLUT   (gpu_unai.PacketBuffer.U4[2] >> 16);
+        gpuSetTexture(gpu_unai.PacketBuffer.U4[4] >> 16);
+
+        u32 driver_idx =
+          (gpu_unai.blit_mask?1024:0) |
+          Dithering |
+          Blending_Mode | gpu_unai.TEXT_MODE |
+          gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
+
+        if (!FastLightingEnabled()) {
+          driver_idx |= Lighting;
+        } else {
+          if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
+            driver_idx |= Lighting;
+        }
+
+        PP driver = gpuPolySpanDrivers[driver_idx];
+        gpuDrawPolyFT(packet, driver, false);
+      } break;
 
       case 0x28:
       case 0x29:
       case 0x2A:
-      case 0x2B: {
-        const PP gpuPolySpanDriver = gpuPolySpanDrivers [Blending_Mode | Masking | Blending | PixelMSB];
-        gpuDrawF3(gpuPolySpanDriver);
-        PacketBuffer.U4[1] = PacketBuffer.U4[4];
-        gpuDrawF3(gpuPolySpanDriver);
-        break;
-      }
+      case 0x2B: {          // Monochrome 4-pt poly
+        PP driver = gpuPolySpanDrivers[
+          (gpu_unai.blit_mask?1024:0) |
+          Blending_Mode |
+          gpu_unai.Masking | Blending | gpu_unai.PixelMSB
+        ];
+        gpuDrawPolyF(packet, driver, true); // is_quad = true
+      } break;
 
       case 0x2C:
       case 0x2D:
       case 0x2E:
-      case 0x2F: {
-        gpuSetCLUT   (PacketBuffer.U4[2] >> 16);
-        gpuSetTexture(PacketBuffer.U4[4] >> 16);
-        PP gpuPolySpanDriver;
-        if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-          gpuPolySpanDriver = gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | PixelMSB];
-        else
-          gpuPolySpanDriver = gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | PixelMSB];
-        gpuDrawFT3(gpuPolySpanDriver);
-        PacketBuffer.U4[1] = PacketBuffer.U4[7];
-        PacketBuffer.U4[2] = PacketBuffer.U4[8];
-        gpuDrawFT3(gpuPolySpanDriver);
-        break;
-      }
+      case 0x2F: {          // Textured 4-pt poly
+        gpuSetCLUT   (gpu_unai.PacketBuffer.U4[2] >> 16);
+        gpuSetTexture(gpu_unai.PacketBuffer.U4[4] >> 16);
+
+        u32 driver_idx =
+          (gpu_unai.blit_mask?1024:0) |
+          Dithering |
+          Blending_Mode | gpu_unai.TEXT_MODE |
+          gpu_unai.Masking | Blending | gpu_unai.PixelMSB;
+
+        if (!FastLightingEnabled()) {
+          driver_idx |= Lighting;
+        } else {
+          if (!((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F)))
+            driver_idx |= Lighting;
+        }
+
+        PP driver = gpuPolySpanDrivers[driver_idx];
+        gpuDrawPolyFT(packet, driver, true); // is_quad = true
+      } break;
 
       case 0x30:
       case 0x31:
       case 0x32:
-      case 0x33:
-        gpuDrawG3(gpuPolySpanDrivers [Blending_Mode | Masking | Blending | 129 | PixelMSB]);
-        break;
+      case 0x33: {          // Gouraud-shaded 3-pt poly
+        //NOTE: The '129' here is CF_GOURAUD | CF_LIGHT, however
+        // this is an untextured poly, so CF_LIGHT (texture blend)
+        // shouldn't apply. Until the original array of template
+        // instantiation ptrs is fixed, we're stuck with this. (TODO)
+        PP driver = gpuPolySpanDrivers[
+          (gpu_unai.blit_mask?1024:0) |
+          Dithering |
+          Blending_Mode |
+          gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
+        ];
+        gpuDrawPolyG(packet, driver, false);
+      } break;
 
       case 0x34:
       case 0x35:
       case 0x36:
-      case 0x37:
-        gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-        gpuSetTexture (PacketBuffer.U4[5] >> 16);
-        gpuDrawGT3(gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | ((Lighting)?129:0) | PixelMSB]);
-        break;
+      case 0x37: {          // Gouraud-shaded, textured 3-pt poly
+        gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+        gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
+        PP driver = gpuPolySpanDrivers[
+          (gpu_unai.blit_mask?1024:0) |
+          Dithering |
+          Blending_Mode | gpu_unai.TEXT_MODE |
+          gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
+        ];
+        gpuDrawPolyGT(packet, driver, false);
+      } break;
 
       case 0x38:
       case 0x39:
       case 0x3A:
-      case 0x3B: {
-        const PP gpuPolySpanDriver  = gpuPolySpanDrivers [Blending_Mode | Masking | Blending | 129 | PixelMSB];
-        gpuDrawG3(gpuPolySpanDriver);
-        PacketBuffer.U4[0] = PacketBuffer.U4[6];
-        PacketBuffer.U4[1] = PacketBuffer.U4[7];
-        gpuDrawG3(gpuPolySpanDriver);
-        break;
-      }
+      case 0x3B: {          // Gouraud-shaded 4-pt poly
+        // See notes regarding '129' for 0x30..0x33 further above -senquack
+        PP driver = gpuPolySpanDrivers[
+          (gpu_unai.blit_mask?1024:0) |
+          Dithering |
+          Blending_Mode |
+          gpu_unai.Masking | Blending | 129 | gpu_unai.PixelMSB
+        ];
+        gpuDrawPolyG(packet, driver, true); // is_quad = true
+      } break;
 
       case 0x3C:
       case 0x3D:
       case 0x3E:
-      case 0x3F: {
-        gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-        gpuSetTexture (PacketBuffer.U4[5] >> 16);
-        const PP gpuPolySpanDriver  = gpuPolySpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | ((Lighting)?129:0) | PixelMSB];
-        gpuDrawGT3(gpuPolySpanDriver);
-        PacketBuffer.U4[0] = PacketBuffer.U4[9];
-        PacketBuffer.U4[1] = PacketBuffer.U4[10];
-        PacketBuffer.U4[2] = PacketBuffer.U4[11];
-        gpuDrawGT3(gpuPolySpanDriver);
-        break;
-      }
+      case 0x3F: {          // Gouraud-shaded, textured 4-pt poly
+        gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+        gpuSetTexture (gpu_unai.PacketBuffer.U4[5] >> 16);
+        PP driver = gpuPolySpanDrivers[
+          (gpu_unai.blit_mask?1024:0) |
+          Dithering |
+          Blending_Mode | gpu_unai.TEXT_MODE |
+          gpu_unai.Masking | Blending | ((Lighting)?129:0) | gpu_unai.PixelMSB
+        ];
+        gpuDrawPolyGT(packet, driver, true); // is_quad = true
+      } break;
 
       case 0x40:
       case 0x41:
       case 0x42:
-      case 0x43:
-        gpuDrawLF(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
-        break;
-
-      case 0x48 ... 0x4F:
-      {
+      case 0x43: {          // Monochrome line
+        // Shift index right by one, as untextured prims don't use lighting
+        u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
+        PSD driver = gpuPixelSpanDrivers[driver_idx];
+        gpuDrawLineF(packet, driver);
+      } break;
+
+      case 0x48 ... 0x4F: { // Monochrome line strip
         u32 num_vertexes = 1;
         u32 *list_position = &(list[2]);
 
-        gpuDrawLF(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
+        // Shift index right by one, as untextured prims don't use lighting
+        u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
+        PSD driver = gpuPixelSpanDrivers[driver_idx];
+        gpuDrawLineF(packet, driver);
 
         while(1)
         {
-          PacketBuffer.U4[1] = PacketBuffer.U4[2];
-          PacketBuffer.U4[2] = *list_position++;
-          gpuDrawLF(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
+          gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[2];
+          gpu_unai.PacketBuffer.U4[2] = *list_position++;
+          gpuDrawLineF(packet, driver);
 
           num_vertexes++;
           if(list_position >= list_end) {
@@ -317,30 +595,38 @@ int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
         }
 
         len += (num_vertexes - 2);
-        break;
-      }
+      } break;
 
       case 0x50:
       case 0x51:
       case 0x52:
-      case 0x53:
-        gpuDrawLG(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
-        break;
-
-      case 0x58 ... 0x5F:
-      {
+      case 0x53: {          // Gouraud-shaded line
+        // Shift index right by one, as untextured prims don't use lighting
+        u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
+        // Index MSB selects Gouraud-shaded PixelSpanDriver:
+        driver_idx |= (1 << 5);
+        PSD driver = gpuPixelSpanDrivers[driver_idx];
+        gpuDrawLineG(packet, driver);
+      } break;
+
+      case 0x58 ... 0x5F: { // Gouraud-shaded line strip
         u32 num_vertexes = 1;
         u32 *list_position = &(list[2]);
 
-        gpuDrawLG(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
+        // Shift index right by one, as untextured prims don't use lighting
+        u32 driver_idx = (Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1;
+        // Index MSB selects Gouraud-shaded PixelSpanDriver:
+        driver_idx |= (1 << 5);
+        PSD driver = gpuPixelSpanDrivers[driver_idx];
+        gpuDrawLineG(packet, driver);
 
         while(1)
         {
-          PacketBuffer.U4[0] = PacketBuffer.U4[2];
-          PacketBuffer.U4[1] = PacketBuffer.U4[3];
-          PacketBuffer.U4[2] = *list_position++;
-          PacketBuffer.U4[3] = *list_position++;
-          gpuDrawLG(gpuPixelDrivers [ (Blending_Mode | Masking | Blending | (PixelMSB>>3)) >> 1]);
+          gpu_unai.PacketBuffer.U4[0] = gpu_unai.PacketBuffer.U4[2];
+          gpu_unai.PacketBuffer.U4[1] = gpu_unai.PacketBuffer.U4[3];
+          gpu_unai.PacketBuffer.U4[2] = *list_position++;
+          gpu_unai.PacketBuffer.U4[3] = *list_position++;
+          gpuDrawLineG(packet, driver);
 
           num_vertexes++;
           if(list_position >= list_end) {
@@ -352,91 +638,116 @@ int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
         }
 
         len += (num_vertexes - 2) * 2;
-        break;
-      }
+      } break;
 
       case 0x60:
       case 0x61:
       case 0x62:
-      case 0x63:
-        gpuDrawT(gpuTileSpanDrivers [Blending_Mode | Masking | Blending | (PixelMSB>>3)]);
-        break;
+      case 0x63: {          // Monochrome rectangle (variable size)
+        PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
+        gpuDrawT(packet, driver);
+      } break;
 
       case 0x64:
       case 0x65:
       case 0x66:
-      case 0x67:
-        gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-        gpuSetTexture (GPU_GP1);
-        if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-          gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | (enableAbbeyHack<<7)  | PixelMSB]);
-        else
-          gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | (enableAbbeyHack<<7)  | PixelMSB]);
-        break;
+      case 0x67: {          // Textured rectangle (variable size)
+        gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+        u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
+
+        //senquack - Only color 808080h-878787h allows skipping lighting calculation:
+        // This fixes Silent Hill running animation on loading screens:
+        // (On PSX, color values 0x00-0x7F darken the source texture's color,
+        //  0x81-FF lighten textures (ultimately clamped to 0x1F),
+        //  0x80 leaves source texture color unchanged, HOWEVER,
+        //   gpu_unai uses a simple lighting LUT whereby only the upper
+        //   5 bits of an 8-bit color are used, so 0x80-0x87 all behave as
+        //   0x80.
+        // 
+        // NOTE: I've changed all textured sprite draw commands here and
+        //  elsewhere to use proper behavior, but left poly commands
+        //  alone, I don't want to slow rendering down too much. (TODO)
+        //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
+        // Strip lower 3 bits of each color and determine if lighting should be used:
+        if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
+          driver_idx |= Lighting;
+        PS driver = gpuSpriteSpanDrivers[driver_idx];
+        gpuDrawS(packet, driver);
+      } break;
 
       case 0x68:
       case 0x69:
       case 0x6A:
-      case 0x6B:
-        PacketBuffer.U4[2] = 0x00010001;
-        gpuDrawT(gpuTileSpanDrivers [Blending_Mode | Masking | Blending | (PixelMSB>>3)]);
-        break;
+      case 0x6B: {          // Monochrome rectangle (1x1 dot)
+        gpu_unai.PacketBuffer.U4[2] = 0x00010001;
+        PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
+        gpuDrawT(packet, driver);
+      } break;
 
       case 0x70:
       case 0x71:
       case 0x72:
-      case 0x73:
-        PacketBuffer.U4[2] = 0x00080008;
-        gpuDrawT(gpuTileSpanDrivers [Blending_Mode | Masking | Blending | (PixelMSB>>3)]);
-        break;
+      case 0x73: {          // Monochrome rectangle (8x8)
+        gpu_unai.PacketBuffer.U4[2] = 0x00080008;
+        PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
+        gpuDrawT(packet, driver);
+      } break;
 
       case 0x74:
       case 0x75:
       case 0x76:
-      case 0x77:
-        PacketBuffer.U4[3] = 0x00080008;
-        gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-        gpuSetTexture (GPU_GP1);
-        if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-          gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | (enableAbbeyHack<<7)  | PixelMSB]);
-        else
-          gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | (enableAbbeyHack<<7)  | PixelMSB]);
-        break;
+      case 0x77: {          // Textured rectangle (8x8)
+        gpu_unai.PacketBuffer.U4[3] = 0x00080008;
+        gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+        u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
+
+        //senquack - Only color 808080h-878787h allows skipping lighting calculation:
+        //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
+        // Strip lower 3 bits of each color and determine if lighting should be used:
+        if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
+          driver_idx |= Lighting;
+        PS driver = gpuSpriteSpanDrivers[driver_idx];
+        gpuDrawS(packet, driver);
+      } break;
 
       case 0x78:
       case 0x79:
       case 0x7A:
-      case 0x7B:
-        PacketBuffer.U4[2] = 0x00100010;
-        gpuDrawT(gpuTileSpanDrivers [Blending_Mode | Masking | Blending | (PixelMSB>>3)]);
-        break;
+      case 0x7B: {          // Monochrome rectangle (16x16)
+        gpu_unai.PacketBuffer.U4[2] = 0x00100010;
+        PT driver = gpuTileSpanDrivers[(Blending_Mode | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>3)) >> 1];
+        gpuDrawT(packet, driver);
+      } break;
 
       case 0x7C:
       case 0x7D:
 #ifdef __arm__
-        if ((GPU_GP1 & 0x180) == 0 && (Masking | PixelMSB) == 0)
+        if ((gpu_unai.GPU_GP1 & 0x180) == 0 && (gpu_unai.Masking | gpu_unai.PixelMSB) == 0)
         {
-          gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-          gpuSetTexture (GPU_GP1);
-          gpuDrawS16();
+          gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+          gpuDrawS16(packet);
           break;
         }
         // fallthrough
 #endif
       case 0x7E:
-      case 0x7F:
-        PacketBuffer.U4[3] = 0x00100010;
-        gpuSetCLUT    (PacketBuffer.U4[2] >> 16);
-        gpuSetTexture (GPU_GP1);
-        if ((PacketBuffer.U1[0]>0x5F) && (PacketBuffer.U1[1]>0x5F) && (PacketBuffer.U1[2]>0x5F))
-          gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | (enableAbbeyHack<<7)  | PixelMSB]);
-        else
-          gpuDrawS(gpuSpriteSpanDrivers [Blending_Mode | TEXT_MODE | Masking | Blending | Lighting | (enableAbbeyHack<<7)  | PixelMSB]);
-        break;
+      case 0x7F: {          // Textured rectangle (16x16)
+        gpu_unai.PacketBuffer.U4[3] = 0x00100010;
+        gpuSetCLUT    (gpu_unai.PacketBuffer.U4[2] >> 16);
+        u32 driver_idx = Blending_Mode | gpu_unai.TEXT_MODE | gpu_unai.Masking | Blending | (gpu_unai.PixelMSB>>1);
+        //senquack - Only color 808080h-878787h allows skipping lighting calculation:
+        //if ((gpu_unai.PacketBuffer.U1[0]>0x5F) && (gpu_unai.PacketBuffer.U1[1]>0x5F) && (gpu_unai.PacketBuffer.U1[2]>0x5F))
+        // Strip lower 3 bits of each color and determine if lighting should be used:
+        if ((gpu_unai.PacketBuffer.U4[0] & 0xF8F8F8) != 0x808080)
+          driver_idx |= Lighting;
+        PS driver = gpuSpriteSpanDrivers[driver_idx];
+        gpuDrawS(packet, driver);
+      } break;
 
       case 0x80:          //  vid -> vid
-        gpuMoveImage();   //  prim handles updateLace && skip
+        gpuMoveImage(packet);
         break;
+
 #ifdef TEST
       case 0xA0:          //  sys -> vid
       {
@@ -445,70 +756,25 @@ int do_cmd_list(unsigned int *list, int list_len, int *last_cmd)
         u32 load_size = load_width * load_height;
 
         len += load_size / 2;
-        break;
-      }
+      } break;
+
       case 0xC0:
         break;
 #else
       case 0xA0:          //  sys ->vid
       case 0xC0:          //  vid -> sys
+        // Handled by gpulib
         goto breakloop;
 #endif
-      case 0xE1: {
-        const u32 temp = PacketBuffer.U4[0];
-        GPU_GP1 = (GPU_GP1 & ~0x000007FF) | (temp & 0x000007FF);
-        gpuSetTexture(temp);
-        gpu.ex_regs[1] = temp;
-        break;
-      }
-      case 0xE2: {
-        static const u8  TextureMask[32] = {
-          255, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7,
-          127, 7, 15, 7, 31, 7, 15, 7, 63, 7, 15, 7, 31, 7, 15, 7
-        };
-        const u32 temp = PacketBuffer.U4[0];
-        TextureWindow[0] = ((temp >> 10) & 0x1F) << 3;
-        TextureWindow[1] = ((temp >> 15) & 0x1F) << 3;
-        TextureWindow[2] = TextureMask[(temp >> 0) & 0x1F];
-        TextureWindow[3] = TextureMask[(temp >> 5) & 0x1F];
-        gpuSetTexture(GPU_GP1);
-        gpu.ex_regs[2] = temp;
-        break;
-      }
-      case 0xE3: {
-        const u32 temp = PacketBuffer.U4[0];
-        DrawingArea[0] = temp         & 0x3FF;
-        DrawingArea[1] = (temp >> 10) & 0x3FF;
-        gpu.ex_regs[3] = temp;
-        break;
-      }
-      case 0xE4: {
-        const u32 temp = PacketBuffer.U4[0];
-        DrawingArea[2] = (temp         & 0x3FF) + 1;
-        DrawingArea[3] = ((temp >> 10) & 0x3FF) + 1;
-        gpu.ex_regs[4] = temp;
-        break;
-      }
-      case 0xE5: {
-        const u32 temp = PacketBuffer.U4[0];
-        DrawingOffset[0] = ((s32)temp<<(32-11))>>(32-11);
-        DrawingOffset[1] = ((s32)temp<<(32-22))>>(32-11);
-        gpu.ex_regs[5] = temp;
-        break;
-      }
-      case 0xE6: {
-        const u32 temp = PacketBuffer.U4[0];
-        Masking = (temp & 0x2) <<  1;
-        PixelMSB =(temp & 0x1) <<  8;
-        gpu.ex_regs[6] = temp;
-        break;
-      }
+      case 0xE1 ... 0xE6: { // Draw settings
+        gpuGP0Cmd_0xEx(gpu_unai, gpu_unai.PacketBuffer.U4[0]);
+      } break;
     }
   }
 
 breakloop:
   gpu.ex_regs[1] &= ~0x1ff;
-  gpu.ex_regs[1] |= GPU_GP1 & 0x1ff;
+  gpu.ex_regs[1] |= gpu_unai.GPU_GP1 & 0x1ff;
 
   *last_cmd = cmd;
   return list - list_start;
@@ -532,20 +798,33 @@ void renderer_set_interlace(int enable, int is_odd)
 {
 }
 
-#ifndef TEST
-
 #include "../../frontend/plugin_lib.h"
-
+// Handle any gpulib settings applicable to gpu_unai:
 void renderer_set_config(const struct rearmed_cbs *cbs)
 {
-  force_interlace = cbs->gpu_unai.lineskip;
-  enableAbbeyHack = cbs->gpu_unai.abe_hack;
-  light = !cbs->gpu_unai.no_light;
-  blend = !cbs->gpu_unai.no_blend;
+  gpu_unai.vram = (u16*)gpu.vram;
+  gpu_unai.config.ilace_force   = cbs->gpu_unai.ilace_force;
+  gpu_unai.config.pixel_skip    = cbs->gpu_unai.pixel_skip;
+  gpu_unai.config.lighting      = cbs->gpu_unai.lighting;
+  gpu_unai.config.fast_lighting = cbs->gpu_unai.fast_lighting;
+  gpu_unai.config.blending      = cbs->gpu_unai.blending;
+  gpu_unai.config.dithering     = cbs->gpu_unai.dithering;
+  gpu_unai.config.scale_hires   = cbs->gpu_unai.scale_hires;
+
+  gpu.state.downscale_enable    = gpu_unai.config.scale_hires;
+  if (gpu_unai.config.scale_hires) {
+    map_downscale_buffer();
+  } else {
+    unmap_downscale_buffer();
+  }
+}
 
-  GPU_FrameBuffer = (u16 *)gpu.vram;
+void renderer_sync(void)
+{
 }
 
-#endif
+void renderer_notify_update_lace(int updated)
+{
+}
 
 // vim:shiftwidth=2:expandtab
index 238b98b..0a731f8 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __GPU_UNAI_GPU_PORT_H__
+#define __GPU_UNAI_GPU_PORT_H__
+
 #include <stddef.h>
 #include <string.h>
 
@@ -34,3 +37,5 @@ void GPUwriteStatus(u32 data);
 #undef s32
 
 }
+
+#endif /* __GPU_UNAI_GPU_PORT_H__ */
index c09c95f..a23ee38 100644 (file)
@@ -1,4 +1,9 @@
+#ifndef __GPU_UNAI_GPU_PROFILER_H__
+#define __GPU_UNAI_GPU_PROFILER_H__
+
 #define pcsx4all_prof_pause(...)
 #define pcsx4all_prof_start_with_pause(...)
 #define pcsx4all_prof_end_with_resume(...)
 #define pcsx4all_prof_resume(...)
+
+#endif /* __GPU_UNAI_GPU_PROFILER_H__ */
index d67df03..ed37b71 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h> /* for calloc */
+
 #include "gpu.h"
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@@ -38,6 +40,8 @@ static void finish_vram_transfer(int is_read);
 
 static noinline void do_cmd_reset(void)
 {
+  renderer_sync();
+
   if (unlikely(gpu.cmd_len > 0))
     do_cmd_buffer(gpu.cmd_buffer, gpu.cmd_len);
   gpu.cmd_len = 0;
@@ -50,7 +54,6 @@ static noinline void do_cmd_reset(void)
 static noinline void do_reset(void)
 {
   unsigned int i;
-
   do_cmd_reset();
 
   memset(gpu.regs, 0, sizeof(gpu.regs));
@@ -126,11 +129,11 @@ static noinline void get_gpu_info(uint32_t data)
     case 0x02:
     case 0x03:
     case 0x04:
-    case 0x05:
       gpu.gp0 = gpu.ex_regs[data & 7] & 0xfffff;
       break;
+    case 0x05:
     case 0x06:
-      gpu.gp0 = gpu.ex_regs[5] & 0xfffff;
+      gpu.gp0 = gpu.ex_regs[5] & 0x3fffff;
       break;
     case 0x07:
       gpu.gp0 = 2;
@@ -142,13 +145,30 @@ static noinline void get_gpu_info(uint32_t data)
 }
 
 // double, for overdraw guard
-#define VRAM_SIZE (1024 * 512 * 2 * 2)
+#define VRAM_SIZE ((1024 * 512 * 2 * 2) + 4096)
+
+//  Minimum 16-byte VRAM alignment needed by gpu_unai's pixel-skipping
+//  renderer/downscaler it uses in high res modes:
+#ifdef GCW_ZERO
+       // On GCW platform (MIPS), align to 8192 bytes (1 TLB entry) to reduce # of
+       // fills. (Will change this value if it ever gets large page support)
+       #define VRAM_ALIGN 8192
+#else
+       #define VRAM_ALIGN 16
+#endif
+
+// vram ptr received from mmap/malloc/alloc (will deallocate using this)
+static uint16_t *vram_ptr_orig = NULL;
 
+#ifdef GPULIB_USE_MMAP
 static int map_vram(void)
 {
-  gpu.vram = gpu.mmap(VRAM_SIZE);
+  gpu.vram = vram_ptr_orig = gpu.mmap(VRAM_SIZE + (VRAM_ALIGN-1));
   if (gpu.vram != NULL) {
-    gpu.vram += 4096 / 2;
+       // 4kb guard in front
+    gpu.vram += (4096 / 2);
+       // Align
+       gpu.vram = (uint16_t*)(((uintptr_t)gpu.vram + (VRAM_ALIGN-1)) & ~(VRAM_ALIGN-1));
     return 0;
   }
   else {
@@ -156,9 +176,54 @@ static int map_vram(void)
     return -1;
   }
 }
+#else
+static int map_vram(void)
+{
+  gpu.vram = vram_ptr_orig = (uint16_t*)calloc(VRAM_SIZE + (VRAM_ALIGN-1), 1);
+  if (gpu.vram != NULL) {
+       // 4kb guard in front
+    gpu.vram += (4096 / 2);
+       // Align
+       gpu.vram = (uint16_t*)(((uintptr_t)gpu.vram + (VRAM_ALIGN-1)) & ~(VRAM_ALIGN-1));
+    return 0;
+  } else {
+    fprintf(stderr, "could not allocate vram, expect crashes\n");
+    return -1;
+  }
+}
+
+static int allocate_vram(void)
+{
+  gpu.vram = vram_ptr_orig = (uint16_t*)calloc(VRAM_SIZE + (VRAM_ALIGN-1), 1);
+  if (gpu.vram != NULL) {
+       // 4kb guard in front
+    gpu.vram += (4096 / 2);
+       // Align
+       gpu.vram = (uint16_t*)(((uintptr_t)gpu.vram + (VRAM_ALIGN-1)) & ~(VRAM_ALIGN-1));
+    return 0;
+  } else {
+    fprintf(stderr, "could not allocate vram, expect crashes\n");
+    return -1;
+  }
+}
+#endif
 
 long GPUinit(void)
 {
+#ifndef GPULIB_USE_MMAP
+  if (gpu.vram == NULL) {
+    if (allocate_vram() != 0) {
+      printf("ERROR: could not allocate VRAM, exiting..\n");
+         exit(1);
+       }
+  }
+#endif
+
+  //extern uint32_t hSyncCount;         // in psxcounters.cpp
+  //extern uint32_t frame_counter;      // in psxcounters.cpp
+  //gpu.state.hcnt = &hSyncCount;
+  //gpu.state.frame_count = &frame_counter;
+
   int ret;
   ret  = vout_init();
   ret |= renderer_init();
@@ -169,10 +234,10 @@ long GPUinit(void)
   gpu.cmd_len = 0;
   do_reset();
 
-  if (gpu.mmap != NULL) {
+  /*if (gpu.mmap != NULL) {
     if (map_vram() != 0)
       ret = -1;
-  }
+  }*/
   return ret;
 }
 
@@ -182,17 +247,24 @@ long GPUshutdown(void)
 
   renderer_finish();
   ret = vout_finish();
-  if (gpu.vram != NULL) {
-    gpu.vram -= 4096 / 2;
-    gpu.munmap(gpu.vram, VRAM_SIZE);
+
+  if (vram_ptr_orig != NULL) {
+#ifdef GPULIB_USE_MMAP
+    gpu.munmap(vram_ptr_orig, VRAM_SIZE);
+#else
+    free(vram_ptr_orig);
+#endif
   }
-  gpu.vram = NULL;
+  vram_ptr_orig = gpu.vram = NULL;
 
   return ret;
 }
 
 void GPUwriteStatus(uint32_t data)
 {
+       //senquack TODO: Would it be wise to add cmd buffer flush here, since
+       // status settings can affect commands already in buffer?
+
   static const short hres[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
   static const short vres[4] = { 240, 480, 256, 480 };
   uint32_t cmd = data >> 24;
@@ -299,6 +371,8 @@ static int do_vram_io(uint32_t *data, int count, int is_read)
   int l;
   count *= 2; // operate in 16bpp pixels
 
+  renderer_sync();
+
   if (gpu.dma.offset) {
     l = w - gpu.dma.offset;
     if (count < l)
@@ -387,7 +461,7 @@ static noinline int do_cmd_list_skip(uint32_t *data, int count, int *last_cmd)
 
     switch (cmd) {
       case 0x02:
-        if ((list[2] & 0x3ff) > gpu.screen.w || ((list[2] >> 16) & 0x1ff) > gpu.screen.h)
+        if ((int)(list[2] & 0x3ff) > gpu.screen.w || (int)((list[2] >> 16) & 0x1ff) > gpu.screen.h)
           // clearing something large, don't skip
           do_cmd_list(list, 3, &dummy);
         else
@@ -643,12 +717,15 @@ long GPUfreeze(uint32_t type, struct GPUFreeze *freeze)
     case 1: // save
       if (gpu.cmd_len > 0)
         flush_cmd_buffer();
+
+      renderer_sync();
       memcpy(freeze->psxVRam, gpu.vram, 1024 * 512 * 2);
       memcpy(freeze->ulControl, gpu.regs, sizeof(gpu.regs));
       memcpy(freeze->ulControl + 0xe0, gpu.ex_regs, sizeof(gpu.ex_regs));
       freeze->ulStatus = gpu.status.reg;
       break;
     case 0: // load
+      renderer_sync();
       memcpy(gpu.vram, freeze->psxVRam, 1024 * 512 * 2);
       memcpy(gpu.regs, freeze->ulControl, sizeof(gpu.regs));
       memcpy(gpu.ex_regs, freeze->ulControl + 0xe0, sizeof(gpu.ex_regs));
@@ -681,6 +758,8 @@ void GPUupdateLace(void)
     return;
   }
 
+  renderer_notify_update_lace(0);
+
   if (!gpu.state.fb_dirty)
     return;
 
@@ -696,6 +775,7 @@ void GPUupdateLace(void)
   vout_update();
   gpu.state.fb_dirty = 0;
   gpu.state.blanked = 0;
+  renderer_notify_update_lace(1);
 }
 
 void GPUvBlank(int is_vblank, int lcf)
@@ -732,6 +812,7 @@ void GPUrearmedCallbacks(const struct rearmed_cbs *cbs)
   gpu.state.allow_interlace = cbs->gpu_neon.allow_interlace;
   gpu.state.enhancement_enable = cbs->gpu_neon.enhancement_enable;
 
+  gpu.useDithering = cbs->gpu_neon.allow_dithering;
   gpu.mmap = cbs->mmap;
   gpu.munmap = cbs->munmap;
 
index d11f991..64d2eec 100644 (file)
@@ -8,6 +8,9 @@
  * See the COPYING file in the top-level directory.
  */
 
+#ifndef __GPULIB_GPU_H__
+#define __GPULIB_GPU_H__
+
 #include <stdint.h>
 
 #ifdef __cplusplus
@@ -68,6 +71,8 @@ struct psx_gpu {
     uint32_t blanked:1;
     uint32_t enhancement_enable:1;
     uint32_t enhancement_active:1;
+    uint32_t downscale_enable:1;
+    uint32_t downscale_active:1;
     uint32_t *frame_count;
     uint32_t *hcnt; /* hsync count */
     struct {
@@ -88,8 +93,12 @@ struct psx_gpu {
     uint32_t last_flip_frame;
     uint32_t pending_fill[3];
   } frameskip;
+  uint32_t scratch_ex_regs[8]; // for threaded rendering
+  int useDithering:1; /* 0 - off , 1 - on */
   uint16_t *(*get_enhancement_bufer)
     (int *x, int *y, int *w, int *h, int *vram_h);
+  uint16_t *(*get_downscale_buffer)
+    (int *x, int *y, int *w, int *h, int *vram_h);
   void *(*mmap)(unsigned int size);
   void  (*munmap)(void *ptr, unsigned int size);
 };
@@ -110,6 +119,8 @@ void renderer_flush_queues(void);
 void renderer_set_interlace(int enable, int is_odd);
 void renderer_set_config(const struct rearmed_cbs *config);
 void renderer_notify_res_change(void);
+void renderer_notify_update_lace(int updated);
+void renderer_sync(void);
 
 int  vout_init(void);
 int  vout_finish(void);
@@ -139,3 +150,5 @@ void GPUrearmedCallbacks(const struct rearmed_cbs *cbs_);
 #ifdef __cplusplus
 }
 #endif
+
+#endif /* __GPULIB_GPU_H__ */
diff --git a/plugins/gpulib/gpulib_thread_if.c b/plugins/gpulib/gpulib_thread_if.c
new file mode 100644 (file)
index 0000000..1583783
--- /dev/null
@@ -0,0 +1,497 @@
+/**************************************************************************
+*   Copyright (C) 2020 The RetroArch Team                                 *
+*                                                                         *
+*   This program is free software; you can redistribute it and/or modify  *
+*   it under the terms of the GNU General Public License as published by  *
+*   the Free Software Foundation; either version 2 of the License, or     *
+*   (at your option) any later version.                                   *
+*                                                                         *
+*   This program is distributed in the hope that it will be useful,       *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+*   GNU General Public License for more details.                          *
+*                                                                         *
+*   You should have received a copy of the GNU General Public License     *
+*   along with this program; if not, write to the                         *
+*   Free Software Foundation, Inc.,                                       *
+*   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
+***************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include "../gpulib/gpu.h"
+#include "../../frontend/plugin_lib.h"
+#include "gpulib_thread_if.h"
+
+#define FALSE 0
+#define TRUE 1
+#define BOOL unsigned short
+
+typedef struct {
+       uint32_t *cmd_list;
+       int count;
+       int last_cmd;
+} video_thread_cmd;
+
+#define QUEUE_SIZE 0x2000
+
+typedef struct {
+       size_t start;
+       size_t end;
+       size_t used;
+       video_thread_cmd queue[QUEUE_SIZE];
+} video_thread_queue;
+
+typedef struct {
+       pthread_t thread;
+       pthread_mutex_t queue_lock;
+       pthread_cond_t cond_msg_avail;
+       pthread_cond_t cond_msg_done;
+       pthread_cond_t cond_queue_empty;
+       video_thread_queue *queue;
+       video_thread_queue *bg_queue;
+       BOOL running;
+} video_thread_state;
+
+static video_thread_state thread;
+static video_thread_queue queues[2];
+static int thread_rendering;
+static BOOL hold_cmds;
+static BOOL needs_display;
+static BOOL flushed;
+
+extern const unsigned char cmd_lengths[];
+
+static void *video_thread_main(void *arg) {
+       video_thread_state *thread = (video_thread_state *)arg;
+       video_thread_cmd *cmd;
+       int i;
+
+#ifdef _3DS
+       static int processed = 0;
+#endif /* _3DS */
+
+       while(1) {
+               int result, last_cmd, start, end;
+               video_thread_queue *queue;
+               pthread_mutex_lock(&thread->queue_lock);
+
+               while (!thread->queue->used && thread->running) {
+                       pthread_cond_wait(&thread->cond_msg_avail, &thread->queue_lock);
+               }
+
+               if (!thread->running) {
+                       pthread_mutex_unlock(&thread->queue_lock);
+                       break;
+               }
+
+               queue = thread->queue;
+               start = queue->start;
+               end = queue->end > queue->start ? queue->end : QUEUE_SIZE;
+               queue->start = end % QUEUE_SIZE;
+               pthread_mutex_unlock(&thread->queue_lock);
+
+               for (i = start; i < end; i++) {
+                       cmd = &queue->queue[i];
+                       result = real_do_cmd_list(cmd->cmd_list, cmd->count, &last_cmd);
+
+                       if (result != cmd->count) {
+                               fprintf(stderr, "Processed wrong cmd count: expected %d, got %d\n", cmd->count, result);
+                       }
+
+#ifdef _3DS
+                       /* Periodically yield so as not to starve other threads */
+                       processed += cmd->count;
+                       if (processed >= 512) {
+                               svcSleepThread(1);
+                               processed %= 512;
+                       }
+#endif /* _3DS */
+               }
+
+               pthread_mutex_lock(&thread->queue_lock);
+               queue->used -= (end - start);
+
+               if (!queue->used)
+                       pthread_cond_signal(&thread->cond_queue_empty);
+
+               pthread_cond_signal(&thread->cond_msg_done);
+               pthread_mutex_unlock(&thread->queue_lock);
+       }
+
+       return 0;
+}
+
+static void cmd_queue_swap() {
+       video_thread_queue *tmp;
+       if (!thread.bg_queue->used) return;
+
+       pthread_mutex_lock(&thread.queue_lock);
+       if (!thread.queue->used) {
+               tmp = thread.queue;
+               thread.queue = thread.bg_queue;
+               thread.bg_queue = tmp;
+               pthread_cond_signal(&thread.cond_msg_avail);
+       }
+       pthread_mutex_unlock(&thread.queue_lock);
+}
+
+/* Waits for the main queue to completely finish. */
+void renderer_wait() {
+       if (!thread.running) return;
+
+       /* Not completely safe, but should be fine since the render thread
+        * only decreases used, and we check again inside the lock. */
+       if (!thread.queue->used) {
+               return;
+       }
+
+       pthread_mutex_lock(&thread.queue_lock);
+
+       while (thread.queue->used) {
+               pthread_cond_wait(&thread.cond_queue_empty, &thread.queue_lock);
+       }
+
+       pthread_mutex_unlock(&thread.queue_lock);
+}
+
+/* Waits for all GPU commands in both queues to finish, bringing VRAM
+ * completely up-to-date. */
+void renderer_sync(void) {
+       if (!thread.running) return;
+
+       /* Not completely safe, but should be fine since the render thread
+        * only decreases used, and we check again inside the lock. */
+       if (!thread.queue->used && !thread.bg_queue->used) {
+               return;
+       }
+
+       if (thread.bg_queue->used) {
+               /* When we flush the background queue, the vblank handler can't
+                * know that we had a frame pending, and we delay rendering too
+                * long. Force it. */
+               flushed = TRUE;
+       }
+
+       /* Flush both queues. This is necessary because gpulib could be
+        * trying to process a DMA write that a command in the queue should
+        * run beforehand. For example, Xenogears sprites write a black
+        * rectangle over the to-be-DMA'd spot in VRAM -- if this write
+        * happens after the DMA, it will clear the DMA, resulting in
+        * flickering sprites. We need to be totally up-to-date. This may
+        * drop a frame. */
+       renderer_wait();
+       cmd_queue_swap();
+       hold_cmds = FALSE;
+       renderer_wait();
+}
+
+static void video_thread_stop() {
+       int i;
+       renderer_sync();
+
+       if (thread.running) {
+               thread.running = FALSE;
+               pthread_cond_signal(&thread.cond_msg_avail);
+               pthread_join(thread.thread, NULL);
+       }
+
+       pthread_mutex_destroy(&thread.queue_lock);
+       pthread_cond_destroy(&thread.cond_msg_avail);
+       pthread_cond_destroy(&thread.cond_msg_done);
+       pthread_cond_destroy(&thread.cond_queue_empty);
+
+       for (i = 0; i < QUEUE_SIZE; i++) {
+               video_thread_cmd *cmd = &thread.queue->queue[i];
+               free(cmd->cmd_list);
+               cmd->cmd_list = NULL;
+       }
+
+       for (i = 0; i < QUEUE_SIZE; i++) {
+               video_thread_cmd *cmd = &thread.bg_queue->queue[i];
+               free(cmd->cmd_list);
+               cmd->cmd_list = NULL;
+       }
+}
+
+static void video_thread_start() {
+       fprintf(stdout, "Starting render thread\n");
+
+       if (pthread_cond_init(&thread.cond_msg_avail, NULL) ||
+                       pthread_cond_init(&thread.cond_msg_done, NULL) ||
+                       pthread_cond_init(&thread.cond_queue_empty, NULL) ||
+                       pthread_mutex_init(&thread.queue_lock, NULL) ||
+                       pthread_create(&thread.thread, NULL, video_thread_main, &thread)) {
+               goto error;
+       }
+
+       thread.queue = &queues[0];
+       thread.bg_queue = &queues[1];
+
+       thread.running = TRUE;
+       return;
+
+ error:
+       fprintf(stderr,"Failed to start rendering thread\n");
+       video_thread_stop();
+}
+
+static void video_thread_queue_cmd(uint32_t *list, int count, int last_cmd) {
+       video_thread_cmd *cmd;
+       uint32_t *cmd_list;
+       video_thread_queue *queue;
+       BOOL lock;
+
+       cmd_list = (uint32_t *)calloc(count, sizeof(uint32_t));
+
+       if (!cmd_list) {
+               /* Out of memory, disable the thread and run sync from now on */
+               fprintf(stderr,"Failed to allocate render thread command list, stopping thread\n");
+               video_thread_stop();
+       }
+
+       memcpy(cmd_list, list, count * sizeof(uint32_t));
+
+       if (hold_cmds && thread.bg_queue->used >= QUEUE_SIZE) {
+               /* If the bg queue is full, do a full sync to empty both queues
+                * and clear space. This should be very rare, I've only seen it in
+                * Tekken 3 post-battle-replay. */
+               renderer_sync();
+       }
+
+       if (hold_cmds) {
+               queue = thread.bg_queue;
+               lock = FALSE;
+       } else {
+               queue = thread.queue;
+               lock = TRUE;
+       }
+
+       if (lock) {
+               pthread_mutex_lock(&thread.queue_lock);
+
+               while (queue->used >= QUEUE_SIZE) {
+                       pthread_cond_wait(&thread.cond_msg_done, &thread.queue_lock);
+               }
+       }
+
+       cmd = &queue->queue[queue->end];
+       free(cmd->cmd_list);
+       cmd->cmd_list = cmd_list;
+       cmd->count = count;
+       cmd->last_cmd = last_cmd;
+       queue->end = (queue->end + 1) % QUEUE_SIZE;
+       queue->used++;
+
+       if (lock) {
+               pthread_cond_signal(&thread.cond_msg_avail);
+               pthread_mutex_unlock(&thread.queue_lock);
+       }
+}
+
+/* Slice off just the part of the list that can be handled async, and
+ * update ex_regs. */
+static int scan_cmd_list(uint32_t *data, int count, int *last_cmd)
+{
+       int cmd = 0, pos = 0, len, v;
+
+       while (pos < count) {
+               uint32_t *list = data + pos;
+               cmd = list[0] >> 24;
+               len = 1 + cmd_lengths[cmd];
+
+               switch (cmd) {
+                       case 0x02:
+                               break;
+                       case 0x24 ... 0x27:
+                       case 0x2c ... 0x2f:
+                       case 0x34 ... 0x37:
+                       case 0x3c ... 0x3f:
+                               gpu.ex_regs[1] &= ~0x1ff;
+                               gpu.ex_regs[1] |= list[4 + ((cmd >> 4) & 1)] & 0x1ff;
+                               break;
+                       case 0x48 ... 0x4F:
+                               for (v = 3; pos + v < count; v++)
+                               {
+                                       if ((list[v] & 0xf000f000) == 0x50005000)
+                                               break;
+                               }
+                               len += v - 3;
+                               break;
+                       case 0x58 ... 0x5F:
+                               for (v = 4; pos + v < count; v += 2)
+                               {
+                                       if ((list[v] & 0xf000f000) == 0x50005000)
+                                               break;
+                               }
+                               len += v - 4;
+                               break;
+                       default:
+                               if ((cmd & 0xf8) == 0xe0)
+                                       gpu.ex_regs[cmd & 7] = list[0];
+                               break;
+               }
+
+               if (pos + len > count) {
+                       cmd = -1;
+                       break; /* incomplete cmd */
+               }
+               if (0xa0 <= cmd && cmd <= 0xdf)
+                       break; /* image i/o */
+
+               pos += len;
+       }
+
+       *last_cmd = cmd;
+       return pos;
+}
+
+int do_cmd_list(uint32_t *list, int count, int *last_cmd) {
+       int pos = 0;
+
+       if (thread.running) {
+               pos = scan_cmd_list(list, count, last_cmd);
+               video_thread_queue_cmd(list, pos, *last_cmd);
+       } else {
+               pos = real_do_cmd_list(list, count, last_cmd);
+               memcpy(gpu.ex_regs, gpu.scratch_ex_regs, sizeof(gpu.ex_regs));
+       }
+       return pos;
+}
+
+int renderer_init(void) {
+       if (thread_rendering) {
+               video_thread_start();
+       }
+       return real_renderer_init();
+}
+
+void renderer_finish(void) {
+       real_renderer_finish();
+
+       if (thread_rendering && thread.running) {
+               video_thread_stop();
+       }
+}
+
+void renderer_sync_ecmds(uint32_t * ecmds) {
+       if (thread.running) {
+               int dummy;
+               do_cmd_list(&ecmds[1], 6, &dummy);
+       } else {
+               real_renderer_sync_ecmds(ecmds);
+       }
+}
+
+void renderer_update_caches(int x, int y, int w, int h) {
+       renderer_sync();
+       real_renderer_update_caches(x, y, w, h);
+}
+
+void renderer_flush_queues(void) {
+       /* Called during DMA and updateLace. We want to sync if it's DMA,
+        * but not if it's updateLace. Instead of syncing here, there's a
+        * renderer_sync call during DMA. */
+       real_renderer_flush_queues();
+}
+
+/*
+ * Normally all GPU commands are processed before rendering the
+ * frame. For games that naturally run < 50/60fps, this is unnecessary
+ * -- it forces the game to render as if it was 60fps and leaves the
+ * GPU idle half the time on a 30fps game, for example.
+ *
+ * Allowing the renderer to wait until a frame is done before
+ * rendering it would give it double, triple, or quadruple the amount
+ * of time to finish before we have to wait for it.
+ *
+ * We can use a heuristic to figure out when to force a render.
+ *
+ * - If a frame isn't done when we're asked to render, wait for it and
+ *   put future GPU commands in a separate buffer (for the next frame)
+ *
+ * - If the frame is done, and had no future GPU commands, render it.
+ *
+ * - If we do have future GPU commands, it meant the frame took too
+ *   long to render and there's another frame waiting. Stop until the
+ *   first frame finishes, render it, and start processing the next
+ *   one.
+ *
+ * This may possibly add a frame or two of latency that shouldn't be
+ * different than the real device. It may skip rendering a frame
+ * entirely if a VRAM transfer happens while a frame is waiting, or in
+ * games that natively run at 60fps if frames are coming in too
+ * quickly to process. Depending on how the game treats "60fps," this
+ * may not be noticeable.
+ */
+void renderer_notify_update_lace(int updated) {
+       if (!thread.running) return;
+
+       if (thread_rendering == THREAD_RENDERING_SYNC) {
+               renderer_sync();
+               return;
+       }
+
+       if (updated) {
+               cmd_queue_swap();
+               return;
+       }
+
+       pthread_mutex_lock(&thread.queue_lock);
+       if (thread.bg_queue->used || flushed) {
+               /* We have commands for a future frame to run. Force a wait until
+                * the current frame is finished, and start processing the next
+                * frame after it's drawn (see the `updated` clause above). */
+               pthread_mutex_unlock(&thread.queue_lock);
+               renderer_wait();
+               pthread_mutex_lock(&thread.queue_lock);
+
+               /* We are no longer holding commands back, so the next frame may
+                * get mixed into the following frame. This is usually fine, but can
+                * result in frameskip-like effects for 60fps games. */
+               flushed = FALSE;
+               hold_cmds = FALSE;
+               needs_display = TRUE;
+               gpu.state.fb_dirty = TRUE;
+       } else if (thread.queue->used) {
+               /* We are still drawing during a vblank. Cut off the current frame
+                * by sending new commands to the background queue and skip
+                * drawing our partly rendered frame to the display. */
+               hold_cmds = TRUE;
+               needs_display = TRUE;
+               gpu.state.fb_dirty = FALSE;
+       } else if (needs_display && !thread.queue->used) {
+               /* We have processed all commands in the queue, render the
+                * buffer. We know we have something to render, because
+                * needs_display is TRUE. */
+               hold_cmds = FALSE;
+               needs_display = FALSE;
+               gpu.state.fb_dirty = TRUE;
+       } else {
+               /* Everything went normally, so do the normal thing. */
+       }
+
+       pthread_mutex_unlock(&thread.queue_lock);
+}
+
+void renderer_set_interlace(int enable, int is_odd) {
+       real_renderer_set_interlace(enable, is_odd);
+}
+
+void renderer_set_config(const struct rearmed_cbs *cbs) {
+       renderer_sync();
+       thread_rendering = cbs->thread_rendering;
+       if (!thread.running && thread_rendering != THREAD_RENDERING_OFF) {
+               video_thread_start();
+       } else if (thread.running && thread_rendering == THREAD_RENDERING_OFF) {
+               video_thread_stop();
+       }
+       real_renderer_set_config(cbs);
+}
+
+void renderer_notify_res_change(void) {
+       renderer_sync();
+       real_renderer_notify_res_change();
+}
diff --git a/plugins/gpulib/gpulib_thread_if.h b/plugins/gpulib/gpulib_thread_if.h
new file mode 100644 (file)
index 0000000..b1ea97f
--- /dev/null
@@ -0,0 +1,41 @@
+/**************************************************************************
+*   Copyright (C) 2020 The RetroArch Team                                 *
+*                                                                         *
+*   This program is free software; you can redistribute it and/or modify  *
+*   it under the terms of the GNU General Public License as published by  *
+*   the Free Software Foundation; either version 2 of the License, or     *
+*   (at your option) any later version.                                   *
+*                                                                         *
+*   This program is distributed in the hope that it will be useful,       *
+*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+*   GNU General Public License for more details.                          *
+*                                                                         *
+*   You should have received a copy of the GNU General Public License     *
+*   along with this program; if not, write to the                         *
+*   Free Software Foundation, Inc.,                                       *
+*   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
+***************************************************************************/
+
+#ifndef __GPULIB_THREAD_H__
+#define __GPULIB_THREAD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int  real_do_cmd_list(uint32_t *list, int count, int *last_cmd);
+int  real_renderer_init(void);
+void real_renderer_finish(void);
+void real_renderer_sync_ecmds(uint32_t * ecmds);
+void real_renderer_update_caches(int x, int y, int w, int h);
+void real_renderer_flush_queues(void);
+void real_renderer_set_interlace(int enable, int is_odd);
+void real_renderer_set_config(const struct rearmed_cbs *config);
+void real_renderer_notify_res_change(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GPULIB_THREAD_H__ */
index a9437cb..075e3c3 100644 (file)
@@ -43,6 +43,15 @@ static void check_mode_change(int force)
     h_out *= 2;
   }
 
+  gpu.state.downscale_active =
+    gpu.get_downscale_buffer != NULL && gpu.state.downscale_enable
+    && (w >= 512 || h >= 256);
+
+  if (gpu.state.downscale_active) {
+    w_out = w < 512 ? w : 320;
+    h_out = h < 256 ? h : h / 2;
+  }
+
   // width|rgb24 change?
   if (force || (gpu.status.reg ^ old_status) & ((7<<16)|(1<<21)) || h != old_h)
   {
@@ -69,6 +78,9 @@ void vout_update(void)
   if (gpu.state.enhancement_active)
     vram = gpu.get_enhancement_bufer(&x, &y, &w, &h, &vram_h);
 
+  if (gpu.state.downscale_active)
+    vram = gpu.get_downscale_buffer(&x, &y, &w, &h, &vram_h);
+
   if (y + h > vram_h) {
     if (y + h - vram_h > h / 2) {
       // wrap
index 52128b7..2e0b892 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef __SPUNULL_REGISTER_H__\r
+#define __SPUNULL_REGISTER_H__\r
+\r
 #define H_SPUirqAddr     0x0da4\r
 #define H_SPUaddr        0x0da6\r
 #define H_SPUdata        0x0da8\r
 #define H_SPU_ADSRLevel22  0x0d68\r
 #define H_SPU_ADSRLevel23  0x0d78\r
 \r
+#endif /* __SPUNULL_REGISTER_H__ */\r